From 03c120ceb196f276c34ed2ced761b2f97d48724d Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Wed, 6 Dec 2023 12:37:22 +0000 Subject: [PATCH 001/241] Create file --- tests/unit/pmodel/test_subdaily.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/unit/pmodel/test_subdaily.py diff --git a/tests/unit/pmodel/test_subdaily.py b/tests/unit/pmodel/test_subdaily.py new file mode 100644 index 00000000..12c37f14 --- /dev/null +++ b/tests/unit/pmodel/test_subdaily.py @@ -0,0 +1 @@ +"""TODO: Add tests here.""" From 88051f0cc46efb17b195b667b9faec749ed98e02 Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Mon, 15 Jan 2024 13:18:49 +0000 Subject: [PATCH 002/241] Added first draft of unit test for calc_optimal_chi submodule --- tests/unit/pmodel/test_calc_optimal_chi.py | 113 +++++++++++++++++++++ tests/unit/pmodel/test_subdaily.py | 1 - 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 tests/unit/pmodel/test_calc_optimal_chi.py delete mode 100644 tests/unit/pmodel/test_subdaily.py diff --git a/tests/unit/pmodel/test_calc_optimal_chi.py b/tests/unit/pmodel/test_calc_optimal_chi.py new file mode 100644 index 00000000..c60d4acb --- /dev/null +++ b/tests/unit/pmodel/test_calc_optimal_chi.py @@ -0,0 +1,113 @@ +"""Testing CalcOptimal submodule.""" + +import numpy as np +import pytest + +from pyrealm.constants import PModelConst +from pyrealm.pmodel import CalcOptimalChi, PModelEnvironment + + +@pytest.fixture +def rootzonestress(): + """Return the root zone stress.""" + return np.array([1]) + # return np.array([0]) + + +@pytest.fixture +def const(): + """Return the PModelConst.""" + return PModelConst() + + +@pytest.mark.parametrize( + argnames=["pmodelenv_args", "pmodel_args", "expected"], + argvalues=[ + ( # Single site, C3 prentice14 + dict(tc=20, patm=101325, co2=400, vpd=1000), + dict(method_optchi="prentice14"), + dict( + # beta=24.97251, + chi=0.69435, + mc=0.33408, + mj=0.7123, + mjoc=2.13211, + ), + ), + ( # Single site, C3 lavergne20 + dict(tc=20, patm=101325, co2=400, vpd=1000, theta=0.5), + dict(method_optchi="lavergne20_c3"), + dict( + beta=224.75255, + chi=0.73663, + mc=0.34911, + mj=0.7258, + mjoc=2.07901, + ), + ), + ( # Single site, C4 + dict(tc=20, patm=101325, co2=400, vpd=1000), + dict(method_optchi="c4"), + dict( + # beta=21.481, + chi=0.44967, + mc=1.0, + mj=1.0, + # mjoc=-19.619, + ), + ), + # ( # Single site, C4 no gamma + # dict(tc=20, patm=101325, co2=400, vpd=1000), + # dict(method_optchi="c4_no_gamma"), + # dict( + # # beta=21.481, + # chi=0.3919, + # mc=0.3, + # mj=1.0, + # # mjoc=-19.619, + # ), + # ), + ( # Single site, C4 lavergne20 + dict(tc=20, patm=101325, co2=400, vpd=1000, theta=0.5), + dict(method_optchi="lavergne20_c4"), + dict( + beta=24.97251, + chi=0.44432, + mc=0.28091, + mj=1, + mjoc=3.55989, + ), + ), + # ( # Single site, C3 prentice14 with all-zero inputs + # dict(tc=20, patm=101325, co2=400, vpd=1000), + # dict(method_optchi="prentice14"), + # dict( + # # beta=24.97251, + # chi=0, + # mc=0, + # mj=0, + # mjoc=0, + # ), + # ), + # ( # Single site, C3 prentice14 with all-zero inputs + # dict(tc=20, patm=101325, co2=400, vpd=1000), + # dict(method_optchi="prentice14"), + # dict( + # # beta=24.97251, + # chi=np.nan, + # mc=np.nan, + # mj=np.nan, + # mjoc=np.nan, + # ), + # ), + ], +) +def test_calcoptimalchi(pmodelenv_args, pmodel_args, expected, rootzonestress, const): + """Test CalcOptimalChi.""" + env = PModelEnvironment(**pmodelenv_args) + calc_optimal_chi = CalcOptimalChi( + env, rootzonestress, pmodel_args["method_optchi"], const + ) + + for key in expected: + assert np.allclose(getattr(calc_optimal_chi, key), expected[key], atol=0.0001) diff --git a/tests/unit/pmodel/test_subdaily.py b/tests/unit/pmodel/test_subdaily.py deleted file mode 100644 index 12c37f14..00000000 --- a/tests/unit/pmodel/test_subdaily.py +++ /dev/null @@ -1 +0,0 @@ -"""TODO: Add tests here.""" From 38f2620d8a12bf3a7fc2ecb3cf5b395cd7e8610d Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Wed, 6 Dec 2023 12:37:22 +0000 Subject: [PATCH 003/241] Create file --- tests/unit/pmodel/test_subdaily.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/unit/pmodel/test_subdaily.py diff --git a/tests/unit/pmodel/test_subdaily.py b/tests/unit/pmodel/test_subdaily.py new file mode 100644 index 00000000..12c37f14 --- /dev/null +++ b/tests/unit/pmodel/test_subdaily.py @@ -0,0 +1 @@ +"""TODO: Add tests here.""" From 78ae040cdb77c73bf3ee2aeb5d5cdee038be37ee Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Mon, 15 Jan 2024 13:18:49 +0000 Subject: [PATCH 004/241] Added first draft of unit test for calc_optimal_chi submodule --- tests/unit/pmodel/test_subdaily.py | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tests/unit/pmodel/test_subdaily.py diff --git a/tests/unit/pmodel/test_subdaily.py b/tests/unit/pmodel/test_subdaily.py deleted file mode 100644 index 12c37f14..00000000 --- a/tests/unit/pmodel/test_subdaily.py +++ /dev/null @@ -1 +0,0 @@ -"""TODO: Add tests here.""" From 7f4b0ca879cdcde9cca6580a9106bad5af91d1e0 Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Thu, 15 Feb 2024 13:35:45 +0000 Subject: [PATCH 005/241] Added updated test for new OptimalChi --- tests/unit/pmodel/test_calc_optimal_chi.py | 156 ++++++++------------- 1 file changed, 58 insertions(+), 98 deletions(-) diff --git a/tests/unit/pmodel/test_calc_optimal_chi.py b/tests/unit/pmodel/test_calc_optimal_chi.py index c60d4acb..5005ce5f 100644 --- a/tests/unit/pmodel/test_calc_optimal_chi.py +++ b/tests/unit/pmodel/test_calc_optimal_chi.py @@ -1,113 +1,73 @@ """Testing CalcOptimal submodule.""" + import numpy as np import pytest -from pyrealm.constants import PModelConst -from pyrealm.pmodel import CalcOptimalChi, PModelEnvironment +from pyrealm.pmodel.optimal_chi import ( + OptimalChiC4, + OptimalChiC4NoGamma, + OptimalChiC4RootzoneStress, + OptimalChiLavergne20C3, + OptimalChiLavergne20C4, + OptimalChiPrentice14, + OptimalChiPrentice14RootzoneStress, +) +from pyrealm.pmodel.pmodel_environment import PModelEnvironment @pytest.fixture -def rootzonestress(): - """Return the root zone stress.""" - return np.array([1]) - # return np.array([0]) +def photo_env(): + """Photosynthesis Environment setup.""" + return PModelEnvironment( + tc=np.array([20]), + vpd=np.array([1000]), + co2=np.array([400]), + patm=np.array([101325.0]), + rootzonestress=np.array([1]), + theta=np.array([0.5]), + ) -@pytest.fixture -def const(): - """Return the PModelConst.""" - return PModelConst() +@pytest.mark.parametrize( + """optimal_chi_class""", + [ + OptimalChiPrentice14, + OptimalChiPrentice14RootzoneStress, + OptimalChiC4, + OptimalChiC4RootzoneStress, + OptimalChiLavergne20C3, + OptimalChiLavergne20C4, + OptimalChiC4NoGamma, + ], +) +def test_set_beta(optimal_chi_class, photo_env): + """Test that beta is set correctly.""" + optimal_chi_instance = optimal_chi_class(env=photo_env) + optimal_chi_instance.set_beta() + # Test that beta attribute is set correctly + assert isinstance(optimal_chi_instance.beta, np.ndarray) @pytest.mark.parametrize( - argnames=["pmodelenv_args", "pmodel_args", "expected"], - argvalues=[ - ( # Single site, C3 prentice14 - dict(tc=20, patm=101325, co2=400, vpd=1000), - dict(method_optchi="prentice14"), - dict( - # beta=24.97251, - chi=0.69435, - mc=0.33408, - mj=0.7123, - mjoc=2.13211, - ), - ), - ( # Single site, C3 lavergne20 - dict(tc=20, patm=101325, co2=400, vpd=1000, theta=0.5), - dict(method_optchi="lavergne20_c3"), - dict( - beta=224.75255, - chi=0.73663, - mc=0.34911, - mj=0.7258, - mjoc=2.07901, - ), - ), - ( # Single site, C4 - dict(tc=20, patm=101325, co2=400, vpd=1000), - dict(method_optchi="c4"), - dict( - # beta=21.481, - chi=0.44967, - mc=1.0, - mj=1.0, - # mjoc=-19.619, - ), - ), - # ( # Single site, C4 no gamma - # dict(tc=20, patm=101325, co2=400, vpd=1000), - # dict(method_optchi="c4_no_gamma"), - # dict( - # # beta=21.481, - # chi=0.3919, - # mc=0.3, - # mj=1.0, - # # mjoc=-19.619, - # ), - # ), - ( # Single site, C4 lavergne20 - dict(tc=20, patm=101325, co2=400, vpd=1000, theta=0.5), - dict(method_optchi="lavergne20_c4"), - dict( - beta=24.97251, - chi=0.44432, - mc=0.28091, - mj=1, - mjoc=3.55989, - ), - ), - # ( # Single site, C3 prentice14 with all-zero inputs - # dict(tc=20, patm=101325, co2=400, vpd=1000), - # dict(method_optchi="prentice14"), - # dict( - # # beta=24.97251, - # chi=0, - # mc=0, - # mj=0, - # mjoc=0, - # ), - # ), - # ( # Single site, C3 prentice14 with all-zero inputs - # dict(tc=20, patm=101325, co2=400, vpd=1000), - # dict(method_optchi="prentice14"), - # dict( - # # beta=24.97251, - # chi=np.nan, - # mc=np.nan, - # mj=np.nan, - # mjoc=np.nan, - # ), - # ), + """optimal_chi_class""", + [ + OptimalChiPrentice14, + OptimalChiPrentice14RootzoneStress, + OptimalChiC4, + OptimalChiC4RootzoneStress, + OptimalChiLavergne20C3, + OptimalChiLavergne20C4, + OptimalChiC4NoGamma, ], ) -def test_calcoptimalchi(pmodelenv_args, pmodel_args, expected, rootzonestress, const): - """Test CalcOptimalChi.""" - env = PModelEnvironment(**pmodelenv_args) - calc_optimal_chi = CalcOptimalChi( - env, rootzonestress, pmodel_args["method_optchi"], const - ) - - for key in expected: - assert np.allclose(getattr(calc_optimal_chi, key), expected[key], atol=0.0001) +def test_estimate_chi(optimal_chi_class, photo_env): + """Test that chi is estimated correctly.""" + optimal_chi_instance = optimal_chi_class(env=photo_env) + optimal_chi_instance.set_beta() + optimal_chi_instance.estimate_chi() + # Test that chi and other related attributes are calculated correctly + assert isinstance(optimal_chi_instance.chi, np.ndarray) + assert isinstance(optimal_chi_instance.mc, np.ndarray) + assert isinstance(optimal_chi_instance.mj, np.ndarray) + assert isinstance(optimal_chi_instance.mjoc, np.ndarray) From 2503d9172a22e70c9f7b066197416796f24aaf81 Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Fri, 16 Feb 2024 15:02:06 +0000 Subject: [PATCH 006/241] Test updated with new testcase --- tests/unit/pmodel/test_optimal_chi.py | 129 ++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 tests/unit/pmodel/test_optimal_chi.py diff --git a/tests/unit/pmodel/test_optimal_chi.py b/tests/unit/pmodel/test_optimal_chi.py new file mode 100644 index 00000000..4c041297 --- /dev/null +++ b/tests/unit/pmodel/test_optimal_chi.py @@ -0,0 +1,129 @@ +"""Testing CalcOptimal submodule.""" + + +import numpy as np +import pytest + +from pyrealm.pmodel.optimal_chi import ( + OptimalChiC4, + OptimalChiC4NoGamma, + OptimalChiC4NoGammaRootzoneStress, + OptimalChiC4RootzoneStress, + OptimalChiLavergne20C3, + OptimalChiLavergne20C4, + OptimalChiPrentice14, + OptimalChiPrentice14RootzoneStress, +) +from pyrealm.pmodel.pmodel_environment import PModelEnvironment + + +@pytest.fixture +def photo_env(): + """Photosynthesis Environment setup.""" + return PModelEnvironment( + tc=np.array([20]), + vpd=np.array([1000]), + co2=np.array([400]), + patm=np.array([101325.0]), + rootzonestress=np.array([1]), + theta=np.array([0.5]), + ) + + +@pytest.mark.parametrize( + """optimal_chi_class""", + [ + OptimalChiPrentice14, + OptimalChiPrentice14RootzoneStress, + OptimalChiC4NoGammaRootzoneStress, + OptimalChiC4, + OptimalChiC4RootzoneStress, + OptimalChiLavergne20C3, + OptimalChiLavergne20C4, + OptimalChiC4NoGamma, + ], +) +def test_set_beta(optimal_chi_class, photo_env): + """Test that beta is set correctly.""" + optimal_chi_instance = optimal_chi_class(env=photo_env) + optimal_chi_instance.set_beta() + # Test that beta attribute is set correctly + assert isinstance(optimal_chi_instance.beta, np.ndarray) + + +@pytest.mark.parametrize( + """optimal_chi_class""", + [ + OptimalChiPrentice14, + OptimalChiPrentice14RootzoneStress, + OptimalChiC4NoGammaRootzoneStress, + OptimalChiC4, + OptimalChiC4RootzoneStress, + OptimalChiLavergne20C3, + OptimalChiLavergne20C4, + OptimalChiC4NoGamma, + ], +) +def test_estimate_chi(optimal_chi_class, photo_env): + """Test that chi is estimated correctly.""" + optimal_chi_instance = optimal_chi_class(env=photo_env) + optimal_chi_instance.set_beta() + optimal_chi_instance.estimate_chi() + # Test that chi and other related attributes are calculated correctly + assert isinstance(optimal_chi_instance.chi, np.ndarray) + assert isinstance(optimal_chi_instance.mc, np.ndarray) + assert isinstance(optimal_chi_instance.mj, np.ndarray) + assert isinstance(optimal_chi_instance.mjoc, np.ndarray) + + +@pytest.mark.parametrize( + argnames=["subclass", "pmodelenv_args", "expected"], + argvalues=[ + ( + OptimalChiPrentice14, + dict(tc=20, patm=101325, co2=400, vpd=1000), + dict(chi=0.69435, mc=0.33408, mj=0.7123, mjoc=2.13211), + ), + ( + OptimalChiPrentice14RootzoneStress, + dict(tc=20, patm=101325, co2=400, vpd=1000, rootzonestress=0.5), + dict(chi=0.62016), + ), + ( + OptimalChiC4, + dict(tc=20, patm=101325, co2=400, vpd=1000), + dict(chi=0.44967, mj=1.0, mjoc=1.0), + ), + ( + OptimalChiC4RootzoneStress, + dict(tc=20, patm=101325, co2=400, vpd=1000, rootzonestress=0.5), + dict(chi=0.37659, mj=1.0, mjoc=1.0), + ), + ( + OptimalChiLavergne20C3, + dict(tc=20, patm=101325, co2=400, vpd=1000, theta=0.5), + dict(beta=224.75255, chi=0.73663, mc=0.34911, mj=0.7258, mjoc=2.07901), + ), + ( + OptimalChiLavergne20C4, + dict(tc=20, patm=101325, co2=400, vpd=1000, theta=0.5), + dict(beta=24.97251, chi=0.44432, mc=0.28091, mj=1.0, mjoc=3.55989), + ), + ( + OptimalChiC4NoGamma, + dict(tc=20, patm=101325, co2=400, vpd=1000), + dict(chi=0.3919, mc=0.25626, mj=1.0), + ), + ( + OptimalChiC4NoGammaRootzoneStress, + dict(tc=20, patm=101325, co2=400, vpd=1000, rootzonestress=0.5), + dict(chi=0.31305, mc=0.21583, mj=1.0), + ), + ], +) +def test_subclasses(pmodelenv_args, subclass, expected): + """Test that subclasses work as expected.""" + env = PModelEnvironment(**pmodelenv_args) + instance = subclass(env) + for key, value in expected.items(): + assert getattr(instance, key) == pytest.approx(value, rel=1e-3) From 4373bf2903de63c484a627c428987b55b4124320 Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Fri, 16 Feb 2024 21:08:09 +0000 Subject: [PATCH 007/241] Added new testcase for Nan value handling --- tests/unit/pmodel/test_optimal_chi.py | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/unit/pmodel/test_optimal_chi.py b/tests/unit/pmodel/test_optimal_chi.py index 4c041297..dda7d38e 100644 --- a/tests/unit/pmodel/test_optimal_chi.py +++ b/tests/unit/pmodel/test_optimal_chi.py @@ -127,3 +127,56 @@ def test_subclasses(pmodelenv_args, subclass, expected): instance = subclass(env) for key, value in expected.items(): assert getattr(instance, key) == pytest.approx(value, rel=1e-3) + + +@pytest.mark.parametrize( + argnames=["subclass", "pmodelenv_args", "expected"], + argvalues=[ + ( + OptimalChiPrentice14, + dict(tc=np.nan, patm=101325, co2=400, vpd=1000), + dict(chi=0.69435, mc=0.33408, mj=0.7123, mjoc=2.13211), + ), + ( + OptimalChiPrentice14RootzoneStress, + dict(tc=20, patm=101325, co2=400, vpd=1000, rootzonestress=np.nan), + dict(chi=0.62016), + ), + ( + OptimalChiC4, + dict(tc=np.nan, patm=101325, co2=400, vpd=1000), + dict(chi=0.44967, mj=1.0, mjoc=1.0), + ), + ( + OptimalChiC4RootzoneStress, + dict(tc=20, patm=101325, co2=400, vpd=1000, rootzonestress=np.nan), + dict(chi=0.37659, mj=1.0, mjoc=1.0), + ), + ( + OptimalChiLavergne20C3, + dict(tc=20, patm=101325, co2=400, vpd=1000, theta=np.nan), + dict(beta=224.75255, chi=0.73663, mc=0.34911, mj=0.7258, mjoc=2.07901), + ), + ( + OptimalChiLavergne20C4, + dict(tc=20, patm=101325, co2=400, vpd=1000, theta=np.nan), + dict(beta=24.97251, chi=0.44432, mc=0.28091, mj=1.0, mjoc=3.55989), + ), + ( + OptimalChiC4NoGamma, + dict(tc=np.nan, patm=101325, co2=400, vpd=1000), + dict(chi=0.3919, mc=0.25626, mj=1.0), + ), + ( + OptimalChiC4NoGammaRootzoneStress, + dict(tc=20, patm=101325, co2=400, vpd=1000, rootzonestress=np.nan), + dict(chi=0.31305, mc=0.21583, mj=1.0), + ), + ], +) +def test_nan_handling(pmodelenv_args, subclass, expected): + """Test that subclasses handles NaNs correctly.""" + env = PModelEnvironment(**pmodelenv_args) + instance = subclass(env) + for key, value in expected.items(): + assert getattr(instance, key) == pytest.approx(value, rel=1e-3) From d07ef13bb00f9b68bae5a2617caa55e9df6165bd Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Wed, 21 Feb 2024 15:41:19 +0000 Subject: [PATCH 008/241] Added test_jmax_limitation and updated test_optimal_chi --- tests/unit/pmodel/test_calc_optimal_chi.py | 73 ---------------------- tests/unit/pmodel/test_jmax_limitation.py | 54 ++++++++++++++++ tests/unit/pmodel/test_optimal_chi.py | 2 +- 3 files changed, 55 insertions(+), 74 deletions(-) delete mode 100644 tests/unit/pmodel/test_calc_optimal_chi.py create mode 100644 tests/unit/pmodel/test_jmax_limitation.py diff --git a/tests/unit/pmodel/test_calc_optimal_chi.py b/tests/unit/pmodel/test_calc_optimal_chi.py deleted file mode 100644 index 5005ce5f..00000000 --- a/tests/unit/pmodel/test_calc_optimal_chi.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Testing CalcOptimal submodule.""" - - -import numpy as np -import pytest - -from pyrealm.pmodel.optimal_chi import ( - OptimalChiC4, - OptimalChiC4NoGamma, - OptimalChiC4RootzoneStress, - OptimalChiLavergne20C3, - OptimalChiLavergne20C4, - OptimalChiPrentice14, - OptimalChiPrentice14RootzoneStress, -) -from pyrealm.pmodel.pmodel_environment import PModelEnvironment - - -@pytest.fixture -def photo_env(): - """Photosynthesis Environment setup.""" - return PModelEnvironment( - tc=np.array([20]), - vpd=np.array([1000]), - co2=np.array([400]), - patm=np.array([101325.0]), - rootzonestress=np.array([1]), - theta=np.array([0.5]), - ) - - -@pytest.mark.parametrize( - """optimal_chi_class""", - [ - OptimalChiPrentice14, - OptimalChiPrentice14RootzoneStress, - OptimalChiC4, - OptimalChiC4RootzoneStress, - OptimalChiLavergne20C3, - OptimalChiLavergne20C4, - OptimalChiC4NoGamma, - ], -) -def test_set_beta(optimal_chi_class, photo_env): - """Test that beta is set correctly.""" - optimal_chi_instance = optimal_chi_class(env=photo_env) - optimal_chi_instance.set_beta() - # Test that beta attribute is set correctly - assert isinstance(optimal_chi_instance.beta, np.ndarray) - - -@pytest.mark.parametrize( - """optimal_chi_class""", - [ - OptimalChiPrentice14, - OptimalChiPrentice14RootzoneStress, - OptimalChiC4, - OptimalChiC4RootzoneStress, - OptimalChiLavergne20C3, - OptimalChiLavergne20C4, - OptimalChiC4NoGamma, - ], -) -def test_estimate_chi(optimal_chi_class, photo_env): - """Test that chi is estimated correctly.""" - optimal_chi_instance = optimal_chi_class(env=photo_env) - optimal_chi_instance.set_beta() - optimal_chi_instance.estimate_chi() - # Test that chi and other related attributes are calculated correctly - assert isinstance(optimal_chi_instance.chi, np.ndarray) - assert isinstance(optimal_chi_instance.mc, np.ndarray) - assert isinstance(optimal_chi_instance.mj, np.ndarray) - assert isinstance(optimal_chi_instance.mjoc, np.ndarray) diff --git a/tests/unit/pmodel/test_jmax_limitation.py b/tests/unit/pmodel/test_jmax_limitation.py new file mode 100644 index 00000000..0cb22457 --- /dev/null +++ b/tests/unit/pmodel/test_jmax_limitation.py @@ -0,0 +1,54 @@ +"""Testing jmax_limitation submodule.""" + +import numpy as np +import pytest + +# from pyrealm.constants import PModelConst +from pyrealm.pmodel.jmax_limitation import JmaxLimitation +from pyrealm.pmodel.optimal_chi import OptimalChiPrentice14 +from pyrealm.pmodel.pmodel_environment import PModelEnvironment + + +@pytest.fixture +def mock_optimal_chi(): + """Build an OptimalChiABC instance.""" + # Create an instance of OptimalChiABC for testing + env = PModelEnvironment( + tc=np.array([20]), + vpd=np.array([1000]), + co2=np.array([400]), + patm=np.array([101325.0]), + ) + return OptimalChiPrentice14(env) + + +@pytest.mark.parametrize( + "method, expected_f_j, expected_f_v", + [ + ("simple", [1.0], [1.0]), + ( + "wang17", + pytest.approx([0.66722], rel=1e-3), + pytest.approx([0.55502], rel=1e-3), + ), + ( + "smith19", + pytest.approx([1.10204], rel=1e-3), + pytest.approx([0.75442], rel=1e-3), + ), + ], +) +def test_jmax_limitation(mock_optimal_chi, method, expected_f_j, expected_f_v): + """Test that JmaxLimitation class works as expected.""" + # Create an instance of JmaxLimitation with mock OptimalChiABC and test method + jmax_limitation = JmaxLimitation(mock_optimal_chi, method=method) + # Assert that calculated f_j and f_v match expected values + assert jmax_limitation.f_j == expected_f_j + assert jmax_limitation.f_v == expected_f_v + + +def test_invalid_method(mock_optimal_chi): + """Test that JmaxLimitation raises ValueError for invalid method.""" + # Test invalid method + with pytest.raises(ValueError): + JmaxLimitation(mock_optimal_chi, method="invalid_method") diff --git a/tests/unit/pmodel/test_optimal_chi.py b/tests/unit/pmodel/test_optimal_chi.py index dda7d38e..f979967d 100644 --- a/tests/unit/pmodel/test_optimal_chi.py +++ b/tests/unit/pmodel/test_optimal_chi.py @@ -1,4 +1,4 @@ -"""Testing CalcOptimal submodule.""" +"""Testing Optimal submodule.""" import numpy as np From 37439562dfdd2de617fa6ebc7fbf81dc96797f69 Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Wed, 6 Mar 2024 12:18:15 +0000 Subject: [PATCH 009/241] Added initial realised values for FastSlowPModel --- pyrealm/pmodel/subdaily.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 1a6c708c..3a4b04af 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -2,7 +2,7 @@ incorporate modelling of the fast and slow responses of photosynthesis to changing conditions. """ # noqa: D205, D415 -from typing import Optional +from typing import Optional, Tuple from warnings import warn import numpy as np @@ -185,6 +185,7 @@ def __init__( kphio: float = 1 / 8, handle_nan: bool = False, fill_kind: str = "previous", + init_realised: Optional[Tuple[NDArray, NDArray, NDArray]] = None, ) -> None: # Warn about the API warn( @@ -255,6 +256,9 @@ def __init__( self.jmax25_opt = self.pmodel_acclim.jmax * ( 1 / calc_ftemp_arrh(tk_acclim, ha_jmax25) ) + """Instantaneous optimal :math:`x_{i}`, :math:`V_{cmax}` and :math:`J_{max}`""" + if init_realised is not None: + self.init_xi_real, self.init_vcmax_real, self.init_jmax_real = init_realised # Calculate the realised values from the instantaneous optimal values self.xi_real: NDArray = memory_effect( @@ -268,6 +272,7 @@ def __init__( self.jmax25_real: NDArray = memory_effect( self.jmax25_opt, alpha=alpha, handle_nan=handle_nan ) + r"""Realised daily slow responses in :math:`J_{max25}`""" # Fill the daily realised values onto the subdaily scale From 63c5950a433adb67da9f49a797921c082c175188 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 9 Jul 2024 11:42:11 +0100 Subject: [PATCH 010/241] Updating xarray --- poetry.lock | 914 +++++++++++++++++++++++++------------------------ pyproject.toml | 2 +- 2 files changed, 464 insertions(+), 452 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7c1ca517..da069290 100644 --- a/poetry.lock +++ b/poetry.lock @@ -240,13 +240,13 @@ css = ["tinycss2 (>=1.1.0,<1.3)"] [[package]] name = "certifi" -version = "2024.6.2" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, - {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] @@ -575,63 +575,63 @@ test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" -version = "7.5.3" +version = "7.5.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, - {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, - {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, - {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, - {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, - {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, - {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, - {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, - {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, - {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, - {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, - {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, - {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"}, - {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"}, - {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"}, - {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"}, - {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, - {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, - {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, - {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, - {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, - {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, + {file = "coverage-7.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99"}, + {file = "coverage-7.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47"}, + {file = "coverage-7.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e"}, + {file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d"}, + {file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3"}, + {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016"}, + {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136"}, + {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9"}, + {file = "coverage-7.5.4-cp310-cp310-win32.whl", hash = "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8"}, + {file = "coverage-7.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f"}, + {file = "coverage-7.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5"}, + {file = "coverage-7.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba"}, + {file = "coverage-7.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b"}, + {file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080"}, + {file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c"}, + {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da"}, + {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0"}, + {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078"}, + {file = "coverage-7.5.4-cp311-cp311-win32.whl", hash = "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806"}, + {file = "coverage-7.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d"}, + {file = "coverage-7.5.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233"}, + {file = "coverage-7.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747"}, + {file = "coverage-7.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638"}, + {file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e"}, + {file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555"}, + {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f"}, + {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c"}, + {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805"}, + {file = "coverage-7.5.4-cp312-cp312-win32.whl", hash = "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b"}, + {file = "coverage-7.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7"}, + {file = "coverage-7.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882"}, + {file = "coverage-7.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d"}, + {file = "coverage-7.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53"}, + {file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4"}, + {file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4"}, + {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9"}, + {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f"}, + {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f"}, + {file = "coverage-7.5.4-cp38-cp38-win32.whl", hash = "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f"}, + {file = "coverage-7.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633"}, + {file = "coverage-7.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088"}, + {file = "coverage-7.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4"}, + {file = "coverage-7.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7"}, + {file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8"}, + {file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d"}, + {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029"}, + {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c"}, + {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7"}, + {file = "coverage-7.5.4-cp39-cp39-win32.whl", hash = "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace"}, + {file = "coverage-7.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d"}, + {file = "coverage-7.5.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5"}, + {file = "coverage-7.5.4.tar.gz", hash = "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353"}, ] [package.dependencies] @@ -670,33 +670,33 @@ dev = ["black", "coveralls", "mypy", "pre-commit", "pylint", "pytest (>=5)", "py [[package]] name = "debugpy" -version = "1.8.1" +version = "1.8.2" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" files = [ - {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, - {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, - {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, - {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, - {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, - {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, - {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, - {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, - {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, - {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, - {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, - {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, - {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, - {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, - {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, - {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, - {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, - {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, - {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, - {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, - {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, - {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, + {file = "debugpy-1.8.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7ee2e1afbf44b138c005e4380097d92532e1001580853a7cb40ed84e0ef1c3d2"}, + {file = "debugpy-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f8c3f7c53130a070f0fc845a0f2cee8ed88d220d6b04595897b66605df1edd6"}, + {file = "debugpy-1.8.2-cp310-cp310-win32.whl", hash = "sha256:f179af1e1bd4c88b0b9f0fa153569b24f6b6f3de33f94703336363ae62f4bf47"}, + {file = "debugpy-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:0600faef1d0b8d0e85c816b8bb0cb90ed94fc611f308d5fde28cb8b3d2ff0fe3"}, + {file = "debugpy-1.8.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:8a13417ccd5978a642e91fb79b871baded925d4fadd4dfafec1928196292aa0a"}, + {file = "debugpy-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acdf39855f65c48ac9667b2801234fc64d46778021efac2de7e50907ab90c634"}, + {file = "debugpy-1.8.2-cp311-cp311-win32.whl", hash = "sha256:2cbd4d9a2fc5e7f583ff9bf11f3b7d78dfda8401e8bb6856ad1ed190be4281ad"}, + {file = "debugpy-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:d3408fddd76414034c02880e891ea434e9a9cf3a69842098ef92f6e809d09afa"}, + {file = "debugpy-1.8.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:5d3ccd39e4021f2eb86b8d748a96c766058b39443c1f18b2dc52c10ac2757835"}, + {file = "debugpy-1.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62658aefe289598680193ff655ff3940e2a601765259b123dc7f89c0239b8cd3"}, + {file = "debugpy-1.8.2-cp312-cp312-win32.whl", hash = "sha256:bd11fe35d6fd3431f1546d94121322c0ac572e1bfb1f6be0e9b8655fb4ea941e"}, + {file = "debugpy-1.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:15bc2f4b0f5e99bf86c162c91a74c0631dbd9cef3c6a1d1329c946586255e859"}, + {file = "debugpy-1.8.2-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:5a019d4574afedc6ead1daa22736c530712465c0c4cd44f820d803d937531b2d"}, + {file = "debugpy-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40f062d6877d2e45b112c0bbade9a17aac507445fd638922b1a5434df34aed02"}, + {file = "debugpy-1.8.2-cp38-cp38-win32.whl", hash = "sha256:c78ba1680f1015c0ca7115671fe347b28b446081dada3fedf54138f44e4ba031"}, + {file = "debugpy-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:cf327316ae0c0e7dd81eb92d24ba8b5e88bb4d1b585b5c0d32929274a66a5210"}, + {file = "debugpy-1.8.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1523bc551e28e15147815d1397afc150ac99dbd3a8e64641d53425dba57b0ff9"}, + {file = "debugpy-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e24ccb0cd6f8bfaec68d577cb49e9c680621c336f347479b3fce060ba7c09ec1"}, + {file = "debugpy-1.8.2-cp39-cp39-win32.whl", hash = "sha256:7f8d57a98c5a486c5c7824bc0b9f2f11189d08d73635c326abef268f83950326"}, + {file = "debugpy-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:16c8dcab02617b75697a0a925a62943e26a0330da076e2a10437edd9f0bf3755"}, + {file = "debugpy-1.8.2-py2.py3-none-any.whl", hash = "sha256:16e16df3a98a35c63c3ab1e4d19be4cbc7fdda92d9ddc059294f18910928e0ca"}, + {file = "debugpy-1.8.2.zip", hash = "sha256:95378ed08ed2089221896b9b3a8d021e642c24edc8fef20e5d4342ca8be65c00"}, ] [[package]] @@ -802,13 +802,13 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "filelock" -version = "3.15.3" +version = "3.15.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.15.3-py3-none-any.whl", hash = "sha256:0151273e5b5d6cf753a61ec83b3a9b7d8821c39ae9af9d7ecf2f9e2f17404103"}, - {file = "filelock-3.15.3.tar.gz", hash = "sha256:e1199bf5194a2277273dacd50269f0d87d0682088a3c561c15674ea9005d8635"}, + {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, + {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, ] [package.extras] @@ -818,53 +818,53 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "fonttools" -version = "4.53.0" +version = "4.53.1" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.53.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:52a6e0a7a0bf611c19bc8ec8f7592bdae79c8296c70eb05917fd831354699b20"}, - {file = "fonttools-4.53.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:099634631b9dd271d4a835d2b2a9e042ccc94ecdf7e2dd9f7f34f7daf333358d"}, - {file = "fonttools-4.53.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e40013572bfb843d6794a3ce076c29ef4efd15937ab833f520117f8eccc84fd6"}, - {file = "fonttools-4.53.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715b41c3e231f7334cbe79dfc698213dcb7211520ec7a3bc2ba20c8515e8a3b5"}, - {file = "fonttools-4.53.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74ae2441731a05b44d5988d3ac2cf784d3ee0a535dbed257cbfff4be8bb49eb9"}, - {file = "fonttools-4.53.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:95db0c6581a54b47c30860d013977b8a14febc206c8b5ff562f9fe32738a8aca"}, - {file = "fonttools-4.53.0-cp310-cp310-win32.whl", hash = "sha256:9cd7a6beec6495d1dffb1033d50a3f82dfece23e9eb3c20cd3c2444d27514068"}, - {file = "fonttools-4.53.0-cp310-cp310-win_amd64.whl", hash = "sha256:daaef7390e632283051e3cf3e16aff2b68b247e99aea916f64e578c0449c9c68"}, - {file = "fonttools-4.53.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a209d2e624ba492df4f3bfad5996d1f76f03069c6133c60cd04f9a9e715595ec"}, - {file = "fonttools-4.53.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f520d9ac5b938e6494f58a25c77564beca7d0199ecf726e1bd3d56872c59749"}, - {file = "fonttools-4.53.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eceef49f457253000e6a2d0f7bd08ff4e9fe96ec4ffce2dbcb32e34d9c1b8161"}, - {file = "fonttools-4.53.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1f3e34373aa16045484b4d9d352d4c6b5f9f77ac77a178252ccbc851e8b2ee"}, - {file = "fonttools-4.53.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:28d072169fe8275fb1a0d35e3233f6df36a7e8474e56cb790a7258ad822b6fd6"}, - {file = "fonttools-4.53.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4a2a6ba400d386e904fd05db81f73bee0008af37799a7586deaa4aef8cd5971e"}, - {file = "fonttools-4.53.0-cp311-cp311-win32.whl", hash = "sha256:bb7273789f69b565d88e97e9e1da602b4ee7ba733caf35a6c2affd4334d4f005"}, - {file = "fonttools-4.53.0-cp311-cp311-win_amd64.whl", hash = "sha256:9fe9096a60113e1d755e9e6bda15ef7e03391ee0554d22829aa506cdf946f796"}, - {file = "fonttools-4.53.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d8f191a17369bd53a5557a5ee4bab91d5330ca3aefcdf17fab9a497b0e7cff7a"}, - {file = "fonttools-4.53.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93156dd7f90ae0a1b0e8871032a07ef3178f553f0c70c386025a808f3a63b1f4"}, - {file = "fonttools-4.53.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bff98816cb144fb7b85e4b5ba3888a33b56ecef075b0e95b95bcd0a5fbf20f06"}, - {file = "fonttools-4.53.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:973d030180eca8255b1bce6ffc09ef38a05dcec0e8320cc9b7bcaa65346f341d"}, - {file = "fonttools-4.53.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4ee5a24e281fbd8261c6ab29faa7fd9a87a12e8c0eed485b705236c65999109"}, - {file = "fonttools-4.53.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd5bc124fae781a4422f61b98d1d7faa47985f663a64770b78f13d2c072410c2"}, - {file = "fonttools-4.53.0-cp312-cp312-win32.whl", hash = "sha256:a239afa1126b6a619130909c8404070e2b473dd2b7fc4aacacd2e763f8597fea"}, - {file = "fonttools-4.53.0-cp312-cp312-win_amd64.whl", hash = "sha256:45b4afb069039f0366a43a5d454bc54eea942bfb66b3fc3e9a2c07ef4d617380"}, - {file = "fonttools-4.53.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:93bc9e5aaa06ff928d751dc6be889ff3e7d2aa393ab873bc7f6396a99f6fbb12"}, - {file = "fonttools-4.53.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2367d47816cc9783a28645bc1dac07f8ffc93e0f015e8c9fc674a5b76a6da6e4"}, - {file = "fonttools-4.53.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:907fa0b662dd8fc1d7c661b90782ce81afb510fc4b7aa6ae7304d6c094b27bce"}, - {file = "fonttools-4.53.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e0ad3c6ea4bd6a289d958a1eb922767233f00982cf0fe42b177657c86c80a8f"}, - {file = "fonttools-4.53.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:73121a9b7ff93ada888aaee3985a88495489cc027894458cb1a736660bdfb206"}, - {file = "fonttools-4.53.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ee595d7ba9bba130b2bec555a40aafa60c26ce68ed0cf509983e0f12d88674fd"}, - {file = "fonttools-4.53.0-cp38-cp38-win32.whl", hash = "sha256:fca66d9ff2ac89b03f5aa17e0b21a97c21f3491c46b583bb131eb32c7bab33af"}, - {file = "fonttools-4.53.0-cp38-cp38-win_amd64.whl", hash = "sha256:31f0e3147375002aae30696dd1dc596636abbd22fca09d2e730ecde0baad1d6b"}, - {file = "fonttools-4.53.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d6166192dcd925c78a91d599b48960e0a46fe565391c79fe6de481ac44d20ac"}, - {file = "fonttools-4.53.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef50ec31649fbc3acf6afd261ed89d09eb909b97cc289d80476166df8438524d"}, - {file = "fonttools-4.53.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f193f060391a455920d61684a70017ef5284ccbe6023bb056e15e5ac3de11d1"}, - {file = "fonttools-4.53.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9f09ff17f947392a855e3455a846f9855f6cf6bec33e9a427d3c1d254c712f"}, - {file = "fonttools-4.53.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c555e039d268445172b909b1b6bdcba42ada1cf4a60e367d68702e3f87e5f64"}, - {file = "fonttools-4.53.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a4788036201c908079e89ae3f5399b33bf45b9ea4514913f4dbbe4fac08efe0"}, - {file = "fonttools-4.53.0-cp39-cp39-win32.whl", hash = "sha256:d1a24f51a3305362b94681120c508758a88f207fa0a681c16b5a4172e9e6c7a9"}, - {file = "fonttools-4.53.0-cp39-cp39-win_amd64.whl", hash = "sha256:1e677bfb2b4bd0e5e99e0f7283e65e47a9814b0486cb64a41adf9ef110e078f2"}, - {file = "fonttools-4.53.0-py3-none-any.whl", hash = "sha256:6b4f04b1fbc01a3569d63359f2227c89ab294550de277fd09d8fca6185669fa4"}, - {file = "fonttools-4.53.0.tar.gz", hash = "sha256:c93ed66d32de1559b6fc348838c7572d5c0ac1e4a258e76763a5caddd8944002"}, + {file = "fonttools-4.53.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397"}, + {file = "fonttools-4.53.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3"}, + {file = "fonttools-4.53.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d"}, + {file = "fonttools-4.53.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0"}, + {file = "fonttools-4.53.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41"}, + {file = "fonttools-4.53.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f"}, + {file = "fonttools-4.53.1-cp310-cp310-win32.whl", hash = "sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4"}, + {file = "fonttools-4.53.1-cp310-cp310-win_amd64.whl", hash = "sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671"}, + {file = "fonttools-4.53.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1"}, + {file = "fonttools-4.53.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923"}, + {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719"}, + {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3"}, + {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb"}, + {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2"}, + {file = "fonttools-4.53.1-cp311-cp311-win32.whl", hash = "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88"}, + {file = "fonttools-4.53.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02"}, + {file = "fonttools-4.53.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58"}, + {file = "fonttools-4.53.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8"}, + {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60"}, + {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f"}, + {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2"}, + {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f"}, + {file = "fonttools-4.53.1-cp312-cp312-win32.whl", hash = "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670"}, + {file = "fonttools-4.53.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab"}, + {file = "fonttools-4.53.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749"}, + {file = "fonttools-4.53.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2"}, + {file = "fonttools-4.53.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb"}, + {file = "fonttools-4.53.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f"}, + {file = "fonttools-4.53.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d"}, + {file = "fonttools-4.53.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169"}, + {file = "fonttools-4.53.1-cp38-cp38-win32.whl", hash = "sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d"}, + {file = "fonttools-4.53.1-cp38-cp38-win_amd64.whl", hash = "sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8"}, + {file = "fonttools-4.53.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a"}, + {file = "fonttools-4.53.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31"}, + {file = "fonttools-4.53.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c"}, + {file = "fonttools-4.53.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407"}, + {file = "fonttools-4.53.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb"}, + {file = "fonttools-4.53.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122"}, + {file = "fonttools-4.53.1-cp39-cp39-win32.whl", hash = "sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb"}, + {file = "fonttools-4.53.1-cp39-cp39-win_amd64.whl", hash = "sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb"}, + {file = "fonttools-4.53.1-py3-none-any.whl", hash = "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d"}, + {file = "fonttools-4.53.1.tar.gz", hash = "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4"}, ] [package.extras] @@ -1048,13 +1048,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "identify" -version = "2.5.36" +version = "2.6.0" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, - {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, + {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"}, + {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, ] [package.extras] @@ -1084,22 +1084,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.1.0" +version = "8.0.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, - {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, + {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"}, + {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "iniconfig" @@ -1114,13 +1114,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.29.4" +version = "6.29.5" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, - {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, + {file = "ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"}, + {file = "ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215"}, ] [package.dependencies] @@ -1147,13 +1147,13 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio [[package]] name = "ipython" -version = "8.25.0" +version = "8.26.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" files = [ - {file = "ipython-8.25.0-py3-none-any.whl", hash = "sha256:53eee7ad44df903a06655871cbab66d156a051fd86f3ec6750470ac9604ac1ab"}, - {file = "ipython-8.25.0.tar.gz", hash = "sha256:c6ed726a140b6e725b911528f80439c534fac915246af3efc39440a6b0f9d716"}, + {file = "ipython-8.26.0-py3-none-any.whl", hash = "sha256:e6b347c27bdf9c32ee9d31ae85defc525755a1869f14057e900675b9e8d6e6ff"}, + {file = "ipython-8.26.0.tar.gz", hash = "sha256:1cec0fbba8404af13facebe83d04436a7434c7400e59f47acf467c64abd0956c"}, ] [package.dependencies] @@ -1180,7 +1180,7 @@ nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] +test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] [[package]] @@ -1257,13 +1257,13 @@ files = [ [[package]] name = "jsonschema" -version = "4.22.0" +version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, - {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, + {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, + {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, ] [package.dependencies] @@ -1278,11 +1278,11 @@ rfc3339-validator = {version = "*", optional = true, markers = "extra == \"forma rfc3986-validator = {version = ">0.1.0", optional = true, markers = "extra == \"format-nongpl\""} rpds-py = ">=0.7.1" uri-template = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -webcolors = {version = ">=1.11", optional = true, markers = "extra == \"format-nongpl\""} +webcolors = {version = ">=24.6.0", optional = true, markers = "extra == \"format-nongpl\""} [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] [[package]] name = "jsonschema-specifications" @@ -1463,13 +1463,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.2.2" +version = "4.2.3" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.2.2-py3-none-any.whl", hash = "sha256:59ee9b839f43308c3dfd55d72d1f1a299ed42a7f91f2d1afe9c12a783f9e525f"}, - {file = "jupyterlab-4.2.2.tar.gz", hash = "sha256:a534b6a25719a92a40d514fb133a9fe8f0d9981b0bbce5d8a5fcaa33344a3038"}, + {file = "jupyterlab-4.2.3-py3-none-any.whl", hash = "sha256:0b59d11808e84bb84105c73364edfa867dd475492429ab34ea388a52f2e2e596"}, + {file = "jupyterlab-4.2.3.tar.gz", hash = "sha256:df6e46969ea51d66815167f23d92f105423b7f1f06fa604d4f44aeb018c82c7b"}, ] [package.dependencies] @@ -1796,40 +1796,40 @@ files = [ [[package]] name = "matplotlib" -version = "3.9.0" +version = "3.9.1" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2bcee1dffaf60fe7656183ac2190bd630842ff87b3153afb3e384d966b57fe56"}, - {file = "matplotlib-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f988bafb0fa39d1074ddd5bacd958c853e11def40800c5824556eb630f94d3b"}, - {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe428e191ea016bb278758c8ee82a8129c51d81d8c4bc0846c09e7e8e9057241"}, - {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaf3978060a106fab40c328778b148f590e27f6fa3cd15a19d6892575bce387d"}, - {file = "matplotlib-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2e7f03e5cbbfacdd48c8ea394d365d91ee8f3cae7e6ec611409927b5ed997ee4"}, - {file = "matplotlib-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:13beb4840317d45ffd4183a778685e215939be7b08616f431c7795276e067463"}, - {file = "matplotlib-3.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:063af8587fceeac13b0936c42a2b6c732c2ab1c98d38abc3337e430e1ff75e38"}, - {file = "matplotlib-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a2fa6d899e17ddca6d6526cf6e7ba677738bf2a6a9590d702c277204a7c6152"}, - {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550cdda3adbd596078cca7d13ed50b77879104e2e46392dcd7c75259d8f00e85"}, - {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cce0f31b351e3551d1f3779420cf8f6ec0d4a8cf9c0237a3b549fd28eb4abb"}, - {file = "matplotlib-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c53aeb514ccbbcbab55a27f912d79ea30ab21ee0531ee2c09f13800efb272674"}, - {file = "matplotlib-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5be985db2596d761cdf0c2eaf52396f26e6a64ab46bd8cd810c48972349d1be"}, - {file = "matplotlib-3.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c79f3a585f1368da6049318bdf1f85568d8d04b2e89fc24b7e02cc9b62017382"}, - {file = "matplotlib-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bdd1ecbe268eb3e7653e04f451635f0fb0f77f07fd070242b44c076c9106da84"}, - {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e85a1a6d732f645f1403ce5e6727fd9418cd4574521d5803d3d94911038e5"}, - {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a490715b3b9984fa609116481b22178348c1a220a4499cda79132000a79b4db"}, - {file = "matplotlib-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8146ce83cbc5dc71c223a74a1996d446cd35cfb6a04b683e1446b7e6c73603b7"}, - {file = "matplotlib-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:d91a4ffc587bacf5c4ce4ecfe4bcd23a4b675e76315f2866e588686cc97fccdf"}, - {file = "matplotlib-3.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:616fabf4981a3b3c5a15cd95eba359c8489c4e20e03717aea42866d8d0465956"}, - {file = "matplotlib-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd53c79fd02f1c1808d2cfc87dd3cf4dbc63c5244a58ee7944497107469c8d8a"}, - {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06a478f0d67636554fa78558cfbcd7b9dba85b51f5c3b5a0c9be49010cf5f321"}, - {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c40af649d19c85f8073e25e5806926986806fa6d54be506fbf02aef47d5a89"}, - {file = "matplotlib-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52146fc3bd7813cc784562cb93a15788be0b2875c4655e2cc6ea646bfa30344b"}, - {file = "matplotlib-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:0fc51eaa5262553868461c083d9adadb11a6017315f3a757fc45ec6ec5f02888"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bd4f2831168afac55b881db82a7730992aa41c4f007f1913465fb182d6fb20c0"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:290d304e59be2b33ef5c2d768d0237f5bd132986bdcc66f80bc9bcc300066a03"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff2e239c26be4f24bfa45860c20ffccd118d270c5b5d081fa4ea409b5469fcd"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af4001b7cae70f7eaacfb063db605280058246de590fa7874f00f62259f2df7e"}, - {file = "matplotlib-3.9.0.tar.gz", hash = "sha256:e6d29ea6c19e34b30fb7d88b7081f869a03014f66fe06d62cc77d5a6ea88ed7a"}, + {file = "matplotlib-3.9.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7ccd6270066feb9a9d8e0705aa027f1ff39f354c72a87efe8fa07632f30fc6bb"}, + {file = "matplotlib-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:591d3a88903a30a6d23b040c1e44d1afdd0d778758d07110eb7596f811f31842"}, + {file = "matplotlib-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd2a59ff4b83d33bca3b5ec58203cc65985367812cb8c257f3e101632be86d92"}, + {file = "matplotlib-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fc001516ffcf1a221beb51198b194d9230199d6842c540108e4ce109ac05cc0"}, + {file = "matplotlib-3.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:83c6a792f1465d174c86d06f3ae85a8fe36e6f5964633ae8106312ec0921fdf5"}, + {file = "matplotlib-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:421851f4f57350bcf0811edd754a708d2275533e84f52f6760b740766c6747a7"}, + {file = "matplotlib-3.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b3fce58971b465e01b5c538f9d44915640c20ec5ff31346e963c9e1cd66fa812"}, + {file = "matplotlib-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a973c53ad0668c53e0ed76b27d2eeeae8799836fd0d0caaa4ecc66bf4e6676c0"}, + {file = "matplotlib-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd5acf8f3ef43f7532c2f230249720f5dc5dd40ecafaf1c60ac8200d46d7eb"}, + {file = "matplotlib-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab38a4f3772523179b2f772103d8030215b318fef6360cb40558f585bf3d017f"}, + {file = "matplotlib-3.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2315837485ca6188a4b632c5199900e28d33b481eb083663f6a44cfc8987ded3"}, + {file = "matplotlib-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:a0c977c5c382f6696caf0bd277ef4f936da7e2aa202ff66cad5f0ac1428ee15b"}, + {file = "matplotlib-3.9.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:565d572efea2b94f264dd86ef27919515aa6d629252a169b42ce5f570db7f37b"}, + {file = "matplotlib-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d397fd8ccc64af2ec0af1f0efc3bacd745ebfb9d507f3f552e8adb689ed730a"}, + {file = "matplotlib-3.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26040c8f5121cd1ad712abffcd4b5222a8aec3a0fe40bc8542c94331deb8780d"}, + {file = "matplotlib-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12cb1837cffaac087ad6b44399d5e22b78c729de3cdae4629e252067b705e2b"}, + {file = "matplotlib-3.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0e835c6988edc3d2d08794f73c323cc62483e13df0194719ecb0723b564e0b5c"}, + {file = "matplotlib-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:44a21d922f78ce40435cb35b43dd7d573cf2a30138d5c4b709d19f00e3907fd7"}, + {file = "matplotlib-3.9.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0c584210c755ae921283d21d01f03a49ef46d1afa184134dd0f95b0202ee6f03"}, + {file = "matplotlib-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11fed08f34fa682c2b792942f8902e7aefeed400da71f9e5816bea40a7ce28fe"}, + {file = "matplotlib-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0000354e32efcfd86bda75729716b92f5c2edd5b947200be9881f0a671565c33"}, + {file = "matplotlib-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4db17fea0ae3aceb8e9ac69c7e3051bae0b3d083bfec932240f9bf5d0197a049"}, + {file = "matplotlib-3.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:208cbce658b72bf6a8e675058fbbf59f67814057ae78165d8a2f87c45b48d0ff"}, + {file = "matplotlib-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:dc23f48ab630474264276be156d0d7710ac6c5a09648ccdf49fef9200d8cbe80"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3fda72d4d472e2ccd1be0e9ccb6bf0d2eaf635e7f8f51d737ed7e465ac020cb3"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:84b3ba8429935a444f1fdc80ed930babbe06725bcf09fbeb5c8757a2cd74af04"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b918770bf3e07845408716e5bbda17eadfc3fcbd9307dc67f37d6cf834bb3d98"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f1f2e5d29e9435c97ad4c36fb6668e89aee13d48c75893e25cef064675038ac9"}, + {file = "matplotlib-3.9.1.tar.gz", hash = "sha256:de06b19b8db95dd33d0dc17c926c7c9ebed9f572074b6fac4f65068a6814d010"}, ] [package.dependencies] @@ -1988,13 +1988,13 @@ files = [ [[package]] name = "myst-nb" -version = "1.1.0" +version = "1.1.1" description = "A Jupyter Notebook Sphinx reader built on top of the MyST markdown parser." optional = false python-versions = ">=3.9" files = [ - {file = "myst_nb-1.1.0-py3-none-any.whl", hash = "sha256:0ac29b2a346f9a1257edbfb5d6c47d528728a37e6b9438903c2821f69fda9235"}, - {file = "myst_nb-1.1.0.tar.gz", hash = "sha256:9278840e844f5d780b5acc5400cbf63d97caaccf8eb442a55ebd9a03e2522d5e"}, + {file = "myst_nb-1.1.1-py3-none-any.whl", hash = "sha256:8b8f9085287d948eef46cb3764aafc21915e0e981882b8c742719f5b1a84c36f"}, + {file = "myst_nb-1.1.1.tar.gz", hash = "sha256:74227c11f76d03494f43b7788659b161b94f4dedef230a2912412bc8c3c9e553"}, ] [package.dependencies] @@ -2133,36 +2133,36 @@ files = [ [[package]] name = "netcdf4" -version = "1.7.1" +version = "1.7.1.post1" description = "Provides an object-oriented python interface to the netCDF version 4 library" optional = false python-versions = ">=3.8" files = [ - {file = "netCDF4-1.7.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7503bc1a7b013c7ba5d715a72826f7debf65633eace4a4280c2700b1cc001945"}, - {file = "netCDF4-1.7.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:3b345b68365ecae2c8c9c33e7d41a1a94e80ef987f40928a02e2f210d05d02b2"}, - {file = "netCDF4-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:867466bef3d109d79d35b2bbcb713565f29b2df0cb52cd19691cba65374129ac"}, - {file = "netCDF4-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73f017f4d909cea6ab1065e8199d597a9bf5cf60f91c37ae8a040c35256bc196"}, - {file = "netCDF4-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:48c56e96107ec8e2daf08cb0a9dde2b66e118de397c5f06511b31c37ef35e113"}, - {file = "netCDF4-1.7.1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:dfb92f8db5731b285546b732dfbe5870ed09b16a0453bb213a8dba83d1045935"}, - {file = "netCDF4-1.7.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:9cd8b9ab2508cc4a8d52957f84c1f34d94755c748ef6f285f756044842184852"}, - {file = "netCDF4-1.7.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b43f6569ef09fba75d2bd194fe60d286736b96329e0e50e90df4e236b272db0e"}, - {file = "netCDF4-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56af0fa24a39a14bc68cc1ab97e6d33fbaff934ba0659f740ad54bd80fbf732f"}, - {file = "netCDF4-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ce2207d836e5289f8caa66a540b222f76c242e6be565cefe8478a19bb08c206"}, - {file = "netCDF4-1.7.1-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:5724ba076ea49b63625447cd6e8d936929a2b23d3e63157c16a607e8e7505598"}, - {file = "netCDF4-1.7.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b6917f8ad44722fefb26134b540e97a9eef5ffd0b73e4564666b697f0f43ae5d"}, - {file = "netCDF4-1.7.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d407f5725daf8972ff7a4af48925a75c349158681e3f14f264616a013fe97aca"}, - {file = "netCDF4-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e26fd9a30c26d7757444410fe85d68ce8d3f64119d33feaa4daed374d1779590"}, - {file = "netCDF4-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:7258b98ebfaf7f0a3f362946d0192020d0d0284b131e7ef775e66858d3ff13ae"}, - {file = "netCDF4-1.7.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:b300b6933ab83496914c0f1731075a3a40829b9010c3f1548eece5ccb3ea629a"}, - {file = "netCDF4-1.7.1-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:c4ece6fe318f787b212e6169dee5e2c3326650dd64b1af44e2b815c6b48f2231"}, - {file = "netCDF4-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a9d8906ff7c86e1af176efbd85603088c98271cf844562a482286411289a7ec"}, - {file = "netCDF4-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f858bef2edd5dfccacd4c556eae7db55b185ba6af9b6520d8ae1ea16a72004a6"}, - {file = "netCDF4-1.7.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:225a03e1d216618d14f721c72b47a42f09e68dcc6b1509c93c784c60c630129f"}, - {file = "netCDF4-1.7.1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:85d28a26080b2a05b0786135be7b215ed0629a974895b135bd4ef2eddbb3e1ad"}, - {file = "netCDF4-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec569b56ab8714aded398b1667e1ca01489c71ed51965e9a0bd51d7c217ce352"}, - {file = "netCDF4-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7553e9cd37ef9a2382e3f8088b0f4c00e8078e76e2358c140eb882eefabe6db7"}, - {file = "netCDF4-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:6e343b7e42cd11184c2686e2899915bb1f3f1df7c9c62681590c35c088a9c66b"}, - {file = "netcdf4-1.7.1.tar.gz", hash = "sha256:87d666093870ebbc0153c8eb42a4a70d6a1d33b47fa3d8fd2e01b6d8de52023e"}, + {file = "netCDF4-1.7.1.post1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5abdc8ab27bcb11325547841311717a0ba8f5b73a5fc5e93b933bc23285d0c03"}, + {file = "netCDF4-1.7.1.post1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:33f5d66ee9cedf43d3932d0e5447eb471f9c53332f93476133b4bfc6b682f790"}, + {file = "netCDF4-1.7.1.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d649fad9d1f63e25a191576c7de158c8c3afa8d4b4001e8683e20da90b49b939"}, + {file = "netCDF4-1.7.1.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:860222bc57bbc714e55705f263162be2c935129dcb700a944bda61aee785ff03"}, + {file = "netCDF4-1.7.1.post1-cp310-cp310-win_amd64.whl", hash = "sha256:d5420155ca6c768c070922d80acd9f4088a913afd25a9fd2f429e7af626374eb"}, + {file = "netCDF4-1.7.1.post1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:a8d3209516aa8c58d70863ab1059af4ec82ef8ecb1c6b8cb4842d7825a6f64da"}, + {file = "netCDF4-1.7.1.post1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:7a10da9b60d3358876d53a0cd691d2c900c2b39903bf25ad5235fd321d59eb2f"}, + {file = "netCDF4-1.7.1.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac99e03d6e28419b206444fd6dc80a5e21d0ae8e53ff37d756fbc16c5d3775"}, + {file = "netCDF4-1.7.1.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e15f3afa4e6910fc158a318ea73fdc6f9e41058c71bf98a99fd63994334d16b0"}, + {file = "netCDF4-1.7.1.post1-cp311-cp311-win_amd64.whl", hash = "sha256:115160fc8e09333754542c33d721d42625a7bd62381a74f2f759297e3e38810b"}, + {file = "netCDF4-1.7.1.post1-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:75bba24ef0354fb6913bc3acdcb3790534e86bf329bbeaaf54122b18e5fd05ea"}, + {file = "netCDF4-1.7.1.post1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ce7f89b98dbb3acd9582db30e6478ce7a7003b2cb70dc20d85fe9506e65ab001"}, + {file = "netCDF4-1.7.1.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac4e30a0d5a8e227d6a890502cfa201388acf606c0c73a5a7594232f3a74e67e"}, + {file = "netCDF4-1.7.1.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:988c45f9122337a12267fb158953c0609e3ea50a557335a3105f104416a4821a"}, + {file = "netCDF4-1.7.1.post1-cp312-cp312-win_amd64.whl", hash = "sha256:8fb3ed3541fa1b5b46e9d92d7e803734a1a3f37d8f5adf5fdf7957c7750cb20e"}, + {file = "netCDF4-1.7.1.post1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:a4d05cc4c3628a7b88d623cb1a02908100a4938335a0289fa79c19016c21d7f9"}, + {file = "netCDF4-1.7.1.post1-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:3a9ba8dc93f3d9019db921e42d40fa6791e7e244f3bb3a874bf2bfb96aea7380"}, + {file = "netCDF4-1.7.1.post1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fbbca82a822ba74b605254f7a267d258f13d67f8a4156a09e26322bfa002a82d"}, + {file = "netCDF4-1.7.1.post1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a09da245f4784421fb4d5740dae0367cdbb270d0a931a33474ec17a9433314d"}, + {file = "netCDF4-1.7.1.post1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:fdcec3a3150f9248e76301ad723f51955efc770edf015dfb61a6480cc7c04a70"}, + {file = "netCDF4-1.7.1.post1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:0fed0eb65a7751a99a0cee08c6df383737d46d17c73cabae81d113f1b4fa3643"}, + {file = "netCDF4-1.7.1.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daa6169fe6617a4612cb75a8ef61ee14011a012633ad1ace1b629a1ff87bf5cf"}, + {file = "netCDF4-1.7.1.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcad21e965978cc5530131bd7e73dcabe7dda1f681f9e4ebf940a65a176d25fe"}, + {file = "netCDF4-1.7.1.post1-cp39-cp39-win_amd64.whl", hash = "sha256:f24027ae19b68cc1274aad8b00d6d81879d506ddca011a080dff2117014398b9"}, + {file = "netcdf4-1.7.1.post1.tar.gz", hash = "sha256:797f0b25d87827fc6821e415d9e15a2068604b18c3be62563e72682bcba76548"}, ] [package.dependencies] @@ -2410,84 +2410,95 @@ ptyprocess = ">=0.5" [[package]] name = "pillow" -version = "10.3.0" +version = "10.4.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, - {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, - {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, - {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, - {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, - {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, - {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, - {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, - {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, - {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, - {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, - {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, - {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, - {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, - {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, - {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, - {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] + {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, + {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, + {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, + {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, + {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, + {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, + {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, + {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, + {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, + {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, + {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, + {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, + {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, + {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, + {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, + {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, + {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, + {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, + {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] @@ -3088,179 +3099,179 @@ files = [ [[package]] name = "rpds-py" -version = "0.18.1" +version = "0.19.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, - {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, - {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, - {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, - {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, - {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, - {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, - {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, - {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, - {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, - {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, - {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, - {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, - {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, - {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, - {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, - {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, - {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, - {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, - {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, - {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, + {file = "rpds_py-0.19.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:fb37bd599f031f1a6fb9e58ec62864ccf3ad549cf14bac527dbfa97123edcca4"}, + {file = "rpds_py-0.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3384d278df99ec2c6acf701d067147320b864ef6727405d6470838476e44d9e8"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e54548e0be3ac117595408fd4ca0ac9278fde89829b0b518be92863b17ff67a2"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8eb488ef928cdbc05a27245e52de73c0d7c72a34240ef4d9893fdf65a8c1a955"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5da93debdfe27b2bfc69eefb592e1831d957b9535e0943a0ee8b97996de21b5"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79e205c70afddd41f6ee79a8656aec738492a550247a7af697d5bd1aee14f766"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:959179efb3e4a27610e8d54d667c02a9feaa86bbabaf63efa7faa4dfa780d4f1"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a6e605bb9edcf010f54f8b6a590dd23a4b40a8cb141255eec2a03db249bc915b"}, + {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9133d75dc119a61d1a0ded38fb9ba40a00ef41697cc07adb6ae098c875195a3f"}, + {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd36b712d35e757e28bf2f40a71e8f8a2d43c8b026d881aa0c617b450d6865c9"}, + {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:354f3a91718489912f2e0fc331c24eaaf6a4565c080e00fbedb6015857c00582"}, + {file = "rpds_py-0.19.0-cp310-none-win32.whl", hash = "sha256:ebcbf356bf5c51afc3290e491d3722b26aaf5b6af3c1c7f6a1b757828a46e336"}, + {file = "rpds_py-0.19.0-cp310-none-win_amd64.whl", hash = "sha256:75a6076289b2df6c8ecb9d13ff79ae0cad1d5fb40af377a5021016d58cd691ec"}, + {file = "rpds_py-0.19.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6d45080095e585f8c5097897313def60caa2046da202cdb17a01f147fb263b81"}, + {file = "rpds_py-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5c9581019c96f865483d031691a5ff1cc455feb4d84fc6920a5ffc48a794d8a"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1540d807364c84516417115c38f0119dfec5ea5c0dd9a25332dea60b1d26fc4d"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e65489222b410f79711dc3d2d5003d2757e30874096b2008d50329ea4d0f88c"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9da6f400eeb8c36f72ef6646ea530d6d175a4f77ff2ed8dfd6352842274c1d8b"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37f46bb11858717e0efa7893c0f7055c43b44c103e40e69442db5061cb26ed34"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:071d4adc734de562bd11d43bd134330fb6249769b2f66b9310dab7460f4bf714"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9625367c8955e4319049113ea4f8fee0c6c1145192d57946c6ffcd8fe8bf48dd"}, + {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e19509145275d46bc4d1e16af0b57a12d227c8253655a46bbd5ec317e941279d"}, + {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d438e4c020d8c39961deaf58f6913b1bf8832d9b6f62ec35bd93e97807e9cbc"}, + {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90bf55d9d139e5d127193170f38c584ed3c79e16638890d2e36f23aa1630b952"}, + {file = "rpds_py-0.19.0-cp311-none-win32.whl", hash = "sha256:8d6ad132b1bc13d05ffe5b85e7a01a3998bf3a6302ba594b28d61b8c2cf13aaf"}, + {file = "rpds_py-0.19.0-cp311-none-win_amd64.whl", hash = "sha256:7ec72df7354e6b7f6eb2a17fa6901350018c3a9ad78e48d7b2b54d0412539a67"}, + {file = "rpds_py-0.19.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:5095a7c838a8647c32aa37c3a460d2c48debff7fc26e1136aee60100a8cd8f68"}, + {file = "rpds_py-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f2f78ef14077e08856e788fa482107aa602636c16c25bdf59c22ea525a785e9"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7cc6cb44f8636fbf4a934ca72f3e786ba3c9f9ba4f4d74611e7da80684e48d2"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf902878b4af334a09de7a45badbff0389e7cf8dc2e4dcf5f07125d0b7c2656d"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:688aa6b8aa724db1596514751ffb767766e02e5c4a87486ab36b8e1ebc1aedac"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57dbc9167d48e355e2569346b5aa4077f29bf86389c924df25c0a8b9124461fb"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4cf5a9497874822341c2ebe0d5850fed392034caadc0bad134ab6822c0925b"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8a790d235b9d39c70a466200d506bb33a98e2ee374a9b4eec7a8ac64c2c261fa"}, + {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1d16089dfa58719c98a1c06f2daceba6d8e3fb9b5d7931af4a990a3c486241cb"}, + {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bc9128e74fe94650367fe23f37074f121b9f796cabbd2f928f13e9661837296d"}, + {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c8f77e661ffd96ff104bebf7d0f3255b02aa5d5b28326f5408d6284c4a8b3248"}, + {file = "rpds_py-0.19.0-cp312-none-win32.whl", hash = "sha256:5f83689a38e76969327e9b682be5521d87a0c9e5a2e187d2bc6be4765f0d4600"}, + {file = "rpds_py-0.19.0-cp312-none-win_amd64.whl", hash = "sha256:06925c50f86da0596b9c3c64c3837b2481337b83ef3519e5db2701df695453a4"}, + {file = "rpds_py-0.19.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:52e466bea6f8f3a44b1234570244b1cff45150f59a4acae3fcc5fd700c2993ca"}, + {file = "rpds_py-0.19.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e21cc693045fda7f745c790cb687958161ce172ffe3c5719ca1764e752237d16"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b31f059878eb1f5da8b2fd82480cc18bed8dcd7fb8fe68370e2e6285fa86da6"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1dd46f309e953927dd018567d6a9e2fb84783963650171f6c5fe7e5c41fd5666"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34a01a4490e170376cd79258b7f755fa13b1a6c3667e872c8e35051ae857a92b"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcf426a8c38eb57f7bf28932e68425ba86def6e756a5b8cb4731d8e62e4e0223"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68eea5df6347d3f1378ce992d86b2af16ad7ff4dcb4a19ccdc23dea901b87fb"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dab8d921b55a28287733263c0e4c7db11b3ee22aee158a4de09f13c93283c62d"}, + {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6fe87efd7f47266dfc42fe76dae89060038f1d9cb911f89ae7e5084148d1cc08"}, + {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:535d4b52524a961d220875688159277f0e9eeeda0ac45e766092bfb54437543f"}, + {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8b1a94b8afc154fbe36978a511a1f155f9bd97664e4f1f7a374d72e180ceb0ae"}, + {file = "rpds_py-0.19.0-cp38-none-win32.whl", hash = "sha256:7c98298a15d6b90c8f6e3caa6457f4f022423caa5fa1a1ca7a5e9e512bdb77a4"}, + {file = "rpds_py-0.19.0-cp38-none-win_amd64.whl", hash = "sha256:b0da31853ab6e58a11db3205729133ce0df26e6804e93079dee095be3d681dc1"}, + {file = "rpds_py-0.19.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5039e3cef7b3e7a060de468a4a60a60a1f31786da94c6cb054e7a3c75906111c"}, + {file = "rpds_py-0.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab1932ca6cb8c7499a4d87cb21ccc0d3326f172cfb6a64021a889b591bb3045c"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2afd2164a1e85226fcb6a1da77a5c8896c18bfe08e82e8ceced5181c42d2179"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1c30841f5040de47a0046c243fc1b44ddc87d1b12435a43b8edff7e7cb1e0d0"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f757f359f30ec7dcebca662a6bd46d1098f8b9fb1fcd661a9e13f2e8ce343ba1"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15e65395a59d2e0e96caf8ee5389ffb4604e980479c32742936ddd7ade914b22"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb0f6eb3a320f24b94d177e62f4074ff438f2ad9d27e75a46221904ef21a7b05"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b228e693a2559888790936e20f5f88b6e9f8162c681830eda303bad7517b4d5a"}, + {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2575efaa5d949c9f4e2cdbe7d805d02122c16065bfb8d95c129372d65a291a0b"}, + {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5c872814b77a4e84afa293a1bee08c14daed1068b2bb1cc312edbf020bbbca2b"}, + {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850720e1b383df199b8433a20e02b25b72f0fded28bc03c5bd79e2ce7ef050be"}, + {file = "rpds_py-0.19.0-cp39-none-win32.whl", hash = "sha256:ce84a7efa5af9f54c0aa7692c45861c1667080814286cacb9958c07fc50294fb"}, + {file = "rpds_py-0.19.0-cp39-none-win_amd64.whl", hash = "sha256:1c26da90b8d06227d7769f34915913911222d24ce08c0ab2d60b354e2d9c7aff"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:75969cf900d7be665ccb1622a9aba225cf386bbc9c3bcfeeab9f62b5048f4a07"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8445f23f13339da640d1be8e44e5baf4af97e396882ebbf1692aecd67f67c479"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5a7c1062ef8aea3eda149f08120f10795835fc1c8bc6ad948fb9652a113ca55"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:462b0c18fbb48fdbf980914a02ee38c423a25fcc4cf40f66bacc95a2d2d73bc8"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3208f9aea18991ac7f2b39721e947bbd752a1abbe79ad90d9b6a84a74d44409b"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3444fe52b82f122d8a99bf66777aed6b858d392b12f4c317da19f8234db4533"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb4bac7185a9f0168d38c01d7a00addece9822a52870eee26b8d5b61409213"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6b130bd4163c93798a6b9bb96be64a7c43e1cec81126ffa7ffaa106e1fc5cef5"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:a707b158b4410aefb6b054715545bbb21aaa5d5d0080217290131c49c2124a6e"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dc9ac4659456bde7c567107556ab065801622396b435a3ff213daef27b495388"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:81ea573aa46d3b6b3d890cd3c0ad82105985e6058a4baed03cf92518081eec8c"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f148c3f47f7f29a79c38cc5d020edcb5ca780020fab94dbc21f9af95c463581"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0906357f90784a66e89ae3eadc2654f36c580a7d65cf63e6a616e4aec3a81be"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f629ecc2db6a4736b5ba95a8347b0089240d69ad14ac364f557d52ad68cf94b0"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6feacd1d178c30e5bc37184526e56740342fd2aa6371a28367bad7908d454fc"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b6068ee374fdfab63689be0963333aa83b0815ead5d8648389a8ded593378"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78d57546bad81e0da13263e4c9ce30e96dcbe720dbff5ada08d2600a3502e526"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b6683a37338818646af718c9ca2a07f89787551057fae57c4ec0446dc6224b"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8481b946792415adc07410420d6fc65a352b45d347b78fec45d8f8f0d7496f0"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bec35eb20792ea64c3c57891bc3ca0bedb2884fbac2c8249d9b731447ecde4fa"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:aa5476c3e3a402c37779e95f7b4048db2cb5b0ed0b9d006983965e93f40fe05a"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:19d02c45f2507b489fd4df7b827940f1420480b3e2e471e952af4d44a1ea8e34"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a3e2fd14c5d49ee1da322672375963f19f32b3d5953f0615b175ff7b9d38daed"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:93a91c2640645303e874eada51f4f33351b84b351a689d470f8108d0e0694210"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b9fc03bf76a94065299d4a2ecd8dfbae4ae8e2e8098bbfa6ab6413ca267709"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a4b07cdf3f84310c08c1de2c12ddadbb7a77568bcb16e95489f9c81074322ed"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba0ed0dc6763d8bd6e5de5cf0d746d28e706a10b615ea382ac0ab17bb7388633"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:474bc83233abdcf2124ed3f66230a1c8435896046caa4b0b5ab6013c640803cc"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329c719d31362355a96b435f4653e3b4b061fcc9eba9f91dd40804ca637d914e"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef9101f3f7b59043a34f1dccbb385ca760467590951952d6701df0da9893ca0c"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:0121803b0f424ee2109d6e1f27db45b166ebaa4b32ff47d6aa225642636cd834"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8344127403dea42f5970adccf6c5957a71a47f522171fafaf4c6ddb41b61703a"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:443cec402ddd650bb2b885113e1dcedb22b1175c6be223b14246a714b61cd521"}, + {file = "rpds_py-0.19.0.tar.gz", hash = "sha256:4fdc9afadbeb393b4bbbad75481e0ea78e4469f2e1d713a90811700830b553a9"}, ] [[package]] name = "ruff" -version = "0.4.9" +version = "0.4.10" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.4.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b262ed08d036ebe162123170b35703aaf9daffecb698cd367a8d585157732991"}, - {file = "ruff-0.4.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:98ec2775fd2d856dc405635e5ee4ff177920f2141b8e2d9eb5bd6efd50e80317"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4555056049d46d8a381f746680db1c46e67ac3b00d714606304077682832998e"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e91175fbe48f8a2174c9aad70438fe9cb0a5732c4159b2a10a3565fea2d94cde"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8e7b95673f22e0efd3571fb5b0cf71a5eaaa3cc8a776584f3b2cc878e46bff"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2d45ddc6d82e1190ea737341326ecbc9a61447ba331b0a8962869fcada758505"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78de3fdb95c4af084087628132336772b1c5044f6e710739d440fc0bccf4d321"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06b60f91bfa5514bb689b500a25ba48e897d18fea14dce14b48a0c40d1635893"}, - {file = "ruff-0.4.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88bffe9c6a454bf8529f9ab9091c99490578a593cc9f9822b7fc065ee0712a06"}, - {file = "ruff-0.4.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:673bddb893f21ab47a8334c8e0ea7fd6598ecc8e698da75bcd12a7b9d0a3206e"}, - {file = "ruff-0.4.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8c1aff58c31948cc66d0b22951aa19edb5af0a3af40c936340cd32a8b1ab7438"}, - {file = "ruff-0.4.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:784d3ec9bd6493c3b720a0b76f741e6c2d7d44f6b2be87f5eef1ae8cc1d54c84"}, - {file = "ruff-0.4.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:732dd550bfa5d85af8c3c6cbc47ba5b67c6aed8a89e2f011b908fc88f87649db"}, - {file = "ruff-0.4.9-py3-none-win32.whl", hash = "sha256:8064590fd1a50dcf4909c268b0e7c2498253273309ad3d97e4a752bb9df4f521"}, - {file = "ruff-0.4.9-py3-none-win_amd64.whl", hash = "sha256:e0a22c4157e53d006530c902107c7f550b9233e9706313ab57b892d7197d8e52"}, - {file = "ruff-0.4.9-py3-none-win_arm64.whl", hash = "sha256:5d5460f789ccf4efd43f265a58538a2c24dbce15dbf560676e430375f20a8198"}, - {file = "ruff-0.4.9.tar.gz", hash = "sha256:f1cb0828ac9533ba0135d148d214e284711ede33640465e706772645483427e3"}, + {file = "ruff-0.4.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c2c4d0859305ac5a16310eec40e4e9a9dec5dcdfbe92697acd99624e8638dac"}, + {file = "ruff-0.4.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a79489607d1495685cdd911a323a35871abfb7a95d4f98fc6f85e799227ac46e"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1dd1681dfa90a41b8376a61af05cc4dc5ff32c8f14f5fe20dba9ff5deb80cd6"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c75c53bb79d71310dc79fb69eb4902fba804a81f374bc86a9b117a8d077a1784"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18238c80ee3d9100d3535d8eb15a59c4a0753b45cc55f8bf38f38d6a597b9739"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d8f71885bce242da344989cae08e263de29752f094233f932d4f5cfb4ef36a81"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:330421543bd3222cdfec481e8ff3460e8702ed1e58b494cf9d9e4bf90db52b9d"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e9b6fb3a37b772628415b00c4fc892f97954275394ed611056a4b8a2631365e"}, + {file = "ruff-0.4.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f54c481b39a762d48f64d97351048e842861c6662d63ec599f67d515cb417f6"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:67fe086b433b965c22de0b4259ddfe6fa541c95bf418499bedb9ad5fb8d1c631"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:acfaaab59543382085f9eb51f8e87bac26bf96b164839955f244d07125a982ef"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3cea07079962b2941244191569cf3a05541477286f5cafea638cd3aa94b56815"}, + {file = "ruff-0.4.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:338a64ef0748f8c3a80d7f05785930f7965d71ca260904a9321d13be24b79695"}, + {file = "ruff-0.4.10-py3-none-win32.whl", hash = "sha256:ffe3cd2f89cb54561c62e5fa20e8f182c0a444934bf430515a4b422f1ab7b7ca"}, + {file = "ruff-0.4.10-py3-none-win_amd64.whl", hash = "sha256:67f67cef43c55ffc8cc59e8e0b97e9e60b4837c8f21e8ab5ffd5d66e196e25f7"}, + {file = "ruff-0.4.10-py3-none-win_arm64.whl", hash = "sha256:dd1fcee327c20addac7916ca4e2653fbbf2e8388d8a6477ce5b4e986b68ae6c0"}, + {file = "ruff-0.4.10.tar.gz", hash = "sha256:3aa4f2bc388a30d346c56524f7cacca85945ba124945fe489952aadb6b5cd804"}, ] [[package]] name = "scipy" -version = "1.13.1" +version = "1.14.0" description = "Fundamental algorithms for scientific computing in Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, - {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, - {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, - {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, - {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, - {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, - {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, - {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, - {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, - {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, - {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, - {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, - {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, - {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, - {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, - {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, - {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, - {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, - {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, - {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, - {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, - {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, - {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, - {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, - {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, -] - -[package.dependencies] -numpy = ">=1.22.4,<2.3" - -[package.extras] -dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] -doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] -test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + {file = "scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1"}, + {file = "scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0"}, + {file = "scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0"}, + {file = "scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d"}, + {file = "scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6d056a8709ccda6cf36cdd2eac597d13bc03dba38360f418560a93050c76a16e"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f0a50da861a7ec4573b7c716b2ebdcdf142b66b756a0d392c236ae568b3a93fb"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:94c164a9e2498e68308e6e148646e486d979f7fcdb8b4cf34b5441894bdb9caf"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a7d46c3e0aea5c064e734c3eac5cf9eb1f8c4ceee756262f2c7327c4c2691c86"}, + {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eee2989868e274aae26125345584254d97c56194c072ed96cb433f32f692ed8"}, + {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3154691b9f7ed73778d746da2df67a19d046a6c8087c8b385bc4cdb2cfca74"}, + {file = "scipy-1.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c40003d880f39c11c1edbae8144e3813904b10514cd3d3d00c277ae996488cdb"}, + {file = "scipy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:5b083c8940028bb7e0b4172acafda6df762da1927b9091f9611b0bcd8676f2bc"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff2438ea1330e06e53c424893ec0072640dac00f29c6a43a575cbae4c99b2b9"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bbc0471b5f22c11c389075d091d3885693fd3f5e9a54ce051b46308bc787e5d4"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:64b2ff514a98cf2bb734a9f90d32dc89dc6ad4a4a36a312cd0d6327170339eb0"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:7d3da42fbbbb860211a811782504f38ae7aaec9de8764a9bef6b262de7a2b50f"}, + {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d91db2c41dd6c20646af280355d41dfa1ec7eead235642178bd57635a3f82209"}, + {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a01cc03bcdc777c9da3cfdcc74b5a75caffb48a6c39c8450a9a05f82c4250a14"}, + {file = "scipy-1.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65df4da3c12a2bb9ad52b86b4dcf46813e869afb006e58be0f516bc370165159"}, + {file = "scipy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:4c4161597c75043f7154238ef419c29a64ac4a7c889d588ea77690ac4d0d9b20"}, + {file = "scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b"}, +] + +[package.dependencies] +numpy = ">=1.23.5,<2.3" + +[package.extras] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.13.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "send2trash" @@ -3280,18 +3291,18 @@ win32 = ["pywin32"] [[package]] name = "setuptools" -version = "70.1.0" +version = "70.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-70.1.0-py3-none-any.whl", hash = "sha256:d9b8b771455a97c8a9f3ab3448ebe0b29b5e105f1228bba41028be116985a267"}, - {file = "setuptools-70.1.0.tar.gz", hash = "sha256:01a1e793faa5bd89abc851fa15d0a0db26f160890c7102cd8dce643e886b47f5"}, + {file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"}, + {file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -3830,13 +3841,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.26.2" +version = "20.26.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, - {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, + {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, + {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, ] [package.dependencies] @@ -3903,23 +3914,24 @@ test = ["websockets"] [[package]] name = "xarray" -version = "2023.12.0" +version = "2024.6.0" description = "N-D labeled arrays and datasets in Python" optional = false python-versions = ">=3.9" files = [ - {file = "xarray-2023.12.0-py3-none-any.whl", hash = "sha256:3c22b6824681762b6c3fcad86dfd18960a617bccbc7f456ce21b43a20e455fb9"}, - {file = "xarray-2023.12.0.tar.gz", hash = "sha256:4565dbc890de47e278346c44d6b33bb07d3427383e077a7ca8ab6606196fd433"}, + {file = "xarray-2024.6.0-py3-none-any.whl", hash = "sha256:721a7394e8ec3d592b2d8ebe21eed074ac077dc1bb1bd777ce00e41700b4866c"}, + {file = "xarray-2024.6.0.tar.gz", hash = "sha256:0b91e0bc4dc0296947947640fe31ec6e867ce258d2f7cbc10bedf4a6d68340c7"}, ] [package.dependencies] -numpy = ">=1.22" -packaging = ">=21.3" -pandas = ">=1.4" +numpy = ">=1.23" +packaging = ">=23.1" +pandas = ">=2.0" [package.extras] accel = ["bottleneck", "flox", "numbagg", "opt-einsum", "scipy"] -complete = ["xarray[accel,io,parallel,viz]"] +complete = ["xarray[accel,dev,io,parallel,viz]"] +dev = ["hypothesis", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-env", "pytest-timeout", "pytest-xdist", "ruff", "xarray[complete]"] io = ["cftime", "fsspec", "h5netcdf", "netCDF4", "pooch", "pydap", "scipy", "zarr"] parallel = ["dask[complete]"] viz = ["matplotlib", "nc-time-axis", "seaborn"] @@ -3942,4 +3954,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = ">=3.10" -content-hash = "60c570ef4d977a74de54a3703da5282cd59e10c89ea5b8ad2e8573d305b30499" +content-hash = "47bf9006da7dea679c3ebd0892d08041d477bbcc3d898326280382a6e48777c8" diff --git a/pyproject.toml b/pyproject.toml index 44fafcff..d59e54c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ sphinx = "^7.0.0" sphinx-external-toc = "^1.0.0" sphinx-rtd-theme = "^2.0.0" sphinxcontrib-bibtex = "^2.6.1" -xarray = "^2023.4.0" +xarray = "^2024.6.0" [build-system] build-backend = "poetry.core.masonry.api" From a08e34bdfea2a12ce535bb8b6cdbc7384df46f75 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 17 Jul 2024 13:14:26 +0100 Subject: [PATCH 011/241] Allow kphio as an array in PModel and SubdailyPModel --- pyrealm/pmodel/pmodel.py | 19 +++++++++++++------ pyrealm/pmodel/subdaily.py | 25 +++++++++++++++++++++---- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index 4498b2c1..5ecfd444 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -186,7 +186,7 @@ class PModel: def __init__( self, env: PModelEnvironment, - kphio: float | None = None, + kphio: float | NDArray | None = None, do_ftemp_kphio: bool = True, method_optchi: str = "prentice14", method_jmaxlim: str = "wang17", @@ -205,7 +205,7 @@ def __init__( """The CoreConst instance used to create the model environment.""" # kphio calculation: - self.init_kphio: float + self.init_kphio: NDArray r"""The initial value of :math:`\phi_0` (``kphio``)""" self.kphio: NDArray r"""The value of :math:`\phi_0` used with any temperature correction applied.""" @@ -215,11 +215,18 @@ def __init__( # Set context specific defaults for kphio to match Stocker paper if kphio is None: if not self.do_ftemp_kphio: - self.init_kphio = 0.049977 + self.init_kphio = np.array([0.049977]) else: - self.init_kphio = 0.081785 + self.init_kphio = np.array([0.081785]) else: - self.init_kphio = kphio + if isinstance(kphio, float): + # A single scalar global value + self.init_kphio = np.array([kphio]) + elif isinstance(kphio, np.ndarray): + # An array of values, which must match the shape of the inputs to the + # PModelEnvironment instance. + _ = check_input_shapes(self.env.tc, kphio) + self.init_kphio = kphio # ----------------------------------------------------------------------- # Optimal ci @@ -251,7 +258,7 @@ def __init__( ) self.kphio = self.init_kphio * ftemp_kphio else: - self.kphio = np.array([self.init_kphio]) + self.kphio = self.init_kphio # ----------------------------------------------------------------------- # Calculation of Jmax limitation terms diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index b7d15d01..dbf0cd09 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -26,6 +26,7 @@ from numpy.typing import NDArray from pyrealm import ExperimentalFeatureWarning +from pyrealm.core.utilities import check_input_shapes from pyrealm.pmodel import ( PModel, PModelEnvironment, @@ -221,7 +222,7 @@ def __init__( fs_scaler: SubdailyScaler, fapar: NDArray, ppfd: NDArray, - kphio: float = 1 / 8, + kphio: float | NDArray = 1 / 8, do_ftemp_kphio: bool = True, method_optchi: str = "prentice14", method_jmaxlim: str = "wang17", @@ -254,9 +255,25 @@ def __init__( # Set up kphio attributes self.env: PModelEnvironment = env - self.init_kphio: float = kphio - self.do_ftemp_kphio = do_ftemp_kphio + """The PModelEnvironment used to fit the P Model.""" + self.do_ftemp_kphio: bool = do_ftemp_kphio + r"""Records if :math:`\phi_0` (``kphio``) is temperature corrected.""" + + # kphio calculation: + self.init_kphio: NDArray + r"""The initial value of :math:`\phi_0` (``kphio``)""" self.kphio: NDArray + r"""The value of :math:`\phi_0` used with any temperature correction applied.""" + + # Setup initial kphio + if isinstance(kphio, float): + # A single scalar global value + self.init_kphio = np.array([kphio]) + elif isinstance(kphio, np.ndarray): + # An array of values, which must match the shape of the inputs to the + # PModelEnvironment instance. + _ = check_input_shapes(self.env.tc, kphio) + self.init_kphio = kphio # 1) Generate a PModelEnvironment containing the average conditions within the # daily acclimation window, including any optional variables required by the @@ -371,7 +388,7 @@ def __init__( ) self.kphio = self.init_kphio * ftemp_kphio else: - self.kphio = np.array([self.init_kphio]) + self.kphio = self.init_kphio self.subdaily_Ac: NDArray = self.subdaily_vcmax * self.optimal_chi.mc """Estimated subdaily :math:`A_c`.""" From e1bc29af986c9f44611807559c0e4e65e8141602 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 17 Jul 2024 16:27:35 +0100 Subject: [PATCH 012/241] Docstrings and updates to args for subdaily model --- pyrealm/pmodel/pmodel.py | 4 +++- pyrealm/pmodel/subdaily.py | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index 5ecfd444..853aa621 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -145,7 +145,9 @@ class PModel: kphio: (Optional) The quantum yield efficiency of photosynthesis (:math:`\phi_0`, unitless). Note that :math:`\phi_0` is sometimes used to refer to the quantum yield of electron transfer, which is exactly four times - larger, so check definitions here. + larger, so check definitions here. This is often a single global value, but + the argument also accepts externally calculated per-observation estimates of + kphio. method_optchi: (Optional, default=`prentice14`) Selects the method to be used for calculating optimal :math:`chi`. The choice of method also sets the choice of C3 or C4 photosynthetic pathway (see diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index dbf0cd09..bf50298a 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -211,7 +211,11 @@ class SubdailyPModel: function be allowed to hold over values to fill missing values. allow_partial_data: Should estimates of daily optimal conditions be calculated with missing values in the acclimation window. - kphio: The quantum yield efficiency of photosynthesis (:math:`\phi_0`, -). + kphio: The quantum yield efficiency of photosynthesis (:math:`\phi_0`, -). Note + that :math:`\phi_0` is sometimes used to refer to the quantum yield of + electron transfer, which is exactly four times larger, so check definitions + here. This is often a single global value, but the argument also accepts + externally calculated per-observation estimates of kphio. fill_kind: The approach used to fill daily realised values to the subdaily timescale, currently one of 'previous' or 'linear'. """ From b7218003bd47f0ad278bb5a8bb45c53e3fb0344a Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 17 Jul 2024 16:28:02 +0100 Subject: [PATCH 013/241] Testing of array inputs of kphio --- tests/unit/pmodel/test_kphio_inputs.py | 99 ++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 tests/unit/pmodel/test_kphio_inputs.py diff --git a/tests/unit/pmodel/test_kphio_inputs.py b/tests/unit/pmodel/test_kphio_inputs.py new file mode 100644 index 00000000..baefd562 --- /dev/null +++ b/tests/unit/pmodel/test_kphio_inputs.py @@ -0,0 +1,99 @@ +"""Test kphio inputs to PModel. + +These tests check that the behaviour of the array kphio input options work as +expected. The input values here are the simple scalar inputs to the rpmodel regression +tests. +""" + +from types import SimpleNamespace + +import numpy as np +import pytest + + +@pytest.fixture +def basic_inputs_and_expected(): + """Provides some simple test values and expectations.""" + return ( + SimpleNamespace( + tc=np.array([20]), + patm=np.array([101325]), + co2=np.array([400]), + vpd=np.array([1000]), + fapar=np.array([1]), + ppfd=np.array([300]), + ), + SimpleNamespace( + gpp=np.array([71.2246803]), + chi=np.array([0.69435201]), + vcmax=np.array([17.75034477]), + jmax=np.array([40.03293277]), + ), + ) + + +def test_scalar_kphio(basic_inputs_and_expected): + """Test that the basic test inputs give the correct answer.""" + + from pyrealm.pmodel import PModel, PModelEnvironment + + inputs, expected = basic_inputs_and_expected + + env = PModelEnvironment( + tc=inputs.tc, patm=inputs.patm, co2=inputs.co2, vpd=inputs.vpd + ) + mod = PModel(env, kphio=0.05, do_ftemp_kphio=False) + mod.estimate_productivity(fapar=inputs.fapar, ppfd=inputs.ppfd) + + assert np.allclose(mod.gpp, expected.gpp) + assert np.allclose(mod.optchi.chi, expected.chi) + assert np.allclose(mod.jmax, expected.jmax) + assert np.allclose(mod.vcmax, expected.vcmax) + + +@pytest.fixture +def variable_kphio(self, basic_inputs_and_expected): + """Calculates gpp with alternate kphio by iteration. + + This uses the original single scalar value approach (tested above) to get + expected values for a wide range of kphio values by iteration. + """ + + from pyrealm.pmodel import PModel, PModelEnvironment + + inputs, _ = basic_inputs_and_expected + + # Set a large range of values to use in testing + kphio_values = np.arange(0.001, 0.126, step=0.001) + gpp = np.empty_like(kphio_values) + + for idx, kph in enumerate(kphio_values): + env = PModelEnvironment( + tc=inputs.tc, patm=inputs.patm, co2=inputs.co2, vpd=inputs.vpd + ) + mod = PModel(env, kphio=kph, do_ftemp_kphio=False) + mod.estimate_productivity(fapar=inputs.fapar, ppfd=inputs.ppfd) + gpp[idx] = mod.gpp + + return kphio_values, gpp + + +@pytest.mark.parametrize(argnames="shape", argvalues=[(125,), (25, 5), (5, 5, 5)]) +def test_kphio_arrays(self, basic_inputs_and_expected, variable_kphio, shape): + """Check behaviour with array inputs of kphio.""" + + from pyrealm.pmodel import PModel, PModelEnvironment + + inputs, _ = basic_inputs_and_expected + kphio_vals, expected_gpp = variable_kphio + + env = PModelEnvironment( + tc=np.broadcast_to(inputs.tc, shape), + patm=np.broadcast_to(inputs.patm, shape), + co2=np.broadcast_to(inputs.co2, shape), + vpd=np.broadcast_to(inputs.vpd, shape), + ) + mod = PModel(env, kphio=kphio_vals.reshape(shape), do_ftemp_kphio=False) + mod.estimate_productivity(fapar=inputs.fapar, ppfd=inputs.ppfd) + + assert np.allclose(mod.gpp, expected_gpp.reshape(shape)) From 52011625367bee2cadf03a50ec1e0e6909ae70ea Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 17 Jul 2024 18:25:03 +0100 Subject: [PATCH 014/241] Made subdaily test data available as a fixture through the pmodel unit test suite --- tests/unit/pmodel/conftest.py | 21 +++++++++++++++++++++ tests/unit/pmodel/test_subdaily.py | 17 ----------------- 2 files changed, 21 insertions(+), 17 deletions(-) create mode 100644 tests/unit/pmodel/conftest.py diff --git a/tests/unit/pmodel/conftest.py b/tests/unit/pmodel/conftest.py new file mode 100644 index 00000000..de2616f6 --- /dev/null +++ b/tests/unit/pmodel/conftest.py @@ -0,0 +1,21 @@ +"""Shared fixture definitions for the PModel unit test suite.""" + +from importlib import resources + +import pandas +import pytest + + +@pytest.fixture(scope="module") +def be_vie_data(): + """Import the subdaily model benchmark test data.""" + + # Load the BE-Vie data + data_path = ( + resources.files("pyrealm_build_data.subdaily") / "subdaily_BE_Vie_2014.csv" + ) + + data = pandas.read_csv(str(data_path)) + data["time"] = pandas.to_datetime(data["time"]) + + return data diff --git a/tests/unit/pmodel/test_subdaily.py b/tests/unit/pmodel/test_subdaily.py index e6ed5c0e..c3e3be96 100644 --- a/tests/unit/pmodel/test_subdaily.py +++ b/tests/unit/pmodel/test_subdaily.py @@ -2,30 +2,13 @@ import datetime from contextlib import nullcontext as does_not_raise -from importlib import resources import numpy as np -import pandas import pytest from pyrealm.pmodel.optimal_chi import OPTIMAL_CHI_CLASS_REGISTRY -@pytest.fixture(scope="module") -def be_vie_data(): - """Import the benchmark test data.""" - - # Load the BE-Vie data - data_path = ( - resources.files("pyrealm_build_data.subdaily") / "subdaily_BE_Vie_2014.csv" - ) - - data = pandas.read_csv(str(data_path)) - data["time"] = pandas.to_datetime(data["time"]) - - return data - - @pytest.fixture(scope="function") def be_vie_data_components(be_vie_data): """Provides a data factory to convert the test data into a PModelEnv and arrays. From c53408d1f6aa104f21b61b636941680af83939de Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 17 Jul 2024 19:28:10 +0100 Subject: [PATCH 015/241] Extended array kphio testing to subdaily - fixed (experimentally) what subdaily model does with internal daily model and array kphio --- pyrealm/pmodel/pmodel.py | 6 +- pyrealm/pmodel/subdaily.py | 14 ++++- tests/unit/pmodel/conftest.py | 87 ++++++++++++++++++++++++++ tests/unit/pmodel/test_kphio_inputs.py | 86 ++++++++++++++++++++++++- tests/unit/pmodel/test_subdaily.py | 86 ------------------------- 5 files changed, 186 insertions(+), 93 deletions(-) diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index 853aa621..bdaa3627 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -217,13 +217,13 @@ def __init__( # Set context specific defaults for kphio to match Stocker paper if kphio is None: if not self.do_ftemp_kphio: - self.init_kphio = np.array([0.049977]) + self.init_kphio = np.array(0.049977) else: - self.init_kphio = np.array([0.081785]) + self.init_kphio = np.array(0.081785) else: if isinstance(kphio, float): # A single scalar global value - self.init_kphio = np.array([kphio]) + self.init_kphio = np.array(kphio) elif isinstance(kphio, np.ndarray): # An array of values, which must match the shape of the inputs to the # PModelEnvironment instance. diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index bf50298a..a10838f0 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -272,7 +272,7 @@ def __init__( # Setup initial kphio if isinstance(kphio, float): # A single scalar global value - self.init_kphio = np.array([kphio]) + self.init_kphio = np.array(kphio) elif isinstance(kphio, np.ndarray): # An array of values, which must match the shape of the inputs to the # PModelEnvironment instance. @@ -306,9 +306,19 @@ def __init__( # 2) Fit a PModel to those environmental conditions, using the supplied settings # for the original model. + + # If the kphio is a non-scalar array, use the mean kphio within the window to + # calculate the daily optimal behaviour. + if np.ndim(self.init_kphio) > 0: + daily_kphio = fs_scaler.get_daily_means( + self.init_kphio, allow_partial_data=allow_partial_data + ) + else: + daily_kphio = self.init_kphio + self.pmodel_acclim: PModel = PModel( pmodel_env_acclim, - kphio=kphio, + kphio=daily_kphio, do_ftemp_kphio=do_ftemp_kphio, method_optchi=method_optchi, method_jmaxlim=method_jmaxlim, diff --git a/tests/unit/pmodel/conftest.py b/tests/unit/pmodel/conftest.py index de2616f6..a98bf84e 100644 --- a/tests/unit/pmodel/conftest.py +++ b/tests/unit/pmodel/conftest.py @@ -1,7 +1,9 @@ """Shared fixture definitions for the PModel unit test suite.""" +import datetime from importlib import resources +import numpy as np import pandas import pytest @@ -19,3 +21,88 @@ def be_vie_data(): data["time"] = pandas.to_datetime(data["time"]) return data + + +@pytest.fixture(scope="function") +def be_vie_data_components(be_vie_data): + """Provides a data factory to convert the test data into a PModelEnv and arrays. + + This fixture returns an instance of a DataFactory class, that provides a `get` + method to allow different subsets of the data to be built into the inputs for + subdaily model testing. Providing this as a DataFactory generator allows tests to + access more than one subset of the same data, which is useful in comparing the + behaviour of complete and incomplete daily datetime sequences. + + The get method supports two modes, "pad" and "crop, both of which also require a + `start` and `end` value. + + * In "pad" mode, the original time series is extended by the specified number of + half hourly steps at the start and end of the original data. The datetimes are + filled in to give an actual time series but the data values are simply padded with + `np.nan`. This is used to check that the presence of incomplete days does not + affect the prediction of the sequence of GPP values. Since the actual data are not + changed, the padded data should pass without affecting the calculations. + + * In "crop" mode, the original time series is cropped to only the rows in start:end. + This is used to assess the behaviour of incomplete day handling and the switch + points between providing daily estimates. + """ + + from pyrealm.pmodel import PModelEnvironment + + class DataFactory: + def get( + self, + mode: str = "", + start: int = 0, + end: int = 0, + pre_average: list[datetime.time] | None = None, + ): + # Get a copy of the data so as to not break the module scope loaded object. + data = be_vie_data.copy() + + # Implement the two sampling modes + if mode == "pad": + # Get the new time series with the padded times + datetime_subdaily = data["time"].to_numpy() + spacing = np.diff(datetime_subdaily)[0] + pad_start = datetime_subdaily[0] - np.arange(start, 0, -1) * spacing + pad_end = datetime_subdaily[-1] + np.arange(1, end + 1, 1) * spacing + + # Pad the data frame with np.nan as requested + data.index = range(start, len(data) + start) + data = data.reindex(range(0, len(data) + start + end)) + + # Set the new times into the data frame + data["time"] = np.concatenate([pad_start, datetime_subdaily, pad_end]) + + if mode == "crop": + # Crop the data to the requested block + data = data.iloc[start:end] + + datetime_subdaily = data["time"].to_numpy() + ppfd_subdaily = data["ppfd"].to_numpy() + fapar_subdaily = data["fapar"].to_numpy() + expected_gpp = data["GPP_JAMES"].to_numpy() + + # Create the environment including some randomly distributed water variables + # to test the methods that require those variables + rng = np.random.default_rng() + subdaily_env = PModelEnvironment( + tc=data["ta"].to_numpy(), + vpd=data["vpd"].to_numpy(), + co2=data["co2"].to_numpy(), + patm=data["patm"].to_numpy(), + theta=rng.uniform(low=0.5, high=0.8, size=ppfd_subdaily.shape), + rootzonestress=rng.uniform(low=0.7, high=1.0, size=ppfd_subdaily.shape), + ) + + return ( + subdaily_env, + ppfd_subdaily, + fapar_subdaily, + datetime_subdaily, + expected_gpp, + ) + + return DataFactory() diff --git a/tests/unit/pmodel/test_kphio_inputs.py b/tests/unit/pmodel/test_kphio_inputs.py index baefd562..eddf01c7 100644 --- a/tests/unit/pmodel/test_kphio_inputs.py +++ b/tests/unit/pmodel/test_kphio_inputs.py @@ -52,7 +52,7 @@ def test_scalar_kphio(basic_inputs_and_expected): @pytest.fixture -def variable_kphio(self, basic_inputs_and_expected): +def variable_kphio(basic_inputs_and_expected): """Calculates gpp with alternate kphio by iteration. This uses the original single scalar value approach (tested above) to get @@ -79,7 +79,7 @@ def variable_kphio(self, basic_inputs_and_expected): @pytest.mark.parametrize(argnames="shape", argvalues=[(125,), (25, 5), (5, 5, 5)]) -def test_kphio_arrays(self, basic_inputs_and_expected, variable_kphio, shape): +def test_kphio_arrays(basic_inputs_and_expected, variable_kphio, shape): """Check behaviour with array inputs of kphio.""" from pyrealm.pmodel import PModel, PModelEnvironment @@ -97,3 +97,85 @@ def test_kphio_arrays(self, basic_inputs_and_expected, variable_kphio, shape): mod.estimate_productivity(fapar=inputs.fapar, ppfd=inputs.ppfd) assert np.allclose(mod.gpp, expected_gpp.reshape(shape)) + + +@pytest.fixture +def variable_kphio_subdaily(be_vie_data_components): + """Calculates gpp with alternate kphio by iteration. + + This uses the original single scalar value approach (tested above) to get + expected values for a wide range of kphio values by iteration across the time frame + of a subdaily model. + """ + + from pyrealm.pmodel import SubdailyScaler + from pyrealm.pmodel.subdaily import SubdailyPModel + + env, ppfd, fapar, datetime, expected_gpp = be_vie_data_components.get() + + # Get the fast slow scaler and set window + fsscaler = SubdailyScaler(datetime) + fsscaler.set_window( + window_center=np.timedelta64(12, "h"), + half_width=np.timedelta64(30, "m"), + ) + + # Set a large range of values to use in testing + kphio_values = np.arange(0.001, 0.126, step=0.001) + gpp = np.empty((len(datetime), len(kphio_values))) + + for idx, kphio in enumerate(kphio_values): + # Run as a subdaily model + subdaily_pmodel = SubdailyPModel( + env=env, + ppfd=ppfd, + fapar=fapar, + kphio=kphio, + fs_scaler=fsscaler, + allow_holdover=True, + ) + gpp[:, idx] = subdaily_pmodel.gpp + + return kphio_values, gpp + + +@pytest.mark.parametrize( + argnames="shape,new_dims", + argvalues=[((17520, 125), (1,)), ((17520, 25, 5), (1, 2))], +) +def test_kphio_arrays_subdaily( + be_vie_data_components, variable_kphio_subdaily, shape, new_dims +): + """Check behaviour with array inputs of kphio.""" + + from pyrealm.pmodel import PModelEnvironment, SubdailyPModel, SubdailyScaler + + env, ppfd, fapar, datetime, expected_gpp = be_vie_data_components.get() + kphio_vals, expected_gpp = variable_kphio_subdaily + + # Get the fast slow scaler and set window + fsscaler = SubdailyScaler(datetime) + fsscaler.set_window( + window_center=np.timedelta64(12, "h"), + half_width=np.timedelta64(30, "m"), + ) + + # Run a subdaily model, reshaping the inputs to arrays rather than a single site to + # then test input arrays of kphio values. + env = PModelEnvironment( + tc=np.broadcast_to(np.expand_dims(env.tc, axis=new_dims), shape), + patm=np.broadcast_to(np.expand_dims(env.patm, axis=new_dims), shape), + co2=np.broadcast_to(np.expand_dims(env.co2, axis=new_dims), shape), + vpd=np.broadcast_to(np.expand_dims(env.vpd, axis=new_dims), shape), + ) + + subdaily_pmodel = SubdailyPModel( + env=env, + ppfd=np.broadcast_to(np.expand_dims(ppfd, axis=new_dims), shape), + fapar=np.broadcast_to(np.expand_dims(fapar, axis=new_dims), shape), + kphio=np.broadcast_to(kphio_vals.reshape(shape[1:]), shape), + fs_scaler=fsscaler, + allow_holdover=True, + ) + + assert np.allclose(subdaily_pmodel.gpp, expected_gpp.reshape(shape), equal_nan=True) diff --git a/tests/unit/pmodel/test_subdaily.py b/tests/unit/pmodel/test_subdaily.py index c3e3be96..f52eb913 100644 --- a/tests/unit/pmodel/test_subdaily.py +++ b/tests/unit/pmodel/test_subdaily.py @@ -1,6 +1,5 @@ """Tests the implementation of the FastSlowModel against the reference benchmark.""" -import datetime from contextlib import nullcontext as does_not_raise import numpy as np @@ -9,91 +8,6 @@ from pyrealm.pmodel.optimal_chi import OPTIMAL_CHI_CLASS_REGISTRY -@pytest.fixture(scope="function") -def be_vie_data_components(be_vie_data): - """Provides a data factory to convert the test data into a PModelEnv and arrays. - - This fixture returns an instance of a DataFactory class, that provides a `get` - method to allow different subsets of the data to be built into the inputs for - subdaily model testing. Providing this as a DataFactory generator allows tests to - access more than one subset of the same data, which is useful in comparing the - behaviour of complete and incomplete daily datetime sequences. - - The get method supports two modes, "pad" and "crop, both of which also require a - `start` and `end` value. - - * In "pad" mode, the original time series is extended by the specified number of - half hourly steps at the start and end of the original data. The datetimes are - filled in to give an actual time series but the data values are simply padded with - `np.nan`. This is used to check that the presence of incomplete days does not - affect the prediction of the sequence of GPP values. Since the actual data are not - changed, the padded data should pass without affecting the calculations. - - * In "crop" mode, the original time series is cropped to only the rows in start:end. - This is used to assess the behaviour of incomplete day handling and the switch - points between providing daily estimates. - """ - - from pyrealm.pmodel import PModelEnvironment - - class DataFactory: - def get( - self, - mode: str = "", - start: int = 0, - end: int = 0, - pre_average: list[datetime.time] | None = None, - ): - # Get a copy of the data so as to not break the module scope loaded object. - data = be_vie_data.copy() - - # Implement the two sampling modes - if mode == "pad": - # Get the new time series with the padded times - datetime_subdaily = data["time"].to_numpy() - spacing = np.diff(datetime_subdaily)[0] - pad_start = datetime_subdaily[0] - np.arange(start, 0, -1) * spacing - pad_end = datetime_subdaily[-1] + np.arange(1, end + 1, 1) * spacing - - # Pad the data frame with np.nan as requested - data.index = range(start, len(data) + start) - data = data.reindex(range(0, len(data) + start + end)) - - # Set the new times into the data frame - data["time"] = np.concatenate([pad_start, datetime_subdaily, pad_end]) - - if mode == "crop": - # Crop the data to the requested block - data = data.iloc[start:end] - - datetime_subdaily = data["time"].to_numpy() - ppfd_subdaily = data["ppfd"].to_numpy() - fapar_subdaily = data["fapar"].to_numpy() - expected_gpp = data["GPP_JAMES"].to_numpy() - - # Create the environment including some randomly distributed water variables - # to test the methods that require those variables - rng = np.random.default_rng() - subdaily_env = PModelEnvironment( - tc=data["ta"].to_numpy(), - vpd=data["vpd"].to_numpy(), - co2=data["co2"].to_numpy(), - patm=data["patm"].to_numpy(), - theta=rng.uniform(low=0.5, high=0.8, size=ppfd_subdaily.shape), - rootzonestress=rng.uniform(low=0.7, high=1.0, size=ppfd_subdaily.shape), - ) - - return ( - subdaily_env, - ppfd_subdaily, - fapar_subdaily, - datetime_subdaily, - expected_gpp, - ) - - return DataFactory() - - def test_SubdailyPModel_JAMES(be_vie_data_components): """Test SubdailyPModel_JAMES. From 5badcda327204194ba7ba9fa5a6434294cd55c67 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 17 Jul 2024 19:32:19 +0100 Subject: [PATCH 016/241] Docstring warning on array kphio and subdaily models --- pyrealm/pmodel/subdaily.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index a10838f0..706b151e 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -181,6 +181,12 @@ class SubdailyPModel: :math:`\xi` but subdaily values in the other parameters. * Predictions of GPP are then made as in the standard P Model. + As with the :class:`~pyrealm.pmodel.pmodel.PModel`, the values of the `kphio` + argument _can_ be provided as an array of values, potentially varying through time + and space. The behaviour of the daily model that drives acclimation here is to take + the daily mean `kphio` value for each time series within the acclimation window, as + for the other variables. This is an experimental solution! + Missing values: Missing data can arise in a number of ways: actual gaps in the forcing data, the From ff1516a73a54e8772ff7cc32f39857caf70d78a7 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 18 Jul 2024 09:22:52 +0100 Subject: [PATCH 017/241] Short user facing documentation on per-observation kphio --- .../pmodel/pmodel_details/lue_limitation.md | 59 +++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/docs/source/users/pmodel/pmodel_details/lue_limitation.md b/docs/source/users/pmodel/pmodel_details/lue_limitation.md index eb082d02..986157fb 100644 --- a/docs/source/users/pmodel/pmodel_details/lue_limitation.md +++ b/docs/source/users/pmodel/pmodel_details/lue_limitation.md @@ -63,6 +63,14 @@ where $\phi_0$ is the quantum yield efficiency of photosynthesis, $M_C$ is the molar mass of carbon and $m_j$ is the $\ce{CO2}$ limitation term of light use efficiency from the calculation of optimal $\chi$. +```{warning} + +Note that $\phi_0$ is sometimes used to refer to the quantum yield of electron +transfer, which is exactly four times larger than the quantum yield of +photosynthesis. + +``` + However, the {class}`pyrealm.pmodel.pmodel.PModel` class also incorporates two further factors: @@ -70,23 +78,14 @@ factors: * $J_{max}$ limitation of $m_j$ by a factor $f_v$ and $$ - \text{LUE} = \phi_0(t) \cdot M_C \cdot m_j \cdot f_v$ + \text{LUE} = \phi_0(t) \cdot M_C \cdot m_j \cdot f_v $$ ### $\phi_0$ and temperature dependency The {class}`~pyrealm.pmodel.pmodel.PModel` uses a single variable to capture the -apparent quantum yield efficiency of photosynthesis (`kphio`, $\phi_0$). - -```{warning} - -Note that $\phi_0$ is sometimes used to refer to the quantum yield of electron -transfer, which is exactly four times larger than the quantum yield of -photosynthesis. - -``` - -The value of $\phi_0$ shows temperature dependence, which is modelled following +apparent quantum yield efficiency of photosynthesis (`kphio`, $\phi_0$). The value of +$\phi_0$ shows temperature dependence, which is modelled following {cite:t}`Bernacchi:2003dc` for C3 plants and {cite:t}`cai:2020a` for C4 plants (see {func}`~pyrealm.pmodel.functions.calc_ftemp_kphio`). The temperature dependency is applied by default but can be turned off using the @@ -142,6 +141,42 @@ pyplot.legend() pyplot.show() ``` +### Setting $\phi_0$ directly + +In addition to fixed or temperature dependent $\phi_0$, it is also possible to provide +$\phi_0$ values for each observation in the P Model. In this case, you will need to +provide an array of values that has the same shape as the other driver variables and +these values are then used within the calculations for each observation. + +This option is provided to allow users to experiment with alternative per-observation +calculations of $\phi_0$ limitation - for example, modulation of $\phi_0$ by temperature +and aridity - that are not implemented within the `PModel` or `SubdailyPModel` classes. +This approach is used in the plot below to show the simple linear scaling of LUE with +$\phi_0$ for a constant environment. + +```{code-cell} +:tags: [hide-input] + +# A constant environment to show a range of kphio values +kphio_values = np.arange(0, 0.126, step=0.001) +n_vals = len(kphio_values) + +env = PModelEnvironment( + tc=np.repeat(20, n_vals), + patm=np.repeat(101325, n_vals), + vpd=np.repeat(820, n_vals), + co2=np.repeat(400, n_vals), +) +model_var_kphio = PModel(env, kphio=kphio_values, do_ftemp_kphio=False) + +# Create a line plot of ftemp kphio +pyplot.plot(kphio_values, model_var_kphio.lue) +pyplot.title("Variation in LUE with changing $\phi_0$") +pyplot.xlabel("$\phi_0$") +pyplot.ylabel("LUE") +pyplot.show() +``` + ### Limitation of electron transfer rate ($J_{max}$) and carboxylation capacity ($V_{cmax}$) The {class}`~pyrealm.pmodel.pmodel.PModel` implements three alternative approaches to From 7886411e1af6ab5f6c6ae2e748c5a29738af3a51 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 25 Jul 2024 16:35:38 +0100 Subject: [PATCH 018/241] Initial draft of new quantum yield module: some mypy issues --- pyrealm/pmodel/functions.py | 75 +- pyrealm/pmodel/quantum_yield.py | 255 + pyrealm_build_data/sandoval_kphio/calc_phi0.R | 91 + .../sandoval_kphio/sandoval_kphio.csv | 8001 +++++++++++++++++ 4 files changed, 8420 insertions(+), 2 deletions(-) create mode 100644 pyrealm/pmodel/quantum_yield.py create mode 100644 pyrealm_build_data/sandoval_kphio/calc_phi0.R create mode 100644 pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index 91d921d3..f666794a 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -14,6 +14,7 @@ def calc_ftemp_arrh( tk: NDArray, ha: float, + tk_ref: NDArray | None = None, pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), ) -> NDArray: @@ -47,6 +48,7 @@ def calc_ftemp_arrh( Args: tk: Temperature (in Kelvin) ha: Activation energy (in :math:`J \text{mol}^{-1}`) + tk_ref: The reference temperature for the reaction. pmodel_const: Instance of :class:`~pyrealm.constants.pmodel_const.PModelConst`. core_const: Instance of :class:`~pyrealm.constants.core_const.CoreConst`. @@ -69,9 +71,10 @@ def calc_ftemp_arrh( # exp( ha * (tc - 25.0)/(298.15 * kR * (tc + 273.15)) ) # exp( (ha/kR) * (1/298.15 - 1/tk) ) - tkref = pmodel_const.plant_T_ref + core_const.k_CtoK + if tk_ref is None: + tk_ref = np.array([pmodel_const.plant_T_ref + core_const.k_CtoK]) - return np.exp(ha * (tk - tkref) / (tkref * core_const.k_R * tk)) + return np.exp(ha * (tk - tk_ref) / (tk_ref * core_const.k_R * tk)) def calc_ftemp_inst_rd( @@ -194,6 +197,74 @@ def calc_ftemp_inst_vcmax( return fva * fvb +def calc_modified_arrhenius_factor( + tk: NDArray, + Ha: NDArray, + Hd: NDArray, + deltaS: NDArray, + mode: str = "M2002", + tk_ref: NDArray | None = None, + pmodel_const: PModelConst = PModelConst(), + core_const: CoreConst = CoreConst(), +) -> NDArray: + r"""Calculate the modified Arrhenius factor with temperature for an enzyme. + + This function returns a temperature-determined factor expressing the rate of an + enzymatic process relative to the rate at a given reference temperature. This is + used in the calculation of :math:`V_{cmax}` but also other temperature dependent + enzymatic processes. + + The function can operate in one of two modes ("M2002" or "J1942") using the two + alternative derivations of the modified Arrhenius relationship presented in + :cite:`murphy:2021a`. + + Args: + tk: The temperature at which to calculate the factor (K) + Ha: The activation energy of the enzyme (:math:`H_a`) + Hd: The deactivation energy of the enzyme (:math:`H_d`) + deltaS: The entropy of the process (:math:`\Delta S`) + tk_ref: The reference temperature for the process (K) + mode: The calculation mode. + pmodel_const: Instance of :class:`~pyrealm.constants.pmodel_const.PModelConst`. + core_const: Instance of :class:`~pyrealm.constants.core_const.CoreConst`. + + PModel Parameters: + To: The standard reference temperature expressed in Kelvin (`T_0`, ``k_To``) + R: the universal gas constant (:math:`R`, ``k_R``) + + Returns: + Values for :math:`f` + + Examples: + >>> # Relative change in Vcmax going (instantaneously, i.e. not + >>> # not acclimatedly) from 10 to 25 degrees (percent change): + >>> val = ((calc_ftemp_inst_vcmax(25)/calc_ftemp_inst_vcmax(10)-1) * 100) + >>> round(val, 4) + np.float64(283.1775) + """ + + if mode not in ["M2002", "J1942"]: + raise ValueError( + f"Unknown mode option for calc_modified_arrhenius_factor: {mode}" + ) + + # Convert temperatures to Kelvin + if tk_ref is None: + tk_ref = pmodel_const.plant_T_ref + core_const.k_CtoK + + # Calculate Arrhenius components + fva = calc_ftemp_arrh(tk=tk, ha=Ha, tk_ref=tk_ref) + + fvb = (1 + np.exp((tk_ref * deltaS - Hd) / (core_const.k_R * tk_ref))) / ( + 1 + np.exp((tk * deltaS - Hd) / (core_const.k_R * tk)) + ) + + if mode == "M2002": + return fva * fvb + elif mode == "J1942": + return fva * (tk / tk_ref) * fvb + + def calc_ftemp_kphio( tc: NDArray, c4: bool = False, pmodel_const: PModelConst = PModelConst() ) -> NDArray: diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py new file mode 100644 index 00000000..04fc9338 --- /dev/null +++ b/pyrealm/pmodel/quantum_yield.py @@ -0,0 +1,255 @@ +r"""The module :mod:`~pyrealm.pmodel.quantum_yield` provides +the abstract base class :class:`~pyrealm.pmodel.quantum_yield.QuantumYieldABC`, +which is used to support different implementations of the calculation of the intrinsic +quantum yield of photosynthesis. +""" # noqa D210, D415 + +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Any +from warnings import warn + +import numpy as np +from numpy.typing import NDArray + +from pyrealm import ExperimentalFeatureWarning +from pyrealm.constants import CoreConst, PModelConst +from pyrealm.core.utilities import ( + check_input_shapes, + evaluate_horner_polynomial, + summarize_attrs, +) +from pyrealm.pmodel.functions import calc_modified_arrhenius_factor +from pyrealm.pmodel.pmodel_environment import PModelEnvironment + +QUANTUM_YIELD_CLASS_REGISTRY: dict[str, type[QuantumYieldABC]] = {} +r"""A registry for intrinsic quantum yield of photosynthesis calculation classes. + +Different implementations of the calculation of the intrinsic quantum yield of +photosynthesis (:math:`\phi_{0}`) must all be subclasses of +:class:`~pyrealm.pmodel.quantum_yield.QuantumYieldABC` abstract base class. This +dictionary is used as a registry for defined subclasses and a method name is used to +retrieve a particular implementation from this registry. For example: + +.. code:: python + + bianchi_phi_0 = QUANTUM_YIELD_CLASS_REGISTRY['bianchi'] +""" + + +class QuantumYieldABC(ABC): + r"""ABC for calculating the intrinsic quantum yield of photosynthesis. + + This provides an abstract base class for the implementation of alternative + approaches to calculating the the intrinsic quantum yield of photosynthesis. All + implementations estimate the :math:`\phi_{0} following values, which is then stored + in the ``kphio`` attribute of the resulting class instance. + + The abstract base class requires that implementations of specific approaches defines + the `calculate_kphio` method. The provides the approach specific calculation of + ``kphio`` and is automatically called by the ``__init__`` method when a subclass + instance is created. + + Args: + env: An instance of + :class:`~pyrealm.pmodel.pmodel_environment.PModelEnvironment` providing the + photosynthetic environment for the model. + pmodel_const: An instance of + :class:`~pyrealm.constants.pmodel_const.PModelConst`. + + Returns: + Instances of the abstract base class should not be created - use instances of + specific subclasses. + """ + + method: str + """A short method name used to identify the class in + :data:`~pyrealm.pmodel.quantum_yield.QUANTUM_YIELD_CLASS_REGISTRY`. + """ + is_c4: bool + """A flag indicating if the method captures the C4 photosynthetic pathway.""" + requires: list[str] + """A list of names of optional attributes of + :class:`~pyrealm.pmodel.pmodel_environment.PModelEnvironment` that must be populated + to use a method. + """ + + def __init__( + self, + env: PModelEnvironment, + pmodel_const: PModelConst = PModelConst(), + core_const: CoreConst = CoreConst(), + ): + self.env: PModelEnvironment = env + """The PModelEnvironment containing the photosynthetic environment for the + model.""" + self.shape: tuple[int, ...] = env.shape + """The shape of the input environment data.""" + self.pmodel_const: PModelConst = pmodel_const + """The PModelConst used for calculating quantum yield""" + self.core_const: CoreConst = core_const + """The CoreConst used for calculating quantum yield""" + + # Declare attributes populated by methods. These are typed but not assigned a + # default value as they must are populated by the subclass specific + # calculate_kphio method, which is called below to populate the values. + self.kphio: NDArray + """The intrinsic quantum yield of photosynthesis.""" + + # Run the calculation methods after checking for any required variables + self._check_requires() + self._calculate_kphio() + + # Validate that the subclass methods populate the attributes correctly. + _ = check_input_shapes(env.ca, self.kphio) + + @abstractmethod + def _calculate_kphio(self, **kwargs: Any) -> None: + """Calculate the intrinsic quantum yield of photosynthesis.""" + + def _check_requires(self) -> None: + """Check additional required variables are present.""" + + for required_var in self.requires: + if getattr(self.env, required_var) is None: + raise ValueError( + f"{self.__class__.__name__} (method {self.method}) requires " + f"{required_var} to be provided in the PModelEnvironment." + ) + + def __repr__(self) -> str: + """Generates a string representation of an QuantumYield instance.""" + return f"{type(self).__name__}(shape={self.shape})" + + def summarize(self, dp: int = 2) -> None: + """Print QuantumYield summary. + + Prints a summary of the variables calculated within an instance + of QuantumYield including the mean, range and number of nan values. + + Args: + dp: The number of decimal places used in rounding summary stats. + """ + + attrs = [("kphio", "-")] + + summarize_attrs(self, attrs, dp=dp) + + @classmethod + def __init_subclass__(cls, method: str, is_c4: bool, requires: list[str]) -> None: + """Initialise a subclass deriving from this ABC.""" + + cls.method = method + cls.is_c4 = is_c4 + cls.requires = requires + QUANTUM_YIELD_CLASS_REGISTRY[cls.method] = cls + + +class QuantumYieldConstant( + QuantumYieldABC, + method="constant", + is_c4=False, + requires=[], +): + """Constant kphio.""" + + def _calculate_kphio(self, **kwargs: Any) -> None: + """Constant kphio.""" + + if "init_kphio" not in kwargs: + raise ValueError("Missing definition of initial kphio.") + + self.kphio = np.array([kwargs["init_kphio"]]) + + +class QuantumYieldBernacchiC3( + QuantumYieldABC, + method="bernacchi_c3", + is_c4=False, + requires=[], +): + """Calculate kphio following Bernacchi for C3 plants.""" + + def _calculate_kphio(self, **kwargs: Any) -> None: + """Calculate kphio.""" + + if "init_kphio" not in kwargs: + raise ValueError("Missing definition of constant kphio.") + + ftemp = evaluate_horner_polynomial(self.env.tc, self.pmodel_const.kphio_C3) + ftemp = np.clip(ftemp, 0.0, None) + + self.kphio = ftemp * kwargs["init_kphio"] + + +class QuantumYieldBernacchiC4( + QuantumYieldABC, + method="bernacchi_c4", + is_c4=True, + requires=[], +): + """Calculate kphio following Bernacchi.""" + + def _calculate_kphio(self, **kwargs: Any) -> None: + """Calculate kphio.""" + + if "init_kphio" not in kwargs: + raise ValueError("Missing definition of constant kphio.") + + ftemp = evaluate_horner_polynomial(self.env.tc, self.pmodel_const.kphio_C4) + ftemp = np.clip(ftemp, 0.0, None) + + self.kphio = ftemp * kwargs["init_kphio"] + + +class QuantumYieldSandoval( + QuantumYieldABC, + method="sandoval", + is_c4=False, + requires=["aridity_index", "mean_growth_temperature"], +): + """Calculate kphio following Sandoval.""" + + def _calculate_kphio(self, **kwargs: Any) -> None: + """Constant kphio.""" + + # Warn that this is an experimental feature. + warn( + "The sandoval method for calculating kphi0 is experimental, " + "see the class documentation", + ExperimentalFeatureWarning, + ) + + # Calculate activation entropy as a function of mean growth temperature, J/mol/K + deltaS = 1558.853 - 50.223 * self.env.mean_growth_temperature + # Calculate deaactivation energy J/mol + Hd = 294.804 * deltaS + # activation energy J/mol + Ha = 75000 + + # theoretical maximum phi0 and curvature parameters (Long, 1993;Sandoval et al., + # in.prep.) + phi_o_theo = 0.111 + m = 6.8681 + n = 0.07956432 + + # Calculate the optimal temperature to be used as the reference temperature in + # the modified Arrhenius calculation + Topt = Hd / (deltaS - self.core_const.k_R * np.log(Ha / (Hd - Ha))) + + # Calculate peak kphio given the aridity index + kphio_peak = phi_o_theo / (1 + (self.env.aridity_index) ** m) ** n + + # Calculate the modified Arrhenius factor using the + f_kphio = calc_modified_arrhenius_factor( + tk=self.env.tc + self.core_const.k_CtoK, + Ha=Ha, + Hd=Hd, + deltaS=deltaS, + mode="J1942", + tk_ref=Topt, + ) + + # Apply the factor and store it. + self.kphio = kphio_peak * f_kphio diff --git a/pyrealm_build_data/sandoval_kphio/calc_phi0.R b/pyrealm_build_data/sandoval_kphio/calc_phi0.R new file mode 100644 index 00000000..125f504d --- /dev/null +++ b/pyrealm_build_data/sandoval_kphio/calc_phi0.R @@ -0,0 +1,91 @@ +# calc_phi0 +calc_phi0 <- function(AI, tc, mGDD0 = NA) { + # ************************************************************************ + # Name: calc_phi0 + # Inputs: - double - scalar (AI), climatological aridity index, defined as PET/P + # - double - vector (tc), air temperature, degrees C + # - double - scalar (mGDD0), mean temperature during growing degree days with tc>0 + # Returns: double, intrinsic quantum yield at temperature tc, mol CO2/mol photon + # Features: This function calculates the temperature and aridity dependence of the + # Intrinsic quantum Yield + # * Ref: Sandoval, Flo, Morfopoulus and Prentice + # The temperature effect on the intrinsic quantum yield at the ecosystem level + # in prep.; + # doi: + # ************************************************************************ + ############################################################################################### + # 01.define the parameters/constants + ############################################################################################### + phi_o_theo <- 0.111 # theoretical maximum phi0 (Long, 1993;Sandoval et al., in.prep.) + m <- 6.8681 # curvature parameter phio max (Sandoval et al., in.prep.) + n <- 0.07956432 # curvature parameter phio max (Sandoval et al., in.prep.) + Rgas <- 8.3145 # ideal gas constant J/mol/K + Ha <- 75000 # activation energy J/mol (Sandoval et al., in.prep.) + # if mGDD0 is missing, calculate + if (is.na(mGDD0)) { + mGDD0 <- mean(tc[tc > 0], na.rm = T) + } + ## calc activation entropy, J/mol/K (Sandoval et al., in.prep.) + DeltaS <- 1558.853 - 50.223 * mGDD0 + ## calc deaactivation energy J/mol (Sandoval et al., in.prep.) + Hd <- 294.804 * DeltaS + + ############################################################################################### + # 02.define the functions + ############################################################################################### + + no_acc_f_arr <- function(tcleaf, Ha = 71513, Hd = 2e+05, dent = 649) { + ### 10.1111/nph.16883 + + ## fix for optimization + if (!is.na(Ha) & !is.na(Hd) & Ha > Hd) { + Ha <- Hd - 1 + } + + Top <- Hd / (dent - Rgas * log(Ha / (Hd - Ha))) + tkleaf <- tcleaf + 273.15 + + f1 <- (tkleaf / Top) * exp((Ha * (tkleaf - Top)) / (Top * Rgas * tkleaf)) + f2 <- 1 + exp((Top * dent - Hd) / (Top * Rgas)) + f3 <- 1 + exp((tkleaf * dent - Hd) / (tkleaf * Rgas)) + + farr <- f1 * (f2 / f3) + + return(farr) + } + ############################################################################################### + # 03.calculate maximum phi0 + ############################################################################################### + phi_o_peak <- (phi_o_theo / (1 + (AI)^m)^n) + ############################################################################################### + # 04.calculate temperature dependence of phi0 + ############################################################################################### + phi0_fT <- no_acc_f_arr(tcleaf = tc, Ha = Ha, Hd = Hd, dent = DeltaS) + ############################################################################################### + # 05.calculate phi0 + ############################################################################################### + phi0 <- phi_o_peak * phi0_fT + return(phi0) +} + + +aridity_index <- exp(seq(log(0.2), log(30), length = 20)) +temp <- seq(5, 45, length = 20) +mean_gdd_temp <- seq(5, 45, length = 20) + +data <- expand.grid( + aridity_index = aridity_index, + temp = temp, + mean_gdd_temp = mean_gdd_temp +) + +data$phio <- NA + +for (row_idx in seq_along(data$aridity_index)) { + data$phio[row_idx] <- with( + data[row_idx, ], + calc_phi0(AI = aridity_index, tc = temp, mGDD0 = mean_gdd_temp) + ) +} + +write.csv(data, "sandoval_kphio.csv") diff --git a/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv b/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv new file mode 100644 index 00000000..1555dbdb --- /dev/null +++ b/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv @@ -0,0 +1,8001 @@ +"","aridity_index","temp","mean_gdd_temp","phio" +"1",0.2,5,5,0.0276881368424111 +"2",0.260352117694686,5,5,0.0276879584022285 +"3",0.338916125940539,5,5,0.0276868670405322 +"4",0.441187655547492,5,5,0.0276802027440709 +"5",0.574320702112717,5,5,0.0276398979166404 +"6",0.747628055154725,5,5,0.0274093291367171 +"7",0.973232737037462,5,5,0.0263883834725151 +"8",1.2669160204875,5,5,0.0239847712093153 +"9",1.64922134437622,5,5,0.0210119432069007 +"10",2.14689134777813,5,5,0.0182302846850997 +"11",2.79473854427218,5,5,0.0157891550428931 +"12",3.63808049202114,5,5,0.0136709140267692 +"13",4.73590980220715,5,5,0.0118362854838696 +"14",6.16502073107827,5,5,0.0102477828037349 +"15",8.02538101483936,5,5,0.00887245565279721 +"16",10.4471247126008,5,5,0.00768170582439186 +"17",13.5996552137305,5,5,0.00665076329089655 +"18",17.7034951740616,5,5,0.005758180945173 +"19",23.045712295823,5,5,0.0049853898442698 +"20",30,5,5,0.00431631310865178 +"21",0.2,7.10526315789474,5,0.0355860341585567 +"22",0.260352117694686,7.10526315789474,5,0.0355858048192382 +"23",0.338916125940539,7.10526315789474,5,0.0355844021522828 +"24",0.441187655547492,7.10526315789474,5,0.0355758368998477 +"25",0.574320702112717,7.10526315789474,5,0.0355240353295991 +"26",0.747628055154725,7.10526315789474,5,0.0352276980019938 +"27",0.973232737037462,7.10526315789474,5,0.0339155328864028 +"28",1.2669160204875,7.10526315789474,5,0.0308263027013246 +"29",1.64922134437622,7.10526315789474,5,0.027005490941994 +"30",2.14689134777813,7.10526315789474,5,0.0234303787653369 +"31",2.79473854427218,7.10526315789474,5,0.020292929563628 +"32",3.63808049202114,7.10526315789474,5,0.0175704712926049 +"33",4.73590980220715,7.10526315789474,5,0.0152125244806734 +"34",6.16502073107827,7.10526315789474,5,0.0131709096563185 +"35",8.02538101483936,7.10526315789474,5,0.0114032775743544 +"36",10.4471247126008,7.10526315789474,5,0.00987287253810712 +"37",13.5996552137305,7.10526315789474,5,0.00854785899814665 +"38",17.7034951740616,7.10526315789474,5,0.0074006721713469 +"39",23.045712295823,7.10526315789474,5,0.0064074464201636 +"40",30,7.10526315789474,5,0.00554751901862288 +"41",0.2,9.21052631578947,5,0.0455460855578743 +"42",0.260352117694686,9.21052631578947,5,0.0455457920295711 +"43",0.338916125940539,9.21052631578947,5,0.0455439967750375 +"44",0.441187655547492,9.21052631578947,5,0.0455330342238721 +"45",0.574320702112717,9.21052631578947,5,0.0454667340921951 +"46",0.747628055154725,9.21052631578947,5,0.0450874559400705 +"47",0.973232737037462,9.21052631578947,5,0.0434080334915199 +"48",1.2669160204875,9.21052631578947,5,0.0394541694084747 +"49",1.64922134437622,9.21052631578947,5,0.0345639639274247 +"50",2.14689134777813,9.21052631578947,5,0.0299882260311615 +"51",2.79473854427218,9.21052631578947,5,0.0259726470785359 +"52",3.63808049202114,9.21052631578947,5,0.0224882094256276 +"53",4.73590980220715,9.21052631578947,5,0.0194703050770102 +"54",6.16502073107827,9.21052631578947,5,0.0168572697763646 +"55",8.02538101483936,9.21052631578947,5,0.0145949012954805 +"56",10.4471247126008,9.21052631578947,5,0.0126361565135094 +"57",13.5996552137305,9.21052631578947,5,0.0109402895397553 +"58",17.7034951740616,9.21052631578947,5,0.0094720205797615 +"59",23.045712295823,9.21052631578947,5,0.0082008043256513 +"60",30,9.21052631578947,5,0.00710019483290408 +"61",0.2,11.3157894736842,5,0.0579899207005014 +"62",0.260352117694686,11.3157894736842,5,0.0579895469761118 +"63",0.338916125940539,11.3157894736842,5,0.0579872612326331 +"64",0.441187655547492,11.3157894736842,5,0.0579733035573474 +"65",0.574320702112717,11.3157894736842,5,0.0578888892914166 +"66",0.747628055154725,11.3157894736842,5,0.0574059869805871 +"67",0.973232737037462,11.3157894736842,5,0.0552677225519055 +"68",1.2669160204875,11.3157894736842,5,0.0502336068462867 +"69",1.64922134437622,11.3157894736842,5,0.0440073280216245 +"70",2.14689134777813,11.3157894736842,5,0.0381814337762583 +"71",2.79473854427218,11.3157894736842,5,0.0330687418253008 +"72",3.63808049202114,11.3157894736842,5,0.0286323064938552 +"73",4.73590980220715,11.3157894736842,5,0.0247898679678125 +"74",6.16502073107827,11.3157894736842,5,0.0214629144433541 +"75",8.02538101483936,11.3157894736842,5,0.0185824348764531 +"76",10.4471247126008,11.3157894736842,5,0.0160885332998908 +"77",13.5996552137305,11.3157894736842,5,0.0139293314689972 +"78",17.7034951740616,11.3157894736842,5,0.0120599106501903 +"79",23.045712295823,11.3157894736842,5,0.0104413801252044 +"80",30,11.3157894736842,5,0.00904006854321278 +"81",0.2,13.4210526315789,5,0.0731885108045797 +"82",0.260352117694686,13.4210526315789,5,0.0731880391306888 +"83",0.338916125940539,13.4210526315789,5,0.0731851543162372 +"84",0.441187655547492,13.4210526315789,5,0.0731675384709986 +"85",0.574320702112717,13.4210526315789,5,0.0730610000529511 +"86",0.747628055154725,13.4210526315789,5,0.0724515337773161 +"87",0.973232737037462,13.4210526315789,5,0.0697528511898737 +"88",1.2669160204875,13.4210526315789,5,0.0633993430756782 +"89",1.64922134437622,13.4210526315789,5,0.0555412175682368 +"90",2.14689134777813,13.4210526315789,5,0.0481884135158657 +"91",2.79473854427218,13.4210526315789,5,0.0417357350922185 +"92",3.63808049202114,13.4210526315789,5,0.0361365535229546 +"93",4.73590980220715,13.4210526315789,5,0.031287049502564 +"94",6.16502073107827,13.4210526315789,5,0.0270881340526063 +"95",8.02538101483936,13.4210526315789,5,0.0234527090104975 +"96",10.4471247126008,13.4210526315789,5,0.0203051802627955 +"97",13.5996552137305,13.4210526315789,5,0.0175800727851393 +"98",17.7034951740616,13.4210526315789,5,0.0152206950839318 +"99",23.045712295823,13.4210526315789,5,0.0131779635646516 +"100",30,13.4210526315789,5,0.0114093819452895 +"101",0.2,15.5263157894737,5,0.0905487587090105 +"102",0.260352117694686,15.5263157894737,5,0.0905481751545036 +"103",0.338916125940539,15.5263157894737,5,0.0905446060646994 +"104",0.441187655547492,15.5263157894737,5,0.0905228117570625 +"105",0.574320702112717,15.5263157894737,5,0.090391002523578 +"106",0.747628055154725,15.5263157894737,5,0.0896369714041157 +"107",0.973232737037462,15.5263157894737,5,0.0862981637722047 +"108",1.2669160204875,15.5263157894737,5,0.0784376093373134 +"109",1.64922134437622,15.5263157894737,5,0.0687155436379809 +"110",2.14689134777813,15.5263157894737,5,0.0596186611812453 +"111",2.79473854427218,15.5263157894737,5,0.0516354133300934 +"112",3.63808049202114,15.5263157894737,5,0.0447081110075068 +"113",4.73590980220715,15.5263157894737,5,0.0387083090635486 +"114",6.16502073107827,15.5263157894737,5,0.033513414704611 +"115",8.02538101483936,15.5263157894737,5,0.02901567016351 +"116",10.4471247126008,15.5263157894737,5,0.0251215504721512 +"117",13.5996552137305,15.5263157894737,5,0.0217500499902071 +"118",17.7034951740616,15.5263157894737,5,0.0188310300535877 +"119",23.045712295823,15.5263157894737,5,0.0163037644839893 +"120",30,15.5263157894737,5,0.0141156769201309 +"121",0.2,17.6315789473684,5,0.106348964803431 +"122",0.260352117694686,17.6315789473684,5,0.106348279422222 +"123",0.338916125940539,17.6315789473684,5,0.106344087548016 +"124",0.441187655547492,17.6315789473684,5,0.106318490266631 +"125",0.574320702112717,17.6315789473684,5,0.106163681125871 +"126",0.747628055154725,17.6315789473684,5,0.10527807617526 +"127",0.973232737037462,17.6315789473684,5,0.101356666976569 +"128",1.2669160204875,17.6315789473684,5,0.0921244937380803 +"129",1.64922134437622,17.6315789473684,5,0.0807059868737551 +"130",2.14689134777813,17.6315789473684,5,0.0700217539145677 +"131",2.79473854427218,17.6315789473684,5,0.0606454780070469 +"132",3.63808049202114,17.6315789473684,5,0.0525094036821078 +"133",4.73590980220715,17.6315789473684,5,0.0454626728945981 +"134",6.16502073107827,17.6315789473684,5,0.0393613011561779 +"135",8.02538101483936,17.6315789473684,5,0.0340787276265557 +"136",10.4471247126008,17.6315789473684,5,0.0295051078011581 +"137",13.5996552137305,17.6315789473684,5,0.025545301049513 +"138",17.7034951740616,17.6315789473684,5,0.022116929938456 +"139",23.045712295823,17.6315789473684,5,0.0191486719419673 +"140",30,17.6315789473684,5,0.016578776444411 +"141",0.2,19.7368421052632,5,0.109842441357903 +"142",0.260352117694686,19.7368421052632,5,0.109841733462481 +"143",0.338916125940539,19.7368421052632,5,0.109837403888635 +"144",0.441187655547492,19.7368421052632,5,0.109810965757481 +"145",0.574320702112717,19.7368421052632,5,0.109651071263003 +"146",0.747628055154725,19.7368421052632,5,0.108736374913738 +"147",0.973232737037462,19.7368421052632,5,0.104686150628587 +"148",1.2669160204875,19.7368421052632,5,0.0951507080464326 +"149",1.64922134437622,19.7368421052632,5,0.0833571125661408 +"150",2.14689134777813,19.7368421052632,5,0.0723219112885083 +"151",2.79473854427218,19.7368421052632,5,0.0626376323824464 +"152",3.63808049202114,19.7368421052632,5,0.0542342946671006 +"153",4.73590980220715,19.7368421052632,5,0.0469560845338602 +"154",6.16502073107827,19.7368421052632,5,0.0406542877216493 +"155",8.02538101483936,19.7368421052632,5,0.0351981859700352 +"156",10.4471247126008,19.7368421052632,5,0.0304743264722664 +"157",13.5996552137305,19.7368421052632,5,0.0263844433059361 +"158",17.7034951740616,19.7368421052632,5,0.0228434530065433 +"159",23.045712295823,19.7368421052632,5,0.0197776901613942 +"160",30,19.7368421052632,5,0.0171233756976096 +"161",0.2,21.8421052631579,5,0.0888418552461558 +"162",0.260352117694686,21.8421052631579,5,0.0888412826920339 +"163",0.338916125940539,21.8421052631579,5,0.0888377808819122 +"164",0.441187655547492,21.8421052631579,5,0.088816397411262 +"165",0.574320702112717,21.8421052631579,5,0.0886870728682391 +"166",0.747628055154725,21.8421052631579,5,0.0879472557297001 +"167",0.973232737037462,21.8421052631579,5,0.0846713868104779 +"168",1.2669160204875,21.8421052631579,5,0.0769590089798401 +"169",1.64922134437622,21.8421052631579,5,0.0674202105924496 +"170",2.14689134777813,21.8421052631579,5,0.0584948103336808 +"171",2.79473854427218,21.8421052631579,5,0.0506620519381133 +"172",3.63808049202114,21.8421052631579,5,0.0438653338056497 +"173",4.73590980220715,21.8421052631579,5,0.0379786320616346 +"174",6.16502073107827,21.8421052631579,5,0.0328816648669879 +"175",8.02538101483936,21.8421052631579,5,0.0284687057590801 +"176",10.4471247126008,21.8421052631579,5,0.0246479927767774 +"177",13.5996552137305,21.8421052631579,5,0.0213400472891778 +"178",17.7034951740616,21.8421052631579,5,0.01847605279199 +"179",23.045712295823,21.8421052631579,5,0.015996427835182 +"180",30,21.8421052631579,5,0.0138495871563503 +"181",0.2,23.9473684210526,5,0.0535735001038172 +"182",0.260352117694686,23.9473684210526,5,0.0535731548416857 +"183",0.338916125940539,23.9473684210526,5,0.0535710431768134 +"184",0.441187655547492,23.9473684210526,5,0.0535581484959907 +"185",0.574320702112717,23.9473684210526,5,0.0534801630869752 +"186",0.747628055154725,23.9473684210526,5,0.0530340378519887 +"187",0.973232737037462,23.9473684210526,5,0.0510586202585832 +"188",1.2669160204875,23.9473684210526,5,0.0464078948390662 +"189",1.64922134437622,23.9473684210526,5,0.0406557995571605 +"190",2.14689134777813,23.9473684210526,5,0.0352735961985645 +"191",2.79473854427218,23.9473684210526,5,0.030550278776214 +"192",3.63808049202114,23.9473684210526,5,0.0264517153393489 +"193",4.73590980220715,23.9473684210526,5,0.0229019108511341 +"194",6.16502073107827,23.9473684210526,5,0.0198283328424919 +"195",8.02538101483936,23.9473684210526,5,0.0171672260413046 +"196",10.4471247126008,23.9473684210526,5,0.014863256062437 +"197",13.5996552137305,23.9473684210526,5,0.0128684956262403 +"198",17.7034951740616,23.9473684210526,5,0.0111414469388024 +"199",23.045712295823,23.9473684210526,5,0.00964618113741957 +"200",30,23.9473684210526,5,0.00835159122806211 +"201",0.2,26.0526315789474,5,0.0262903125252139 +"202",0.260352117694686,26.0526315789474,5,0.0262901430935113 +"203",0.338916125940539,26.0526315789474,5,0.0262891068287659 +"204",0.441187655547492,26.0526315789474,5,0.0262827789765986 +"205",0.574320702112717,26.0526315789474,5,0.0262445089219736 +"206",0.747628055154725,26.0526315789474,5,0.0260255803130448 +"207",0.973232737037462,26.0526315789474,5,0.0250561766750933 +"208",1.2669160204875,26.0526315789474,5,0.0227739097985382 +"209",1.64922134437622,26.0526315789474,5,0.0199511638076461 +"210",2.14689134777813,26.0526315789474,5,0.0173099361839601 +"211",2.79473854427218,26.0526315789474,5,0.0149920459780048 +"212",3.63808049202114,26.0526315789474,5,0.012980743497286 +"213",4.73590980220715,26.0526315789474,5,0.0112387354295338 +"214",6.16502073107827,26.0526315789474,5,0.00973042766055773 +"215",8.02538101483936,26.0526315789474,5,0.00842453334096666 +"216",10.4471247126008,26.0526315789474,5,0.00729389803291769 +"217",13.5996552137305,26.0526315789474,5,0.0063150022135496 +"218",17.7034951740616,26.0526315789474,5,0.00546748152419732 +"219",23.045712295823,26.0526315789474,5,0.00473370446743528 +"220",30,26.0526315789474,5,0.00409840579844705 +"221",0.2,28.1578947368421,5,0.0117694227293028 +"222",0.260352117694686,28.1578947368421,5,0.0117693468795642 +"223",0.338916125940539,28.1578947368421,5,0.0117688829734073 +"224",0.441187655547492,28.1578947368421,5,0.0117660501745558 +"225",0.574320702112717,28.1578947368421,5,0.0117489177631278 +"226",0.747628055154725,28.1578947368421,5,0.0116509096719896 +"227",0.973232737037462,28.1578947368421,5,0.0112169353249965 +"228",1.2669160204875,28.1578947368421,5,0.0101952295683418 +"229",1.64922134437622,28.1578947368421,5,0.00893156673465001 +"230",2.14689134777813,28.1578947368421,5,0.0077491644943701 +"231",2.79473854427218,28.1578947368421,5,0.00671151118964672 +"232",3.63808049202114,28.1578947368421,5,0.00581110846109899 +"233",4.73590980220715,28.1578947368421,5,0.00503126115698007 +"234",6.16502073107827,28.1578947368421,5,0.00435603480803706 +"235",8.02538101483936,28.1578947368421,5,0.00377142318456084 +"236",10.4471247126008,28.1578947368421,5,0.003265270019575 +"237",13.5996552137305,28.1578947368421,5,0.00282704629381896 +"238",17.7034951740616,28.1578947368421,5,0.00244763546501079 +"239",23.045712295823,28.1578947368421,5,0.00211914441486395 +"240",30,28.1578947368421,5,0.0018347393288645 +"241",0.2,30.2631578947368,5,0.00512403416617755 +"242",0.260352117694686,30.2631578947368,5,0.00512400114360193 +"243",0.338916125940539,30.2631578947368,5,0.00512379917354337 +"244",0.441187655547492,30.2631578947368,5,0.00512256586257863 +"245",0.574320702112717,30.2631578947368,5,0.0051151069528661 +"246",0.747628055154725,30.2631578947368,5,0.00507243733184013 +"247",0.973232737037462,30.2631578947368,5,0.00488349863600239 +"248",1.2669160204875,30.2631578947368,5,0.00443868028549447 +"249",1.64922134437622,30.2631578947368,5,0.00388852148133799 +"250",2.14689134777813,30.2631578947368,5,0.00337374096773857 +"251",2.79473854427218,30.2631578947368,5,0.00292197955952509 +"252",3.63808049202114,30.2631578947368,5,0.00252997270833848 +"253",4.73590980220715,30.2631578947368,5,0.00219045187349261 +"254",6.16502073107827,30.2631578947368,5,0.00189647969138439 +"255",8.02538101483936,30.2631578947368,5,0.00164195829288126 +"256",10.4471247126008,30.2631578947368,5,0.00142159522407508 +"257",13.5996552137305,30.2631578947368,5,0.00123080648321246 +"258",17.7034951740616,30.2631578947368,5,0.00106562301631306 +"259",23.045712295823,30.2631578947368,5,0.000922608409484029 +"260",30,30.2631578947368,5,0.000798787436169208 +"261",0.2,32.3684210526316,5,0.00222578274938186 +"262",0.260352117694686,32.3684210526316,5,0.0022257684050046 +"263",0.338916125940539,32.3684210526316,5,0.00222568067306183 +"264",0.441187655547492,32.3684210526316,5,0.00222514494629247 +"265",0.574320702112717,32.3684210526316,5,0.00222190493812138 +"266",0.747628055154725,32.3684210526316,5,0.00220337006826646 +"267",0.973232737037462,32.3684210526316,5,0.00212129870101013 +"268",1.2669160204875,32.3684210526316,5,0.00192807809024523 +"269",1.64922134437622,32.3684210526316,5,0.00168909959478654 +"270",2.14689134777813,32.3684210526316,5,0.00146548875424012 +"271",2.79473854427218,32.3684210526316,5,0.00126925221158098 +"272",3.63808049202114,32.3684210526316,5,0.00109897190924226 +"273",4.73590980220715,32.3684210526316,5,0.000951490531728452 +"274",6.16502073107827,32.3684210526316,5,0.000823794620554866 +"275",8.02538101483936,32.3684210526316,5,0.0007132353776294 +"276",10.4471247126008,32.3684210526316,5,0.000617513861877773 +"277",13.5996552137305,32.3684210526316,5,0.000534638870334714 +"278",17.7034951740616,32.3684210526316,5,0.000462886321623268 +"279",23.045712295823,32.3684210526316,5,0.000400763503065414 +"280",30,32.3684210526316,5,0.000346978032969419 +"281",0.2,34.4736842105263,5,0.00097334128672763 +"282",0.260352117694686,34.4736842105263,5,0.000973335013889629 +"283",0.338916125940539,34.4736842105263,5,0.000973296648455226 +"284",0.441187655547492,34.4736842105263,5,0.000973062373576795 +"285",0.574320702112717,34.4736842105263,5,0.000971645508555656 +"286",0.747628055154725,34.4736842105263,5,0.000963540155920081 +"287",0.973232737037462,34.4736842105263,5,0.00092765010769729 +"288",1.2669160204875,34.4736842105263,5,0.000843154171174989 +"289",1.64922134437622,34.4736842105263,5,0.000738648178245267 +"290",2.14689134777813,34.4736842105263,5,0.000640862505621045 +"291",2.79473854427218,34.4736842105263,5,0.000555047693286875 +"292",3.63808049202114,34.4736842105263,5,0.000480583620533697 +"293",4.73590980220715,34.4736842105263,5,0.000416089584088533 +"294",6.16502073107827,34.4736842105263,5,0.000360247789768727 +"295",8.02538101483936,34.4736842105263,5,0.000311899910444659 +"296",10.4471247126008,34.4736842105263,5,0.000270040612480793 +"297",13.5996552137305,34.4736842105263,5,0.000233799137014032 +"298",17.7034951740616,34.4736842105263,5,0.000202421538230781 +"299",23.045712295823,34.4736842105263,5,0.000175255048524163 +"300",30,34.4736842105263,5,0.000151734505611777 +"301",0.2,36.5789473684211,5,0.000429770626656847 +"302",0.260352117694686,36.5789473684211,5,0.000429767856938193 +"303",0.338916125940539,36.5789473684211,5,0.000429750917004574 +"304",0.441187655547492,36.5789473684211,5,0.000429647474910125 +"305",0.574320702112717,36.5789473684211,5,0.000429021870123472 +"306",0.747628055154725,36.5789473684211,5,0.000425443020105534 +"307",0.973232737037462,36.5789473684211,5,0.000409596072353722 +"308",1.2669160204875,36.5789473684211,5,0.000372287605031604 +"309",1.64922134437622,36.5789473684211,5,0.000326143866259563 +"310",2.14689134777813,36.5789473684211,5,0.000282967428174764 +"311",2.79473854427218,36.5789473684211,5,0.000245076622373966 +"312",3.63808049202114,36.5789473684211,5,0.000212197639794128 +"313",4.73590980220715,36.5789473684211,5,0.000183720842563165 +"314",6.16502073107827,36.5789473684211,5,0.000159064369786642 +"315",8.02538101483936,36.5789473684211,5,0.000137716771900918 +"316",10.4471247126008,36.5789473684211,5,0.000119234152327851 +"317",13.5996552137305,36.5789473684211,5,0.000103232034843774 +"318",17.7034951740616,36.5789473684211,5,8.93775210407048e-05 +"319",23.045712295823,36.5789473684211,5,7.7382386893532e-05 +"320",30,36.5789473684211,5,6.69970897684607e-05 +"321",0.2,38.6842105263158,5,0.00019176639425231 +"322",0.260352117694686,38.6842105263158,5,0.000191765158386184 +"323",0.338916125940539,38.6842105263158,5,0.000191757599679778 +"324",0.441187655547492,38.6842105263158,5,0.000191711443157586 +"325",0.574320702112717,38.6842105263158,5,0.000191432294312314 +"326",0.747628055154725,38.6842105263158,5,0.00018983538861206 +"327",0.973232737037462,38.6842105263158,5,0.000182764379469557 +"328",1.2669160204875,38.6842105263158,5,0.000166117103435136 +"329",1.64922134437622,38.6842105263158,5,0.000145527472937424 +"330",2.14689134777813,38.6842105263158,5,0.000126261870928771 +"331",2.79473854427218,38.6842105263158,5,0.000109354751751603 +"332",3.63808049202114,38.6842105263158,5,9.46839400559162e-05 +"333",4.73590980220715,38.6842105263158,5,8.19774115355382e-05 +"334",6.16502073107827,38.6842105263158,5,7.09755361488579e-05 +"335",8.02538101483936,38.6842105263158,5,6.14501018390763e-05 +"336",10.4471247126008,38.6842105263158,5,5.32030391223072e-05 +"337",13.5996552137305,38.6842105263158,5,4.60627922557534e-05 +"338",17.7034951740616,38.6842105263158,5,3.98808198468881e-05 +"339",23.045712295823,38.6842105263158,5,3.45285144977076e-05 +"340",30,38.6842105263158,5,2.98945286936848e-05 +"341",0.2,40.7894736842105,5,8.64848587374021e-05 +"342",0.260352117694686,40.7894736842105,5,8.64843013732834e-05 +"343",0.338916125940539,40.7894736842105,5,8.6480892467055e-05 +"344",0.441187655547492,40.7894736842105,5,8.64600763051977e-05 +"345",0.574320702112717,40.7894736842105,5,8.63341827744556e-05 +"346",0.747628055154725,40.7894736842105,5,8.56139931685455e-05 +"347",0.973232737037462,40.7894736842105,5,8.24250338662414e-05 +"348",1.2669160204875,40.7894736842105,5,7.4917267337007e-05 +"349",1.64922134437622,40.7894736842105,5,6.56315356425e-05 +"350",2.14689134777813,40.7894736842105,5,5.69429284717511e-05 +"351",2.79473854427218,40.7894736842105,5,4.93179751039051e-05 +"352",3.63808049202114,40.7894736842105,5,4.27015755933886e-05 +"353",4.73590980220715,40.7894736842105,5,3.69710495102742e-05 +"354",6.16502073107827,40.7894736842105,5,3.2009306122579e-05 +"355",8.02538101483936,40.7894736842105,5,2.7713423917014e-05 +"356",10.4471247126008,40.7894736842105,5,2.39940754000895e-05 +"357",13.5996552137305,40.7894736842105,5,2.07738905287424e-05 +"358",17.7034951740616,40.7894736842105,5,1.79858785176504e-05 +"359",23.045712295823,40.7894736842105,5,1.55720386274647e-05 +"360",30,40.7894736842105,5,1.34821541656192e-05 +"361",0.2,42.8947368421053,5,3.94187457033001e-05 +"362",0.260352117694686,42.8947368421053,5,3.94184916635205e-05 +"363",0.338916125940539,42.8947368421053,5,3.94169379255632e-05 +"364",0.441187655547492,42.8947368421053,5,3.94074501724149e-05 +"365",0.574320702112717,42.8947368421053,5,3.93500694337924e-05 +"366",0.747628055154725,42.8947368421053,5,3.90218157793611e-05 +"367",0.973232737037462,42.8947368421053,5,3.75683269533299e-05 +"368",1.2669160204875,42.8947368421053,5,3.41463783725473e-05 +"369",1.64922134437622,42.8947368421053,5,2.99140549152558e-05 +"370",2.14689134777813,42.8947368421053,5,2.59538935462056e-05 +"371",2.79473854427218,42.8947368421053,5,2.24785326310741e-05 +"372",3.63808049202114,42.8947368421053,5,1.94628582854825e-05 +"373",4.73590980220715,42.8947368421053,5,1.68509542630421e-05 +"374",6.16502073107827,42.8947368421053,5,1.4589452033635e-05 +"375",8.02538101483936,42.8947368421053,5,1.26314412245214e-05 +"376",10.4471247126008,42.8947368421053,5,1.09362074516854e-05 +"377",13.5996552137305,42.8947368421053,5,9.46848639143988e-06 +"378",17.7034951740616,42.8947368421053,5,8.19774445941366e-06 +"379",23.045712295823,42.8947368421053,5,7.09754562474105e-06 +"380",30,42.8947368421053,5,6.14500173031322e-06 +"381",0.2,45,5,1.81547071246715e-05 +"382",0.260352117694686,45,5,1.81545901240487e-05 +"383",0.338916125940539,45,5,1.81538745341166e-05 +"384",0.441187655547492,45,5,1.81495048522151e-05 +"385",0.574320702112717,45,5,1.81230775652555e-05 +"386",0.747628055154725,45,5,1.79718969821984e-05 +"387",0.973232737037462,45,5,1.73024778143691e-05 +"388",1.2669160204875,45,5,1.57264643423171e-05 +"389",1.64922134437622,45,5,1.37772244197091e-05 +"390",2.14689134777813,45,5,1.19533315347682e-05 +"391",2.79473854427218,45,5,1.03527184649956e-05 +"392",3.63808049202114,45,5,8.96381875368349e-06 +"393",4.73590980220715,45,5,7.76087960077208e-06 +"394",6.16502073107827,45,5,6.71932158302827e-06 +"395",8.02538101483936,45,5,5.81753964775418e-06 +"396",10.4471247126008,45,5,5.03678236832831e-06 +"397",13.5996552137305,45,5,4.36080839924183e-06 +"398",17.7034951740616,45,5,3.77555518543793e-06 +"399",23.045712295823,45,5,3.26884734210049e-06 +"400",30,45,5,2.83014349401525e-06 +"401",0.2,5,7.10526315789474,0.0283427684942027 +"402",0.260352117694686,5,7.10526315789474,0.0283425858351522 +"403",0.338916125940539,5,7.10526315789474,0.0283414686703506 +"404",0.441187655547492,5,7.10526315789474,0.0283346468096796 +"405",0.574320702112717,5,7.10526315789474,0.0282933890537113 +"406",0.747628055154725,5,7.10526315789474,0.0280573689275269 +"407",0.973232737037462,5,7.10526315789474,0.0270122850069175 +"408",1.2669160204875,5,7.10526315789474,0.0245518440493538 +"409",1.64922134437622,5,7.10526315789474,0.0215087293636282 +"410",2.14689134777813,5,7.10526315789474,0.0186613039856746 +"411",2.79473854427218,5,7.10526315789474,0.0161624586243132 +"412",3.63808049202114,5,7.10526315789474,0.0139941359568609 +"413",4.73590980220715,5,7.10526315789474,0.0121161312229124 +"414",6.16502073107827,5,7.10526315789474,0.0104900715146797 +"415",8.02538101483936,5,7.10526315789474,0.00908222745262962 +"416",10.4471247126008,5,7.10526315789474,0.00786332468163098 +"417",13.5996552137305,5,7.10526315789474,0.00680800753537478 +"418",17.7034951740616,5,7.10526315789474,0.00589432183196895 +"419",23.045712295823,5,7.10526315789474,0.00510325960225152 +"420",30,5,7.10526315789474,0.00441836386042496 +"421",0.2,7.10526315789474,7.10526315789474,0.0364210918339983 +"422",0.260352117694686,7.10526315789474,7.10526315789474,0.0364208571130304 +"423",0.338916125940539,7.10526315789474,7.10526315789474,0.0364194215312579 +"424",0.441187655547492,7.10526315789474,7.10526315789474,0.0364106552876205 +"425",0.574320702112717,7.10526315789474,7.10526315789474,0.0363576381478413 +"426",0.747628055154725,7.10526315789474,7.10526315789474,0.0360543470034991 +"427",0.973232737037462,7.10526315789474,7.10526315789474,0.0347113907762506 +"428",1.2669160204875,7.10526315789474,7.10526315789474,0.0315496690804365 +"429",1.64922134437622,7.10526315789474,7.10526315789474,0.0276391986035362 +"430",2.14689134777813,7.10526315789474,7.10526315789474,0.0239801932667034 +"431",2.79473854427218,7.10526315789474,7.10526315789474,0.0207691210525081 +"432",3.63808049202114,7.10526315789474,7.10526315789474,0.0179827778971746 +"433",4.73590980220715,7.10526315789474,7.10526315789474,0.0155694997837889 +"434",6.16502073107827,7.10526315789474,7.10526315789474,0.0134799766670467 +"435",8.02538101483936,7.10526315789474,7.10526315789474,0.0116708655393753 +"436",10.4471247126008,7.10526315789474,7.10526315789474,0.0101045481992631 +"437",13.5996552137305,7.10526315789474,7.10526315789474,0.00874844204803614 +"438",17.7034951740616,7.10526315789474,7.10526315789474,0.00757433547062252 +"439",23.045712295823,7.10526315789474,7.10526315789474,0.00655780280124552 +"440",30,7.10526315789474,7.10526315789474,0.00567769644484347 +"441",0.2,9.21052631578947,7.10526315789474,0.0465931014786481 +"442",0.260352117694686,9.21052631578947,7.10526315789474,0.0465928012027002 +"443",0.338916125940539,9.21052631578947,7.10526315789474,0.0465909646787565 +"444",0.441187655547492,9.21052631578947,7.10526315789474,0.0465797501198618 +"445",0.574320702112717,9.21052631578947,7.10526315789474,0.0465119258771099 +"446",0.747628055154725,9.21052631578947,7.10526315789474,0.0461239288579562 +"447",0.973232737037462,9.21052631578947,7.10526315789474,0.0444058997537556 +"448",1.2669160204875,9.21052631578947,7.10526315789474,0.0403611440256257 +"449",1.64922134437622,9.21052631578947,7.10526315789474,0.0353585222319157 +"450",2.14689134777813,9.21052631578947,7.10526315789474,0.0306775970211337 +"451",2.79473854427218,9.21052631578947,7.10526315789474,0.0265697077186059 +"452",3.63808049202114,9.21052631578947,7.10526315789474,0.0230051696212169 +"453",4.73590980220715,9.21052631578947,7.10526315789474,0.0199178895213869 +"454",6.16502073107827,9.21052631578947,7.10526315789474,0.0172447856214795 +"455",8.02538101483936,9.21052631578947,7.10526315789474,0.0149304096894801 +"456",10.4471247126008,9.21052631578947,7.10526315789474,0.0129266371746899 +"457",13.5996552137305,9.21052631578947,7.10526315789474,0.0111917855176356 +"458",17.7034951740616,9.21052631578947,7.10526315789474,0.00968976391000458 +"459",23.045712295823,9.21052631578947,7.10526315789474,0.00838932486670191 +"460",30,9.21052631578947,7.10526315789474,0.00726341450237931 +"461",0.2,11.3157894736842,7.10526315789474,0.0592522492172405 +"462",0.260352117694686,11.3157894736842,7.10526315789474,0.0592518673575931 +"463",0.338916125940539,11.3157894736842,7.10526315789474,0.0592495318578957 +"464",0.441187655547492,11.3157894736842,7.10526315789474,0.0592352703509902 +"465",0.574320702112717,11.3157894736842,7.10526315789474,0.0591490185496082 +"466",0.747628055154725,11.3157894736842,7.10526315789474,0.0586556043886089 +"467",0.973232737037462,11.3157894736842,7.10526315789474,0.0564707940751934 +"468",1.2669160204875,11.3157894736842,7.10526315789474,0.0513270953983443 +"469",1.64922134437622,11.3157894736842,7.10526315789474,0.0449652825150285 +"470",2.14689134777813,11.3157894736842,7.10526315789474,0.0390125698096162 +"471",2.79473854427218,11.3157894736842,7.10526315789474,0.0337885844344044 +"472",3.63808049202114,11.3157894736842,7.10526315789474,0.0292555764785458 +"473",4.73590980220715,11.3157894736842,7.10526315789474,0.025329495490733 +"474",6.16502073107827,11.3157894736842,7.10526315789474,0.0219301206168908 +"475",8.02538101483936,11.3157894736842,7.10526315789474,0.0189869385759174 +"476",10.4471247126008,11.3157894736842,7.10526315789474,0.0164387495811278 +"477",13.5996552137305,11.3157894736842,7.10526315789474,0.0142325460987125 +"478",17.7034951740616,11.3157894736842,7.10526315789474,0.0123224316010584 +"479",23.045712295823,11.3157894736842,7.10526315789474,0.0106686687941135 +"480",30,11.3157894736842,7.10526315789474,0.00923685336680843 +"481",0.2,13.4210526315789,7.10526315789474,0.0745711441746302 +"482",0.260352117694686,13.4210526315789,7.10526315789474,0.0745706635901596 +"483",0.338916125940539,13.4210526315789,7.10526315789474,0.0745677242775267 +"484",0.441187655547492,13.4210526315789,7.10526315789474,0.0745497756443245 +"485",0.574320702112717,13.4210526315789,7.10526315789474,0.074441224566498 +"486",0.747628055154725,13.4210526315789,7.10526315789474,0.0738202446201878 +"487",0.973232737037462,13.4210526315789,7.10526315789474,0.0710705801428346 +"488",1.2669160204875,13.4210526315789,7.10526315789474,0.0645970453709164 +"489",1.64922134437622,13.4210526315789,7.10526315789474,0.056590468878024 +"490",2.14689134777813,13.4210526315789,7.10526315789474,0.0490987600695034 +"491",2.79473854427218,13.4210526315789,7.10526315789474,0.0425241815222349 +"492",3.63808049202114,13.4210526315789,7.10526315789474,0.0368192235790903 +"493",4.73590980220715,13.4210526315789,7.10526315789474,0.0318781056426209 +"494",6.16502073107827,13.4210526315789,7.10526315789474,0.0275998668049442 +"495",8.02538101483936,13.4210526315789,7.10526315789474,0.0238957634973223 +"496",10.4471247126008,13.4210526315789,7.10526315789474,0.0206887735277438 +"497",13.5996552137305,13.4210526315789,7.10526315789474,0.0179121849570286 +"498",17.7034951740616,13.4210526315789,7.10526315789474,0.0155082353099463 +"499",23.045712295823,13.4210526315789,7.10526315789474,0.0134269137342001 +"500",30,13.4210526315789,7.10526315789474,0.0116249211335554 +"501",0.2,15.5263157894737,7.10526315789474,0.0917241652255641 +"502",0.260352117694686,15.5263157894737,7.10526315789474,0.0917235740959807 +"503",0.338916125940539,15.5263157894737,7.10526315789474,0.0917199586760945 +"504",0.441187655547492,15.5263157894737,7.10526315789474,0.0916978814582158 +"505",0.574320702112717,15.5263157894737,7.10526315789474,0.091564361219145 +"506",0.747628055154725,15.5263157894737,7.10526315789474,0.0908005420793484 +"507",0.973232737037462,15.5263157894737,7.10526315789474,0.0874183936407381 +"508",1.2669160204875,15.5263157894737,7.10526315789474,0.0794558019494755 +"509",1.64922134437622,15.5263157894737,7.10526315789474,0.0696075348583151 +"510",2.14689134777813,15.5263157894737,7.10526315789474,0.0603925664656438 +"511",2.79473854427218,15.5263157894737,7.10526315789474,0.0523056886842611 +"512",3.63808049202114,15.5263157894737,7.10526315789474,0.0452884635796486 +"513",4.73590980220715,15.5263157894737,7.10526315789474,0.0392107786651946 +"514",6.16502073107827,15.5263157894737,7.10526315789474,0.0339484497796069 +"515",8.02538101483936,15.5263157894737,7.10526315789474,0.029392320360361 +"516",10.4471247126008,15.5263157894737,7.10526315789474,0.0254476513988992 +"517",13.5996552137305,15.5263157894737,7.10526315789474,0.0220323857268682 +"518",17.7034951740616,15.5263157894737,7.10526315789474,0.0190754742155395 +"519",23.045712295823,15.5263157894737,7.10526315789474,0.0165154024047301 +"520",30,15.5263157894737,7.10526315789474,0.0142989114434313 +"521",0.2,17.6315789473684,7.10526315789474,0.10677969121116 +"522",0.260352117694686,17.6315789473684,7.10526315789474,0.106779003054073 +"523",0.338916125940539,17.6315789473684,7.10526315789474,0.10677479420226 +"524",0.441187655547492,17.6315789473684,7.10526315789474,0.106749093248732 +"525",0.574320702112717,17.6315789473684,7.10526315789474,0.106593657111882 +"526",0.747628055154725,17.6315789473684,7.10526315789474,0.105704465352131 +"527",0.973232737037462,17.6315789473684,7.10526315789474,0.101767173963139 +"528",1.2669160204875,17.6315789473684,7.10526315789474,0.0924976092857967 +"529",1.64922134437622,17.6315789473684,7.10526315789474,0.0810328560621168 +"530",2.14689134777813,17.6315789473684,7.10526315789474,0.0703053506433397 +"531",2.79473854427218,17.6315789473684,7.10526315789474,0.0608910996634052 +"532",3.63808049202114,17.6315789473684,7.10526315789474,0.0527220732352324 +"533",4.73590980220715,17.6315789473684,7.10526315789474,0.0456468023200031 +"534",6.16502073107827,17.6315789473684,7.10526315789474,0.0395207192744633 +"535",8.02538101483936,17.6315789473684,7.10526315789474,0.0342167506713282 +"536",10.4471247126008,17.6315789473684,7.10526315789474,0.0296246071222503 +"537",13.5996552137305,17.6315789473684,7.10526315789474,0.0256487626654842 +"538",17.7034951740616,17.6315789473684,7.10526315789474,0.0222065062291138 +"539",23.045712295823,17.6315789473684,7.10526315789474,0.0192262264221036 +"540",30,17.6315789473684,7.10526315789474,0.0166459225312173 +"541",0.2,19.7368421052632,7.10526315789474,0.109938439774541 +"542",0.260352117694686,19.7368421052632,7.10526315789474,0.109937731260444 +"543",0.338916125940539,19.7368421052632,7.10526315789474,0.109933397902703 +"544",0.441187655547492,19.7368421052632,7.10526315789474,0.109906936665556 +"545",0.574320702112717,19.7368421052632,7.10526315789474,0.109746902428933 +"546",0.747628055154725,19.7368421052632,7.10526315789474,0.108831406667346 +"547",0.973232737037462,19.7368421052632,7.10526315789474,0.10477764262913 +"548",1.2669160204875,19.7368421052632,7.10526315789474,0.0952338664067311 +"549",1.64922134437622,19.7368421052632,7.10526315789474,0.083429963740268 +"550",2.14689134777813,19.7368421052632,7.10526315789474,0.0723851180862283 +"551",2.79473854427218,19.7368421052632,7.10526315789474,0.0626923754622285 +"552",3.63808049202114,19.7368421052632,7.10526315789474,0.054281693526332 +"553",4.73590980220715,19.7368421052632,7.10526315789474,0.0469971224943341 +"554",6.16502073107827,19.7368421052632,7.10526315789474,0.0406898181341438 +"555",8.02538101483936,19.7368421052632,7.10526315789474,0.0352289479421828 +"556",10.4471247126008,19.7368421052632,7.10526315789474,0.030500959957951 +"557",13.5996552137305,19.7368421052632,7.10526315789474,0.0264075023780939 +"558",17.7034951740616,19.7368421052632,7.10526315789474,0.0228634173781657 +"559",23.045712295823,19.7368421052632,7.10526315789474,0.0197949751645022 +"560",30,19.7368421052632,7.10526315789474,0.0171383409235656 +"561",0.2,21.8421052631579,7.10526315789474,0.0913380947515251 +"562",0.260352117694686,21.8421052631579,7.10526315789474,0.0913375061100285 +"563",0.338916125940539,21.8421052631579,7.10526315789474,0.091333905907581 +"564",0.441187655547492,21.8421052631579,7.10526315789474,0.0913119216135458 +"565",0.574320702112717,21.8421052631579,7.10526315789474,0.0911789633662017 +"566",0.747628055154725,21.8421052631579,7.10526315789474,0.0904183591699988 +"567",0.973232737037462,21.8421052631579,7.10526315789474,0.0870504463218433 +"568",1.2669160204875,21.8421052631579,7.10526315789474,0.0791213694795986 +"569",1.64922134437622,21.8421052631579,7.10526315789474,0.0693145541163988 +"570",2.14689134777813,21.8421052631579,7.10526315789474,0.0601383718735591 +"571",2.79473854427218,21.8421052631579,7.10526315789474,0.0520855320660394 +"572",3.63808049202114,21.8421052631579,7.10526315789474,0.0450978427267938 +"573",4.73590980220715,21.8421052631579,7.10526315789474,0.0390457390175785 +"574",6.16502073107827,21.8421052631579,7.10526315789474,0.0338055594729242 +"575",8.02538101483936,21.8421052631579,7.10526315789474,0.0292686069743986 +"576",10.4471247126008,21.8421052631579,7.10526315789474,0.0253405412735076 +"577",13.5996552137305,21.8421052631579,7.10526315789474,0.0219396505836171 +"578",17.7034951740616,21.8421052631579,7.10526315789474,0.0189951848244635 +"579",23.045712295823,21.8421052631579,7.10526315789474,0.016445888452549 +"580",30,21.8421052631579,7.10526315789474,0.0142387267853793 +"581",0.2,23.9473684210526,7.10526315789474,0.0591062000636878 +"582",0.260352117694686,23.9473684210526,7.10526315789474,0.0591058191452751 +"583",0.338916125940539,23.9473684210526,7.10526315789474,0.0591034894022834 +"584",0.441187655547492,23.9473684210526,7.10526315789474,0.0590892630481533 +"585",0.574320702112717,23.9473684210526,7.10526315789474,0.0590032238463392 +"586",0.747628055154725,23.9473684210526,7.10526315789474,0.0585110258876195 +"587",0.973232737037462,23.9473684210526,7.10526315789474,0.0563316008498883 +"588",1.2669160204875,23.9473684210526,7.10526315789474,0.0512005807269812 +"589",1.64922134437622,23.9473684210526,7.10526315789474,0.0448544488920465 +"590",2.14689134777813,23.9473684210526,7.10526315789474,0.0389164088558316 +"591",2.79473854427218,23.9473684210526,7.10526315789474,0.0337052999309201 +"592",3.63808049202114,23.9473684210526,7.10526315789474,0.0291834652551267 +"593",4.73590980220715,23.9473684210526,7.10526315789474,0.0252670615506681 +"594",6.16502073107827,23.9473684210526,7.10526315789474,0.0218760656975297 +"595",8.02538101483936,23.9473684210526,7.10526315789474,0.0189401382207544 +"596",10.4471247126008,23.9473684210526,7.10526315789474,0.0163982301832398 +"597",13.5996552137305,23.9473684210526,7.10526315789474,0.0141974647079117 +"598",17.7034951740616,23.9473684210526,7.10526315789474,0.0122920583961789 +"599",23.045712295823,23.9473684210526,7.10526315789474,0.0106423719012951 +"600",30,23.9473684210526,7.10526315789474,0.00921408571438114 +"601",0.2,26.0526315789474,7.10526315789474,0.0318569743435326 +"602",0.260352117694686,26.0526315789474,7.10526315789474,0.0318567690366767 +"603",0.338916125940539,26.0526315789474,7.10526315789474,0.0318555133551639 +"604",0.441187655547492,26.0526315789474,7.10526315789474,0.0318478456553619 +"605",0.574320702112717,26.0526315789474,7.10526315789474,0.0318014723706341 +"606",0.747628055154725,26.0526315789474,7.10526315789474,0.0315361882257224 +"607",0.973232737037462,26.0526315789474,7.10526315789474,0.0303615248666189 +"608",1.2669160204875,26.0526315789474,7.10526315789474,0.0275960150514816 +"609",1.64922134437622,26.0526315789474,7.10526315789474,0.0241755860807755 +"610",2.14689134777813,26.0526315789474,7.10526315789474,0.0209751098383384 +"611",2.79473854427218,26.0526315789474,7.10526315789474,0.0181664338763685 +"612",3.63808049202114,26.0526315789474,7.10526315789474,0.0157292619536729 +"613",4.73590980220715,26.0526315789474,7.10526315789474,0.0136184043414864 +"614",6.16502073107827,26.0526315789474,7.10526315789474,0.0117907302941605 +"615",8.02538101483936,26.0526315789474,7.10526315789474,0.0102083283430738 +"616",10.4471247126008,26.0526315789474,7.10526315789474,0.00883829442027947 +"617",13.5996552137305,26.0526315789474,7.10526315789474,0.00765212902294186 +"618",17.7034951740616,26.0526315789474,7.10526315789474,0.00662515588101306 +"619",23.045712295823,26.0526315789474,7.10526315789474,0.00573601023663465 +"620",30,26.0526315789474,7.10526315789474,0.0049661946104785 +"621",0.2,28.1578947368421,7.10526315789474,0.015693767801349 +"622",0.260352117694686,28.1578947368421,7.10526315789474,0.0156936666606038 +"623",0.338916125940539,28.1578947368421,7.10526315789474,0.0156930480715978 +"624",0.441187655547492,28.1578947368421,7.10526315789474,0.015689270716631 +"625",0.574320702112717,28.1578947368421,7.10526315789474,0.015666425748529 +"626",0.747628055154725,28.1578947368421,7.10526315789474,0.0155357382661985 +"627",0.973232737037462,28.1578947368421,7.10526315789474,0.014957061402422 +"628",1.2669160204875,28.1578947368421,7.10526315789474,0.0135946825266664 +"629",1.64922134437622,28.1578947368421,7.10526315789474,0.0119096694595618 +"630",2.14689134777813,28.1578947368421,7.10526315789474,0.0103330121643363 +"631",2.79473854427218,28.1578947368421,7.10526315789474,0.00894936825951792 +"632",3.63808049202114,28.1578947368421,7.10526315789474,0.00774873916542079 +"633",4.73590980220715,28.1578947368421,7.10526315789474,0.00670886297158851 +"634",6.16502073107827,28.1578947368421,7.10526315789474,0.00580849208871753 +"635",8.02538101483936,28.1578947368421,7.10526315789474,0.00502895011084612 +"636",10.4471247126008,28.1578947368421,7.10526315789474,0.00435402743826435 +"637",13.5996552137305,28.1578947368421,7.10526315789474,0.00376968430137161 +"638",17.7034951740616,28.1578947368421,7.10526315789474,0.00326376437771997 +"639",23.045712295823,28.1578947368421,7.10526315789474,0.0028257427020272 +"640",30,28.1578947368421,7.10526315789474,0.00244650682242154 +"641",0.2,30.2631578947368,7.10526315789474,0.00748790720975263 +"642",0.260352117694686,30.2631578947368,7.10526315789474,0.00748785895285698 +"643",0.338916125940539,30.2631578947368,7.10526315789474,0.00748756380785822 +"644",0.441187655547492,30.2631578947368,7.10526315789474,0.00748576153297767 +"645",0.574320702112717,30.2631578947368,7.10526315789474,0.00747486160100961 +"646",0.747628055154725,30.2631578947368,7.10526315789474,0.00741250718404909 +"647",0.973232737037462,30.2631578947368,7.10526315789474,0.00713640531257776 +"648",1.2669160204875,30.2631578947368,7.10526315789474,0.00648637870741108 +"649",1.64922134437622,30.2631578947368,7.10526315789474,0.0056824148885622 +"650",2.14689134777813,30.2631578947368,7.10526315789474,0.00493015044335911 +"651",2.79473854427218,30.2631578947368,7.10526315789474,0.00426997773647546 +"652",3.63808049202114,30.2631578947368,7.10526315789474,0.00369712618395306 +"653",4.73590980220715,30.2631578947368,7.10526315789474,0.00320097404588094 +"654",6.16502073107827,30.2631578947368,7.10526315789474,0.00277138354150751 +"655",8.02538101483936,30.2631578947368,7.10526315789474,0.00239944366892277 +"656",10.4471247126008,30.2631578947368,7.10526315789474,0.00207742040401783 +"657",13.5996552137305,30.2631578947368,7.10526315789474,0.00179861500539759 +"658",17.7034951740616,30.2631578947368,7.10526315789474,0.00155722737357962 +"659",23.045712295823,30.2631578947368,7.10526315789474,0.00134823577226602 +"660",30,30.2631578947368,7.10526315789474,0.00116729241226218 +"661",0.2,32.3684210526316,7.10526315789474,0.0035512116737005 +"662",0.260352117694686,32.3684210526316,7.10526315789474,0.00355118878740579 +"663",0.338916125940539,32.3684210526316,7.10526315789474,0.00355104881206479 +"664",0.441187655547492,32.3684210526316,7.10526315789474,0.00355019406595006 +"665",0.574320702112717,32.3684210526316,7.10526315789474,0.00354502466887245 +"666",0.747628055154725,32.3684210526316,7.10526315789474,0.00351545248972891 +"667",0.973232737037462,32.3684210526316,7.10526315789474,0.00338450853414376 +"668",1.2669160204875,32.3684210526316,7.10526315789474,0.003076227194135 +"669",1.64922134437622,32.3684210526316,7.10526315789474,0.00269493965694298 +"670",2.14689134777813,32.3684210526316,7.10526315789474,0.00233817104260497 +"671",2.79473854427218,32.3684210526316,7.10526315789474,0.00202507781673136 +"672",3.63808049202114,32.3684210526316,7.10526315789474,0.00175339748421263 +"673",4.73590980220715,32.3684210526316,7.10526315789474,0.00151809258321728 +"674",6.16502073107827,32.3684210526316,7.10526315789474,0.00131435517417797 +"675",8.02538101483936,32.3684210526316,7.10526315789474,0.00113795912913654 +"676",10.4471247126008,32.3684210526316,7.10526315789474,0.000985236513123862 +"677",13.5996552137305,32.3684210526316,7.10526315789474,0.000853010383908297 +"678",17.7034951740616,32.3684210526316,7.10526315789474,0.000738529988787697 +"679",23.045712295823,32.3684210526316,7.10526315789474,0.000639413721251211 +"680",30,32.3684210526316,7.10526315789474,0.000553599600653227 +"681",0.2,34.4736842105263,7.10526315789474,0.00169112122481658 +"682",0.260352117694686,34.4736842105263,7.10526315789474,0.00169111032614247 +"683",0.338916125940539,34.4736842105263,7.10526315789474,0.00169104366853603 +"684",0.441187655547492,34.4736842105263,7.10526315789474,0.00169063663019834 +"685",0.574320702112717,34.4736842105263,7.10526315789474,0.00168817491348846 +"686",0.747628055154725,34.4736842105263,7.10526315789474,0.00167409235677013 +"687",0.973232737037462,34.4736842105263,7.10526315789474,0.00161173558311131 +"688",1.2669160204875,34.4736842105263,7.10526315789474,0.0014649290378511 +"689",1.64922134437622,34.4736842105263,7.10526315789474,0.00128335623787447 +"690",2.14689134777813,34.4736842105263,7.10526315789474,0.00111345958526894 +"691",2.79473854427218,34.4736842105263,7.10526315789474,0.000964361573583984 +"692",3.63808049202114,34.4736842105263,7.10526315789474,0.000834984780843018 +"693",4.73590980220715,34.4736842105263,7.10526315789474,0.000722930319171929 +"694",6.16502073107827,34.4736842105263,7.10526315789474,0.000625908601410877 +"695",8.02538101483936,34.4736842105263,7.10526315789474,0.000541907104695695 +"696",10.4471247126008,34.4736842105263,7.10526315789474,0.000469179123043332 +"697",13.5996552137305,34.4736842105263,7.10526315789474,0.000406211765944404 +"698",17.7034951740616,34.4736842105263,7.10526315789474,0.000351695098450997 +"699",23.045712295823,34.4736842105263,7.10526315789474,0.000304494976589242 +"700",30,34.4736842105263,7.10526315789474,0.000263629465302781 +"701",0.2,36.5789473684211,7.10526315789474,0.000811642162220618 +"702",0.260352117694686,36.5789473684211,7.10526315789474,0.000811636931475895 +"703",0.338916125940539,36.5789473684211,7.10526315789474,0.000811604939609776 +"704",0.441187655547492,36.5789473684211,7.10526315789474,0.000811409584320242 +"705",0.574320702112717,36.5789473684211,7.10526315789474,0.000810228100081349 +"706",0.747628055154725,36.5789473684211,7.10526315789474,0.000803469272495996 +"707",0.973232737037462,36.5789473684211,7.10526315789474,0.000773541561898531 +"708",1.2669160204875,36.5789473684211,7.10526315789474,0.000703082756181594 +"709",1.64922134437622,36.5789473684211,7.10526315789474,0.000615938122307424 +"710",2.14689134777813,36.5789473684211,7.10526315789474,0.000534397376173298 +"711",2.79473854427218,36.5789473684211,7.10526315789474,0.000462838796687136 +"712",3.63808049202114,36.5789473684211,7.10526315789474,0.000400745282478635 +"713",4.73590980220715,36.5789473684211,7.10526315789474,0.000346965503582504 +"714",6.16502073107827,36.5789473684211,7.10526315789474,0.000300400588169962 +"715",8.02538101483936,36.5789473684211,7.10526315789474,0.000260084639541813 +"716",10.4471247126008,36.5789473684211,7.10526315789474,0.000225179338008111 +"717",13.5996552137305,36.5789473684211,7.10526315789474,0.000194958582029701 +"718",17.7034951740616,36.5789473684211,7.10526315789474,0.000168793677212655 +"719",23.045712295823,36.5789473684211,7.10526315789474,0.000146140298848779 +"720",30,36.5789473684211,7.10526315789474,0.000126527173867516 +"721",0.2,38.6842105263158,7.10526315789474,0.000393093382630405 +"722",0.260352117694686,38.6842105263158,7.10526315789474,0.000393090849283528 +"723",0.338916125940539,38.6842105263158,7.10526315789474,0.000393075355028233 +"724",0.441187655547492,38.6842105263158,7.10526315789474,0.000392980740831051 +"725",0.574320702112717,38.6842105263158,7.10526315789474,0.000392408526057585 +"726",0.747628055154725,38.6842105263158,7.10526315789474,0.000389135100252704 +"727",0.973232737037462,38.6842105263158,7.10526315789474,0.000374640553837133 +"728",1.2669160204875,38.6842105263158,7.10526315789474,0.000340516044829873 +"729",1.64922134437622,38.6842105263158,7.10526315789474,0.000298310279158505 +"730",2.14689134777813,38.6842105263158,7.10526315789474,0.000258818580461662 +"731",2.79473854427218,38.6842105263158,7.10526315789474,0.000224161430579895 +"732",3.63808049202114,38.6842105263158,7.10526315789474,0.00019408838770981 +"733",4.73590980220715,38.6842105263158,7.10526315789474,0.000168041841353031 +"734",6.16502073107827,38.6842105263158,7.10526315789474,0.000145489587461569 +"735",8.02538101483936,38.6842105263158,7.10526315789474,0.000125963824313886 +"736",10.4471247126008,38.6842105263158,7.10526315789474,0.000109058538104904 +"737",13.5996552137305,38.6842105263158,7.10526315789474,9.44220643654181e-05 +"738",17.7034951740616,38.6842105263158,7.10526315789474,8.17499147168649e-05 +"739",23.045712295823,38.6842105263158,7.10526315789474,7.07784625873956e-05 +"740",30,38.6842105263158,7.10526315789474,6.12794616708538e-05 +"741",0.2,40.7894736842105,7.10526315789474,0.000192186214212522 +"742",0.260352117694686,40.7894736842105,7.10526315789474,0.000192184975640806 +"743",0.338916125940539,40.7894736842105,7.10526315789474,0.000192177400386684 +"744",0.441187655547492,40.7894736842105,7.10526315789474,0.000192131142817438 +"745",0.574320702112717,40.7894736842105,7.10526315789474,0.000191851382852278 +"746",0.747628055154725,40.7894736842105,7.10526315789474,0.00019025098116468 +"747",0.973232737037462,40.7894736842105,7.10526315789474,0.000183164491985706 +"748",1.2669160204875,40.7894736842105,7.10526315789474,0.000166480771303151 +"749",1.64922134437622,40.7894736842105,7.10526315789474,0.000145846065452742 +"750",2.14689134777813,40.7894736842105,7.10526315789474,0.000126538286688875 +"751",2.79473854427218,40.7894736842105,7.10526315789474,0.000109594154008231 +"752",3.63808049202114,40.7894736842105,7.10526315789474,9.48912245913635e-05 +"753",4.73590980220715,40.7894736842105,7.10526315789474,8.21568786094399e-05 +"754",6.16502073107827,40.7894736842105,7.10526315789474,7.11309176320329e-05 +"755",8.02538101483936,40.7894736842105,7.10526315789474,6.15846299945944e-05 +"756",10.4471247126008,40.7894736842105,7.10526315789474,5.33195125943906e-05 +"757",13.5996552137305,40.7894736842105,7.10526315789474,4.61636341143464e-05 +"758",17.7034951740616,40.7894736842105,7.10526315789474,3.99681279712684e-05 +"759",23.045712295823,40.7894736842105,7.10526315789474,3.46041052165045e-05 +"760",30,40.7894736842105,7.10526315789474,2.99599745706628e-05 +"761",0.2,42.8947368421053,7.10526315789474,9.48530216347067e-05 +"762",0.260352117694686,42.8947368421053,7.10526315789474,9.48524103407579e-05 +"763",0.338916125940539,42.8947368421053,7.10526315789474,9.48486715931788e-05 +"764",0.441187655547492,42.8947368421053,7.10526315789474,9.48258412864659e-05 +"765",0.574320702112717,42.8947368421053,7.10526315789474,9.4687766460774e-05 +"766",0.747628055154725,42.8947368421053,7.10526315789474,9.38978922415433e-05 +"767",0.973232737037462,42.8947368421053,7.10526315789474,9.04003733681867e-05 +"768",1.2669160204875,42.8947368421053,7.10526315789474,8.21661650752867e-05 +"769",1.64922134437622,42.8947368421053,7.10526315789474,7.19819580109322e-05 +"770",2.14689134777813,42.8947368421053,7.10526315789474,6.24526524657281e-05 +"771",2.79473854427218,42.8947368421053,7.10526315789474,5.40899184875186e-05 +"772",3.63808049202114,42.8947368421053,7.10526315789474,4.68333247313739e-05 +"773",4.73590980220715,42.8947368421053,7.10526315789474,4.05483203678895e-05 +"774",6.16502073107827,42.8947368421053,7.10526315789474,3.51064851175374e-05 +"775",8.02538101483936,42.8947368421053,7.10526315789474,3.03949389147292e-05 +"776",10.4471247126008,42.8947368421053,7.10526315789474,2.63157110534218e-05 +"777",13.5996552137305,42.8947368421053,7.10526315789474,2.27839452654117e-05 +"778",17.7034951740616,42.8947368421053,7.10526315789474,1.97261688237701e-05 +"779",23.045712295823,42.8947368421053,7.10526315789474,1.70787689127439e-05 +"780",30,42.8947368421053,7.10526315789474,1.47866699376462e-05 +"781",0.2,45,7.10526315789474,4.72536466185546e-05 +"782",0.260352117694686,45,7.10526315789474,4.72533420856284e-05 +"783",0.338916125940539,45,7.10526315789474,4.72514795254922e-05 +"784",0.441187655547492,45,7.10526315789474,4.7240105979062e-05 +"785",0.574320702112717,45,7.10526315789474,4.71713201996771e-05 +"786",0.747628055154725,45,7.10526315789474,4.67778225905827e-05 +"787",0.973232737037462,45,7.10526315789474,4.5035437181715e-05 +"788",1.2669160204875,45,7.10526315789474,4.09333394082278e-05 +"789",1.64922134437622,45,7.10526315789474,3.58597960100794e-05 +"790",2.14689134777813,45,7.10526315789474,3.11125098509999e-05 +"791",2.79473854427218,45,7.10526315789474,2.69463834655575e-05 +"792",3.63808049202114,45,7.10526315789474,2.33313113139519e-05 +"793",4.73590980220715,45,7.10526315789474,2.02002631926605e-05 +"794",6.16502073107827,45,7.10526315789474,1.74892630005228e-05 +"795",8.02538101483936,45,7.10526315789474,1.51420764221984e-05 +"796",10.4471247126008,45,7.10526315789474,1.31098966506659e-05 +"797",13.5996552137305,45,7.10526315789474,1.13504501975119e-05 +"798",17.7034951740616,45,7.10526315789474,9.82713459910816e-06 +"799",23.045712295823,45,7.10526315789474,8.50825937829127e-06 +"800",30,45,7.10526315789474,7.36638710983433e-06 +"801",0.2,5,9.21052631578947,0.0290720151230221 +"802",0.260352117694686,5,9.21052631578947,0.0290718277642367 +"803",0.338916125940539,5,9.21052631578947,0.0290706818552895 +"804",0.441187655547492,5,9.21052631578947,0.0290636844712254 +"805",0.574320702112717,5,9.21052631578947,0.0290213651718352 +"806",0.747628055154725,5,9.21052631578947,0.0287792723544319 +"807",0.973232737037462,5,9.21052631578947,0.0277072988966873 +"808",1.2669160204875,5,9.21052631578947,0.0251835519048497 +"809",1.64922134437622,5,9.21052631578947,0.0220621392530616 +"810",2.14689134777813,5,9.21052631578947,0.0191414509065271 +"811",2.79473854427218,5,9.21052631578947,0.0165783113829322 +"812",3.63808049202114,5,9.21052631578947,0.0143541987528389 +"813",4.73590980220715,5,9.21052631578947,0.0124278738055204 +"814",6.16502073107827,5,9.21052631578947,0.010759976315607 +"815",8.02538101483936,5,9.21052631578947,0.00931590906186816 +"816",10.4471247126008,5,9.21052631578947,0.00806564447324076 +"817",13.5996552137305,5,9.21052631578947,0.00698317449357663 +"818",17.7034951740616,5,9.21052631578947,0.00604598006980196 +"819",23.045712295823,5,9.21052631578947,0.00523456416629554 +"820",30,5,9.21052631578947,0.00453204636645013 +"821",0.2,7.10526315789474,9.21052631578947,0.0373464009349278 +"822",0.260352117694686,7.10526315789474,9.21052631578947,0.0373461602506722 +"823",0.338916125940539,7.10526315789474,9.21052631578947,0.0373446881967125 +"824",0.441187655547492,7.10526315789474,9.21052631578947,0.0373356992391309 +"825",0.574320702112717,7.10526315789474,9.21052631578947,0.0372813351534071 +"826",0.747628055154725,7.10526315789474,9.21052631578947,0.0369703386372059 +"827",0.973232737037462,7.10526315789474,9.21052631578947,0.0355932634542466 +"828",1.2669160204875,7.10526315789474,9.21052631578947,0.0323512155048133 +"829",1.64922134437622,7.10526315789474,9.21052631578947,0.0283413961688045 +"830",2.14689134777813,7.10526315789474,9.21052631578947,0.0245894306605976 +"831",2.79473854427218,7.10526315789474,9.21052631578947,0.0212967784005026 +"832",3.63808049202114,7.10526315789474,9.21052631578947,0.0184396458055858 +"833",4.73590980220715,7.10526315789474,9.21052631578947,0.0159650562902364 +"834",6.16502073107827,7.10526315789474,9.21052631578947,0.0138224470451229 +"835",8.02538101483936,7.10526315789474,9.21052631578947,0.0119673738963606 +"836",10.4471247126008,7.10526315789474,9.21052631578947,0.0103612629197381 +"837",13.5996552137305,7.10526315789474,9.21052631578947,0.00897070372769412 +"838",17.7034951740616,7.10526315789474,9.21052631578947,0.00776676796485977 +"839",23.045712295823,7.10526315789474,9.21052631578947,0.00672440941045292 +"840",30,7.10526315789474,9.21052631578947,0.00582194319660682 +"841",0.2,9.21052631578947,9.21052631578947,0.0477401634356467 +"842",0.260352117694686,9.21052631578947,9.21052631578947,0.0477398557672929 +"843",0.338916125940539,9.21052631578947,9.21052631578947,0.0477379740305027 +"844",0.441187655547492,9.21052631578947,9.21052631578947,0.0477264833836579 +"845",0.574320702112717,9.21052631578947,9.21052631578947,0.0476569893956829 +"846",0.747628055154725,9.21052631578947,9.21052631578947,0.0472594403912358 +"847",0.973232737037462,9.21052631578947,9.21052631578947,0.0454991156302984 +"848",1.2669160204875,9.21052631578947,9.21052631578947,0.041354783242237 +"849",1.64922134437622,9.21052631578947,9.21052631578947,0.036229003363688 +"850",2.14689134777813,9.21052631578947,9.21052631578947,0.0314328398222854 +"851",2.79473854427218,9.21052631578947,9.21052631578947,0.0272238195927972 +"852",3.63808049202114,9.21052631578947,9.21052631578947,0.0235715271730723 +"853",4.73590980220715,9.21052631578947,9.21052631578947,0.020408242226157 +"854",6.16502073107827,9.21052631578947,9.21052631578947,0.017669329962063 +"855",8.02538101483936,9.21052631578947,9.21052631578947,0.0152979770849464 +"856",10.4471247126008,9.21052631578947,9.21052631578947,0.0132448742798503 +"857",13.5996552137305,9.21052631578947,9.21052631578947,0.0114673128165438 +"858",17.7034951740616,9.21052631578947,9.21052631578947,0.00992831337764536 +"859",23.045712295823,9.21052631578947,9.21052631578947,0.00859585920535086 +"860",30,9.21052631578947,9.21052631578947,0.00744223038261019 +"861",0.2,11.3157894736842,9.21052631578947,0.0606037267353759 +"862",0.260352117694686,11.3157894736842,9.21052631578947,0.0606033361659371 +"863",0.338916125940539,11.3157894736842,9.21052631578947,0.0606009473961044 +"864",0.441187655547492,11.3157894736842,9.21052631578947,0.0605863606001809 +"865",0.574320702112717,11.3157894736842,9.21052631578947,0.0604981414917007 +"866",0.747628055154725,11.3157894736842,9.21052631578947,0.05999347310568 +"867",0.973232737037462,11.3157894736842,9.21052631578947,0.0577588297132004 +"868",1.2669160204875,11.3157894736842,9.21052631578947,0.0524978090238765 +"869",1.64922134437622,11.3157894736842,9.21052631578947,0.0459908903057617 +"870",2.14689134777813,11.3157894736842,9.21052631578947,0.039902402882941 +"871",2.79473854427218,11.3157894736842,9.21052631578947,0.0345592642454829 +"872",3.63808049202114,11.3157894736842,9.21052631578947,0.029922863449305 +"873",4.73590980220715,11.3157894736842,9.21052631578947,0.0259072329463345 +"874",6.16502073107827,11.3157894736842,9.21052631578947,0.0224303221345591 +"875",8.02538101483936,11.3157894736842,9.21052631578947,0.0194200094038194 +"876",10.4471247126008,11.3157894736842,9.21052631578947,0.0168136990687615 +"877",13.5996552137305,11.3157894736842,9.21052631578947,0.0145571745530302 +"878",17.7034951740616,11.3157894736842,9.21052631578947,0.0126034924805625 +"879",23.045712295823,11.3157894736842,9.21052631578947,0.010912009194084 +"880",30,11.3157894736842,9.21052631578947,0.00944753565867866 +"881",0.2,13.4210526315789,9.21052631578947,0.0759866374247321 +"882",0.260352117694686,13.4210526315789,9.21052631578947,0.0759861477179115 +"883",0.338916125940539,13.4210526315789,9.21052631578947,0.0759831526118852 +"884",0.441187655547492,13.4210526315789,9.21052631578947,0.0759648632816288 +"885",0.574320702112717,13.4210526315789,9.21052631578947,0.0758542517108374 +"886",0.747628055154725,13.4210526315789,9.21052631578947,0.0752214844581612 +"887",0.973232737037462,13.4210526315789,9.21052631578947,0.0724196264473599 +"888",1.2669160204875,13.4210526315789,9.21052631578947,0.0658232124454746 +"889",1.64922134437622,13.4210526315789,9.21052631578947,0.057664656857886 +"890",2.14689134777813,13.4210526315789,9.21052631578947,0.0500307420611436 +"891",2.79473854427218,13.4210526315789,9.21052631578947,0.0433313662929268 +"892",3.63808049202114,13.4210526315789,9.21052631578947,0.0375181180781226 +"893",4.73590980220715,13.4210526315789,9.21052631578947,0.0324832089149737 +"894",6.16502073107827,13.4210526315789,9.21052631578947,0.0281237614775889 +"895",8.02538101483936,13.4210526315789,9.21052631578947,0.0243493476860976 +"896",10.4471247126008,13.4210526315789,9.21052631578947,0.0210814833299808 +"897",13.5996552137305,13.4210526315789,9.21052631578947,0.0182521901585295 +"898",17.7034951740616,13.4210526315789,9.21052631578947,0.0158026092617635 +"899",23.045712295823,13.4210526315789,9.21052631578947,0.013681780492258 +"900",30,13.4210526315789,9.21052631578947,0.0118455828597451 +"901",0.2,15.5263157894737,9.21052631578947,0.0928252531132363 +"902",0.260352117694686,15.5263157894737,9.21052631578947,0.0928246548875336 +"903",0.338916125940539,15.5263157894737,9.21052631578947,0.0928209960669248 +"904",0.441187655547492,15.5263157894737,9.21052631578947,0.0927986538266593 +"905",0.574320702112717,15.5263157894737,9.21052631578947,0.0926635307655008 +"906",0.747628055154725,15.5263157894737,9.21052631578947,0.091890542482533 +"907",0.973232737037462,15.5263157894737,9.21052631578947,0.0884677935906954 +"908",1.2669160204875,15.5263157894737,9.21052631578947,0.0804096162569342 +"909",1.64922134437622,15.5263157894737,9.21052631578947,0.0704431272383028 +"910",2.14689134777813,15.5263157894737,9.21052631578947,0.0611175392498303 +"911",2.79473854427218,15.5263157894737,9.21052631578947,0.052933583853707 +"912",3.63808049202114,15.5263157894737,9.21052631578947,0.0458321216066931 +"913",4.73590980220715,15.5263157894737,9.21052631578947,0.0396814781079017 +"914",6.16502073107827,15.5263157894737,9.21052631578947,0.0343559784473866 +"915",8.02538101483936,15.5263157894737,9.21052631578947,0.0297451557103452 +"916",10.4471247126008,15.5263157894737,9.21052631578947,0.0257531336091339 +"917",13.5996552137305,15.5263157894737,9.21052631578947,0.0222968699334098 +"918",17.7034951740616,15.5263157894737,9.21052631578947,0.0193044626566846 +"919",23.045712295823,15.5263157894737,9.21052631578947,0.0167136588783994 +"920",30,15.5263157894737,9.21052631578947,0.0144705604102934 +"921",0.2,17.6315789473684,9.21052631578947,0.107093176344978 +"922",0.260352117694686,17.6315789473684,9.21052631578947,0.107092486167591 +"923",0.338916125940539,17.6315789473684,9.21052631578947,0.107088264959379 +"924",0.441187655547492,17.6315789473684,9.21052631578947,0.107062488552675 +"925",0.574320702112717,17.6315789473684,9.21052631578947,0.106906596084499 +"926",0.747628055154725,17.6315789473684,9.21052631578947,0.106014793824617 +"927",0.973232737037462,17.6315789473684,9.21052631578947,0.102065943287027 +"928",1.2669160204875,17.6315789473684,9.21052631578947,0.0927691649074315 +"929",1.64922134437622,17.6315789473684,9.21052631578947,0.0812707533199021 +"930",2.14689134777813,17.6315789473684,9.21052631578947,0.0705117539584699 +"931",2.79473854427218,17.6315789473684,9.21052631578947,0.0610698645044513 +"932",3.63808049202114,17.6315789473684,9.21052631578947,0.0528768553477844 +"933",4.73590980220715,17.6315789473684,9.21052631578947,0.0457808127649796 +"934",6.16502073107827,17.6315789473684,9.21052631578947,0.0396367446893134 +"935",8.02538101483936,17.6315789473684,9.21052631578947,0.0343172046297669 +"936",10.4471247126008,17.6315789473684,9.21052631578947,0.0297115794090465 +"937",13.5996552137305,17.6315789473684,9.21052631578947,0.0257240626191108 +"938",17.7034951740616,17.6315789473684,9.21052631578947,0.022271700363859 +"939",23.045712295823,17.6315789473684,9.21052631578947,0.019282671014651 +"940",30,17.6315789473684,9.21052631578947,0.0166947918357924 +"941",0.2,19.7368421052632,9.21052631578947,0.110116698646416 +"942",0.260352117694686,19.7368421052632,9.21052631578947,0.110115988983504 +"943",0.338916125940539,19.7368421052632,9.21052631578947,0.110111648599472 +"944",0.441187655547492,19.7368421052632,9.21052631578947,0.110085144456947 +"945",0.574320702112717,19.7368421052632,9.21052631578947,0.109924850733992 +"946",0.747628055154725,19.7368421052632,9.21052631578947,0.109007870548558 +"947",0.973232737037462,19.7368421052632,9.21052631578947,0.104947533564558 +"948",1.2669160204875,19.7368421052632,9.21052631578947,0.0953882826566318 +"949",1.64922134437622,19.7368421052632,9.21052631578947,0.0835652406392979 +"950",2.14689134777813,19.7368421052632,9.21052631578947,0.0725024864017785 +"951",2.79473854427218,19.7368421052632,9.21052631578947,0.0627940275517793 +"952",3.63808049202114,19.7368421052632,9.21052631578947,0.054369708177725 +"953",4.73590980220715,19.7368421052632,9.21052631578947,0.0470733256317842 +"954",6.16502073107827,19.7368421052632,9.21052631578947,0.0407557943394843 +"955",8.02538101483936,19.7368421052632,9.21052631578947,0.0352860696598494 +"956",10.4471247126008,19.7368421052632,9.21052631578947,0.030550415514391 +"957",13.5996552137305,19.7368421052632,9.21052631578947,0.026450320627949 +"958",17.7034951740616,19.7368421052632,9.21052631578947,0.0229004890975515 +"959",23.045712295823,19.7368421052632,9.21052631578947,0.0198270715809044 +"960",30,19.7368421052632,9.21052631578947,0.0171661297599826 +"961",0.2,21.8421052631579,9.21052631578947,0.0941042978546259 +"962",0.260352117694686,21.8421052631579,9.21052631578947,0.0941036913859353 +"963",0.338916125940539,21.8421052631579,9.21052631578947,0.0940999821502175 +"964",0.441187655547492,21.8421052631579,9.21052631578947,0.0940773320548805 +"965",0.574320702112717,21.8421052631579,9.21052631578947,0.0939403471249416 +"966",0.747628055154725,21.8421052631579,9.21052631578947,0.0931567077899667 +"967",0.973232737037462,21.8421052631579,9.21052631578947,0.0896867966354432 +"968",1.2669160204875,21.8421052631579,9.21052631578947,0.0815175851919085 +"969",1.64922134437622,21.8421052631579,9.21052631578947,0.0714137673221093 +"970",2.14689134777813,21.8421052631579,9.21052631578947,0.0619596814962814 +"971",2.79473854427218,21.8421052631579,9.21052631578947,0.0536629588869041 +"972",3.63808049202114,21.8421052631579,9.21052631578947,0.0464636451647949 +"973",4.73590980220715,21.8421052631579,9.21052631578947,0.0402282515795836 +"974",6.16502073107827,21.8421052631579,9.21052631578947,0.0348293715391869 +"975",8.02538101483936,21.8421052631579,9.21052631578947,0.0301550159985442 +"976",10.4471247126008,21.8421052631579,9.21052631578947,0.0261079875848821 +"977",13.5996552137305,21.8421052631579,9.21052631578947,0.0226040998442508 +"978",17.7034951740616,21.8421052631579,9.21052631578947,0.0195704600078177 +"979",23.045712295823,21.8421052631579,9.21052631578947,0.0169439573885658 +"980",30,21.8421052631579,9.21052631578947,0.0146699511318589 +"981",0.2,23.9473684210526,9.21052631578947,0.0652331863550116 +"982",0.260352117694686,23.9473684210526,9.21052631578947,0.0652327659503541 +"983",0.338916125940539,23.9473684210526,9.21052631578947,0.065230194704722 +"984",0.441187655547492,23.9473684210526,9.21052631578947,0.0652144936376746 +"985",0.574320702112717,23.9473684210526,9.21052631578947,0.0651195355574778 +"986",0.747628055154725,23.9473684210526,9.21052631578947,0.0645763160453095 +"987",0.973232737037462,23.9473684210526,9.21052631578947,0.0621709704220092 +"988",1.2669160204875,23.9473684210526,9.21052631578947,0.0565080654897305 +"989",1.64922134437622,23.9473684210526,9.21052631578947,0.0495040895925201 +"990",2.14689134777813,23.9473684210526,9.21052631578947,0.0429505085494393 +"991",2.79473854427218,23.9473684210526,9.21052631578947,0.0371992127590022 +"992",3.63808049202114,23.9473684210526,9.21052631578947,0.032208641824739 +"993",4.73590980220715,23.9473684210526,9.21052631578947,0.0278862612213654 +"994",6.16502073107827,23.9473684210526,9.21052631578947,0.0241437525813496 +"995",8.02538101483936,23.9473684210526,9.21052631578947,0.0209034849950235 +"996",10.4471247126008,23.9473684210526,9.21052631578947,0.0180980811536359 +"997",13.5996552137305,23.9473684210526,9.21052631578947,0.0156691829294045 +"998",17.7034951740616,23.9473684210526,9.21052631578947,0.0135662609875211 +"999",23.045712295823,23.9473684210526,9.21052631578947,0.0117455669413441 +"1000",30,23.9473684210526,9.21052631578947,0.0101692236998762 +"1001",0.2,26.0526315789474,9.21052631578947,0.0385563145303862 +"1002",0.260352117694686,26.0526315789474,9.21052631578947,0.0385560660486684 +"1003",0.338916125940539,26.0526315789474,9.21052631578947,0.0385545463044881 +"1004",0.441187655547492,26.0526315789474,9.21052631578947,0.0385452661311075 +"1005",0.574320702112717,26.0526315789474,9.21052631578947,0.0384891408088314 +"1006",0.747628055154725,26.0526315789474,9.21052631578947,0.0381680689198052 +"1007",0.973232737037462,26.0526315789474,9.21052631578947,0.0367463805493869 +"1008",1.2669160204875,26.0526315789474,9.21052631578947,0.0333992997777017 +"1009",1.64922134437622,26.0526315789474,9.21052631578947,0.0292595740836901 +"1010",2.14689134777813,26.0526315789474,9.21052631578947,0.0253860559234356 +"1011",2.79473854427218,26.0526315789474,9.21052631578947,0.0219867314101951 +"1012",3.63808049202114,26.0526315789474,9.21052631578947,0.0190370361188985 +"1013",4.73590980220715,26.0526315789474,9.21052631578947,0.0164822771783073 +"1014",6.16502073107827,26.0526315789474,9.21052631578947,0.0142702536927176 +"1015",8.02538101483936,26.0526315789474,9.21052631578947,0.0123550816276724 +"1016",10.4471247126008,26.0526315789474,9.21052631578947,0.0106969373772194 +"1017",13.5996552137305,26.0526315789474,9.21052631578947,0.00926132815546371 +"1018",17.7034951740616,26.0526315789474,9.21052631578947,0.00801838841336908 +"1019",23.045712295823,26.0526315789474,9.21052631578947,0.00694226050623352 +"1020",30,26.0526315789474,9.21052631578947,0.00601055704022284 +"1021",0.2,28.1578947368421,9.21052631578947,0.0209073332967495 +"1022",0.260352117694686,28.1578947368421,9.21052631578947,0.0209071985564311 +"1023",0.338916125940539,28.1578947368421,9.21052631578947,0.0209063744683799 +"1024",0.441187655547492,28.1578947368421,9.21052631578947,0.0209013422530273 +"1025",0.574320702112717,28.1578947368421,9.21052631578947,0.0208709080470223 +"1026",0.747628055154725,28.1578947368421,9.21052631578947,0.0206968053850368 +"1027",0.973232737037462,28.1578947368421,9.21052631578947,0.0199258885335047 +"1028",1.2669160204875,28.1578947368421,9.21052631578947,0.0181109190760475 +"1029",1.64922134437622,28.1578947368421,9.21052631578947,0.0158661343787547 +"1030",2.14689134777813,28.1578947368421,9.21052631578947,0.0137657019024186 +"1031",2.79473854427218,28.1578947368421,9.21052631578947,0.0119224030433921 +"1032",3.63808049202114,28.1578947368421,9.21052631578947,0.0103229176327627 +"1033",4.73590980220715,28.1578947368421,9.21052631578947,0.00893758821748116 +"1034",6.16502073107827,28.1578947368421,9.21052631578947,0.0077381086293319 +"1035",8.02538101483936,28.1578947368421,9.21052631578947,0.00669959804624783 +"1036",10.4471247126008,28.1578947368421,9.21052631578947,0.00580046194051375 +"1037",13.5996552137305,28.1578947368421,9.21052631578947,0.00502199644533582 +"1038",17.7034951740616,28.1578947368421,9.21052631578947,0.00434800683371804 +"1039",23.045712295823,28.1578947368421,9.21052631578947,0.00376447168264219 +"1040",30,28.1578947368421,9.21052631578947,0.00325925132808081 +"1041",0.2,30.2631578947368,9.21052631578947,0.0109427199361197 +"1042",0.260352117694686,30.2631578947368,9.21052631578947,0.0109426494141862 +"1043",0.338916125940539,30.2631578947368,9.21052631578947,0.0109422180935286 +"1044",0.441187655547492,30.2631578947368,9.21052631578947,0.010939584274931 +"1045",0.574320702112717,30.2631578947368,9.21052631578947,0.0109236552710708 +"1046",0.747628055154725,30.2631578947368,9.21052631578947,0.0108325314226489 +"1047",0.973232737037462,30.2631578947368,9.21052631578947,0.0104290401174395 +"1048",1.2669160204875,30.2631578947368,9.21052631578947,0.00947910058265188 +"1049",1.64922134437622,30.2631578947368,9.21052631578947,0.00830419941707946 +"1050",2.14689134777813,30.2631578947368,9.21052631578947,0.00720485097282572 +"1051",2.79473854427218,30.2631578947368,9.21052631578947,0.00624008407086828 +"1052",3.63808049202114,30.2631578947368,9.21052631578947,0.00540292704840152 +"1053",4.73590980220715,30.2631578947368,9.21052631578947,0.00467785744743759 +"1054",6.16502073107827,30.2631578947368,9.21052631578947,0.00405006006094592 +"1055",8.02538101483936,30.2631578947368,9.21052631578947,0.00350651247885653 +"1056",10.4471247126008,30.2631578947368,9.21052631578947,0.0030359123095355 +"1057",13.5996552137305,30.2631578947368,9.21052631578947,0.00262847010862176 +"1058",17.7034951740616,30.2631578947368,9.21052631578947,0.0022757096941248 +"1059",23.045712295823,30.2631578947368,9.21052631578947,0.00197029237282075 +"1060",30,30.2631578947368,9.21052631578947,0.00170586434809261 +"1061",0.2,32.3684210526316,9.21052631578947,0.00567095390899693 +"1062",0.260352117694686,32.3684210526316,9.21052631578947,0.00567091736171833 +"1063",0.338916125940539,32.3684210526316,9.21052631578947,0.0056706938341508 +"1064",0.441187655547492,32.3684210526316,9.21052631578947,0.00566932888430665 +"1065",0.574320702112717,32.3684210526316,9.21052631578947,0.00566107383919584 +"1066",0.747628055154725,32.3684210526316,9.21052631578947,0.0056138498265712 +"1067",0.973232737037462,32.3684210526316,9.21052631578947,0.00540474453941402 +"1068",1.2669160204875,32.3684210526316,9.21052631578947,0.00491244798521516 +"1069",1.64922134437622,32.3684210526316,9.21052631578947,0.00430356734160155 +"1070",2.14689134777813,32.3684210526316,9.21052631578947,0.00373384113151076 +"1071",2.79473854427218,32.3684210526316,9.21052631578947,0.00323386044427163 +"1072",3.63808049202114,32.3684210526316,9.21052631578947,0.00280001228616136 +"1073",4.73590980220715,32.3684210526316,9.21052631578947,0.00242425230035482 +"1074",6.16502073107827,32.3684210526316,9.21052631578947,0.00209890265568088 +"1075",8.02538101483936,32.3684210526316,9.21052631578947,0.00181721461985706 +"1076",10.4471247126008,32.3684210526316,9.21052631578947,0.00157333084275547 +"1077",13.5996552137305,32.3684210526316,9.21052631578947,0.00136217804386721 +"1078",17.7034951740616,32.3684210526316,9.21052631578947,0.00117936352762178 +"1079",23.045712295823,32.3684210526316,9.21052631578947,0.00102108409049504 +"1080",30,32.3684210526316,9.21052631578947,0.000884046941666011 +"1081",0.2,34.4736842105263,9.21052631578947,0.00294248493466328 +"1082",0.260352117694686,34.4736842105263,9.21052631578947,0.00294246597139565 +"1083",0.338916125940539,34.4736842105263,9.21052631578947,0.00294234998976179 +"1084",0.441187655547492,34.4736842105263,9.21052631578947,0.002941641758939 +"1085",0.574320702112717,34.4736842105263,9.21052631578947,0.00293735846793305 +"1086",0.747628055154725,34.4736842105263,9.21052631578947,0.00291285536881918 +"1087",0.973232737037462,34.4736842105263,9.21052631578947,0.00280435701614481 +"1088",1.2669160204875,34.4736842105263,9.21052631578947,0.00254891935656189 +"1089",1.64922134437622,34.4736842105263,9.21052631578947,0.00223298977053603 +"1090",2.14689134777813,34.4736842105263,9.21052631578947,0.00193737622527069 +"1091",2.79473854427218,34.4736842105263,9.21052631578947,0.00167795150353389 +"1092",3.63808049202114,34.4736842105263,9.21052631578947,0.0014528409331331 +"1093",4.73590980220715,34.4736842105263,9.21052631578947,0.00125787054278468 +"1094",6.16502073107827,34.4736842105263,9.21052631578947,0.00108905654018234 +"1095",8.02538101483936,34.4736842105263,9.21052631578947,0.000942897214081757 +"1096",10.4471247126008,34.4736842105263,9.21052631578947,0.000816353364238138 +"1097",13.5996552137305,34.4736842105263,9.21052631578947,0.000706792620206169 +"1098",17.7034951740616,34.4736842105263,9.21052631578947,0.000611935746297088 +"1099",23.045712295823,34.4736842105263,9.21052631578947,0.000529809376256673 +"1100",30,34.4736842105263,9.21052631578947,0.000458704981407175 +"1101",0.2,36.5789473684211,9.21052631578947,0.00153555162683744 +"1102",0.260352117694686,36.5789473684211,9.21052631578947,0.00153554173075399 +"1103",0.338916125940539,36.5789473684211,9.21052631578947,0.00153548120511307 +"1104",0.441187655547492,36.5789473684211,9.21052631578947,0.00153511161103995 +"1105",0.574320702112717,36.5789473684211,9.21052631578947,0.00153287635253619 +"1106",0.747628055154725,36.5789473684211,9.21052631578947,0.00152008927816118 +"1107",0.973232737037462,36.5789473684211,9.21052631578947,0.00146346882787589 +"1108",1.2669160204875,36.5789473684211,9.21052631578947,0.00133016730809327 +"1109",1.64922134437622,36.5789473684211,9.21052631578947,0.00116529775036906 +"1110",2.14689134777813,36.5789473684211,9.21052631578947,0.00101103022804465 +"1111",2.79473854427218,36.5789473684211,9.21052631578947,0.000875648038381761 +"1112",3.63808049202114,36.5789473684211,9.21052631578947,0.000758172873589866 +"1113",4.73590980220715,36.5789473684211,9.21052631578947,0.000656426524251664 +"1114",6.16502073107827,36.5789473684211,9.21052631578947,0.000568330026874485 +"1115",8.02538101483936,36.5789473684211,9.21052631578947,0.000492055994566856 +"1116",10.4471247126008,36.5789473684211,9.21052631578947,0.000426018404295938 +"1117",13.5996552137305,36.5789473684211,9.21052631578947,0.000368843539353065 +"1118",17.7034951740616,36.5789473684211,9.21052631578947,0.000319341968306119 +"1119",23.045712295823,36.5789473684211,9.21052631578947,0.000276483879336415 +"1120",30,36.5789473684211,9.21052631578947,0.000239377667542358 +"1121",0.2,38.6842105263158,9.21052631578947,0.00080736165864245 +"1122",0.260352117694686,38.6842105263158,9.21052631578947,0.000807356455484048 +"1123",0.338916125940539,38.6842105263158,9.21052631578947,0.0008073246323392 +"1124",0.441187655547492,38.6842105263158,9.21052631578947,0.000807130307330072 +"1125",0.574320702112717,38.6842105263158,9.21052631578947,0.000805955054097585 +"1126",0.747628055154725,38.6842105263158,9.21052631578947,0.00079923187175962 +"1127",0.973232737037462,38.6842105263158,9.21052631578947,0.000769461996324326 +"1128",1.2669160204875,38.6842105263158,9.21052631578947,0.000699374781912059 +"1129",1.64922134437622,38.6842105263158,9.21052631578947,0.000612689738402313 +"1130",2.14689134777813,38.6842105263158,9.21052631578947,0.000531579028399675 +"1131",2.79473854427218,38.6842105263158,9.21052631578947,0.000460397840293356 +"1132",3.63808049202114,38.6842105263158,9.21052631578947,0.000398631799843763 +"1133",4.73590980220715,38.6842105263158,9.21052631578947,0.000345135649061982 +"1134",6.16502073107827,38.6842105263158,9.21052631578947,0.00029881631143768 +"1135",8.02538101483936,38.6842105263158,9.21052631578947,0.000258712984295196 +"1136",10.4471247126008,38.6842105263158,9.21052631578947,0.00022399176914225 +"1137",13.5996552137305,38.6842105263158,9.21052631578947,0.000193930393812261 +"1138",17.7034951740616,38.6842105263158,9.21052631578947,0.000167903479570256 +"1139",23.045712295823,38.6842105263158,9.21052631578947,0.000145369572411373 +"1140",30,38.6842105263158,9.21052631578947,0.000125859884702801 +"1141",0.2,40.7894736842105,9.21052631578947,0.000427950805042532 +"1142",0.260352117694686,40.7894736842105,9.21052631578947,0.00042794804705198 +"1143",0.338916125940539,40.7894736842105,9.21052631578947,0.00042793117884885 +"1144",0.441187655547492,40.7894736842105,9.21052631578947,0.000427828174769816 +"1145",0.574320702112717,40.7894736842105,9.21052631578947,0.000427205219045342 +"1146",0.747628055154725,40.7894736842105,9.21052631578947,0.000423641523317188 +"1147",0.973232737037462,40.7894736842105,9.21052631578947,0.00040786167791312 +"1148",1.2669160204875,40.7894736842105,9.21052631578947,0.000370711189640798 +"1149",1.64922134437622,40.7894736842105,9.21052631578947,0.000324762842009924 +"1150",2.14689134777813,40.7894736842105,9.21052631578947,0.000281769230322237 +"1151",2.79473854427218,40.7894736842105,9.21052631578947,0.000244038869426472 +"1152",3.63808049202114,40.7894736842105,9.21052631578947,0.000211299109677243 +"1153",4.73590980220715,40.7894736842105,9.21052631578947,0.000182942894654306 +"1154",6.16502073107827,40.7894736842105,9.21052631578947,0.000158390827296182 +"1155",8.02538101483936,40.7894736842105,9.21052631578947,0.000137133623722299 +"1156",10.4471247126008,40.7894736842105,9.21052631578947,0.000118729266991088 +"1157",13.5996552137305,40.7894736842105,9.21052631578947,0.000102794908905783 +"1158",17.7034951740616,40.7894736842105,9.21052631578947,8.89990606840978e-05 +"1159",23.045712295823,40.7894736842105,9.21052631578947,7.70547187573181e-05 +"1160",30,40.7894736842105,9.21052631578947,6.67133971554841e-05 +"1161",0.2,42.8947368421053,9.21052631578947,0.000228722834213445 +"1162",0.260352117694686,42.8947368421053,9.21052631578947,0.000228721360176223 +"1163",0.338916125940539,42.8947368421053,9.21052631578947,0.000228712344786645 +"1164",0.441187655547492,42.8947368421053,9.21052631578947,0.000228657293167125 +"1165",0.574320702112717,42.8947368421053,9.21052631578947,0.000228324347891144 +"1166",0.747628055154725,42.8947368421053,9.21052631578947,0.000226419693015833 +"1167",0.973232737037462,42.8947368421053,9.21052631578947,0.000217985987735363 +"1168",1.2669160204875,42.8947368421053,9.21052631578947,0.000198130516335527 +"1169",1.64922134437622,42.8947368421053,9.21052631578947,0.000173572935946086 +"1170",2.14689134777813,42.8947368421053,9.21052631578947,0.00015059454543388 +"1171",2.79473854427218,42.8947368421053,9.21052631578947,0.000130429154977101 +"1172",3.63808049202114,42.8947368421053,9.21052631578947,0.000112931044088942 +"1173",4.73590980220715,42.8947368421053,9.21052631578947,9.77757650447371e-05 +"1174",6.16502073107827,42.8947368421053,9.21052631578947,8.46536529566628e-05 +"1175",8.02538101483936,42.8947368421053,9.21052631578947,7.32925156680266e-05 +"1176",10.4471247126008,42.8947368421053,9.21052631578947,6.34561125491691e-05 +"1177",13.5996552137305,42.8947368421053,9.21052631578947,5.49398263319235e-05 +"1178",17.7034951740616,42.8947368421053,9.21052631578947,4.75664893304223e-05 +"1179",23.045712295823,42.8947368421053,9.21052631578947,4.1182709451714e-05 +"1180",30,42.8947368421053,9.21052631578947,3.56556807409043e-05 +"1181",0.2,45,9.21052631578947,0.000123254185315348 +"1182",0.260352117694686,45,9.21052631578947,0.000123253390986013 +"1183",0.338916125940539,45,9.21052631578947,0.000123248532771914 +"1184",0.441187655547492,45,9.21052631578947,0.000123218866549311 +"1185",0.574320702112717,45,9.21052631578947,0.000123039448963452 +"1186",0.747628055154725,45,9.21052631578947,0.000122013068340936 +"1187",0.973232737037462,45,9.21052631578947,0.000117468312339163 +"1188",1.2669160204875,45,9.21052631578947,0.000106768593791801 +"1189",1.64922134437622,45,9.21052631578947,9.35350022502052e-05 +"1190",2.14689134777813,45,9.21052631578947,8.1152404718221e-05 +"1191",2.79473854427218,45,9.21052631578947,7.02856769563713e-05 +"1192",3.63808049202114,45,9.21052631578947,6.08562930931714e-05 +"1193",4.73590980220715,45,9.21052631578947,5.26894147041204e-05 +"1194",6.16502073107827,45,9.21052631578947,4.56181695414141e-05 +"1195",8.02538101483936,45,9.21052631578947,3.94958786665996e-05 +"1196",10.4471247126008,45,9.21052631578947,3.41952367039492e-05 +"1197",13.5996552137305,45,9.21052631578947,2.96059794781517e-05 +"1198",17.7034951740616,45,9.21052631578947,2.56326348477356e-05 +"1199",23.045712295823,45,9.21052631578947,2.21925428652778e-05 +"1200",30,45,9.21052631578947,1.92141370436288e-05 +"1201",0.2,5,11.3157894736842,0.0298790200958854 +"1202",0.260352117694686,5,11.3157894736842,0.0298788275362403 +"1203",0.338916125940539,5,11.3157894736842,0.0298776498182075 +"1204",0.441187655547492,5,11.3157894736842,0.0298704581949854 +"1205",0.574320702112717,5,11.3157894736842,0.02982696416158 +"1206",0.747628055154725,5,11.3157894736842,0.0295781511320858 +"1207",0.973232737037462,5,11.3157894736842,0.0284764209509934 +"1208",1.2669160204875,5,11.3157894736842,0.0258826177087017 +"1209",1.64922134437622,5,11.3157894736842,0.0226745583101473 +"1210",2.14689134777813,5,11.3157894736842,0.0196727950876586 +"1211",2.79473854427218,5,11.3157894736842,0.0170385058232243 +"1212",3.63808049202114,5,11.3157894736842,0.014752654440413 +"1213",4.73590980220715,5,11.3157894736842,0.0127728569764747 +"1214",6.16502073107827,5,11.3157894736842,0.0110586606124416 +"1215",8.02538101483936,5,11.3157894736842,0.00957450774888235 +"1216",10.4471247126008,5,11.3157894736842,0.00828953728465095 +"1217",13.5996552137305,5,11.3157894736842,0.00717701921052664 +"1218",17.7034951740616,5,11.3157894736842,0.00621380937098786 +"1219",23.045712295823,5,11.3157894736842,0.00537986951561848 +"1220",30,5,11.3157894736842,0.004657850647285 +"1221",0.2,7.10526315789474,11.3157894736842,0.0383612525544718 +"1222",0.260352117694686,7.10526315789474,11.3157894736842,0.038361005329859 +"1223",0.338916125940539,7.10526315789474,11.3157894736842,0.0383594932742845 +"1224",0.441187655547492,7.10526315789474,11.3157894736842,0.0383502600506442 +"1225",0.574320702112717,7.10526315789474,11.3157894736842,0.0382944186744972 +"1226",0.747628055154725,7.10526315789474,11.3157894736842,0.03797497113463 +"1227",0.973232737037462,7.10526315789474,11.3157894736842,0.0365604752914552 +"1228",1.2669160204875,7.10526315789474,11.3157894736842,0.033230327885856 +"1229",1.64922134437622,7.10526315789474,11.3157894736842,0.0291115456633212 +"1230",2.14689134777813,7.10526315789474,11.3157894736842,0.025257624192099 +"1231",2.79473854427218,7.10526315789474,11.3157894736842,0.0218754973535948 +"1232",3.63808049202114,7.10526315789474,11.3157894736842,0.0189407249977206 +"1233",4.73590980220715,7.10526315789474,11.3157894736842,0.01639889095239 +"1234",6.16502073107827,7.10526315789474,11.3157894736842,0.0141980584137859 +"1235",8.02538101483936,7.10526315789474,11.3157894736842,0.0122925754814229 +"1236",10.4471247126008,7.10526315789474,11.3157894736842,0.0106428200227355 +"1237",13.5996552137305,7.10526315789474,11.3157894736842,0.00921447375582516 +"1238",17.7034951740616,7.10526315789474,11.3157894736842,0.00797782222579095 +"1239",23.045712295823,7.10526315789474,11.3157894736842,0.00690713860549814 +"1240",30,7.10526315789474,11.3157894736842,0.00598014876217831 +"1241",0.2,9.21052631578947,11.3157894736842,0.048976328621999 +"1242",0.260352117694686,9.21052631578947,11.3157894736842,0.0489760129870007 +"1243",0.338916125940539,9.21052631578947,11.3157894736842,0.0489740825252514 +"1244",0.441187655547492,9.21052631578947,11.3157894736842,0.0489622943440755 +"1245",0.574320702112717,9.21052631578947,11.3157894736842,0.0488910009058596 +"1246",0.747628055154725,9.21052631578947,11.3157894736842,0.048483157922427 +"1247",0.973232737037462,9.21052631578947,11.3157894736842,0.0466772519981768 +"1248",1.2669160204875,9.21052631578947,11.3157894736842,0.0424256078824188 +"1249",1.64922134437622,9.21052631578947,11.3157894736842,0.0371671030573517 +"1250",2.14689134777813,9.21052631578947,11.3157894736842,0.0322467495264043 +"1251",2.79473854427218,9.21052631578947,11.3157894736842,0.0279287425674643 +"1252",3.63808049202114,9.21052631578947,11.3157894736842,0.0241818791112216 +"1253",4.73590980220715,9.21052631578947,11.3157894736842,0.0209366852967097 +"1254",6.16502073107827,9.21052631578947,11.3157894736842,0.0181268527058784 +"1255",8.02538101483936,9.21052631578947,11.3157894736842,0.015694096941543 +"1256",10.4471247126008,9.21052631578947,11.3157894736842,0.0135878318925622 +"1257",13.5996552137305,9.21052631578947,11.3157894736842,0.0117642429454893 +"1258",17.7034951740616,9.21052631578947,11.3157894736842,0.0101853932549102 +"1259",23.045712295823,9.21052631578947,11.3157894736842,0.00881843703357225 +"1260",30,9.21052631578947,11.3157894736842,0.00763493659569631 +"1261",0.2,11.3157894736842,11.3157894736842,0.0620126961672388 +"1262",0.260352117694686,11.3157894736842,11.3157894736842,0.0620122965174937 +"1263",0.338916125940539,11.3157894736842,11.3157894736842,0.0620098522114118 +"1264",0.441187655547492,11.3157894736842,11.3157894736842,0.0619949262886611 +"1265",0.574320702112717,11.3157894736842,11.3157894736842,0.0619046561837513 +"1266",0.747628055154725,11.3157894736842,11.3157894736842,0.0613882548174761 +"1267",0.973232737037462,11.3157894736842,11.3157894736842,0.0591016584445327 +"1268",1.2669160204875,11.3157894736842,11.3157894736842,0.0537183248591055 +"1269",1.64922134437622,11.3157894736842,11.3157894736842,0.0470601274975259 +"1270",2.14689134777813,11.3157894736842,11.3157894736842,0.0408300894947797 +"1271",2.79473854427218,11.3157894736842,11.3157894736842,0.0353627288100001 +"1272",3.63808049202114,11.3157894736842,11.3157894736842,0.0306185368374775 +"1273",4.73590980220715,11.3157894736842,11.3157894736842,0.0265095473789918 +"1274",6.16502073107827,11.3157894736842,11.3157894736842,0.0229518022470352 +"1275",8.02538101483936,11.3157894736842,11.3157894736842,0.019871503084001 +"1276",10.4471247126008,11.3157894736842,11.3157894736842,0.0172045989242748 +"1277",13.5996552137305,11.3157894736842,11.3157894736842,0.0148956127162321 +"1278",17.7034951740616,11.3157894736842,11.3157894736842,0.0128965097023806 +"1279",23.045712295823,11.3157894736842,11.3157894736842,0.0111657013054917 +"1280",30,11.3157894736842,11.3157894736842,0.00966718038461501 +"1281",0.2,13.4210526315789,11.3157894736842,0.0773736776002224 +"1282",0.260352117694686,13.4210526315789,11.3157894736842,0.0773731789544218 +"1283",0.338916125940539,13.4210526315789,11.3157894736842,0.0773701291765146 +"1284",0.441187655547492,13.4210526315789,11.3157894736842,0.0773515059976145 +"1285",0.574320702112717,13.4210526315789,11.3157894736842,0.0772388753521836 +"1286",0.747628055154725,13.4210526315789,11.3157894736842,0.0765945577318251 +"1287",0.973232737037462,13.4210526315789,11.3157894736842,0.0737415553388178 +"1288",1.2669160204875,13.4210526315789,11.3157894736842,0.0670247321236172 +"1289",1.64922134437622,13.4210526315789,11.3157894736842,0.0587172523993978 +"1290",2.14689134777813,13.4210526315789,11.3157894736842,0.0509439901215955 +"1291",2.79473854427218,13.4210526315789,11.3157894736842,0.0441223257029509 +"1292",3.63808049202114,13.4210526315789,11.3157894736842,0.0382029639779651 +"1293",4.73590980220715,13.4210526315789,11.3157894736842,0.0330761489018042 +"1294",6.16502073107827,13.4210526315789,11.3157894736842,0.028637125252818 +"1295",8.02538101483936,13.4210526315789,11.3157894736842,0.0247938143006527 +"1296",10.4471247126008,13.4210526315789,11.3157894736842,0.021466299204569 +"1297",13.5996552137305,13.4210526315789,11.3157894736842,0.0185853608566756 +"1298",17.7034951740616,13.4210526315789,11.3157894736842,0.0160910659518671 +"1299",23.045712295823,13.4210526315789,11.3157894736842,0.0139315241295364 +"1300",30,13.4210526315789,11.3157894736842,0.012061809026416 +"1301",0.2,15.5263157894737,11.3157894736842,0.0937748493427402 +"1302",0.260352117694686,15.5263157894737,11.3157894736842,0.0937742449972279 +"1303",0.338916125940539,15.5263157894737,11.3157894736842,0.0937705487471251 +"1304",0.441187655547492,15.5263157894737,11.3157894736842,0.0937479779472123 +"1305",0.574320702112717,15.5263157894737,11.3157894736842,0.0936114725860321 +"1306",0.747628055154725,15.5263157894737,11.3157894736842,0.0928305766838084 +"1307",0.973232737037462,15.5263157894737,11.3157894736842,0.0893728132960957 +"1308",1.2669160204875,15.5263157894737,11.3157894736842,0.0812322013386069 +"1309",1.64922134437622,15.5263157894737,11.3157894736842,0.0711637557933184 +"1310",2.14689134777813,15.5263157894737,11.3157894736842,0.0617427676535428 +"1311",2.79473854427218,15.5263157894737,11.3157894736842,0.0534750909323927 +"1312",3.63808049202114,15.5263157894737,11.3157894736842,0.0463009811940167 +"1313",4.73590980220715,15.5263157894737,11.3157894736842,0.0400874170170737 +"1314",6.16502073107827,15.5263157894737,11.3157894736842,0.0347074378455609 +"1315",8.02538101483936,15.5263157894737,11.3157894736842,0.0300494466954083 +"1316",10.4471247126008,15.5263157894737,11.3157894736842,0.0260165864708601 +"1317",13.5996552137305,15.5263157894737,11.3157894736842,0.0225249654452279 +"1318",17.7034951740616,15.5263157894737,11.3157894736842,0.0195019460390248 +"1319",23.045712295823,15.5263157894737,11.3157894736842,0.0168846385086169 +"1320",30,15.5263157894737,11.3157894736842,0.014618593290825 +"1321",0.2,17.6315789473684,11.3157894736842,0.107246338604769 +"1322",0.260352117694686,17.6315789473684,11.3157894736842,0.107245647440306 +"1323",0.338916125940539,17.6315789473684,11.3157894736842,0.107241420195017 +"1324",0.441187655547492,17.6315789473684,11.3157894736842,0.107215606923474 +"1325",0.574320702112717,17.6315789473684,11.3157894736842,0.107059491501384 +"1326",0.747628055154725,17.6315789473684,11.3157894736842,0.106166413805905 +"1327",0.973232737037462,17.6315789473684,11.3157894736842,0.102211915710808 +"1328",1.2669160204875,17.6315789473684,11.3157894736842,0.0929018412872075 +"1329",1.64922134437622,17.6315789473684,11.3157894736842,0.0813869849292188 +"1330",2.14689134777813,17.6315789473684,11.3157894736842,0.0706125982881154 +"1331",2.79473854427218,17.6315789473684,11.3157894736842,0.0611572052554859 +"1332",3.63808049202114,17.6315789473684,11.3157894736842,0.0529524786408095 +"1333",4.73590980220715,17.6315789473684,11.3157894736842,0.0458462874569952 +"1334",6.16502073107827,17.6315789473684,11.3157894736842,0.0396934322729166 +"1335",8.02538101483936,17.6315789473684,11.3157894736842,0.0343662843264404 +"1336",10.4471247126008,17.6315789473684,11.3157894736842,0.029754072243787 +"1337",13.5996552137305,17.6315789473684,11.3157894736842,0.025760852596738 +"1338",17.7034951740616,17.6315789473684,11.3157894736842,0.0223035528503903 +"1339",23.045712295823,17.6315789473684,11.3157894736842,0.0193102486584207 +"1340",30,17.6315789473684,11.3157894736842,0.0167186683527805 +"1341",0.2,19.7368421052632,11.3157894736842,0.110378812038268 +"1342",0.260352117694686,19.7368421052632,11.3157894736842,0.110378100686129 +"1343",0.338916125940539,19.7368421052632,11.3157894736842,0.110373749970577 +"1344",0.441187655547492,19.7368421052632,11.3157894736842,0.110347182739613 +"1345",0.574320702112717,19.7368421052632,11.3157894736842,0.110186507465704 +"1346",0.747628055154725,19.7368421052632,11.3157894736842,0.109267344570566 +"1347",0.973232737037462,19.7368421052632,11.3157894736842,0.105197342670054 +"1348",1.2669160204875,19.7368421052632,11.3157894736842,0.095615337650265 +"1349",1.64922134437622,19.7368421052632,11.3157894736842,0.0837641529653496 +"1350",2.14689134777813,19.7368421052632,11.3157894736842,0.0726750657912996 +"1351",2.79473854427218,19.7368421052632,11.3157894736842,0.0629434976662303 +"1352",3.63808049202114,19.7368421052632,11.3157894736842,0.0544991256847848 +"1353",4.73590980220715,19.7368421052632,11.3157894736842,0.0471853753862608 +"1354",6.16502073107827,19.7368421052632,11.3157894736842,0.0408528063242537 +"1355",8.02538101483936,19.7368421052632,11.3157894736842,0.0353700619291179 +"1356",10.4471247126008,19.7368421052632,11.3157894736842,0.0306231353936772 +"1357",13.5996552137305,19.7368421052632,11.3157894736842,0.0265132809540447 +"1358",17.7034951740616,19.7368421052632,11.3157894736842,0.0229549996753859 +"1359",23.045712295823,19.7368421052632,11.3157894736842,0.0198742664300639 +"1360",30,19.7368421052632,11.3157894736842,0.0172069907061576 +"1361",0.2,21.8421052631579,11.3157894736842,0.0971665071766236 +"1362",0.260352117694686,21.8421052631579,11.3157894736842,0.0971658809730843 +"1363",0.338916125940539,21.8421052631579,11.3157894736842,0.0971620510366498 +"1364",0.441187655547492,21.8421052631579,11.3157894736842,0.0971386638938596 +"1365",0.574320702112717,21.8421052631579,11.3157894736842,0.0969972213935545 +"1366",0.747628055154725,21.8421052631579,11.3157894736842,0.0961880819727031 +"1367",0.973232737037462,21.8421052631579,11.3157894736842,0.0926052578638712 +"1368",1.2669160204875,21.8421052631579,11.3157894736842,0.0841702154646196 +"1369",1.64922134437622,21.8421052631579,11.3157894736842,0.0737376134056385 +"1370",2.14689134777813,21.8421052631579,11.3157894736842,0.0639758860543243 +"1371",2.79473854427218,21.8421052631579,11.3157894736842,0.055409183200732 +"1372",3.63808049202114,21.8421052631579,11.3157894736842,0.0479755995664677 +"1373",4.73590980220715,21.8421052631579,11.3157894736842,0.0415373025985389 +"1374",6.16502073107827,21.8421052631579,11.3157894736842,0.0359627398192562 +"1375",8.02538101483936,21.8421052631579,11.3157894736842,0.0311362779940206 +"1376",10.4471247126008,21.8421052631579,11.3157894736842,0.0269575568902557 +"1377",13.5996552137305,21.8421052631579,11.3157894736842,0.0233396505771766 +"1378",17.7034951740616,21.8421052631579,11.3157894736842,0.020207294312286 +"1379",23.045712295823,21.8421052631579,11.3157894736842,0.0174953237496108 +"1380",30,21.8421052631579,11.3157894736842,0.015147319988897 +"1381",0.2,23.9473684210526,11.3157894736842,0.0720186540344548 +"1382",0.260352117694686,23.9473684210526,11.3157894736842,0.0720181898998742 +"1383",0.338916125940539,23.9473684210526,11.3157894736842,0.0720153511967546 +"1384",0.441187655547492,23.9473684210526,11.3157894736842,0.0719980169259816 +"1385",0.574320702112717,23.9473684210526,11.3157894736842,0.0718931814349134 +"1386",0.747628055154725,23.9473684210526,11.3157894736842,0.0712934569649372 +"1387",0.973232737037462,23.9473684210526,11.3157894736842,0.0686379105481947 +"1388",1.2669160204875,23.9473684210526,11.3157894736842,0.06238595791586 +"1389",1.64922134437622,23.9473684210526,11.3157894736842,0.0546534379334431 +"1390",2.14689134777813,23.9473684210526,11.3157894736842,0.0474181622677752 +"1391",2.79473854427218,23.9473684210526,11.3157894736842,0.0410686244799513 +"1392",3.63808049202114,23.9473684210526,11.3157894736842,0.0355589411173588 +"1393",4.73590980220715,23.9473684210526,11.3157894736842,0.0307869523387409 +"1394",6.16502073107827,23.9473684210526,11.3157894736842,0.0266551530196119 +"1395",8.02538101483936,23.9473684210526,11.3157894736842,0.023077837188239 +"1396",10.4471247126008,23.9473684210526,11.3157894736842,0.0199806190394846 +"1397",13.5996552137305,23.9473684210526,11.3157894736842,0.0172990701121665 +"1398",17.7034951740616,23.9473684210526,11.3157894736842,0.0149774050785171 +"1399",23.045712295823,23.9473684210526,11.3157894736842,0.0129673249039781 +"1400",30,23.9473684210526,11.3157894736842,0.0112270125738553 +"1401",0.2,26.0526315789474,11.3157894736842,0.0465877801991922 +"1402",0.260352117694686,26.0526315789474,11.3157894736842,0.046587479957538 +"1403",0.338916125940539,26.0526315789474,11.3157894736842,0.0465856436433391 +"1404",0.441187655547492,26.0526315789474,11.3157894736842,0.0465744303652306 +"1405",0.574320702112717,26.0526315789474,11.3157894736842,0.0465066138685127 +"1406",0.747628055154725,26.0526315789474,11.3157894736842,0.0461186611615104 +"1407",0.973232737037462,26.0526315789474,11.3157894736842,0.0444008282690383 +"1408",1.2669160204875,26.0526315789474,11.3157894736842,0.0403565344821588 +"1409",1.64922134437622,26.0526315789474,11.3157894736842,0.0353544840251431 +"1410",2.14689134777813,26.0526315789474,11.3157894736842,0.0306740934109081 +"1411",2.79473854427218,26.0526315789474,11.3157894736842,0.0265666732599555 +"1412",3.63808049202114,26.0526315789474,11.3157894736842,0.0230025422593843 +"1413",4.73590980220715,26.0526315789474,11.3157894736842,0.0199156147499518 +"1414",6.16502073107827,26.0526315789474,11.3157894736842,0.0172428161384329 +"1415",8.02538101483936,26.0526315789474,11.3157894736842,0.0149287045254144 +"1416",10.4471247126008,26.0526315789474,11.3157894736842,0.0129251608563799 +"1417",13.5996552137305,26.0526315789474,11.3157894736842,0.0111905073323151 +"1418",17.7034951740616,26.0526315789474,11.3157894736842,0.00968865726674644 +"1419",23.045712295823,26.0526315789474,11.3157894736842,0.00838836674327493 +"1420",30,26.0526315789474,11.3157894736842,0.00726258496630755 +"1421",0.2,28.1578947368421,11.3157894736842,0.0278049450604962 +"1422",0.260352117694686,28.1578947368421,11.3157894736842,0.0278047658675262 +"1423",0.338916125940539,28.1578947368421,11.3157894736842,0.0278036699016915 +"1424",0.441187655547492,28.1578947368421,11.3157894736842,0.0277969774904965 +"1425",0.574320702112717,28.1578947368421,11.3157894736842,0.0277565026286899 +"1426",0.747628055154725,28.1578947368421,11.3157894736842,0.0275249611459632 +"1427",0.973232737037462,28.1578947368421,11.3157894736842,0.0264997084081406 +"1428",1.2669160204875,28.1578947368421,11.3157894736842,0.024085956001997 +"1429",1.64922134437622,28.1578947368421,11.3157894736842,0.0211005865005421 +"1430",2.14689134777813,28.1578947368421,11.3157894736842,0.0183071929682887 +"1431",2.79473854427218,28.1578947368421,11.3157894736842,0.0158557649081985 +"1432",3.63808049202114,28.1578947368421,11.3157894736842,0.013728587647647 +"1433",4.73590980220715,28.1578947368421,11.3157894736842,0.0118862193390794 +"1434",6.16502073107827,28.1578947368421,11.3157894736842,0.0102910152269002 +"1435",8.02538101483936,28.1578947368421,11.3157894736842,0.00890988596964162 +"1436",10.4471247126008,28.1578947368421,11.3157894736842,0.00771411271310049 +"1437",13.5996552137305,28.1578947368421,11.3157894736842,0.00667882093209275 +"1438",17.7034951740616,28.1578947368421,11.3157894736842,0.00578247304035606 +"1439",23.045712295823,28.1578947368421,11.3157894736842,0.00500642175795484 +"1440",30,28.1578947368421,11.3157894736842,0.00433452238166241 +"1441",0.2,30.2631578947368,11.3157894736842,0.0159791895237446 +"1442",0.260352117694686,30.2631578947368,11.3157894736842,0.015979086543558 +"1443",0.338916125940539,30.2631578947368,11.3157894736842,0.0159784567043065 +"1444",0.441187655547492,30.2631578947368,11.3157894736842,0.0159746106507854 +"1445",0.574320702112717,30.2631578947368,11.3157894736842,0.0159513502024605 +"1446",0.747628055154725,30.2631578947368,11.3157894736842,0.0158182859138223 +"1447",0.973232737037462,30.2631578947368,11.3157894736842,0.0152290846846251 +"1448",1.2669160204875,30.2631578947368,11.3157894736842,0.0138419282965349 +"1449",1.64922134437622,30.2631578947368,11.3157894736842,0.0121262699861746 +"1450",2.14689134777813,30.2631578947368,11.3157894736842,0.0105209381083678 +"1451",2.79473854427218,30.2631578947368,11.3157894736842,0.00911212994525947 +"1452",3.63808049202114,30.2631578947368,11.3157894736842,0.00788966507352543 +"1453",4.73590980220715,30.2631578947368,11.3157894736842,0.00683087670652488 +"1454",6.16502073107827,30.2631578947368,11.3157894736842,0.00591413082617485 +"1455",8.02538101483936,30.2631578947368,11.3157894736842,0.00512041135970923 +"1456",10.4471247126008,30.2631578947368,11.3157894736842,0.00443321390428816 +"1457",13.5996552137305,30.2631578947368,11.3157894736842,0.00383824334976613 +"1458",17.7034951740616,30.2631578947368,11.3157894736842,0.0033231222873038 +"1459",23.045712295823,30.2631578947368,11.3157894736842,0.00287713433463375 +"1460",30,30.2631578947368,11.3157894736842,0.00249100131220544 +"1461",0.2,32.3684210526316,11.3157894736842,0.00905832898063802 +"1462",0.260352117694686,32.3684210526316,11.3157894736842,0.00905827060293327 +"1463",0.338916125940539,32.3684210526316,11.3157894736842,0.00905791355784431 +"1464",0.441187655547492,32.3684210526316,11.3157894736842,0.0090557332959468 +"1465",0.574320702112717,32.3684210526316,11.3157894736842,0.00904254734600545 +"1466",0.747628055154725,32.3684210526316,11.3157894736842,0.00896711547880915 +"1467",0.973232737037462,32.3684210526316,11.3157894736842,0.0086331073889787 +"1468",1.2669160204875,32.3684210526316,11.3157894736842,0.00784675218039677 +"1469",1.64922134437622,32.3684210526316,11.3157894736842,0.00687417485596386 +"1470",2.14689134777813,32.3684210526316,11.3157894736842,0.00596413969738022 +"1471",2.79473854427218,32.3684210526316,11.3157894736842,0.00516551046821433 +"1472",3.63808049202114,32.3684210526316,11.3157894736842,0.00447251606077048 +"1473",4.73590980220715,32.3684210526316,11.3157894736842,0.00387230706175262 +"1474",6.16502073107827,32.3684210526316,11.3157894736842,0.00335261951667935 +"1475",8.02538101483936,32.3684210526316,11.3157894736842,0.00290267353945077 +"1476",10.4471247126008,32.3684210526316,11.3157894736842,0.00251311306664885 +"1477",13.5996552137305,32.3684210526316,11.3157894736842,0.0021758344450614 +"1478",17.7034951740616,32.3684210526316,11.3157894736842,0.00188382113351604 +"1479",23.045712295823,32.3684210526316,11.3157894736842,0.00163099819836758 +"1480",30,32.3684210526316,11.3157894736842,0.00141210599846932 +"1481",0.2,34.4736842105263,11.3157894736842,0.00512509624012166 +"1482",0.260352117694686,34.4736842105263,11.3157894736842,0.00512506321070136 +"1483",0.338916125940539,34.4736842105263,11.3157894736842,0.00512486119877986 +"1484",0.441187655547492,34.4736842105263,11.3157894736842,0.00512362763218305 +"1485",0.574320702112717,34.4736842105263,11.3157894736842,0.00511616717643991 +"1486",0.747628055154725,34.4736842105263,11.3157894736842,0.00507348871115349 +"1487",0.973232737037462,34.4736842105263,11.3157894736842,0.00488451085342507 +"1488",1.2669160204875,34.4736842105263,11.3157894736842,0.00443960030408229 +"1489",1.64922134437622,34.4736842105263,11.3157894736842,0.00388932746685888 +"1490",2.14689134777813,34.4736842105263,11.3157894736842,0.00337444025315702 +"1491",2.79473854427218,34.4736842105263,11.3157894736842,0.00292258520700025 +"1492",3.63808049202114,34.4736842105263,11.3157894736842,0.00253049710337679 +"1493",4.73590980220715,34.4736842105263,11.3157894736842,0.00219090589502823 +"1494",6.16502073107827,34.4736842105263,11.3157894736842,0.00189687278042331 +"1495",8.02538101483936,34.4736842105263,11.3157894736842,0.00164229862650583 +"1496",10.4471247126008,34.4736842105263,11.3157894736842,0.00142188988238484 +"1497",13.5996552137305,34.4736842105263,11.3157894736842,0.00123106159616715 +"1498",17.7034951740616,34.4736842105263,11.3157894736842,0.00106584389119468 +"1499",23.045712295823,34.4736842105263,11.3157894736842,0.000922799641298758 +"1500",30,34.4736842105263,11.3157894736842,0.000798953003239084 +"1501",0.2,36.5789473684211,11.3157894736842,0.00290957300546012 +"1502",0.260352117694686,36.5789473684211,11.3157894736842,0.00290955425429815 +"1503",0.338916125940539,36.5789473684211,11.3157894736842,0.00290943956992813 +"1504",0.441187655547492,36.5789473684211,11.3157894736842,0.00290873926072371 +"1505",0.574320702112717,36.5789473684211,11.3157894736842,0.00290450387867005 +"1506",0.747628055154725,36.5789473684211,11.3157894736842,0.00288027484867844 +"1507",0.973232737037462,36.5789473684211,11.3157894736842,0.0027729900587516 +"1508",1.2669160204875,36.5789473684211,11.3157894736842,0.00252040948980964 +"1509",1.64922134437622,36.5789473684211,11.3157894736842,0.00220801360145747 +"1510",2.14689134777813,36.5789473684211,11.3157894736842,0.00191570651732593 +"1511",2.79473854427218,36.5789473684211,11.3157894736842,0.001659183481839 +"1512",3.63808049202114,36.5789473684211,11.3157894736842,0.00143659079116246 +"1513",4.73590980220715,36.5789473684211,11.3157894736842,0.00124380116021514 +"1514",6.16502073107827,36.5789473684211,11.3157894736842,0.00107687535572614 +"1515",8.02538101483936,36.5789473684211,11.3157894736842,0.000932350833371307 +"1516",10.4471247126008,36.5789473684211,11.3157894736842,0.000807222386603533 +"1517",13.5996552137305,36.5789473684211,11.3157894736842,0.000698887088251352 +"1518",17.7034951740616,36.5789473684211,11.3157894736842,0.000605091196059375 +"1519",23.045712295823,36.5789473684211,11.3157894736842,0.000523883416032673 +"1520",30,36.5789473684211,11.3157894736842,0.000453574329523331 +"1521",0.2,38.6842105263158,11.3157894736842,0.00166124956607257 +"1522",0.260352117694686,38.6842105263158,11.3157894736842,0.00166123885991066 +"1523",0.338916125940539,38.6842105263158,11.3157894736842,0.0016611733797321 +"1524",0.441187655547492,38.6842105263158,11.3157894736842,0.00166077353124582 +"1525",0.574320702112717,38.6842105263158,11.3157894736842,0.00165835529785364 +"1526",0.747628055154725,38.6842105263158,11.3157894736842,0.00164452149286425 +"1527",0.973232737037462,38.6842105263158,11.3157894736842,0.00158326617795113 +"1528",1.2669160204875,38.6842105263158,11.3157894736842,0.00143905279689289 +"1529",1.64922134437622,38.6842105263158,11.3157894736842,0.00126068726593904 +"1530",2.14689134777813,38.6842105263158,11.3157894736842,0.00109379163700579 +"1531",2.79473854427218,38.6842105263158,11.3157894736842,0.000947327265570338 +"1532",3.63808049202114,38.6842105263158,11.3157894736842,0.000820235761042565 +"1533",4.73590980220715,38.6842105263158,11.3157894736842,0.00071016060906889 +"1534",6.16502073107827,38.6842105263158,11.3157894736842,0.000614852665342003 +"1535",8.02538101483936,38.6842105263158,11.3157894736842,0.000532334955836774 +"1536",10.4471247126008,38.6842105263158,11.3157894736842,0.000460891628067988 +"1537",13.5996552137305,38.6842105263158,11.3157894736842,0.000399036514949958 +"1538",17.7034951740616,38.6842105263158,11.3157894736842,0.000345482819988222 +"1539",23.045712295823,38.6842105263158,11.3157894736842,0.000299116432522463 +"1540",30,38.6842105263158,11.3157894736842,0.000258972762219153 +"1541",0.2,40.7894736842105,11.3157894736842,0.000954846562880154 +"1542",0.260352117694686,40.7894736842105,11.3157894736842,0.000954840409234062 +"1543",0.338916125940539,40.7894736842105,11.3157894736842,0.000954802772791765 +"1544",0.441187655547492,40.7894736842105,11.3157894736842,0.000954572949434337 +"1545",0.574320702112717,40.7894736842105,11.3157894736842,0.000953183006652758 +"1546",0.747628055154725,40.7894736842105,11.3157894736842,0.000945231666038173 +"1547",0.973232737037462,40.7894736842105,11.3157894736842,0.000910023574432043 +"1548",1.2669160204875,40.7894736842105,11.3157894736842,0.000827133168296178 +"1549",1.64922134437622,40.7894736842105,11.3157894736842,0.000724612922304346 +"1550",2.14689134777813,40.7894736842105,11.3157894736842,0.00062868530197492 +"1551",2.79473854427218,40.7894736842105,11.3157894736842,0.000544501080346996 +"1552",3.63808049202114,40.7894736842105,11.3157894736842,0.000471451919794613 +"1553",4.73590980220715,40.7894736842105,11.3157894736842,0.000408183352165093 +"1554",6.16502073107827,40.7894736842105,11.3157894736842,0.000353402623043254 +"1555",8.02538101483936,40.7894736842105,11.3157894736842,0.000305973414989893 +"1556",10.4471247126008,40.7894736842105,11.3157894736842,0.000264909496988686 +"1557",13.5996552137305,40.7894736842105,11.3157894736842,0.000229356655703709 +"1558",17.7034951740616,40.7894736842105,11.3157894736842,0.000198575271251861 +"1559",23.045712295823,40.7894736842105,11.3157894736842,0.000171924979441994 +"1560",30,40.7894736842105,11.3157894736842,0.000148851356794718 +"1561",0.2,42.8947368421053,11.3157894736842,0.000552683971882075 +"1562",0.260352117694686,42.8947368421053,11.3157894736842,0.000552680410030678 +"1563",0.338916125940539,42.8947368421053,11.3157894736842,0.00055265862531759 +"1564",0.441187655547492,42.8947368421053,11.3157894736842,0.000552525599037816 +"1565",0.574320702112717,42.8947368421053,11.3157894736842,0.000551721072816456 +"1566",0.747628055154725,42.8947368421053,11.3157894736842,0.000547118680470402 +"1567",0.973232737037462,42.8947368421053,11.3157894736842,0.000526739544525702 +"1568",1.2669160204875,42.8947368421053,11.3157894736842,0.000478760947047273 +"1569",1.64922134437622,42.8947368421053,11.3157894736842,0.000419420212152462 +"1570",2.14689134777813,42.8947368421053,11.3157894736842,0.000363895418664236 +"1571",2.79473854427218,42.8947368421053,11.3157894736842,0.000315167935330391 +"1572",3.63808049202114,42.8947368421053,11.3157894736842,0.000272885644367367 +"1573",4.73590980220715,42.8947368421053,11.3157894736842,0.000236264552966777 +"1574",6.16502073107827,42.8947368421053,11.3157894736842,0.000204556389445374 +"1575",8.02538101483936,42.8947368421053,11.3157894736842,0.00017710343091863 +"1576",10.4471247126008,42.8947368421053,11.3157894736842,0.000153334827475696 +"1577",13.5996552137305,42.8947368421053,11.3157894736842,0.00013275614363585 +"1578",17.7034951740616,42.8947368421053,11.3157894736842,0.000114939272862853 +"1579",23.045712295823,42.8947368421053,11.3157894736842,9.95135597672688e-05 +"1580",30,42.8947368421053,11.3157894736842,8.6158093134034e-05 +"1581",0.2,45,11.3157894736842,0.000322180494730967 +"1582",0.260352117694686,45,11.3157894736842,0.000322178418392402 +"1583",0.338916125940539,45,11.3157894736842,0.000322165719255105 +"1584",0.441187655547492,45,11.3157894736842,0.000322088173180296 +"1585",0.574320702112717,45,11.3157894736842,0.000321619184265819 +"1586",0.747628055154725,45,11.3157894736842,0.000318936274830345 +"1587",0.973232737037462,45,11.3157894736842,0.000307056501877106 +"1588",1.2669160204875,45,11.3157894736842,0.000279087953740168 +"1589",1.64922134437622,45,11.3157894736842,0.000244495983828313 +"1590",2.14689134777813,45,11.3157894736842,0.000212128471206311 +"1591",2.79473854427218,45,11.3157894736842,0.000183723369039094 +"1592",3.63808049202114,45,11.3157894736842,0.000159075414486628 +"1593",4.73590980220715,45,11.3157894736842,0.000137727588341333 +"1594",6.16502073107827,45,11.3157894736842,0.000119243694597231 +"1595",8.02538101483936,45,11.3157894736842,0.000103240321584883 +"1596",10.4471247126008,45,11.3157894736842,8.9384699193245e-05 +"1597",13.5996552137305,45,11.3157894736842,7.73886021871096e-05 +"1598",17.7034951740616,45,11.3157894736842,6.70024709941701e-05 +"1599",23.045712295823,45,11.3157894736842,5.80102364993121e-05 +"1600",30,45,11.3157894736842,5.0224827357437e-05 +"1601",0.2,5,13.4210526315789,0.0307552335173888 +"1602",0.260352117694686,5,13.4210526315789,0.0307550353108602 +"1603",0.338916125940539,5,13.4210526315789,0.0307538230558063 +"1604",0.441187655547492,5,13.4210526315789,0.0307464205355478 +"1605",0.574320702112717,5,13.4210526315789,0.0307016510233716 +"1606",0.747628055154725,5,13.4210526315789,0.0304455414588776 +"1607",0.973232737037462,5,13.4210526315789,0.0293115026288252 +"1608",1.2669160204875,5,13.4210526315789,0.0266416351378954 +"1609",1.64922134437622,5,13.4210526315789,0.0233394981995498 +"1610",2.14689134777813,5,13.4210526315789,0.0202497071496665 +"1611",2.79473854427218,5,13.4210526315789,0.0175381663688768 +"1612",3.63808049202114,5,13.4210526315789,0.0151852815406997 +"1613",4.73590980220715,5,13.4210526315789,0.0131474257768509 +"1614",6.16502073107827,5,13.4210526315789,0.0113829599643406 +"1615",8.02538101483936,5,13.4210526315789,0.00985528376385662 +"1616",10.4471247126008,5,13.4210526315789,0.00853263106093795 +"1617",13.5996552137305,5,13.4210526315789,0.00738748797886209 +"1618",17.7034951740616,5,13.4210526315789,0.0063960316511045 +"1619",23.045712295823,5,13.4210526315789,0.00553763619807307 +"1620",30,5,13.4210526315789,0.00479444385681503 +"1621",0.2,7.10526315789474,13.4210526315789,0.039446288961373 +"1622",0.260352117694686,7.10526315789474,13.4210526315789,0.0394460347440868 +"1623",0.338916125940539,7.10526315789474,13.4210526315789,0.0394444799204785 +"1624",0.441187655547492,7.10526315789474,13.4210526315789,0.0394349855379048 +"1625",0.574320702112717,7.10526315789474,13.4210526315789,0.0393775647053507 +"1626",0.747628055154725,7.10526315789474,13.4210526315789,0.0390490816885955 +"1627",0.973232737037462,7.10526315789474,13.4210526315789,0.0375945772590203 +"1628",1.2669160204875,7.10526315789474,13.4210526315789,0.0341702376429271 +"1629",1.64922134437622,7.10526315789474,13.4210526315789,0.0299349569130195 +"1630",2.14689134777813,7.10526315789474,13.4210526315789,0.0259720284405353 +"1631",2.79473854427218,7.10526315789474,13.4210526315789,0.0224942391690247 +"1632",3.63808049202114,7.10526315789474,13.4210526315789,0.0194764576661586 +"1633",4.73590980220715,7.10526315789474,13.4210526315789,0.0168627286149084 +"1634",6.16502073107827,7.10526315789474,13.4210526315789,0.0145996461946956 +"1635",8.02538101483936,7.10526315789474,13.4210526315789,0.0126402672548598 +"1636",10.4471247126008,7.10526315789474,13.4210526315789,0.0109438489628194 +"1637",13.5996552137305,7.10526315789474,13.4210526315789,0.00947510235446929 +"1638",17.7034951740616,7.10526315789474,13.4210526315789,0.0082034725105536 +"1639",23.045712295823,7.10526315789474,13.4210526315789,0.0071025049284261 +"1640",30,7.10526315789474,13.4210526315789,0.00614929545822101 +"1641",0.2,9.21052631578947,13.4210526315789,0.0502613578884334 +"1642",0.260352117694686,9.21052631578947,13.4210526315789,0.050261033971879 +"1643",0.338916125940539,9.21052631578947,13.4210526315789,0.0502590528591333 +"1644",0.441187655547492,9.21052631578947,13.4210526315789,0.0502469553824623 +"1645",0.574320702112717,9.21052631578947,13.4210526315789,0.0501737913639642 +"1646",0.747628055154725,9.21052631578947,13.4210526315789,0.0497552474932956 +"1647",0.973232737037462,9.21052631578947,13.4210526315789,0.0479019586387527 +"1648",1.2669160204875,9.21052631578947,13.4210526315789,0.0435387608954989 +"1649",1.64922134437622,9.21052631578947,13.4210526315789,0.0381422846710226 +"1650",2.14689134777813,9.21052631578947,13.4210526315789,0.033092832073927 +"1651",2.79473854427218,9.21052631578947,13.4210526315789,0.0286615302749893 +"1652",3.63808049202114,9.21052631578947,13.4210526315789,0.0248163575061852 +"1653",4.73590980220715,9.21052631578947,13.4210526315789,0.0214860170679016 +"1654",6.16502073107827,9.21052631578947,13.4210526315789,0.0186024607575799 +"1655",8.02538101483936,9.21052631578947,13.4210526315789,0.016105874925879 +"1656",10.4471247126008,9.21052631578947,13.4210526315789,0.0139443461953 +"1657",13.5996552137305,9.21052631578947,13.4210526315789,0.0120729103549857 +"1658",17.7034951740616,9.21052631578947,13.4210526315789,0.0104526351815912 +"1659",23.045712295823,9.21052631578947,13.4210526315789,0.00904981308790677 +"1660",30,9.21052631578947,13.4210526315789,0.0078352602469149 +"1661",0.2,11.3157894736842,13.4210526315789,0.0634050579206901 +"1662",0.260352117694686,11.3157894736842,13.4210526315789,0.0634046492976694 +"1663",0.338916125940539,11.3157894736842,13.4210526315789,0.0634021501099501 +"1664",0.441187655547492,11.3157894736842,13.4210526315789,0.0633868890576976 +"1665",0.574320702112717,11.3157894736842,13.4210526315789,0.0632945921316798 +"1666",0.747628055154725,11.3157894736842,13.4210526315789,0.0627665960830852 +"1667",0.973232737037462,11.3157894736842,13.4210526315789,0.0604286591052004 +"1668",1.2669160204875,11.3157894736842,13.4210526315789,0.0549244543392943 +"1669",1.64922134437622,11.3157894736842,13.4210526315789,0.0481167614723395 +"1670",2.14689134777813,11.3157894736842,13.4210526315789,0.0417468413619976 +"1671",2.79473854427218,11.3157894736842,13.4210526315789,0.036156722848897 +"1672",3.63808049202114,11.3157894736842,13.4210526315789,0.0313060102465384 +"1673",4.73590980220715,11.3157894736842,13.4210526315789,0.0271047622648641 +"1674",6.16502073107827,11.3157894736842,13.4210526315789,0.0234671356157919 +"1675",8.02538101483936,11.3157894736842,13.4210526315789,0.0203176749582755 +"1676",10.4471247126008,11.3157894736842,13.4210526315789,0.0175908911999893 +"1677",13.5996552137305,11.3157894736842,13.4210526315789,0.0152300616714004 +"1678",17.7034951740616,11.3157894736842,13.4210526315789,0.0131860730978212 +"1679",23.045712295823,11.3157894736842,13.4210526315789,0.0114164031199443 +"1680",30,11.3157894736842,13.4210526315789,0.00988423613389179 +"1681",0.2,13.4210526315789,13.4210526315789,0.0786197138876237 +"1682",0.260352117694686,13.4210526315789,13.4210526315789,0.078619207211563 +"1683",0.338916125940539,13.4210526315789,13.4210526315789,0.0786161083196152 +"1684",0.441187655547492,13.4210526315789,13.4210526315789,0.0785971852304947 +"1685",0.574320702112717,13.4210526315789,13.4210526315789,0.078482740765744 +"1686",0.747628055154725,13.4210526315789,13.4210526315789,0.0778280469662962 +"1687",0.973232737037462,13.4210526315789,13.4210526315789,0.0749290994325125 +"1688",1.2669160204875,13.4210526315789,13.4210526315789,0.0681041075775137 +"1689",1.64922134437622,13.4210526315789,13.4210526315789,0.0596628430635017 +"1690",2.14689134777813,13.4210526315789,13.4210526315789,0.0517643991067352 +"1691",2.79473854427218,13.4210526315789,13.4210526315789,0.0448328776712117 +"1692",3.63808049202114,13.4210526315789,13.4210526315789,0.0388181897353446 +"1693",4.73590980220715,13.4210526315789,13.4210526315789,0.0336088117279411 +"1694",6.16502073107827,13.4210526315789,13.4210526315789,0.029098301434933 +"1695",8.02538101483936,13.4210526315789,13.4210526315789,0.0251930972774983 +"1696",10.4471247126008,13.4210526315789,13.4210526315789,0.021811995423163 +"1697",13.5996552137305,13.4210526315789,13.4210526315789,0.0188846620500545 +"1698",17.7034951740616,13.4210526315789,13.4210526315789,0.0163501986789244 +"1699",23.045712295823,13.4210526315789,13.4210526315789,0.0141558792997003 +"1700",30,13.4210526315789,13.4210526315789,0.012256054048816 +"1701",0.2,15.5263157894737,13.4210526315789,0.0944509136747841 +"1702",0.260352117694686,15.5263157894737,13.4210526315789,0.094450304972278 +"1703",0.338916125940539,15.5263157894737,13.4210526315789,0.0944465820742747 +"1704",0.441187655547492,15.5263157894737,13.4210526315789,0.0944238485514902 +"1705",0.574320702112717,15.5263157894737,13.4210526315789,0.0942863590628337 +"1706",0.747628055154725,15.5263157894737,13.4210526315789,0.0934998333369395 +"1707",0.973232737037462,15.5263157894737,13.4210526315789,0.0900171414048307 +"1708",1.2669160204875,15.5263157894737,13.4210526315789,0.0818178401780544 +"1709",1.64922134437622,15.5263157894737,13.4210526315789,0.0716768067591516 +"1710",2.14689134777813,15.5263157894737,13.4210526315789,0.0621878985523371 +"1711",2.79473854427218,15.5263157894737,13.4210526315789,0.053860616495863 +"1712",3.63808049202114,15.5263157894737,13.4210526315789,0.0466347854298359 +"1713",4.73590980220715,15.5263157894737,13.4210526315789,0.0403764249227005 +"1714",6.16502073107827,15.5263157894737,13.4210526315789,0.0349576591036965 +"1715",8.02538101483936,15.5263157894737,13.4210526315789,0.0302660864367761 +"1716",10.4471247126008,15.5263157894737,13.4210526315789,0.0262041515405751 +"1717",13.5996552137305,15.5263157894737,13.4210526315789,0.0226873578758718 +"1718",17.7034951740616,15.5263157894737,13.4210526315789,0.0196425441867674 +"1719",23.045712295823,15.5263157894737,13.4210526315789,0.0170063673296722 +"1720",30,15.5263157894737,13.4210526315789,0.0147239851904426 +"1721",0.2,17.6315789473684,13.4210526315789,0.107165607115603 +"1722",0.260352117694686,17.6315789473684,13.4210526315789,0.107164916471425 +"1723",0.338916125940539,17.6315789473684,13.4210526315789,0.107160692408267 +"1724",0.441187655547492,17.6315789473684,13.4210526315789,0.107134898568099 +"1725",0.574320702112717,17.6315789473684,13.4210526315789,0.106978900664525 +"1726",0.747628055154725,17.6315789473684,13.4210526315789,0.106086495248335 +"1727",0.973232737037462,17.6315789473684,13.4210526315789,0.102134973968338 +"1728",1.2669160204875,17.6315789473684,13.4210526315789,0.092831907860193 +"1729",1.64922134437622,17.6315789473684,13.4210526315789,0.0813257195044262 +"1730",2.14689134777813,17.6315789473684,13.4210526315789,0.0705594434644837 +"1731",2.79473854427218,17.6315789473684,13.4210526315789,0.0611111681383428 +"1732",3.63808049202114,17.6315789473684,13.4210526315789,0.0529126177699274 +"1733",4.73590980220715,17.6315789473684,13.4210526315789,0.0458117758913111 +"1734",6.16502073107827,17.6315789473684,13.4210526315789,0.0396635523726869 +"1735",8.02538101483936,17.6315789473684,13.4210526315789,0.0343404145266238 +"1736",10.4471247126008,17.6315789473684,13.4210526315789,0.0297316743643605 +"1737",13.5996552137305,17.6315789473684,13.4210526315789,0.0257414606807119 +"1738",17.7034951740616,17.6315789473684,13.4210526315789,0.0222867634750258 +"1739",23.045712295823,17.6315789473684,13.4210526315789,0.0192957125432429 +"1740",30,17.6315789473684,13.4210526315789,0.0167060830933623 +"1741",0.2,19.7368421052632,13.4210526315789,0.110698498916854 +"1742",0.260352117694686,19.7368421052632,13.4210526315789,0.110697785504446 +"1743",0.338916125940539,19.7368421052632,13.4210526315789,0.110693422188047 +"1744",0.441187655547492,19.7368421052632,13.4210526315789,0.1106667780112 +"1745",0.574320702112717,19.7368421052632,13.4210526315789,0.110505637378262 +"1746",0.747628055154725,19.7368421052632,13.4210526315789,0.1095838123389 +"1747",0.973232737037462,19.7368421052632,13.4210526315789,0.105502022612633 +"1748",1.2669160204875,19.7368421052632,13.4210526315789,0.0958922655159838 +"1749",1.64922134437622,19.7368421052632,13.4210526315789,0.0840067565964667 +"1750",2.14689134777813,19.7368421052632,13.4210526315789,0.0728855524282257 +"1751",2.79473854427218,19.7368421052632,13.4210526315789,0.0631257990511121 +"1752",3.63808049202114,19.7368421052632,13.4210526315789,0.0546569698856245 +"1753",4.73590980220715,19.7368421052632,13.4210526315789,0.0473220369890954 +"1754",6.16502073107827,19.7368421052632,13.4210526315789,0.0409711270951888 +"1755",8.02538101483936,19.7368421052632,13.4210526315789,0.0354725031901235 +"1756",10.4471247126008,19.7368421052632,13.4210526315789,0.0307118282721902 +"1757",13.5996552137305,19.7368421052632,13.4210526315789,0.0265900705830754 +"1758",17.7034951740616,19.7368421052632,13.4210526315789,0.0230214835599163 +"1759",23.045712295823,19.7368421052632,13.4210526315789,0.0199318276782952 +"1760",30,19.7368421052632,13.4210526315789,0.0172568268028425 +"1761",0.2,21.8421052631579,13.4210526315789,0.10052835049805 +"1762",0.260352117694686,21.8421052631579,13.4210526315789,0.100527702628627 +"1763",0.338916125940539,21.8421052631579,13.4210526315789,0.100523740181037 +"1764",0.441187655547492,21.8421052631579,13.4210526315789,0.100499543871466 +"1765",0.574320702112717,21.8421052631579,13.4210526315789,0.100353207632167 +"1766",0.747628055154725,21.8421052631579,13.4210526315789,0.09951607296854 +"1767",0.973232737037462,21.8421052631579,13.4210526315789,0.0958092874901775 +"1768",1.2669160204875,21.8421052631579,13.4210526315789,0.0870824028524854 +"1769",1.64922134437622,21.8421052631579,13.4210526315789,0.0762888454131351 +"1770",2.14689134777813,21.8421052631579,13.4210526315789,0.0661893741328151 +"1771",2.79473854427218,21.8421052631579,13.4210526315789,0.0573262737487174 +"1772",3.63808049202114,21.8421052631579,13.4210526315789,0.0496354971348836 +"1773",4.73590980220715,21.8421052631579,13.4210526315789,0.0429744428991275 +"1774",6.16502073107827,21.8421052631579,13.4210526315789,0.0372070070075558 +"1775",8.02538101483936,21.8421052631579,13.4210526315789,0.0322135554558727 +"1776",10.4471247126008,21.8421052631579,13.4210526315789,0.0278902556691543 +"1777",13.5996552137305,21.8421052631579,13.4210526315789,0.0241471741848192 +"1778",17.7034951740616,21.8421052631579,13.4210526315789,0.0209064421915482 +"1779",23.045712295823,21.8421052631579,13.4210526315789,0.0181006407360175 +"1780",30,21.8421052631579,13.4210526315789,0.0156713988924394 +"1781",0.2,23.9473684210526,13.4210526315789,0.0795134673775562 +"1782",0.260352117694686,23.9473684210526,13.4210526315789,0.0795129549415724 +"1783",0.338916125940539,23.9473684210526,13.4210526315789,0.0795098208212403 +"1784",0.441187655547492,23.9473684210526,13.4210526315789,0.0794906826133398 +"1785",0.574320702112717,23.9473684210526,13.4210526315789,0.0793749371372432 +"1786",0.747628055154725,23.9473684210526,13.4210526315789,0.0787128007405235 +"1787",0.973232737037462,23.9473684210526,13.4210526315789,0.0757808978022067 +"1788",1.2669160204875,23.9473684210526,13.4210526315789,0.0688783190419963 +"1789",1.64922134437622,23.9473684210526,13.4210526315789,0.0603410937409783 +"1790",2.14689134777813,23.9473684210526,13.4210526315789,0.0523528598129396 +"1791",2.79473854427218,23.9473684210526,13.4210526315789,0.0453425404377238 +"1792",3.63808049202114,23.9473684210526,13.4210526315789,0.0392594771788274 +"1793",4.73590980220715,23.9473684210526,13.4210526315789,0.0339908786586 +"1794",6.16502073107827,23.9473684210526,13.4210526315789,0.0294290926216797 +"1795",8.02538101483936,23.9473684210526,13.4210526315789,0.0254794938757631 +"1796",10.4471247126008,23.9473684210526,13.4210526315789,0.0220599554584756 +"1797",13.5996552137305,23.9473684210526,13.4210526315789,0.019099343988958 +"1798",17.7034951740616,23.9473684210526,13.4210526315789,0.0165360686905002 +"1799",23.045712295823,23.9473684210526,13.4210526315789,0.0143168041606742 +"1800",30,23.9473684210526,13.4210526315789,0.0123953815856038 +"1801",0.2,26.0526315789474,13.4210526315789,0.0561573431543323 +"1802",0.260352117694686,26.0526315789474,13.4210526315789,0.0561569812402524 +"1803",0.338916125940539,26.0526315789474,13.4210526315789,0.0561547677300537 +"1804",0.441187655547492,26.0526315789474,13.4210526315789,0.0561412511404259 +"1805",0.574320702112717,26.0526315789474,13.4210526315789,0.0560595045051187 +"1806",0.747628055154725,26.0526315789474,13.4210526315789,0.0555918627071703 +"1807",0.973232737037462,26.0526315789474,13.4210526315789,0.0535211709761651 +"1808",1.2669160204875,26.0526315789474,13.4210526315789,0.0486461416651385 +"1809",1.64922134437622,26.0526315789474,13.4210526315789,0.0426166235642785 +"1810",2.14689134777813,26.0526315789474,13.4210526315789,0.0369748372268288 +"1811",2.79473854427218,26.0526315789474,13.4210526315789,0.0320237148099667 +"1812",3.63808049202114,26.0526315789474,13.4210526315789,0.0277274781833172 +"1813",4.73590980220715,26.0526315789474,13.4210526315789,0.0240064670791488 +"1814",6.16502073107827,26.0526315789474,13.4210526315789,0.0207846507966874 +"1815",8.02538101483936,26.0526315789474,13.4210526315789,0.017995199155204 +"1816",10.4471247126008,26.0526315789474,13.4210526315789,0.0155801089992533 +"1817",13.5996552137305,26.0526315789474,13.4210526315789,0.0134891415226258 +"1818",17.7034951740616,26.0526315789474,13.4210526315789,0.0116787974981223 +"1819",23.045712295823,26.0526315789474,13.4210526315789,0.0101114152185909 +"1820",30,26.0526315789474,13.4210526315789,0.00875438740366299 +"1821",0.2,28.1578947368421,13.4210526315789,0.0368681294977417 +"1822",0.260352117694686,28.1578947368421,13.4210526315789,0.0368678918957753 +"1823",0.338916125940539,28.1578947368421,13.4210526315789,0.0368664386934678 +"1824",0.441187655547492,28.1578947368421,13.4210526315789,0.0368575648517087 +"1825",0.574320702112717,28.1578947368421,13.4210526315789,0.0368038969720117 +"1826",0.747628055154725,28.1578947368421,13.4210526315789,0.0364968831890067 +"1827",0.973232737037462,28.1578947368421,13.4210526315789,0.0351374433259278 +"1828",1.2669160204875,28.1578947368421,13.4210526315789,0.0319369142081191 +"1829",1.64922134437622,28.1578947368421,13.4210526315789,0.0279784460601413 +"1830",2.14689134777813,28.1578947368421,13.4210526315789,0.0242745295711427 +"1831",2.79473854427218,28.1578947368421,13.4210526315789,0.0210240441996679 +"1832",3.63808049202114,28.1578947368421,13.4210526315789,0.0182035010719606 +"1833",4.73590980220715,28.1578947368421,13.4210526315789,0.0157606020396115 +"1834",6.16502073107827,28.1578947368421,13.4210526315789,0.0136454318188038 +"1835",8.02538101483936,28.1578947368421,13.4210526315789,0.0118141154037222 +"1836",10.4471247126008,28.1578947368421,13.4210526315789,0.0102285728616969 +"1837",13.5996552137305,28.1578947368421,13.4210526315789,0.00885582167060139 +"1838",17.7034951740616,28.1578947368421,13.4210526315789,0.00766730394198601 +"1839",23.045712295823,28.1578947368421,13.4210526315789,0.00663829420597663 +"1840",30,28.1578947368421,13.4210526315789,0.00574738529892055 +"1841",0.2,30.2631578947368,13.4210526315789,0.0232830828570715 +"1842",0.260352117694686,30.2631578947368,13.4210526315789,0.0232829328058932 +"1843",0.338916125940539,30.2631578947368,13.4210526315789,0.0232820150747744 +"1844",0.441187655547492,30.2631578947368,13.4210526315789,0.0232764110369305 +"1845",0.574320702112717,30.2631578947368,13.4210526315789,0.0232425185203648 +"1846",0.747628055154725,30.2631578947368,13.4210526315789,0.0230486321625444 +"1847",0.973232737037462,30.2631578947368,13.4210526315789,0.0221901142121501 +"1848",1.2669160204875,30.2631578947368,13.4210526315789,0.0201689054974261 +"1849",1.64922134437622,30.2631578947368,13.4210526315789,0.0176690406241053 +"1850",2.14689134777813,30.2631578947368,13.4210526315789,0.0153299310548414 +"1851",2.79473854427218,30.2631578947368,13.4210526315789,0.0132771738018763 +"1852",3.63808049202114,30.2631578947368,13.4210526315789,0.0114959350941091 +"1853",4.73590980220715,30.2631578947368,13.4210526315789,0.00995318743219887 +"1854",6.16502073107827,30.2631578947368,13.4210526315789,0.00861740815131912 +"1855",8.02538101483936,30.2631578947368,13.4210526315789,0.00746088916294812 +"1856",10.4471247126008,30.2631578947368,13.4210526315789,0.00645958210228888 +"1857",13.5996552137305,30.2631578947368,13.4210526315789,0.00559265773807947 +"1858",17.7034951740616,30.2631578947368,13.4210526315789,0.00484208109832493 +"1859",23.045712295823,30.2631578947368,13.4210526315789,0.00419223747266154 +"1860",30,30.2631578947368,13.4210526315789,0.00362960773842563 +"1861",0.2,32.3684210526316,13.4210526315789,0.014454668909586 +"1862",0.260352117694686,32.3684210526316,13.4210526315789,0.014454575754392 +"1863",0.338916125940539,32.3684210526316,13.4210526315789,0.0144540060059806 +"1864",0.441187655547492,32.3684210526316,13.4210526315789,0.0144505268914626 +"1865",0.574320702112717,32.3684210526316,13.4210526315789,0.0144294856441125 +"1866",0.747628055154725,32.3684210526316,13.4210526315789,0.0143091165707564 +"1867",0.973232737037462,32.3684210526316,13.4210526315789,0.0137761290449177 +"1868",1.2669160204875,32.3684210526316,13.4210526315789,0.0125213165723661 +"1869",1.64922134437622,32.3684210526316,13.4210526315789,0.0109693434387233 +"1870",2.14689134777813,32.3684210526316,13.4210526315789,0.00951717086456242 +"1871",2.79473854427218,32.3684210526316,13.4210526315789,0.00824277233986921 +"1872",3.63808049202114,32.3684210526316,13.4210526315789,0.00713693872119553 +"1873",4.73590980220715,32.3684210526316,13.4210526315789,0.00617916578361492 +"1874",6.16502073107827,32.3684210526316,13.4210526315789,0.00534988353779165 +"1875",8.02538101483936,32.3684210526316,13.4210526315789,0.00463189017036801 +"1876",10.4471247126008,32.3684210526316,13.4210526315789,0.00401025590795056 +"1877",13.5996552137305,32.3684210526316,13.4210526315789,0.00347204948867071 +"1878",17.7034951740616,32.3684210526316,13.4210526315789,0.00300607439054807 +"1879",23.045712295823,32.3684210526316,13.4210526315789,0.00260263664522749 +"1880",30,32.3684210526316,13.4210526315789,0.002253343272997 +"1881",0.2,34.4736842105263,13.4210526315789,0.00892695208868101 +"1882",0.260352117694686,34.4736842105263,13.4210526315789,0.00892689455765354 +"1883",0.338916125940539,34.4736842105263,13.4210526315789,0.00892654269094508 +"1884",0.441187655547492,34.4736842105263,13.4210526315789,0.00892439405033582 +"1885",0.574320702112717,34.4736842105263,13.4210526315789,0.00891139934197164 +"1886",0.747628055154725,34.4736842105263,13.4210526315789,0.00883706149601126 +"1887",0.973232737037462,34.4736842105263,13.4210526315789,0.0085078976710363 +"1888",1.2669160204875,34.4736842105263,13.4210526315789,0.00773294731466261 +"1889",1.64922134437622,34.4736842105263,13.4210526315789,0.00677447570292184 +"1890",2.14689134777813,34.4736842105263,13.4210526315789,0.00587763918074917 +"1891",2.79473854427218,34.4736842105263,13.4210526315789,0.00509059281925988 +"1892",3.63808049202114,34.4736842105263,13.4210526315789,0.00440764921164767 +"1893",4.73590980220715,34.4736842105263,13.4210526315789,0.00381614530525607 +"1894",6.16502073107827,34.4736842105263,13.4210526315789,0.00330399501507898 +"1895",8.02538101483936,34.4736842105263,13.4210526315789,0.00286057480040143 +"1896",10.4471247126008,34.4736842105263,13.4210526315789,0.00247666429286964 +"1897",13.5996552137305,34.4736842105263,13.4210526315789,0.00214427737008475 +"1898",17.7034951740616,34.4736842105263,13.4210526315789,0.00185649925482812 +"1899",23.045712295823,34.4736842105263,13.4210526315789,0.0016073431208641 +"1900",30,34.4736842105263,13.4210526315789,0.00139162560991319 +"1901",0.2,36.5789473684211,13.4210526315789,0.00551733522120951 +"1902",0.260352117694686,36.5789473684211,13.4210526315789,0.00551729966394864 +"1903",0.338916125940539,36.5789473684211,13.4210526315789,0.00551708219144913 +"1904",0.441187655547492,36.5789473684211,13.4210526315789,0.00551575421630224 +"1905",0.574320702112717,36.5789473684211,13.4210526315789,0.00550772278951348 +"1906",0.747628055154725,36.5789473684211,13.4210526315789,0.00546177801332205 +"1907",0.973232737037462,36.5789473684211,13.4210526315789,0.00525833711355682 +"1908",1.2669160204875,36.5789473684211,13.4210526315789,0.00477937622596219 +"1909",1.64922134437622,36.5789473684211,13.4210526315789,0.00418698935870298 +"1910",2.14689134777813,36.5789473684211,13.4210526315789,0.003632696282825 +"1911",2.79473854427218,36.5789473684211,13.4210526315789,0.00314625941525453 +"1912",3.63808049202114,36.5789473684211,13.4210526315789,0.00272416363351998 +"1913",4.73590980220715,36.5789473684211,13.4210526315789,0.00235858249184953 +"1914",6.16502073107827,36.5789473684211,13.4210526315789,0.00204204614142713 +"1915",8.02538101483936,36.5789473684211,13.4210526315789,0.00176798866425765 +"1916",10.4471247126008,36.5789473684211,13.4210526315789,0.00153071137812958 +"1917",13.5996552137305,36.5789473684211,13.4210526315789,0.00132527843103492 +"1918",17.7034951740616,36.5789473684211,13.4210526315789,0.00114741611975268 +"1919",23.045712295823,36.5789473684211,13.4210526315789,0.000993424264543426 +"1920",30,36.5789473684211,13.4210526315789,0.000860099271961667 +"1921",0.2,38.6842105263158,13.4210526315789,0.0034225433183194 +"1922",0.260352117694686,38.6842105263158,13.4210526315789,0.00342252126124642 +"1923",0.338916125940539,38.6842105263158,13.4210526315789,0.00342238635752564 +"1924",0.441187655547492,38.6842105263158,13.4210526315789,0.00342156258077769 +"1925",0.574320702112717,38.6842105263158,13.4210526315789,0.00341658048253817 +"1926",0.747628055154725,38.6842105263158,13.4210526315789,0.00338807976970108 +"1927",0.973232737037462,38.6842105263158,13.4210526315789,0.00326188020700499 +"1928",1.2669160204875,38.6842105263158,13.4210526315789,0.00296476859064502 +"1929",1.64922134437622,38.6842105263158,13.4210526315789,0.00259729595519517 +"1930",2.14689134777813,38.6842105263158,13.4210526315789,0.00225345386709 +"1931",2.79473854427218,38.6842105263158,13.4210526315789,0.00195170471027104 +"1932",3.63808049202114,38.6842105263158,13.4210526315789,0.00168986796489566 +"1933",4.73590980220715,38.6842105263158,13.4210526315789,0.00146308868766091 +"1934",6.16502073107827,38.6842105263158,13.4210526315789,0.00126673314142206 +"1935",8.02538101483936,38.6842105263158,13.4210526315789,0.0010967283203055 +"1936",10.4471247126008,38.6842105263158,13.4210526315789,0.000949539186843968 +"1937",13.5996552137305,38.6842105263158,13.4210526315789,0.000822103906540781 +"1938",17.7034951740616,38.6842105263158,13.4210526315789,0.000711771392627217 +"1939",23.045712295823,38.6842105263158,13.4210526315789,0.000616246329532268 +"1940",30,38.6842105263158,13.4210526315789,0.000533541446788955 +"1941",0.2,40.7894736842105,13.4210526315789,0.0021337968636229 +"1942",0.260352117694686,40.7894736842105,13.4210526315789,0.00213378311206192 +"1943",0.338916125940539,40.7894736842105,13.4210526315789,0.00213369900585507 +"1944",0.441187655547492,40.7894736842105,13.4210526315789,0.00213318541929747 +"1945",0.574320702112717,40.7894736842105,13.4210526315789,0.00213007931234453 +"1946",0.747628055154725,40.7894736842105,13.4210526315789,0.00211231044106764 +"1947",0.973232737037462,40.7894736842105,13.4210526315789,0.00203363087268055 +"1948",1.2669160204875,40.7894736842105,13.4210526315789,0.00184839557361467 +"1949",1.64922134437622,40.7894736842105,13.4210526315789,0.00161929344573417 +"1950",2.14689134777813,40.7894736842105,13.4210526315789,0.00140492386704886 +"1951",2.79473854427218,40.7894736842105,13.4210526315789,0.00121679727680973 +"1952",3.63808049202114,40.7894736842105,13.4210526315789,0.00105355422212794 +"1953",4.73590980220715,40.7894736842105,13.4210526315789,0.000912167871250195 +"1954",6.16502073107827,40.7894736842105,13.4210526315789,0.000789749304193128 +"1955",8.02538101483936,40.7894736842105,13.4210526315789,0.000683759190888314 +"1956",10.4471247126008,40.7894736842105,13.4210526315789,0.000591993599592949 +"1957",13.5996552137305,40.7894736842105,13.4210526315789,0.000512543618647385 +"1958",17.7034951740616,40.7894736842105,13.4210526315789,0.000443756418530953 +"1959",23.045712295823,40.7894736842105,13.4210526315789,0.000384200976547688 +"1960",30,40.7894736842105,13.4210526315789,0.000332638321822652 +"1961",0.2,42.8947368421053,13.4210526315789,0.00133783937098357 +"1962",0.260352117694686,42.8947368421053,13.4210526315789,0.00133783074908521 +"1963",0.338916125940539,42.8947368421053,13.4210526315789,0.00133777801651408 +"1964",0.441187655547492,42.8947368421053,13.4210526315789,0.00133745601008091 +"1965",0.574320702112717,42.8947368421053,13.4210526315789,0.00133550855564279 +"1966",0.747628055154725,42.8947368421053,13.4210526315789,0.00132436790023297 +"1967",0.973232737037462,42.8947368421053,13.4210526315789,0.00127503770105856 +"1968",1.2669160204875,42.8947368421053,13.4210526315789,0.00115889961865202 +"1969",1.64922134437622,42.8947368421053,13.4210526315789,0.00101525808843896 +"1970",2.14689134777813,42.8947368421053,13.4210526315789,0.000880853512635317 +"1971",2.79473854427218,42.8947368421053,13.4210526315789,0.000762902660123762 +"1972",3.63808049202114,42.8947368421053,13.4210526315789,0.000660553186602596 +"1973",4.73590980220715,42.8947368421053,13.4210526315789,0.000571907341279348 +"1974",6.16502073107827,42.8947368421053,13.4210526315789,0.000495153840728097 +"1975",8.02538101483936,42.8947368421053,13.4210526315789,0.000428700586001012 +"1976",10.4471247126008,42.8947368421053,13.4210526315789,0.000371165764842786 +"1977",13.5996552137305,42.8947368421053,13.4210526315789,0.000321352535502668 +"1978",17.7034951740616,42.8947368421053,13.4210526315789,0.00027822461357891 +"1979",23.045712295823,42.8947368421053,13.4210526315789,0.000240884782220146 +"1980",30,42.8947368421053,13.4210526315789,0.000208556236452925 +"1981",0.2,45,13.4210526315789,0.000843730768444278 +"1982",0.260352117694686,45,13.4210526315789,0.000843725330899915 +"1983",0.338916125940539,45,13.4210526315789,0.00084369207422223 +"1984",0.441187655547492,45,13.4210526315789,0.000843488995481092 +"1985",0.574320702112717,45,13.4210526315789,0.000842260800777581 +"1986",0.747628055154725,45,13.4210526315789,0.0008352347601678 +"1987",0.973232737037462,45,13.4210526315789,0.000804123845240596 +"1988",1.2669160204875,45,13.4210526315789,0.000730879421702309 +"1989",1.64922134437622,45,13.4210526315789,0.000640289488937749 +"1990",2.14689134777813,45,13.4210526315789,0.000555524995916543 +"1991",2.79473854427218,45,13.4210526315789,0.00048113731860139 +"1992",3.63808049202114,45,13.4210526315789,0.000416588911806939 +"1993",4.73590980220715,45,13.4210526315789,0.000360682927264872 +"1994",6.16502073107827,45,13.4210526315789,0.000312277048797351 +"1995",8.02538101483936,45,13.4210526315789,0.000270367192582485 +"1996",10.4471247126008,45,13.4210526315789,0.000234081895617092 +"1997",13.5996552137305,45,13.4210526315789,0.000202666349639454 +"1998",17.7034951740616,45,13.4210526315789,0.000175467004564578 +"1999",23.045712295823,45,13.4210526315789,0.000151918015583376 +"2000",30,45,13.4210526315789,0.000131529477650897 +"2001",0.2,5,15.5263157894737,0.0316615838339548 +"2002",0.260352117694686,5,15.5263157894737,0.0316613797863212 +"2003",0.338916125940539,5,15.5263157894737,0.0316601318063637 +"2004",0.441187655547492,5,15.5263157894737,0.0316525111353773 +"2005",0.574320702112717,5,15.5263157894737,0.0316064222750156 +"2006",0.747628055154725,5,15.5263157894737,0.0313427652150775 +"2007",0.973232737037462,5,15.5263157894737,0.0301753064972511 +"2008",1.2669160204875,5,15.5263157894737,0.0274267585682676 +"2009",1.64922134437622,5,15.5263157894737,0.024027308343137 +"2010",2.14689134777813,5,15.5263157894737,0.0208464617955089 +"2011",2.79473854427218,5,15.5263157894737,0.0180550124735059 +"2012",3.63808049202114,5,15.5263157894737,0.0156327886202274 +"2013",4.73590980220715,5,15.5263157894737,0.0135348776720914 +"2014",6.16502073107827,5,15.5263157894737,0.0117184134201339 +"2015",8.02538101483936,5,15.5263157894737,0.0101457169206775 +"2016",10.4471247126008,5,15.5263157894737,0.00878408591849413 +"2017",13.5996552137305,5,15.5263157894737,0.0076051957086533 +"2018",17.7034951740616,5,15.5263157894737,0.0065845213697232 +"2019",23.045712295823,5,15.5263157894737,0.00570082918174245 +"2020",30,5,15.5263157894737,0.00493573511720899 +"2021",0.2,7.10526315789474,15.5263157894737,0.0405372676602684 +"2022",0.260352117694686,7.10526315789474,15.5263157894737,0.040537006412013 +"2023",0.338916125940539,7.10526315789474,15.5263157894737,0.0405354085861481 +"2024",0.441187655547492,7.10526315789474,15.5263157894737,0.0405256516143823 +"2025",0.574320702112717,7.10526315789474,15.5263157894737,0.040466642675397 +"2026",0.747628055154725,7.10526315789474,15.5263157894737,0.0401290746982142 +"2027",0.973232737037462,7.10526315789474,15.5263157894737,0.0386343425718924 +"2028",1.2669160204875,7.10526315789474,15.5263157894737,0.0351152948938419 +"2029",1.64922134437622,7.10526315789474,15.5263157894737,0.0307628776428107 +"2030",2.14689134777813,7.10526315789474,15.5263157894737,0.0266903451831692 +"2031",2.79473854427218,7.10526315789474,15.5263157894737,0.0231163695753931 +"2032",3.63808049202114,7.10526315789474,15.5263157894737,0.0200151243190476 +"2033",4.73590980220715,7.10526315789474,15.5263157894737,0.0173291065229071 +"2034",6.16502073107827,7.10526315789474,15.5263157894737,0.0150034333044391 +"2035",8.02538101483936,7.10526315789474,15.5263157894737,0.0129898631911696 +"2036",10.4471247126008,7.10526315789474,15.5263157894737,0.0112465265128941 +"2037",13.5996552137305,7.10526315789474,15.5263157894737,0.00973715830727899 +"2038",17.7034951740616,7.10526315789474,15.5263157894737,0.00843035858784091 +"2039",23.045712295823,7.10526315789474,15.5263157894737,0.00729894119124666 +"2040",30,7.10526315789474,15.5263157894737,0.00631936850019214 +"2041",0.2,9.21052631578947,15.5263157894737,0.0514910310663412 +"2042",0.260352117694686,9.21052631578947,15.5263157894737,0.0514906992249811 +"2043",0.338916125940539,9.21052631578947,15.5263157894737,0.0514886696431667 +"2044",0.441187655547492,9.21052631578947,15.5263157894737,0.0514762761947352 +"2045",0.574320702112717,9.21052631578947,15.5263157894737,0.0514013221762269 +"2046",0.747628055154725,9.21052631578947,15.5263157894737,0.0509725383877932 +"2047",0.973232737037462,9.21052631578947,15.5263157894737,0.0490739077499978 +"2048",1.2669160204875,9.21052631578947,15.5263157894737,0.0446039618514973 +"2049",1.64922134437622,9.21052631578947,15.5263157894737,0.0390754577163707 +"2050",2.14689134777813,9.21052631578947,15.5263157894737,0.0339024673422905 +"2051",2.79473854427218,9.21052631578947,15.5263157894737,0.0293627511830113 +"2052",3.63808049202114,9.21052631578947,15.5263157894737,0.0254235040394417 +"2053",4.73590980220715,9.21052631578947,15.5263157894737,0.0220116848969944 +"2054",6.16502073107827,9.21052631578947,15.5263157894737,0.019057580714495 +"2055",8.02538101483936,9.21052631578947,15.5263157894737,0.0164999144670918 +"2056",10.4471247126008,9.21052631578947,15.5263157894737,0.0142855026864932 +"2057",13.5996552137305,9.21052631578947,15.5263157894737,0.0123682810864284 +"2058",17.7034951740616,9.21052631578947,15.5263157894737,0.010708364944201 +"2059",23.045712295823,9.21052631578947,15.5263157894737,0.00927122199699315 +"2060",30,9.21052631578947,15.5263157894737,0.00802695441858741 +"2061",0.2,11.3157894736842,15.5263157894737,0.0646230734042617 +"2062",0.260352117694686,11.3157894736842,15.5263157894737,0.0646226569315648 +"2063",0.338916125940539,11.3157894736842,15.5263157894737,0.0646201097342791 +"2064",0.441187655547492,11.3157894736842,15.5263157894737,0.0646045555161728 +"2065",0.574320702112717,11.3157894736842,15.5263157894737,0.0645104855599164 +"2066",0.747628055154725,11.3157894736842,15.5263157894737,0.0639723466712465 +"2067",0.973232737037462,11.3157894736842,15.5263157894737,0.0615894977646914 +"2068",1.2669160204875,11.3157894736842,15.5263157894737,0.0559795568501327 +"2069",1.64922134437622,11.3157894736842,15.5263157894737,0.0490410877392745 +"2070",2.14689134777813,11.3157894736842,15.5263157894737,0.0425488010295168 +"2071",2.79473854427218,11.3157894736842,15.5263157894737,0.0368512959588254 +"2072",3.63808049202114,11.3157894736842,15.5263157894737,0.03190740083681 +"2073",4.73590980220715,11.3157894736842,15.5263157894737,0.027625446595102 +"2074",6.16502073107827,11.3157894736842,15.5263157894737,0.0239179408902049 +"2075",8.02538101483936,11.3157894736842,15.5263157894737,0.0207079788788288 +"2076",10.4471247126008,11.3157894736842,15.5263157894737,0.0179288134187216 +"2077",13.5996552137305,11.3157894736842,15.5263157894737,0.0155226321940032 +"2078",17.7034951740616,11.3157894736842,15.5263157894737,0.0134393784606322 +"2079",23.045712295823,11.3157894736842,15.5263157894737,0.0116357130018812 +"2080",30,11.3157894736842,15.5263157894737,0.0100741129836128 +"2081",0.2,13.4210526315789,15.5263157894737,0.0795195333359126 +"2082",0.260352117694686,13.4210526315789,15.5263157894737,0.0795190208608359 +"2083",0.338916125940539,13.4210526315789,15.5263157894737,0.0795158865014066 +"2084",0.441187655547492,13.4210526315789,15.5263157894737,0.0794967468334821 +"2085",0.574320702112717,13.4210526315789,15.5263157894737,0.0793809925273437 +"2086",0.747628055154725,13.4210526315789,15.5263157894737,0.0787188056172715 +"2087",0.973232737037462,13.4210526315789,15.5263157894737,0.0757866790086544 +"2088",1.2669160204875,13.4210526315789,15.5263157894737,0.0688835736614808 +"2089",1.64922134437622,13.4210526315789,15.5263157894737,0.0603456970688658 +"2090",2.14689134777813,13.4210526315789,15.5263157894737,0.0523568537309253 +"2091",2.79473854427218,13.4210526315789,15.5263157894737,0.045345999549383 +"2092",3.63808049202114,13.4210526315789,15.5263157894737,0.0392624722230824 +"2093",4.73590980220715,13.4210526315789,15.5263157894737,0.0339934717696948 +"2094",6.16502073107827,13.4210526315789,15.5263157894737,0.0294313377212358 +"2095",8.02538101483936,13.4210526315789,15.5263157894737,0.0254814376665937 +"2096",10.4471247126008,13.4210526315789,15.5263157894737,0.022061638378056 +"2097",13.5996552137305,13.4210526315789,15.5263157894737,0.019100801048109 +"2098",17.7034951740616,13.4210526315789,15.5263157894737,0.0165373302013783 +"2099",23.045712295823,13.4210526315789,15.5263157894737,0.0143178963673242 +"2100",30,13.4210526315789,15.5263157894737,0.0123963272099237 +"2101",0.2,15.5263157894737,15.5263157894737,0.0946495841111515 +"2102",0.260352117694686,15.5263157894737,15.5263157894737,0.0946489741282851 +"2103",0.338916125940539,15.5263157894737,15.5263157894737,0.0946452433994442 +"2104",0.441187655547492,15.5263157894737,15.5263157894737,0.094622462058394 +"2105",0.574320702112717,15.5263157894737,15.5263157894737,0.0944846833708759 +"2106",0.747628055154725,15.5263157894737,15.5263157894737,0.0936965032469129 +"2107",0.973232737037462,15.5263157894737,15.5263157894737,0.0902064857326687 +"2108",1.2669160204875,15.5263157894737,15.5263157894737,0.0819899378886893 +"2109",1.64922134437622,15.5263157894737,15.5263157894737,0.0718275735640688 +"2110",2.14689134777813,15.5263157894737,15.5263157894737,0.0623187061481716 +"2111",2.79473854427218,15.5263157894737,15.5263157894737,0.0539739082763861 +"2112",3.63808049202114,15.5263157894737,15.5263157894737,0.0467328782148686 +"2113",4.73590980220715,15.5263157894737,15.5263157894737,0.0404613537142416 +"2114",6.16502073107827,15.5263157894737,15.5263157894737,0.0350311899264096 +"2115",8.02538101483936,15.5263157894737,15.5263157894737,0.0303297488870964 +"2116",10.4471247126008,15.5263157894737,15.5263157894737,0.0262592700144856 +"2117",13.5996552137305,15.5263157894737,15.5263157894737,0.0227350790372017 +"2118",17.7034951740616,15.5263157894737,15.5263157894737,0.019683860810113 +"2119",23.045712295823,15.5263157894737,15.5263157894737,0.0170421389520627 +"2120",30,15.5263157894737,15.5263157894737,0.0147549559926195 +"2121",0.2,17.6315789473684,15.5263157894737,0.106708402843287 +"2122",0.260352117694686,17.6315789473684,15.5263157894737,0.106707715145628 +"2123",0.338916125940539,17.6315789473684,15.5263157894737,0.106703509103734 +"2124",0.441187655547492,17.6315789473684,15.5263157894737,0.106677825308702 +"2125",0.574320702112717,17.6315789473684,15.5263157894737,0.106522492944287 +"2126",0.747628055154725,17.6315789473684,15.5263157894737,0.105633894827658 +"2127",0.973232737037462,17.6315789473684,15.5263157894737,0.101699232057215 +"2128",1.2669160204875,17.6315789473684,15.5263157894737,0.0924358559362286 +"2129",1.64922134437622,17.6315789473684,15.5263157894737,0.0809787568229522 +"2130",2.14689134777813,17.6315789473684,15.5263157894737,0.0702584133124367 +"2131",2.79473854427218,17.6315789473684,15.5263157894737,0.0608504474844772 +"2132",3.63808049202114,17.6315789473684,15.5263157894737,0.0526868748701764 +"2133",4.73590980220715,17.6315789473684,15.5263157894737,0.0456163275546325 +"2134",6.16502073107827,17.6315789473684,15.5263157894737,0.0394943344109908 +"2135",8.02538101483936,17.6315789473684,15.5263157894737,0.0341939068488597 +"2136",10.4471247126008,17.6315789473684,15.5263157894737,0.029604829111407 +"2137",13.5996552137305,17.6315789473684,15.5263157894737,0.0256316390120288 +"2138",17.7034951740616,17.6315789473684,15.5263157894737,0.0221916806984602 +"2139",23.045712295823,17.6315789473684,15.5263157894737,0.0192133905889368 +"2140",30,17.6315789473684,15.5263157894737,0.0166348093632026 +"2141",0.2,19.7368421052632,15.5263157894737,0.110978961161913 +"2142",0.260352117694686,19.7368421052632,15.5263157894737,0.110978245942027 +"2143",0.338916125940539,19.7368421052632,15.5263157894737,0.110973871570865 +"2144",0.441187655547492,19.7368421052632,15.5263157894737,0.110947159889167 +"2145",0.574320702112717,19.7368421052632,15.5263157894737,0.110785610995376 +"2146",0.747628055154725,19.7368421052632,15.5263157894737,0.109861450449005 +"2147",0.973232737037462,19.7368421052632,15.5263157894737,0.105769319228303 +"2148",1.2669160204875,19.7368421052632,15.5263157894737,0.0961352151524614 +"2149",1.64922134437622,19.7368421052632,15.5263157894737,0.0842195934803066 +"2150",2.14689134777813,19.7368421052632,15.5263157894737,0.0730702129779752 +"2151",2.79473854427218,19.7368421052632,15.5263157894737,0.0632857325957969 +"2152",3.63808049202114,19.7368421052632,15.5263157894737,0.0547954470703404 +"2153",4.73590980220715,19.7368421052632,15.5263157894737,0.0474419306178674 +"2154",6.16502073107827,19.7368421052632,15.5263157894737,0.0410749302578348 +"2155",8.02538101483936,19.7368421052632,15.5263157894737,0.035562375211695 +"2156",10.4471247126008,19.7368421052632,15.5263157894737,0.0307896387970969 +"2157",13.5996552137305,19.7368421052632,15.5263157894737,0.0266574383519701 +"2158",17.7034951740616,19.7368421052632,15.5263157894737,0.0230798100686494 +"2159",23.045712295823,19.7368421052632,15.5263157894737,0.0199823263317864 +"2160",30,19.7368421052632,15.5263157894737,0.0173005481580107 +"2161",0.2,21.8421052631579,15.5263157894737,0.104127180038011 +"2162",0.260352117694686,21.8421052631579,15.5263157894737,0.104126508975414 +"2163",0.338916125940539,21.8421052631579,15.5263157894737,0.104122404675566 +"2164",0.441187655547492,21.8421052631579,15.5263157894737,0.104097342158669 +"2165",0.574320702112717,21.8421052631579,15.5263157894737,0.10394576720633 +"2166",0.747628055154725,21.8421052631579,15.5263157894737,0.103078663832966 +"2167",0.973232737037462,21.8421052631579,15.5263157894737,0.0992391785837252 +"2168",1.2669160204875,21.8421052631579,15.5263157894737,0.0901998788902765 +"2169",1.64922134437622,21.8421052631579,15.5263157894737,0.0790199212646946 +"2170",2.14689134777813,21.8421052631579,15.5263157894737,0.0685588974929477 +"2171",2.79473854427218,21.8421052631579,15.5263157894737,0.0593785056450997 +"2172",3.63808049202114,21.8421052631579,15.5263157894737,0.0514124057624966 +"2173",4.73590980220715,21.8421052631579,15.5263157894737,0.0445128914442647 +"2174",6.16502073107827,21.8421052631579,15.5263157894737,0.0385389862477298 +"2175",8.02538101483936,21.8421052631579,15.5263157894737,0.0333667733728823 +"2176",10.4471247126008,21.8421052631579,15.5263157894737,0.0288887031268311 +"2177",13.5996552137305,21.8421052631579,15.5263157894737,0.025011622505441 +"2178",17.7034951740616,21.8421052631579,15.5263157894737,0.021654875060104 +"2179",23.045712295823,21.8421052631579,15.5263157894737,0.0187486282962458 +"2180",30,21.8421052631579,15.5263157894737,0.0162324216585269 +"2181",0.2,23.9473684210526,15.5263157894737,0.0877120925204013 +"2182",0.260352117694686,23.9473684210526,15.5263157894737,0.0877115272471978 +"2183",0.338916125940539,23.9473684210526,15.5263157894737,0.0877080699680525 +"2184",0.441187655547492,23.9473684210526,15.5263157894737,0.0876869584215761 +"2185",0.574320702112717,23.9473684210526,15.5263157894737,0.087559278441781 +"2186",0.747628055154725,23.9473684210526,15.5263157894737,0.0868288692317986 +"2187",0.973232737037462,23.9473684210526,15.5263157894737,0.0835946580941383 +"2188",1.2669160204875,23.9473684210526,15.5263157894737,0.0759803551739788 +"2189",1.64922134437622,23.9473684210526,15.5263157894737,0.06656285748249 +"2190",2.14689134777813,23.9473684210526,15.5263157894737,0.05775095760591 +"2191",2.79473854427218,23.9473684210526,15.5263157894737,0.0500178049474203 +"2192",3.63808049202114,23.9473684210526,15.5263157894737,0.043307517684531 +"2193",4.73590980220715,23.9473684210526,15.5263157894737,0.0374956745326692 +"2194",6.16502073107827,23.9473684210526,15.5263157894737,0.0324635232239015 +"2195",8.02538101483936,23.9473684210526,15.5263157894737,0.0281066817724359 +"2196",10.4471247126008,23.9473684210526,15.5263157894737,0.0243345551135643 +"2197",13.5996552137305,23.9473684210526,15.5263157894737,0.0210686753111123 +"2198",17.7034951740616,23.9473684210526,15.5263157894737,0.0182411009699504 +"2199",23.045712295823,23.9473684210526,15.5263157894737,0.0157930083110924 +"2200",30,23.9473684210526,15.5263157894737,0.0136734680591862 +"2201",0.2,26.0526315789474,15.5263157894737,0.0674340448162541 +"2202",0.260352117694686,26.0526315789474,15.5263157894737,0.0674336102278474 +"2203",0.338916125940539,26.0526315789474,15.5263157894737,0.0674309522326938 +"2204",0.441187655547492,26.0526315789474,15.5263157894737,0.0674147214379388 +"2205",0.574320702112717,26.0526315789474,15.5263157894737,0.0673165596311431 +"2206",0.747628055154725,26.0526315789474,15.5263157894737,0.0667550128023669 +"2207",0.973232737037462,26.0526315789474,15.5263157894737,0.064268514845982 +"2208",1.2669160204875,26.0526315789474,15.5263157894737,0.0584145529849862 +"2209",1.64922134437622,26.0526315789474,15.5263157894737,0.0511742746706008 +"2210",2.14689134777813,26.0526315789474,15.5263157894737,0.0443995867784447 +"2211",2.79473854427218,26.0526315789474,15.5263157894737,0.0384542518997649 +"2212",3.63808049202114,26.0526315789474,15.5263157894737,0.0332953074599163 +"2213",4.73590980220715,26.0526315789474,15.5263157894737,0.0288270969736993 +"2214",6.16502073107827,26.0526315789474,15.5263157894737,0.0249583223597692 +"2215",8.02538101483936,26.0526315789474,15.5263157894737,0.0216087335715744 +"2216",10.4471247126008,26.0526315789474,15.5263157894737,0.0187086801028036 +"2217",13.5996552137305,26.0526315789474,15.5263157894737,0.0161978349201759 +"2218",17.7034951740616,26.0526315789474,15.5263157894737,0.0140239639137482 +"2219",23.045712295823,26.0526315789474,15.5263157894737,0.0121418426995795 +"2220",30,26.0526315789474,15.5263157894737,0.0105123162770552 +"2221",0.2,28.1578947368421,15.5263157894737,0.0486368841609512 +"2222",0.260352117694686,28.1578947368421,15.5263157894737,0.0486365707135516 +"2223",0.338916125940539,28.1578947368421,15.5263157894737,0.0486346536314199 +"2224",0.441187655547492,28.1578947368421,15.5263157894737,0.048622947151607 +"2225",0.574320702112717,28.1578947368421,15.5263157894737,0.0485521478329667 +"2226",0.747628055154725,28.1578947368421,15.5263157894737,0.048147131522043 +"2227",0.973232737037462,28.1578947368421,15.5263157894737,0.046353741945596 +"2228",1.2669160204875,28.1578947368421,15.5263157894737,0.0421315650660734 +"2229",1.64922134437622,28.1578947368421,15.5263157894737,0.0369095058135202 +"2230",2.14689134777813,28.1578947368421,15.5263157894737,0.0320232542007743 +"2231",2.79473854427218,28.1578947368421,15.5263157894737,0.0277351744247453 +"2232",3.63808049202114,28.1578947368421,15.5263157894737,0.0240142796779242 +"2233",4.73590980220715,28.1578947368421,15.5263157894737,0.0207915776078194 +"2234",6.16502073107827,28.1578947368421,15.5263157894737,0.0180012193658474 +"2235",8.02538101483936,28.1578947368421,15.5263157894737,0.0155853245115173 +"2236",10.4471247126008,28.1578947368421,15.5263157894737,0.0134936575352073 +"2237",13.5996552137305,28.1578947368421,15.5263157894737,0.0116827074931877 +"2238",17.7034951740616,28.1578947368421,15.5263157894737,0.0101148004722078 +"2239",23.045712295823,28.1578947368421,15.5263157894737,0.00875731833214308 +"2240",30,28.1578947368421,15.5263157894737,0.0075820204827336 +"2241",0.2,30.2631578947368,15.5263157894737,0.0337681539683947 +"2242",0.260352117694686,30.2631578947368,15.5263157894737,0.0337679363446667 +"2243",0.338916125940539,30.2631578947368,15.5263157894737,0.0337666053316771 +"2244",0.441187655547492,30.2631578947368,15.5263157894737,0.0337584776273727 +"2245",0.574320702112717,30.2631578947368,15.5263157894737,0.0337093222932276 +"2246",0.747628055154725,30.2631578947368,15.5263157894737,0.0334281230884899 +"2247",0.973232737037462,30.2631578947368,15.5263157894737,0.0321829887344394 +"2248",1.2669160204875,30.2631578947368,15.5263157894737,0.0292515690637692 +"2249",1.64922134437622,30.2631578947368,15.5263157894737,0.0256259399982076 +"2250",2.14689134777813,30.2631578947368,15.5263157894737,0.0222334591755979 +"2251",2.79473854427218,30.2631578947368,15.5263157894737,0.0192562837129073 +"2252",3.63808049202114,30.2631578947368,15.5263157894737,0.016672899746635 +"2253",4.73590980220715,30.2631578947368,15.5263157894737,0.0144354065030827 +"2254",6.16502073107827,30.2631578947368,15.5263157894737,0.0124980857152198 +"2255",8.02538101483936,30.2631578947368,15.5263157894737,0.0108207515105347 +"2256",10.4471247126008,30.2631578947368,15.5263157894737,0.00936852582368957 +"2257",13.5996552137305,30.2631578947368,15.5263157894737,0.00811119939534312 +"2258",17.7034951740616,30.2631578947368,15.5263157894737,0.00702261556424561 +"2259",23.045712295823,30.2631578947368,15.5263157894737,0.0060801278472414 +"2260",30,30.2631578947368,15.5263157894737,0.00526412905492061 +"2261",0.2,32.3684210526316,15.5263157894737,0.0229867728695842 +"2262",0.260352117694686,32.3684210526316,15.5263157894737,0.0229866247280182 +"2263",0.338916125940539,32.3684210526316,15.5263157894737,0.0229857186763191 +"2264",0.441187655547492,32.3684210526316,15.5263157894737,0.0229801859577414 +"2265",0.574320702112717,32.3684210526316,15.5263157894737,0.0229467247711341 +"2266",0.747628055154725,32.3684210526316,15.5263157894737,0.0227553058900053 +"2267",0.973232737037462,32.3684210526316,15.5263157894737,0.0219077137884216 +"2268",1.2669160204875,32.3684210526316,15.5263157894737,0.0199122277983318 +"2269",1.64922134437622,32.3684210526316,15.5263157894737,0.0174441772227087 +"2270",2.14689134777813,32.3684210526316,15.5263157894737,0.0151348361137236 +"2271",2.79473854427218,32.3684210526316,15.5263157894737,0.0131082030849291 +"2272",3.63808049202114,32.3684210526316,15.5263157894737,0.0113496331458318 +"2273",4.73590980220715,32.3684210526316,15.5263157894737,0.00982651911848809 +"2274",6.16502073107827,32.3684210526316,15.5263157894737,0.00850773950833206 +"2275",8.02538101483936,32.3684210526316,15.5263157894737,0.00736593885125235 +"2276",10.4471247126008,32.3684210526316,15.5263157894737,0.00637737483172887 +"2277",13.5996552137305,32.3684210526316,15.5263157894737,0.00552148329977317 +"2278",17.7034951740616,32.3684210526316,15.5263157894737,0.00478045880378324 +"2279",23.045712295823,32.3684210526316,15.5263157894737,0.00413888535255384 +"2280",30,32.3684210526316,15.5263157894737,0.00358341587327793 +"2281",0.2,34.4736842105263,15.5263157894737,0.0155157062020491 +"2282",0.260352117694686,34.4736842105263,15.5263157894737,0.0155156062088475 +"2283",0.338916125940539,34.4736842105263,15.5263157894737,0.0155149946383566 +"2284",0.441187655547492,34.4736842105263,15.5263157894737,0.0155112601412857 +"2285",0.574320702112717,34.4736842105263,15.5263157894737,0.0154886743723517 +"2286",0.747628055154725,34.4736842105263,15.5263157894737,0.0153594696711103 +"2287",0.973232737037462,34.4736842105263,15.5263157894737,0.0147873584790799 +"2288",1.2669160204875,34.4736842105263,15.5263157894737,0.0134404371635826 +"2289",1.64922134437622,34.4736842105263,15.5263157894737,0.0117745422665291 +"2290",2.14689134777813,34.4736842105263,15.5263157894737,0.0102157737360088 +"2291",2.79473854427218,34.4736842105263,15.5263157894737,0.00884782866461728 +"2292",3.63808049202114,34.4736842105263,15.5263157894737,0.00766082191662384 +"2293",4.73590980220715,34.4736842105263,15.5263157894737,0.00663274416536389 +"2294",6.16502073107827,34.4736842105263,15.5263157894737,0.00574258889683081 +"2295",8.02538101483936,34.4736842105263,15.5263157894737,0.0049718916076956 +"2296",10.4471247126008,34.4736842105263,15.5263157894737,0.00430462661248009 +"2297",13.5996552137305,34.4736842105263,15.5263157894737,0.0037269134369078 +"2298",17.7034951740616,34.4736842105263,15.5263157894737,0.00322673368425036 +"2299",23.045712295823,34.4736842105263,15.5263157894737,0.00279368180555531 +"2300",30,34.4736842105263,15.5263157894737,0.00241874873889356 +"2301",0.2,36.5789473684211,15.5263157894737,0.0104509452069421 +"2302",0.260352117694686,36.5789473684211,15.5263157894737,0.0104508778543216 +"2303",0.338916125940539,36.5789473684211,15.5263157894737,0.0104504659175649 +"2304",0.441187655547492,36.5789473684211,15.5263157894737,0.0104479504649162 +"2305",0.574320702112717,36.5789473684211,15.5263157894737,0.010432737323438 +"2306",0.747628055154725,36.5789473684211,15.5263157894737,0.010345708654838 +"2307",0.973232737037462,36.5789473684211,15.5263157894737,0.00996035057687959 +"2308",1.2669160204875,36.5789473684211,15.5263157894737,0.00905310209698342 +"2309",1.64922134437622,36.5789473684211,15.5263157894737,0.00793100194485947 +"2310",2.14689134777813,36.5789473684211,15.5263157894737,0.00688105911334194 +"2311",2.79473854427218,36.5789473684211,15.5263157894737,0.00595964962020967 +"2312",3.63808049202114,36.5789473684211,15.5263157894737,0.00516011511485073 +"2313",4.73590980220715,36.5789473684211,15.5263157894737,0.00446763073115732 +"2314",6.16502073107827,36.5789473684211,15.5263157894737,0.003868047069546 +"2315",8.02538101483936,36.5789473684211,15.5263157894737,0.00334892695764113 +"2316",10.4471247126008,36.5789473684211,15.5263157894737,0.00289947594247645 +"2317",13.5996552137305,36.5789473684211,15.5263157894737,0.00251034452527824 +"2318",17.7034951740616,36.5789473684211,15.5263157894737,0.00217343745056485 +"2319",23.045712295823,36.5789473684211,15.5263157894737,0.00188174583195147 +"2320",30,36.5789473684211,15.5263157894737,0.00162920141760602 +"2321",0.2,38.6842105263158,15.5263157894737,0.00704897149791719 +"2322",0.260352117694686,38.6842105263158,15.5263157894737,0.00704892606980591 +"2323",0.338916125940539,38.6842105263158,15.5263157894737,0.00704864822599378 +"2324",0.441187655547492,38.6842105263158,15.5263157894737,0.00704695159916487 +"2325",0.574320702112717,38.6842105263158,15.5263157894737,0.00703669061333535 +"2326",0.747628055154725,38.6842105263158,15.5263157894737,0.00697799136725608 +"2327",0.973232737037462,38.6842105263158,15.5263157894737,0.00671807438805152 +"2328",1.2669160204875,38.6842105263158,15.5263157894737,0.00610615187294076 +"2329",1.64922134437622,38.6842105263158,15.5263157894737,0.00534931583241915 +"2330",2.14689134777813,38.6842105263158,15.5263157894737,0.00464114858560463 +"2331",2.79473854427218,38.6842105263158,15.5263157894737,0.00401967472593064 +"2332",3.63808049202114,38.6842105263158,15.5263157894737,0.00348040331762464 +"2333",4.73590980220715,38.6842105263158,15.5263157894737,0.00301333525949673 +"2334",6.16502073107827,38.6842105263158,15.5263157894737,0.00260892704018011 +"2335",8.02538101483936,38.6842105263158,15.5263157894737,0.00225879001425997 +"2336",10.4471247126008,38.6842105263158,15.5263157894737,0.0019556435205341 +"2337",13.5996552137305,38.6842105263158,15.5263157894737,0.00169318149298923 +"2338",17.7034951740616,38.6842105263158,15.5263157894737,0.00146594382978496 +"2339",23.045712295823,38.6842105263158,15.5263157894737,0.00126920316517778 +"2340",30,38.6842105263158,15.5263157894737,0.00109886657423509 +"2341",0.2,40.7894736842105,15.5263157894737,0.00476943338010024 +"2342",0.260352117694686,40.7894736842105,15.5263157894737,0.00476940264280042 +"2343",0.338916125940539,40.7894736842105,15.5263157894737,0.0047692146497645 +"2344",0.441187655547492,40.7894736842105,15.5263157894737,0.00476806668815992 +"2345",0.574320702112717,40.7894736842105,15.5263157894737,0.00476112396065102 +"2346",0.747628055154725,40.7894736842105,15.5263157894737,0.00472140722414274 +"2347",0.973232737037462,40.7894736842105,15.5263157894737,0.00454554373582542 +"2348",1.2669160204875,40.7894736842105,15.5263157894737,0.00413150834492243 +"2349",1.64922134437622,40.7894736842105,15.5263157894737,0.00361942242203379 +"2350",2.14689134777813,40.7894736842105,15.5263157894737,0.00314026649032818 +"2351",2.79473854427218,40.7894736842105,15.5263157894737,0.00271976852519032 +"2352",3.63808049202114,40.7894736842105,15.5263157894737,0.00235488989623456 +"2353",4.73590980220715,40.7894736842105,15.5263157894737,0.00203886507078704 +"2354",6.16502073107827,40.7894736842105,15.5263157894737,0.0017652367746639 +"2355",8.02538101483936,40.7894736842105,15.5263157894737,0.00152832913224742 +"2356",10.4471247126008,40.7894736842105,15.5263157894737,0.00132321594564087 +"2357",13.5996552137305,40.7894736842105,15.5263157894737,0.00114563044177678 +"2358",17.7034951740616,40.7894736842105,15.5263157894737,0.000991878238859993 +"2359",23.045712295823,40.7894736842105,15.5263157894737,0.000858760734657022 +"2360",30,40.7894736842105,15.5263157894737,0.000743508598521335 +"2361",0.2,42.8947368421053,15.5263157894737,0.00324024858026102 +"2362",0.260352117694686,42.8947368421053,15.5263157894737,0.00324022769801272 +"2363",0.338916125940539,42.8947368421053,15.5263157894737,0.00324009997966146 +"2364",0.441187655547492,42.8947368421053,15.5263157894737,0.0032393200796895 +"2365",0.574320702112717,42.8947368421053,15.5263157894737,0.00323460334267673 +"2366",0.747628055154725,42.8947368421053,15.5263157894737,0.00320762066175272 +"2367",0.973232737037462,42.8947368421053,15.5263157894737,0.00308814285948013 +"2368",1.2669160204875,42.8947368421053,15.5263157894737,0.00280685628293442 +"2369",1.64922134437622,42.8947368421053,15.5263157894737,0.0024589563224203 +"2370",2.14689134777813,42.8947368421053,15.5263157894737,0.00213342827669674 +"2371",2.79473854427218,42.8947368421053,15.5263157894737,0.00184775116875652 +"2372",3.63808049202114,42.8947368421053,15.5263157894737,0.00159986061966646 +"2373",4.73590980220715,42.8947368421053,15.5263157894737,0.00138516027470388 +"2374",6.16502073107827,42.8947368421053,15.5263157894737,0.00119926320321284 +"2375",8.02538101483936,42.8947368421053,15.5263157894737,0.00103831333960937 +"2376",10.4471247126008,42.8947368421053,15.5263157894737,0.000898963932933996 +"2377",13.5996552137305,42.8947368421053,15.5263157894737,0.000778316231013797 +"2378",17.7034951740616,42.8947368421053,15.5263157894737,0.000673860351769994 +"2379",23.045712295823,42.8947368421053,15.5263157894737,0.000583423234899625 +"2380",30,42.8947368421053,15.5263157894737,0.000505123457814183 +"2381",0.2,45,15.5263157894737,0.00221133413715916 +"2382",0.260352117694686,45,15.5263157894737,0.00221131988589807 +"2383",0.338916125940539,45,15.5263157894737,0.00221123272346498 +"2384",0.441187655547492,45,15.5263157894737,0.00221070047435234 +"2385",0.574320702112717,45,15.5263157894737,0.00220748149861206 +"2386",0.747628055154725,45,15.5263157894737,0.00218906694739435 +"2387",0.973232737037462,45,15.5263157894737,0.00210752834433542 +"2388",1.2669160204875,45,15.5263157894737,0.00191556202026097 +"2389",1.64922134437622,45,15.5263157894737,0.00167813484763979 +"2390",2.14689134777813,45,15.5263157894737,0.00145597557118908 +"2391",2.79473854427218,45,15.5263157894737,0.00126101289306572 +"2392",3.63808049202114,45,15.5263157894737,0.00109183796098757 +"2393",4.73590980220715,45,15.5263157894737,0.000945313955092513 +"2394",6.16502073107827,45,15.5263157894737,0.000818446978685127 +"2395",8.02538101483936,45,15.5263157894737,0.000708605428278891 +"2396",10.4471247126008,45,15.5263157894737,0.000613505286317159 +"2397",13.5996552137305,45,15.5263157894737,0.000531168275678164 +"2398",17.7034951740616,45,15.5263157894737,0.000459881506815452 +"2399",23.045712295823,45,15.5263157894737,0.000398161956957463 +"2400",30,45,15.5263157894737,0.00034472563387541 +"2401",0.2,5,17.6315789473684,0.0324817254372966 +"2402",0.260352117694686,5,17.6315789473684,0.0324815161041424 +"2403",0.338916125940539,5,17.6315789473684,0.0324802357973029 +"2404",0.441187655547492,5,17.6315789473684,0.0324724177252846 +"2405",0.574320702112717,5,17.6315789473684,0.0324251350082912 +"2406",0.747628055154725,5,17.6315789473684,0.0321546483429548 +"2407",0.973232737037462,5,17.6315789473684,0.0309569485143331 +"2408",1.2669160204875,5,17.6315789473684,0.0281372039415822 +"2409",1.64922134437622,5,17.6315789473684,0.0246496965120888 +"2410",2.14689134777813,5,17.6315789473684,0.0213864553312283 +"2411",2.79473854427218,5,17.6315789473684,0.0185226980749601 +"2412",3.63808049202114,5,17.6315789473684,0.0160377304699761 +"2413",4.73590980220715,5,17.6315789473684,0.0138854765661088 +"2414",6.16502073107827,5,17.6315789473684,0.0120219597752819 +"2415",8.02538101483936,5,17.6315789473684,0.0104085251423387 +"2416",10.4471247126008,5,17.6315789473684,0.00901162331355521 +"2417",13.5996552137305,5,17.6315789473684,0.00780219587879432 +"2418",17.7034951740616,5,17.6315789473684,0.00675508263860109 +"2419",23.045712295823,5,17.6315789473684,0.00584849984818832 +"2420",30,5,17.6315789473684,0.00506358727185569 +"2421",0.2,7.10526315789474,17.6315789473684,0.0414634647218411 +"2422",0.260352117694686,7.10526315789474,17.6315789473684,0.0414631975045754 +"2423",0.338916125940539,7.10526315789474,17.6315789473684,0.0414615631715233 +"2424",0.441187655547492,7.10526315789474,17.6315789473684,0.0414515832720887 +"2425",0.574320702112717,7.10526315789474,17.6315789473684,0.04139122609458 +"2426",0.747628055154725,7.10526315789474,17.6315789473684,0.04104594535118 +"2427",0.973232737037462,7.10526315789474,17.6315789473684,0.0395170615273427 +"2428",1.2669160204875,7.10526315789474,17.6315789473684,0.0359176105116459 +"2429",1.64922134437622,7.10526315789474,17.6315789473684,0.0314657490626873 +"2430",2.14689134777813,7.10526315789474,17.6315789473684,0.0273001672236725 +"2431",2.79473854427218,7.10526315789474,17.6315789473684,0.0236445332827843 +"2432",3.63808049202114,7.10526315789474,17.6315789473684,0.0204724306547059 +"2433",4.73590980220715,7.10526315789474,17.6315789473684,0.0177250426199255 +"2434",6.16502073107827,7.10526315789474,17.6315789473684,0.0153462323296851 +"2435",8.02538101483936,7.10526315789474,17.6315789473684,0.0132866560884788 +"2436",10.4471247126008,7.10526315789474,17.6315789473684,0.011503487586256 +"2437",13.5996552137305,7.10526315789474,17.6315789473684,0.00995963327741885 +"2438",17.7034951740616,7.10526315789474,17.6315789473684,0.00862297574737669 +"2439",23.045712295823,7.10526315789474,17.6315789473684,0.00746570768228351 +"2440",30,7.10526315789474,17.6315789473684,0.00646375367644342 +"2441",0.2,9.21052631578947,17.6315789473684,0.0524208105821597 +"2442",0.260352117694686,9.21052631578947,17.6315789473684,0.0524204727487017 +"2443",0.338916125940539,9.21052631578947,17.6315789473684,0.0524184065184933 +"2444",0.441187655547492,9.21052631578947,17.6315789473684,0.052405789280127 +"2445",0.574320702112717,9.21052631578947,17.6315789473684,0.0523294818082192 +"2446",0.747628055154725,9.21052631578947,17.6315789473684,0.0518929554212214 +"2447",0.973232737037462,9.21052631578947,17.6315789473684,0.0499600409899465 +"2448",1.2669160204875,9.21052631578947,17.6315789473684,0.0454093807602863 +"2449",1.64922134437622,9.21052631578947,17.6315789473684,0.0397810477852335 +"2450",2.14689134777813,9.21052631578947,17.6315789473684,0.0345146481244145 +"2451",2.79473854427218,9.21052631578947,17.6315789473684,0.0298929577842904 +"2452",3.63808049202114,9.21052631578947,17.6315789473684,0.0258825791984873 +"2453",4.73590980220715,9.21052631578947,17.6315789473684,0.0224091524423521 +"2454",6.16502073107827,9.21052631578947,17.6315789473684,0.0194017056582462 +"2455",8.02538101483936,9.21052631578947,17.6315789473684,0.0167978553349779 +"2456",10.4471247126008,9.21052631578947,17.6315789473684,0.0145434576642049 +"2457",13.5996552137305,9.21052631578947,17.6315789473684,0.0125916165715002 +"2458",17.7034951740616,9.21052631578947,17.6315789473684,0.0109017271311069 +"2459",23.045712295823,9.21052631578947,17.6315789473684,0.00943863352713524 +"2460",30,9.21052631578947,17.6315789473684,0.00817189806485457 +"2461",0.2,11.3157894736842,17.6315789473684,0.0653396150124188 +"2462",0.260352117694686,11.3157894736842,17.6315789473684,0.0653391939218665 +"2463",0.338916125940539,11.3157894736842,17.6315789473684,0.065336618481219 +"2464",0.441187655547492,11.3157894736842,17.6315789473684,0.0653208917977088 +"2465",0.574320702112717,11.3157894736842,17.6315789473684,0.0652257787923651 +"2466",0.747628055154725,11.3157894736842,17.6315789473684,0.064681673011618 +"2467",0.973232737037462,11.3157894736842,17.6315789473684,0.0622724030406109 +"2468",1.2669160204875,11.3157894736842,17.6315789473684,0.056600259016964 +"2469",1.64922134437622,11.3157894736842,17.6315789473684,0.0495848560564304 +"2470",2.14689134777813,11.3157894736842,17.6315789473684,0.0430205827741597 +"2471",2.79473854427218,11.3157894736842,17.6315789473684,0.0372599036817021 +"2472",3.63808049202114,11.3157894736842,17.6315789473684,0.0322611905763462 +"2473",4.73590980220715,11.3157894736842,17.6315789473684,0.0279317579617169 +"2474",6.16502073107827,11.3157894736842,17.6315789473684,0.0241831433778994 +"2475",8.02538101483936,11.3157894736842,17.6315789473684,0.0209375892595468 +"2476",10.4471247126008,11.3157894736842,17.6315789473684,0.0181276083710915 +"2477",13.5996552137305,11.3157894736842,17.6315789473684,0.0156947473728271 +"2478",17.7034951740616,11.3157894736842,17.6315789473684,0.0135883944907824 +"2479",23.045712295823,11.3157894736842,17.6315789473684,0.0117647299623446 +"2480",30,11.3157894736842,17.6315789473684,0.0101858148996278 +"2481",0.2,13.4210526315789,17.6315789473684,0.0796890479043038 +"2482",0.260352117694686,13.4210526315789,17.6315789473684,0.079688534336766 +"2483",0.338916125940539,13.4210526315789,17.6315789473684,0.0796853932957133 +"2484",0.441187655547492,13.4210526315789,17.6315789473684,0.0796662128270897 +"2485",0.574320702112717,13.4210526315789,17.6315789473684,0.0795502117634514 +"2486",0.747628055154725,13.4210526315789,17.6315789473684,0.0788866132463998 +"2487",0.973232737037462,13.4210526315789,17.6315789473684,0.0759482361210143 +"2488",1.2669160204875,13.4210526315789,17.6315789473684,0.0690304151829111 +"2489",1.64922134437622,13.4210526315789,17.6315789473684,0.0604743381003679 +"2490",2.14689134777813,13.4210526315789,17.6315789473684,0.0524684646658767 +"2491",2.79473854427218,13.4210526315789,17.6315789473684,0.0454426652014488 +"2492",3.63808049202114,13.4210526315789,17.6315789473684,0.0393461694073296 +"2493",4.73590980220715,13.4210526315789,17.6315789473684,0.0340659368415259 +"2494",6.16502073107827,13.4210526315789,17.6315789473684,0.0294940775324708 +"2495",8.02538101483936,13.4210526315789,17.6315789473684,0.0255357573378346 +"2496",10.4471247126008,13.4210526315789,17.6315789473684,0.0221086679436328 +"2497",13.5996552137305,13.4210526315789,17.6315789473684,0.0191415188932694 +"2498",17.7034951740616,13.4210526315789,17.6315789473684,0.0165725834061423 +"2499",23.045712295823,13.4210526315789,17.6315789473684,0.0143484183274157 +"2500",30,13.4210526315789,17.6315789473684,0.0124227528938843 +"2501",0.2,15.5263157894737,17.6315789473684,0.0939993969741149 +"2502",0.260352117694686,15.5263157894737,17.6315789473684,0.093998791181473 +"2503",0.338916125940539,15.5263157894737,17.6315789473684,0.0939950860805514 +"2504",0.441187655547492,15.5263157894737,17.6315789473684,0.0939724612339545 +"2505",0.574320702112717,15.5263157894737,17.6315789473684,0.0938356290052214 +"2506",0.747628055154725,15.5263157894737,17.6315789473684,0.0930528632164938 +"2507",0.973232737037462,15.5263157894737,17.6315789473684,0.0895868200759049 +"2508",1.2669160204875,15.5263157894737,17.6315789473684,0.0814267150971443 +"2509",1.64922134437622,15.5263157894737,17.6315789473684,0.0713341602558701 +"2510",2.14689134777813,15.5263157894737,17.6315789473684,0.0618906131827896 +"2511",2.79473854427218,15.5263157894737,17.6315789473684,0.0536031391787037 +"2512",3.63808049202114,15.5263157894737,17.6315789473684,0.0464118507473171 +"2513",4.73590980220715,15.5263157894737,17.6315789473684,0.0401834079421693 +"2514",6.16502073107827,15.5263157894737,17.6315789473684,0.0347905461951229 +"2515",8.02538101483936,15.5263157894737,17.6315789473684,0.0301214012986613 +"2516",10.4471247126008,15.5263157894737,17.6315789473684,0.026078884228835 +"2517",13.5996552137305,15.5263157894737,17.6315789473684,0.0225789023768569 +"2518",17.7034951740616,15.5263157894737,17.6315789473684,0.0195486442296479 +"2519",23.045712295823,15.5263157894737,17.6315789473684,0.0169250694515648 +"2520",30,15.5263157894737,17.6315789473684,0.0146535980977694 +"2521",0.2,17.6315789473684,17.6315789473684,0.105566668518954 +"2522",0.260352117694686,17.6315789473684,17.6315789473684,0.105565988179366 +"2523",0.338916125940539,17.6315789473684,17.6315789473684,0.105561827140323 +"2524",0.441187655547492,17.6315789473684,17.6315789473684,0.105536418150926 +"2525",0.574320702112717,17.6315789473684,17.6315789473684,0.105382747776452 +"2526",0.747628055154725,17.6315789473684,17.6315789473684,0.104503657280059 +"2527",0.973232737037462,17.6315789473684,17.6315789473684,0.100611093720362 +"2528",1.2669160204875,17.6315789473684,17.6315789473684,0.0914468317665341 +"2529",1.64922134437622,17.6315789473684,17.6315789473684,0.080112318719269 +"2530",2.14689134777813,17.6315789473684,17.6315789473684,0.0695066783045592 +"2531",2.79473854427218,17.6315789473684,17.6315789473684,0.0601993736918529 +"2532",3.63808049202114,17.6315789473684,17.6315789473684,0.052123147817027 +"2533",4.73590980220715,17.6315789473684,17.6315789473684,0.0451282523372043 +"2534",6.16502073107827,17.6315789473684,17.6315789473684,0.0390717619048692 +"2535",8.02538101483936,17.6315789473684,17.6315789473684,0.0338280466532973 +"2536",10.4471247126008,17.6315789473684,17.6315789473684,0.0292880700871701 +"2537",13.5996552137305,17.6315789473684,17.6315789473684,0.0253573914244987 +"2538",17.7034951740616,17.6315789473684,17.6315789473684,0.0219542391953268 +"2539",23.045712295823,17.6315789473684,17.6315789473684,0.0190078155176425 +"2540",30,17.6315789473684,17.6315789473684,0.0164568240094475 +"2541",0.2,19.7368421052632,17.6315789473684,0.110944463417388 +"2542",0.260352117694686,19.7368421052632,17.6315789473684,0.110943748419826 +"2543",0.338916125940539,19.7368421052632,17.6315789473684,0.110939375408436 +"2544",0.441187655547492,19.7368421052632,17.6315789473684,0.110912672030049 +"2545",0.574320702112717,19.7368421052632,17.6315789473684,0.110751173353635 +"2546",0.747628055154725,19.7368421052632,17.6315789473684,0.109827300082025 +"2547",0.973232737037462,19.7368421052632,17.6315789473684,0.105736440897896 +"2548",1.2669160204875,19.7368421052632,17.6315789473684,0.096105331577615 +"2549",1.64922134437622,19.7368421052632,17.6315789473684,0.0841934138694189 +"2550",2.14689134777813,19.7368421052632,17.6315789473684,0.0730474991454311 +"2551",2.79473854427218,19.7368421052632,17.6315789473684,0.0632660602632002 +"2552",3.63808049202114,19.7368421052632,17.6315789473684,0.0547784139379843 +"2553",4.73590980220715,19.7368421052632,17.6315789473684,0.0474271833217572 +"2554",6.16502073107827,19.7368421052632,17.6315789473684,0.0410621621400257 +"2555",8.02538101483936,19.7368421052632,17.6315789473684,0.0355513206683659 +"2556",10.4471247126008,19.7368421052632,17.6315789473684,0.0307800678560632 +"2557",13.5996552137305,19.7368421052632,17.6315789473684,0.0266491519030041 +"2558",17.7034951740616,19.7368421052632,17.6315789473684,0.0230726357233221 +"2559",23.045712295823,19.7368421052632,17.6315789473684,0.019976114837449 +"2560",30,19.7368421052632,17.6315789473684,0.0172951702928346 +"2561",0.2,21.8421052631579,17.6315789473684,0.107716984371885 +"2562",0.260352117694686,21.8421052631579,17.6315789473684,0.107716290174277 +"2563",0.338916125940539,21.8421052631579,17.6315789473684,0.107712044377911 +"2564",0.441187655547492,21.8421052631579,17.6315789473684,0.107686117825979 +"2565",0.574320702112717,21.8421052631579,17.6315789473684,0.107529317298332 +"2566",0.747628055154725,21.8421052631579,17.6315789473684,0.106632320371273 +"2567",0.973232737037462,21.8421052631579,17.6315789473684,0.102660468137902 +"2568",1.2669160204875,21.8421052631579,17.6315789473684,0.0933095368685012 +"2569",1.64922134437622,21.8421052631579,17.6315789473684,0.0817441480776636 +"2570",2.14689134777813,21.8421052631579,17.6315789473684,0.070922478521993 +"2571",2.79473854427218,21.8421052631579,17.6315789473684,0.0614255909193378 +"2572",3.63808049202114,21.8421052631579,17.6315789473684,0.0531848582283536 +"2573",4.73590980220715,21.8421052631579,17.6315789473684,0.0460474818419069 +"2574",6.16502073107827,21.8421052631579,17.6315789473684,0.0398676251276526 +"2575",8.02538101483936,21.8421052631579,17.6315789473684,0.0345170992303352 +"2576",10.4471247126008,21.8421052631579,17.6315789473684,0.0298846466609482 +"2577",13.5996552137305,21.8421052631579,17.6315789473684,0.0258739029478239 +"2578",17.7034951740616,21.8421052631579,17.6315789473684,0.0224014309959498 +"2579",23.045712295823,21.8421052631579,17.6315789473684,0.0193949908222212 +"2580",30,21.8421052631579,17.6315789473684,0.0167920374821551 +"2581",0.2,23.9473684210526,17.6315789473684,0.096429445142314 +"2582",0.260352117694686,23.9473684210526,17.6315789473684,0.096428823688877 +"2583",0.338916125940539,23.9473684210526,17.6315789473684,0.0964250228046419 +"2584",0.441187655547492,23.9473684210526,17.6315789473684,0.0964018130663456 +"2585",0.574320702112717,23.9473684210526,17.6315789473684,0.0962614434861243 +"2586",0.747628055154725,23.9473684210526,17.6315789473684,0.0954584418381012 +"2587",0.973232737037462,23.9473684210526,17.6315789473684,0.0919027954441318 +"2588",1.2669160204875,23.9473684210526,17.6315789473684,0.0835317375359454 +"2589",1.64922134437622,23.9473684210526,17.6315789473684,0.0731782725697771 +"2590",2.14689134777813,23.9473684210526,17.6315789473684,0.0634905933532472 +"2591",2.79473854427218,23.9473684210526,17.6315789473684,0.0549888737085411 +"2592",3.63808049202114,23.9473684210526,17.6315789473684,0.0476116779432544 +"2593",4.73590980220715,23.9473684210526,17.6315789473684,0.0412222190410188 +"2594",6.16502073107827,23.9473684210526,17.6315789473684,0.0356899424229028 +"2595",8.02538101483936,23.9473684210526,17.6315789473684,0.030900091996747 +"2596",10.4471247126008,23.9473684210526,17.6315789473684,0.0267530688181937 +"2597",13.5996552137305,23.9473684210526,17.6315789473684,0.023162606338021 +"2598",17.7034951740616,23.9473684210526,17.6315789473684,0.0200540107386917 +"2599",23.045712295823,23.9473684210526,17.6315789473684,0.0173626119820636 +"2600",30,23.9473684210526,17.6315789473684,0.0150324191366407 +"2601",0.2,26.0526315789474,17.6315789473684,0.0804195972720802 +"2602",0.260352117694686,26.0526315789474,17.6315789473684,0.0804190789964119 +"2603",0.338916125940539,26.0526315789474,17.6315789473684,0.0804159091598644 +"2604",0.441187655547492,26.0526315789474,17.6315789473684,0.0803965528542897 +"2605",0.574320702112717,26.0526315789474,17.6315789473684,0.0802794883508697 +"2606",0.747628055154725,26.0526315789474,17.6315789473684,0.0796098062942372 +"2607",0.973232737037462,26.0526315789474,17.6315789473684,0.0766444915957762 +"2608",1.2669160204875,26.0526315789474,17.6315789473684,0.0696632515323901 +"2609",1.64922134437622,26.0526315789474,17.6315789473684,0.0610287366109257 +"2610",2.14689134777813,26.0526315789474,17.6315789473684,0.0529494693296026 +"2611",2.79473854427218,26.0526315789474,17.6315789473684,0.0458592608467231 +"2612",3.63808049202114,26.0526315789474,17.6315789473684,0.0397068754257961 +"2613",4.73590980220715,26.0526315789474,17.6315789473684,0.0343782363265463 +"2614",6.16502073107827,26.0526315789474,17.6315789473684,0.0297644644960642 +"2615",8.02538101483936,26.0526315789474,17.6315789473684,0.0257698563999949 +"2616",10.4471247126008,26.0526315789474,17.6315789473684,0.0223113491628637 +"2617",13.5996552137305,26.0526315789474,17.6315789473684,0.019316998772795 +"2618",17.7034951740616,26.0526315789474,17.6315789473684,0.016724512568909 +"2619",23.045712295823,26.0526315789474,17.6315789473684,0.0144799574562339 +"2620",30,26.0526315789474,17.6315789473684,0.0125366384843304 +"2621",0.2,28.1578947368421,17.6315789473684,0.0635838834417348 +"2622",0.260352117694686,28.1578947368421,17.6315789473684,0.0635834736662472 +"2623",0.338916125940539,28.1578947368421,17.6315789473684,0.0635809674299019 +"2624",0.441187655547492,28.1578947368421,17.6315789473684,0.063565663335884 +"2625",0.574320702112717,28.1578947368421,17.6315789473684,0.0634731060986793 +"2626",0.747628055154725,28.1578947368421,17.6315789473684,0.0629436209075526 +"2627",0.973232737037462,28.1578947368421,17.6315789473684,0.0605990900898079 +"2628",1.2669160204875,28.1578947368421,17.6315789473684,0.055079361447456 +"2629",1.64922134437622,28.1578947368421,17.6315789473684,0.048252468389476 +"2630",2.14689134777813,28.1578947368421,17.6315789473684,0.0418645827678625 +"2631",2.79473854427218,28.1578947368421,17.6315789473684,0.0362586980700349 +"2632",3.63808049202114,28.1578947368421,17.6315789473684,0.0313943046788401 +"2633",4.73590980220715,28.1578947368421,17.6315789473684,0.0271812076367912 +"2634",6.16502073107827,28.1578947368421,17.6315789473684,0.0235333215462451 +"2635",8.02538101483936,28.1578947368421,17.6315789473684,0.0203749782544159 +"2636",10.4471247126008,28.1578947368421,17.6315789473684,0.0176405039657155 +"2637",13.5996552137305,28.1578947368421,17.6315789473684,0.0152730160318765 +"2638",17.7034951740616,28.1578947368421,17.6315789473684,0.0132232626607611 +"2639",23.045712295823,28.1578947368421,17.6315789473684,0.0114486015644112 +"2640",30,28.1578947368421,17.6315789473684,0.00991211330544146 +"2641",0.2,30.2631578947368,17.6315789473684,0.0485225184196286 +"2642",0.260352117694686,30.2631578947368,17.6315789473684,0.0485222057092754 +"2643",0.338916125940539,30.2631578947368,17.6315789473684,0.048520293135009 +"2644",0.441187655547492,30.2631578947368,17.6315789473684,0.0485086141820467 +"2645",0.574320702112717,30.2631578947368,17.6315789473684,0.0484379813423389 +"2646",0.747628055154725,30.2631578947368,17.6315789473684,0.0480339173948622 +"2647",0.973232737037462,30.2631578947368,17.6315789473684,0.0462447448305024 +"2648",1.2669160204875,30.2631578947368,17.6315789473684,0.0420324960620657 +"2649",1.64922134437622,30.2631578947368,17.6315789473684,0.0368227160639909 +"2650",2.14689134777813,30.2631578947368,17.6315789473684,0.0319479540809288 +"2651",2.79473854427218,30.2631578947368,17.6315789473684,0.0276699573813735 +"2652",3.63808049202114,30.2631578947368,17.6315789473684,0.0239578120208143 +"2653",4.73590980220715,30.2631578947368,17.6315789473684,0.0207426878767561 +"2654",6.16502073107827,30.2631578947368,17.6315789473684,0.0179588909389138 +"2655",8.02538101483936,30.2631578947368,17.6315789473684,0.0155486768680207 +"2656",10.4471247126008,30.2631578947368,17.6315789473684,0.0134619282792364 +"2657",13.5996552137305,30.2631578947368,17.6315789473684,0.0116552365413337 +"2658",17.7034951740616,30.2631578947368,17.6315789473684,0.0100910163282543 +"2659",23.045712295823,30.2631578947368,17.6315789473684,0.00873672619882016 +"2660",30,30.2631578947368,17.6315789473684,0.00756419196825965 +"2661",0.2,32.3684210526316,17.6315789473684,0.0362541968695133 +"2662",0.260352117694686,32.3684210526316,17.6315789473684,0.036253963224124 +"2663",0.338916125940539,32.3684210526316,17.6315789473684,0.0362525342207202 +"2664",0.441187655547492,32.3684210526316,17.6315789473684,0.0362438081472658 +"2665",0.574320702112717,32.3684210526316,17.6315789473684,0.0361910339517042 +"2666",0.747628055154725,32.3684210526316,17.6315789473684,0.0358891325999853 +"2667",0.973232737037462,32.3684210526316,17.6315789473684,0.0345523302967562 +"2668",1.2669160204875,32.3684210526316,17.6315789473684,0.0314050967835737 +"2669",1.64922134437622,32.3684210526316,17.6315789473684,0.0275125455342006 +"2670",2.14689134777813,32.3684210526316,17.6315789473684,0.0238703071182642 +"2671",2.79473854427218,32.3684210526316,17.6315789473684,0.0206739492290977 +"2672",3.63808049202114,32.3684210526316,17.6315789473684,0.0179003741325602 +"2673",4.73590980220715,32.3684210526316,17.6315789473684,0.0154981545554441 +"2674",6.16502073107827,32.3684210526316,17.6315789473684,0.0134182064093796 +"2675",8.02538101483936,32.3684210526316,17.6315789473684,0.0116173853005461 +"2676",10.4471247126008,32.3684210526316,17.6315789473684,0.0100582454079976 +"2677",13.5996552137305,32.3684210526316,17.6315789473684,0.00870835343862375 +"2678",17.7034951740616,32.3684210526316,17.6315789473684,0.00753962705344688 +"2679",23.045712295823,32.3684210526316,17.6315789473684,0.00652775251415909 +"2680",30,32.3684210526316,17.6315789473684,0.00565167913183053 +"2681",0.2,34.4736842105263,17.6315789473684,0.0267843774652269 +"2682",0.260352117694686,34.4736842105263,17.6315789473684,0.0267842048494516 +"2683",0.338916125940539,34.4736842105263,17.6315789473684,0.0267831491105338 +"2684",0.441187655547492,34.4736842105263,17.6315789473684,0.0267767023411837 +"2685",0.574320702112717,34.4736842105263,17.6315789473684,0.0267377130903824 +"2686",0.747628055154725,34.4736842105263,17.6315789473684,0.0265146702302466 +"2687",0.973232737037462,34.4736842105263,17.6315789473684,0.0255270489180178 +"2688",1.2669160204875,34.4736842105263,17.6315789473684,0.0232018921729464 +"2689",1.64922134437622,34.4736842105263,17.6315789473684,0.0203260992725768 +"2690",2.14689134777813,34.4736842105263,17.6315789473684,0.0176352359526165 +"2691",2.79473854427218,34.4736842105263,17.6315789473684,0.0152737864209794 +"2692",3.63808049202114,34.4736842105263,17.6315789473684,0.0132246862138726 +"2693",4.73590980220715,34.4736842105263,17.6315789473684,0.011449941178438 +"2694",6.16502073107827,34.4736842105263,17.6315789473684,0.0099132882923514 +"2695",8.02538101483936,34.4736842105263,17.6315789473684,0.0085828527430563 +"2696",10.4471247126008,34.4736842105263,17.6315789473684,0.00743096978855535 +"2697",13.5996552137305,34.4736842105263,17.6315789473684,0.00643367791155916 +"2698",17.7034951740616,34.4736842105263,17.6315789473684,0.00557023005290666 +"2699",23.045712295823,34.4736842105263,17.6315789473684,0.00482266337241214 +"2700",30,34.4736842105263,17.6315789473684,0.00417542575068293 +"2701",0.2,36.5789473684211,17.6315789473684,0.0196895552458642 +"2702",0.260352117694686,36.5789473684211,17.6315789473684,0.0196894283536918 +"2703",0.338916125940539,36.5789473684211,17.6315789473684,0.0196886522658483 +"2704",0.441187655547492,36.5789473684211,17.6315789473684,0.0196839131592015 +"2705",0.574320702112717,36.5789473684211,17.6315789473684,0.0196552516378111 +"2706",0.747628055154725,36.5789473684211,17.6315789473684,0.0194912898387161 +"2707",0.973232737037462,36.5789473684211,17.6315789473684,0.0187652761609904 +"2708",1.2669160204875,36.5789473684211,17.6315789473684,0.0170560222406104 +"2709",1.64922134437622,36.5789473684211,17.6315789473684,0.0149419882944788 +"2710",2.14689134777813,36.5789473684211,17.6315789473684,0.0129638985641421 +"2711",2.79473854427218,36.5789473684211,17.6315789473684,0.0112279653294103 +"2712",3.63808049202114,36.5789473684211,17.6315789473684,0.009721644273992 +"2713",4.73590980220715,36.5789473684211,17.6315789473684,0.00841700538634645 +"2714",6.16502073107827,36.5789473684211,17.6315789473684,0.00728739123221503 +"2715",8.02538101483936,36.5789473684211,17.6315789473684,0.00630937020921696 +"2716",10.4471247126008,36.5789473684211,17.6315789473684,0.00546260559432679 +"2717",13.5996552137305,36.5789473684211,17.6315789473684,0.00472948295468877 +"2718",17.7034951740616,36.5789473684211,17.6315789473684,0.0040947508487463 +"2719",23.045712295823,36.5789473684211,17.6315789473684,0.00354520455166795 +"2720",30,36.5789473684211,17.6315789473684,0.00306941149182238 +"2721",0.2,38.6842105263158,17.6315789473684,0.014456566992138 +"2722",0.260352117694686,38.6842105263158,17.6315789473684,0.0144564738247115 +"2723",0.338916125940539,38.6842105263158,17.6315789473684,0.0144559040014849 +"2724",0.441187655547492,38.6842105263158,17.6315789473684,0.0144524244301148 +"2725",0.574320702112717,38.6842105263158,17.6315789473684,0.0144313804197803 +"2726",0.747628055154725,38.6842105263158,17.6315789473684,0.0143109955404282 +"2727",0.973232737037462,38.6842105263158,17.6315789473684,0.0137779380265235 +"2728",1.2669160204875,38.6842105263158,17.6315789473684,0.0125229607810757 +"2729",1.64922134437622,38.6842105263158,17.6315789473684,0.0109707838535483 +"2730",2.14689134777813,38.6842105263158,17.6315789473684,0.00951842059059045 +"2731",2.79473854427218,38.6842105263158,17.6315789473684,0.00824385472110233 +"2732",3.63808049202114,38.6842105263158,17.6315789473684,0.00713787589235776 +"2733",4.73590980220715,38.6842105263158,17.6315789473684,0.00617997718696379 +"2734",6.16502073107827,38.6842105263158,17.6315789473684,0.00535058604579526 +"2735",8.02538101483936,38.6842105263158,17.6315789473684,0.00463249839667678 +"2736",10.4471247126008,38.6842105263158,17.6315789473684,0.00401078250574507 +"2737",13.5996552137305,38.6842105263158,17.6315789473684,0.00347250541309178 +"2738",17.7034951740616,38.6842105263158,17.6315789473684,0.00300646912649025 +"2739",23.045712295823,38.6842105263158,17.6315789473684,0.00260297840464353 +"2740",30,38.6842105263158,17.6315789473684,0.00225363916573429 +"2741",0.2,40.7894736842105,17.6315789473684,0.010625068885736 +"2742",0.260352117694686,40.7894736842105,17.6315789473684,0.0106250004109505 +"2743",0.338916125940539,40.7894736842105,17.6315789473684,0.0106245816108966 +"2744",0.441187655547492,40.7894736842105,17.6315789473684,0.0106220242481755 +"2745",0.574320702112717,40.7894736842105,17.6315789473684,0.0106065576398474 +"2746",0.747628055154725,40.7894736842105,17.6315789473684,0.0105180789825969 +"2747",0.973232737037462,40.7894736842105,17.6315789473684,0.0101263004359767 +"2748",1.2669160204875,40.7894736842105,17.6315789473684,0.00920393624742726 +"2749",1.64922134437622,40.7894736842105,17.6315789473684,0.00806314073305671 +"2750",2.14689134777813,40.7894736842105,17.6315789473684,0.00699570475573016 +"2751",2.79473854427218,40.7894736842105,17.6315789473684,0.0060589436166517 +"2752",3.63808049202114,40.7894736842105,17.6315789473684,0.00524608803012363 +"2753",4.73590980220715,40.7894736842105,17.6315789473684,0.00454206613226203 +"2754",6.16502073107827,40.7894736842105,17.6315789473684,0.00393249277968619 +"2755",8.02538101483936,40.7894736842105,17.6315789473684,0.00340472358371945 +"2756",10.4471247126008,40.7894736842105,17.6315789473684,0.00294778424451819 +"2757",13.5996552137305,40.7894736842105,17.6315789473684,0.00255216949087957 +"2758",17.7034951740616,40.7894736842105,17.6315789473684,0.00220964919189803 +"2759",23.045712295823,40.7894736842105,17.6315789473684,0.0019130976858103 +"2760",30,40.7894736842105,17.6315789473684,0.00165634561736141 +"2761",0.2,42.8947368421053,17.6315789473684,0.00782684290863783 +"2762",0.260352117694686,42.8947368421053,17.6315789473684,0.00782679246742229 +"2763",0.338916125940539,42.8947368421053,17.6315789473684,0.00782648396285942 +"2764",0.441187655547492,42.8947368421053,17.6315789473684,0.00782460010907049 +"2765",0.574320702112717,42.8947368421053,17.6315789473684,0.00781320679811737 +"2766",0.747628055154725,42.8947368421053,17.6315789473684,0.00774802994528804 +"2767",0.973232737037462,42.8947368421053,17.6315789473684,0.00745943048561894 +"2768",1.2669160204875,42.8947368421053,17.6315789473684,0.0067799808099541 +"2769",1.64922134437622,42.8947368421053,17.6315789473684,0.00593962604351642 +"2770",2.14689134777813,42.8947368421053,17.6315789473684,0.00515331079234857 +"2771",2.79473854427218,42.8947368421053,17.6315789473684,0.00446325575766295 +"2772",3.63808049202114,42.8947368421053,17.6315789473684,0.00386447441783513 +"2773",4.73590980220715,42.8947368421053,17.6315789473684,0.00334586424616827 +"2774",6.16502073107827,42.8947368421053,17.6315789473684,0.00289682858125057 +"2775",8.02538101483936,42.8947368421053,17.6315789473684,0.00250805306993175 +"2776",10.4471247126008,42.8947368421053,17.6315789473684,0.00217145361206788 +"2777",13.5996552137305,42.8947368421053,17.6315789473684,0.00188002825168967 +"2778",17.7034951740616,42.8947368421053,17.6315789473684,0.00162771435123607 +"2779",23.045712295823,42.8947368421053,17.6315789473684,0.00140926286848055 +"2780",30,42.8947368421053,17.6315789473684,0.0012201292141176 +"2781",0.2,45,17.6315789473684,0.00578279721279066 +"2782",0.260352117694686,45,17.6315789473684,0.00578275994472179 +"2783",0.338916125940539,45,17.6315789473684,0.00578253200871398 +"2784",0.441187655547492,45,17.6315789473684,0.0057811401391483 +"2785",0.574320702112717,45,17.6315789473684,0.00577272228694489 +"2786",0.747628055154725,45,17.6315789473684,0.00572456691609109 +"2787",0.973232737037462,45,17.6315789473684,0.0055113376267763 +"2788",1.2669160204875,45,17.6315789473684,0.0050093319347584 +"2789",1.64922134437622,45,17.6315789473684,0.00438844286647928 +"2790",2.14689134777813,45,17.6315789473684,0.00380748044064472 +"2791",2.79473854427218,45,17.6315789473684,0.0032976390680974 +"2792",3.63808049202114,45,17.6315789473684,0.00285523449917396 +"2793",4.73590980220715,45,17.6315789473684,0.00247206372517897 +"2794",6.16502073107827,45,17.6315789473684,0.00214029749173842 +"2795",8.02538101483936,45,17.6315789473684,0.00185305396717826 +"2796",10.4471247126008,45,17.6315789473684,0.00160436028193592 +"2797",13.5996552137305,45,17.6315789473684,0.00138904309959261 +"2798",17.7034951740616,45,17.6315789473684,0.00120262309125423 +"2799",23.045712295823,45,17.6315789473684,0.00104122204611323 +"2800",30,45,17.6315789473684,0.000901482232492093 +"2801",0.2,5,19.7368421052632,0.0329017287667389 +"2802",0.260352117694686,5,19.7368421052632,0.0329015167268128 +"2803",0.338916125940539,5,19.7368421052632,0.0329002198650296 +"2804",0.441187655547492,5,19.7368421052632,0.0328923007018213 +"2805",0.574320702112717,5,19.7368421052632,0.0328444065980159 +"2806",0.747628055154725,5,19.7368421052632,0.0325704224183547 +"2807",0.973232737037462,5,19.7368421052632,0.0313572357918823 +"2808",1.2669160204875,5,19.7368421052632,0.0285010306526809 +"2809",1.64922134437622,5,19.7368421052632,0.0249684281824493 +"2810",2.14689134777813,5,19.7368421052632,0.0216629918243843 +"2811",2.79473854427218,5,19.7368421052632,0.0187622048978583 +"2812",3.63808049202114,5,19.7368421052632,0.0162451055432952 +"2813",4.73590980220715,5,19.7368421052632,0.0140650220277536 +"2814",6.16502073107827,5,19.7368421052632,0.0121774091260803 +"2815",8.02538101483936,5,19.7368421052632,0.0105431120571504 +"2816",10.4471247126008,5,19.7368421052632,0.00912814765899614 +"2817",13.5996552137305,5,19.7368421052632,0.00790308178315862 +"2818",17.7034951740616,5,19.7368421052632,0.00684242889747971 +"2819",23.045712295823,5,19.7368421052632,0.00592412358354757 +"2820",30,5,19.7368421052632,0.00512906173432557 +"2821",0.2,7.10526315789474,19.7368421052632,0.0417972395974459 +"2822",0.260352117694686,7.10526315789474,19.7368421052632,0.04179697022912 +"2823",0.338916125940539,7.10526315789474,19.7368421052632,0.0417953227399239 +"2824",0.441187655547492,7.10526315789474,19.7368421052632,0.0417852625037468 +"2825",0.574320702112717,7.10526315789474,19.7368421052632,0.0417244194597155 +"2826",0.747628055154725,7.10526315789474,19.7368421052632,0.0413763592564236 +"2827",0.973232737037462,7.10526315789474,19.7368421052632,0.0398351681396106 +"2828",1.2669160204875,7.10526315789474,19.7368421052632,0.036206742065436 +"2829",1.64922134437622,7.10526315789474,19.7368421052632,0.0317190437776772 +"2830",2.14689134777813,7.10526315789474,19.7368421052632,0.0275199296091895 +"2831",2.79473854427218,7.10526315789474,19.7368421052632,0.0238348683454266 +"2832",3.63808049202114,7.10526315789474,19.7368421052632,0.020637230751392 +"2833",4.73590980220715,7.10526315789474,19.7368421052632,0.0178677266415153 +"2834",6.16502073107827,7.10526315789474,19.7368421052632,0.0154697672735496 +"2835",8.02538101483936,7.10526315789474,19.7368421052632,0.0133936117423994 +"2836",10.4471247126008,7.10526315789474,19.7368421052632,0.0115960889924308 +"2837",13.5996552137305,7.10526315789474,19.7368421052632,0.0100398068803857 +"2838",17.7034951740616,7.10526315789474,19.7368421052632,0.00869238945114535 +"2839",23.045712295823,7.10526315789474,19.7368421052632,0.00752580554602146 +"2840",30,7.10526315789474,19.7368421052632,0.0065157859557951 +"2841",0.2,9.21052631578947,19.7368421052632,0.0524886952377724 +"2842",0.260352117694686,9.21052631578947,19.7368421052632,0.052488356966822 +"2843",0.338916125940539,9.21052631578947,19.7368421052632,0.0524862880608571 +"2844",0.441187655547492,9.21052631578947,19.7368421052632,0.0524736544832379 +"2845",0.574320702112717,9.21052631578947,19.7368421052632,0.0523972481935821 +"2846",0.747628055154725,9.21052631578947,19.7368421052632,0.0519601565073621 +"2847",0.973232737037462,9.21052631578947,19.7368421052632,0.0500247389627427 +"2848",1.2669160204875,9.21052631578947,19.7368421052632,0.0454681856536152 +"2849",1.64922134437622,9.21052631578947,19.7368421052632,0.0398325640189357 +"2850",2.14689134777813,9.21052631578947,19.7368421052632,0.0345593444001016 +"2851",2.79473854427218,9.21052631578947,19.7368421052632,0.0299316689969156 +"2852",3.63808049202114,9.21052631578947,19.7368421052632,0.0259160969933429 +"2853",4.73590980220715,9.21052631578947,19.7368421052632,0.0224381721690451 +"2854",6.16502073107827,9.21052631578947,19.7368421052632,0.0194268307582262 +"2855",8.02538101483936,9.21052631578947,19.7368421052632,0.0168196084633974 +"2856",10.4471247126008,9.21052631578947,19.7368421052632,0.0145622913602884 +"2857",13.5996552137305,9.21052631578947,19.7368421052632,0.0126079226443188 +"2858",17.7034951740616,9.21052631578947,19.7368421052632,0.0109158448065809 +"2859",23.045712295823,9.21052631578947,19.7368421052632,0.00945085650460028 +"2860",30,9.21052631578947,19.7368421052632,0.00818248062700259 +"2861",0.2,11.3157894736842,19.7368421052632,0.0648642077719785 +"2862",0.260352117694686,11.3157894736842,19.7368421052632,0.0648637897452566 +"2863",0.338916125940539,11.3157894736842,19.7368421052632,0.0648612330433656 +"2864",0.441187655547492,11.3157894736842,19.7368421052632,0.0648456207862903 +"2865",0.574320702112717,11.3157894736842,19.7368421052632,0.0647511998176443 +"2866",0.747628055154725,11.3157894736842,19.7368421052632,0.0642110529189274 +"2867",0.973232737037462,11.3157894736842,19.7368421052632,0.0618193126561711 +"2868",1.2669160204875,11.3157894736842,19.7368421052632,0.0561884388227013 +"2869",1.64922134437622,11.3157894736842,19.7368421052632,0.0492240795262819 +"2870",2.14689134777813,11.3157894736842,19.7368421052632,0.042707567514812 +"2871",2.79473854427218,11.3157894736842,19.7368421052632,0.0369888027885453 +"2872",3.63808049202114,11.3157894736842,19.7368421052632,0.0320264600291536 +"2873",4.73590980220715,11.3157894736842,19.7368421052632,0.0277285281145453 +"2874",6.16502073107827,11.3157894736842,19.7368421052632,0.0240071882325213 +"2875",8.02538101483936,11.3157894736842,19.7368421052632,0.0207852485772599 +"2876",10.4471247126008,11.3157894736842,19.7368421052632,0.0179957129463964 +"2877",13.5996552137305,11.3157894736842,19.7368421052632,0.0155805533033257 +"2878",17.7034951740616,11.3157894736842,19.7368421052632,0.0134895261224021 +"2879",23.045712295823,11.3157894736842,19.7368421052632,0.011679130471058 +"2880",30,11.3157894736842,19.7368421052632,0.0101117035025504 +"2881",0.2,13.4210526315789,19.7368421052632,0.0783621516222006 +"2882",0.260352117694686,13.4210526315789,19.7368421052632,0.0783616466060369 +"2883",0.338916125940539,13.4210526315789,19.7368421052632,0.07835855786622 +"2884",0.441187655547492,13.4210526315789,19.7368421052632,0.0783396967701223 +"2885",0.574320702112717,13.4210526315789,19.7368421052632,0.0782256272313811 +"2886",0.747628055154725,13.4210526315789,19.7368421052632,0.0775730782428186 +"2887",0.973232737037462,13.4210526315789,19.7368421052632,0.0746836278116982 +"2888",1.2669160204875,13.4210526315789,19.7368421052632,0.0678809949844387 +"2889",1.64922134437622,13.4210526315789,19.7368421052632,0.05946738449133 +"2890",2.14689134777813,13.4210526315789,19.7368421052632,0.0515948162471326 +"2891",2.79473854427218,13.4210526315789,19.7368421052632,0.0446860028357863 +"2892",3.63808049202114,13.4210526315789,19.7368421052632,0.0386910193299403 +"2893",4.73590980220715,13.4210526315789,19.7368421052632,0.0334987075154124 +"2894",6.16502073107827,13.4210526315789,19.7368421052632,0.0290029738883553 +"2895",8.02538101483936,13.4210526315789,19.7368421052632,0.0251105633825379 +"2896",10.4471247126008,13.4210526315789,19.7368421052632,0.0217405381934582 +"2897",13.5996552137305,13.4210526315789,19.7368421052632,0.0188227949164967 +"2898",17.7034951740616,13.4210526315789,19.7368421052632,0.0162966345789853 +"2899",23.045712295823,13.4210526315789,19.7368421052632,0.0141095039039987 +"2900",30,13.4210526315789,19.7368421052632,0.0122159025792943 +"2901",0.2,15.5263157894737,19.7368421052632,0.0917389665783843 +"2902",0.260352117694686,15.5263157894737,19.7368421052632,0.0917383753534115 +"2903",0.338916125940539,15.5263157894737,19.7368421052632,0.0917347593501119 +"2904",0.441187655547492,15.5263157894737,19.7368421052632,0.0917126785696749 +"2905",0.574320702112717,15.5263157894737,19.7368421052632,0.0915791367846989 +"2906",0.747628055154725,15.5263157894737,19.7368421052632,0.090815194388871 +"2907",0.973232737037462,15.5263157894737,19.7368421052632,0.0874325001794466 +"2908",1.2669160204875,15.5263157894737,19.7368421052632,0.0794686235800172 +"2909",1.64922134437622,15.5263157894737,19.7368421052632,0.0696187672928633 +"2910",2.14689134777813,15.5263157894737,19.7368421052632,0.0604023118983962 +"2911",2.79473854427218,15.5263157894737,19.7368421052632,0.0523141291530385 +"2912",3.63808049202114,15.5263157894737,19.7368421052632,0.0452957716922543 +"2913",4.73590980220715,15.5263157894737,19.7368421052632,0.0392171060334291 +"2914",6.16502073107827,15.5263157894737,19.7368421052632,0.0339539279759105 +"2915",8.02538101483936,15.5263157894737,19.7368421052632,0.0293970633427887 +"2916",10.4471247126008,15.5263157894737,19.7368421052632,0.0254517578376537 +"2917",13.5996552137305,15.5263157894737,19.7368421052632,0.022035941050744 +"2918",17.7034951740616,15.5263157894737,19.7368421052632,0.0190785523882695 +"2919",23.045712295823,15.5263157894737,19.7368421052632,0.0165180674635765 +"2920",30,15.5263157894737,19.7368421052632,0.0143012188313775 +"2921",0.2,17.6315789473684,19.7368421052632,0.103007774009361 +"2922",0.260352117694686,17.6315789473684,19.7368421052632,0.103007110160937 +"2923",0.338916125940539,17.6315789473684,19.7368421052632,0.103003049983843 +"2924",0.441187655547492,17.6315789473684,19.7368421052632,0.102978256898353 +"2925",0.574320702112717,17.6315789473684,19.7368421052632,0.102828311433294 +"2926",0.747628055154725,17.6315789473684,19.7368421052632,0.101970529744655 +"2927",0.973232737037462,17.6315789473684,19.7368421052632,0.0981723203941118 +"2928",1.2669160204875,17.6315789473684,19.7368421052632,0.0892301965443567 +"2929",1.64922134437622,17.6315789473684,19.7368421052632,0.0781704276337824 +"2930",2.14689134777813,17.6315789473684,19.7368421052632,0.0678218637699257 +"2931",2.79473854427218,17.6315789473684,19.7368421052632,0.0587401645590635 +"2932",3.63808049202114,17.6315789473684,19.7368421052632,0.0508597032218446 +"2933",4.73590980220715,17.6315789473684,19.7368421052632,0.0440343612563045 +"2934",6.16502073107827,17.6315789473684,19.7368421052632,0.0381246777691172 +"2935",8.02538101483936,17.6315789473684,19.7368421052632,0.0330080681120987 +"2936",10.4471247126008,17.6315789473684,19.7368421052632,0.0285781387916763 +"2937",13.5996552137305,17.6315789473684,19.7368421052632,0.0247427382332588 +"2938",17.7034951740616,17.6315789473684,19.7368421052632,0.0214220770751485 +"2939",23.045712295823,17.6315789473684,19.7368421052632,0.018547073548138 +"2940",30,17.6315789473684,19.7368421052632,0.0160579170704116 +"2941",0.2,19.7368421052632,19.7368421052632,0.109843838742165 +"2942",0.260352117694686,19.7368421052632,19.7368421052632,0.109843130837738 +"2943",0.338916125940539,19.7368421052632,19.7368421052632,0.109838801208812 +"2944",0.441187655547492,19.7368421052632,19.7368421052632,0.10981236274132 +"2945",0.574320702112717,19.7368421052632,19.7368421052632,0.109652466212709 +"2946",0.747628055154725,19.7368421052632,19.7368421052632,0.108737758226938 +"2947",0.973232737037462,19.7368421052632,19.7368421052632,0.104687482415987 +"2948",1.2669160204875,19.7368421052632,19.7368421052632,0.0951519185266472 +"2949",1.64922134437622,19.7368421052632,19.7368421052632,0.0833581730115918 +"2950",2.14689134777813,19.7368421052632,19.7368421052632,0.0723228313472708 +"2951",2.79473854427218,19.7368421052632,19.7368421052632,0.0626384292405702 +"2952",3.63808049202114,19.7368421052632,19.7368421052632,0.0542349846203547 +"2953",4.73590980220715,19.7368421052632,19.7368421052632,0.0469566818957974 +"2954",6.16502073107827,19.7368421052632,19.7368421052632,0.0406548049139218 +"2955",8.02538101483936,19.7368421052632,19.7368421052632,0.0351986337513348 +"2956",10.4471247126008,19.7368421052632,19.7368421052632,0.0304747141579705 +"2957",13.5996552137305,19.7368421052632,19.7368421052632,0.0263847789613111 +"2958",17.7034951740616,19.7368421052632,19.7368421052632,0.022843743614448 +"2959",23.045712295823,19.7368421052632,19.7368421052632,0.0197779417675369 +"2960",30,19.7368421052632,19.7368421052632,0.0171235935363195 +"2961",0.2,21.8421052631579,19.7368421052632,0.110536034659287 +"2962",0.260352117694686,21.8421052631579,19.7368421052632,0.110535322293904 +"2963",0.338916125940539,21.8421052631579,19.7368421052632,0.110530965381231 +"2964",0.441187655547492,21.8421052631579,19.7368421052632,0.110504360308134 +"2965",0.574320702112717,21.8421052631579,19.7368421052632,0.11034345616976 +"2966",0.747628055154725,21.8421052631579,19.7368421052632,0.109422984026979 +"2967",0.973232737037462,21.8421052631579,19.7368421052632,0.105347184851116 +"2968",1.2669160204875,21.8421052631579,19.7368421052632,0.0957515313066144 +"2969",1.64922134437622,21.8421052631579,19.7368421052632,0.0838834658971838 +"2970",2.14689134777813,21.8421052631579,19.7368421052632,0.0727785835236927 +"2971",2.79473854427218,21.8421052631579,19.7368421052632,0.0630331538375231 +"2972",3.63808049202114,21.8421052631579,19.7368421052632,0.0545767537659824 +"2973",4.73590980220715,21.8421052631579,19.7368421052632,0.047252585825067 +"2974",6.16502073107827,21.8421052631579,19.7368421052632,0.0409109967066983 +"2975",8.02538101483936,21.8421052631579,19.7368421052632,0.035420442738074 +"2976",10.4471247126008,21.8421052631579,19.7368421052632,0.0306667547217123 +"2977",13.5996552137305,21.8421052631579,19.7368421052632,0.0265510462411178 +"2978",17.7034951740616,21.8421052631579,19.7368421052632,0.022987696577516 +"2979",23.045712295823,21.8421052631579,19.7368421052632,0.0199025751625214 +"2980",30,21.8421052631579,19.7368421052632,0.0172315001942443 +"2981",0.2,23.9473684210526,19.7368421052632,0.104934085844921 +"2982",0.260352117694686,23.9473684210526,19.7368421052632,0.104933409582103 +"2983",0.338916125940539,23.9473684210526,19.7368421052632,0.104929273477078 +"2984",0.441187655547492,23.9473684210526,19.7368421052632,0.104904016744892 +"2985",0.574320702112717,23.9473684210526,19.7368421052632,0.10475126720289 +"2986",0.747628055154725,23.9473684210526,19.7368421052632,0.103877444443224 +"2987",0.973232737037462,23.9473684210526,19.7368421052632,0.100008206127186 +"2988",1.2669160204875,23.9473684210526,19.7368421052632,0.090898858791898 +"2989",1.64922134437622,23.9473684210526,19.7368421052632,0.079632265066829 +"2990",2.14689134777813,23.9473684210526,19.7368421052632,0.0690901763817275 +"2991",2.79473854427218,23.9473684210526,19.7368421052632,0.0598386435360245 +"2992",3.63808049202114,23.9473684210526,19.7368421052632,0.0518108124872519 +"2993",4.73590980220715,23.9473684210526,19.7368421052632,0.0448578322231813 +"2994",6.16502073107827,23.9473684210526,19.7368421052632,0.0388376338418003 +"2995",8.02538101483936,23.9473684210526,19.7368421052632,0.0336253402829108 +"2996",10.4471247126008,23.9473684210526,19.7368421052632,0.0291125684259645 +"2997",13.5996552137305,23.9473684210526,19.7368421052632,0.0252054434024681 +"2998",17.7034951740616,23.9473684210526,19.7368421052632,0.0218226837381793 +"2999",23.045712295823,23.9473684210526,19.7368421052632,0.0188939157902344 +"3000",30,23.9473684210526,19.7368421052632,0.0163582104803474 +"3001",0.2,26.0526315789474,19.7368421052632,0.0945448816519 +"3002",0.260352117694686,26.0526315789474,19.7368421052632,0.0945442723438036 +"3003",0.338916125940539,26.0526315789474,19.7368421052632,0.0945405457419379 +"3004",0.441187655547492,26.0526315789474,19.7368421052632,0.0945177896018693 +"3005",0.574320702112717,26.0526315789474,19.7368421052632,0.094380163326721 +"3006",0.747628055154725,26.0526315789474,19.7368421052632,0.0935928550966822 +"3007",0.973232737037462,26.0526315789474,19.7368421052632,0.0901066982799784 +"3008",1.2669160204875,26.0526315789474,19.7368421052632,0.081899239675787 +"3009",1.64922134437622,26.0526315789474,19.7368421052632,0.0717481170755395 +"3010",2.14689134777813,26.0526315789474,19.7368421052632,0.0622497684782138 +"3011",2.79473854427218,26.0526315789474,19.7368421052632,0.0539142017178731 +"3012",3.63808049202114,26.0526315789474,19.7368421052632,0.0466811817671457 +"3013",4.73590980220715,26.0526315789474,19.7368421052632,0.0404165948990993 +"3014",6.16502073107827,26.0526315789474,19.7368421052632,0.0349924380209443 +"3015",8.02538101483936,26.0526315789474,19.7368421052632,0.030296197769817 +"3016",10.4471247126008,26.0526315789474,19.7368421052632,0.0262302217077816 +"3017",13.5996552137305,26.0526315789474,19.7368421052632,0.0227099292311161 +"3018",17.7034951740616,26.0526315789474,19.7368421052632,0.0196620862967462 +"3019",23.045712295823,26.0526315789474,19.7368421052632,0.0170232867418185 +"3020",30,26.0526315789474,19.7368421052632,0.0147386338904879 +"3021",0.2,28.1578947368421,19.7368421052632,0.0816762812329656 +"3022",0.260352117694686,28.1578947368421,19.7368421052632,0.0816757548584166 +"3023",0.338916125940539,28.1578947368421,19.7368421052632,0.0816725354881375 +"3024",0.441187655547492,28.1578947368421,19.7368421052632,0.081652876709539 +"3025",0.574320702112717,28.1578947368421,19.7368421052632,0.081533982887286 +"3026",0.747628055154725,28.1578947368421,19.7368421052632,0.0808538359846706 +"3027",0.973232737037462,28.1578947368421,19.7368421052632,0.0778421835333864 +"3028",1.2669160204875,28.1578947368421,19.7368421052632,0.0707518505037042 +"3029",1.64922134437622,28.1578947368421,19.7368421052632,0.0619824075699157 +"3030",2.14689134777813,28.1578947368421,19.7368421052632,0.0537768889027047 +"3031",2.79473854427218,28.1578947368421,19.7368421052632,0.0465758846488688 +"3032",3.63808049202114,28.1578947368421,19.7368421052632,0.0403273584321416 +"3033",4.73590980220715,28.1578947368421,19.7368421052632,0.0349154508819604 +"3034",6.16502073107827,28.1578947368421,19.7368421052632,0.03022958153725 +"3035",8.02538101483936,28.1578947368421,19.7368421052632,0.0261725513438981 +"3036",10.4471247126008,28.1578947368421,19.7368421052632,0.0226599994370478 +"3037",13.5996552137305,28.1578947368421,19.7368421052632,0.0196188575653488 +"3038",17.7034951740616,28.1578947368421,19.7368421052632,0.0169858596461378 +"3039",23.045712295823,28.1578947368421,19.7368421052632,0.0147062297941566 +"3040",30,28.1578947368421,19.7368421052632,0.0127325433761862 +"3041",0.2,30.2631578947368,19.7368421052632,0.0684178816261654 +"3042",0.260352117694686,30.2631578947368,19.7368421052632,0.0684174406972808 +"3043",0.338916125940539,30.2631578947368,19.7368421052632,0.068414743922999 +"3044",0.441187655547492,30.2631578947368,19.7368421052632,0.0683982763271833 +"3045",0.574320702112717,30.2631578947368,19.7368421052632,0.0682986823773341 +"3046",0.747628055154725,30.2631578947368,19.7368421052632,0.0677289427960373 +"3047",0.973232737037462,30.2631578947368,19.7368421052632,0.0652061677896264 +"3048",1.2669160204875,30.2631578947368,19.7368421052632,0.059266798873806 +"3049",1.64922134437622,30.2631578947368,19.7368421052632,0.0519208876800775 +"3050",2.14689134777813,30.2631578947368,19.7368421052632,0.0450473596939877 +"3051",2.79473854427218,30.2631578947368,19.7368421052632,0.0390152846632551 +"3052",3.63808049202114,30.2631578947368,19.7368421052632,0.0337810732057741 +"3053",4.73590980220715,30.2631578947368,19.7368421052632,0.0292476732449713 +"3054",6.16502073107827,30.2631578947368,19.7368421052632,0.0253224546955661 +"3055",8.02538101483936,30.2631578947368,19.7368421052632,0.0219239966936547 +"3056",10.4471247126008,30.2631578947368,19.7368421052632,0.0189816325587945 +"3057",13.5996552137305,30.2631578947368,19.7368421052632,0.0164341551094625 +"3058",17.7034951740616,30.2631578947368,19.7368421052632,0.0142285681601168 +"3059",23.045712295823,30.2631578947368,19.7368421052632,0.012318987520427 +"3060",30,30.2631578947368,19.7368421052632,0.0106656869333606 +"3061",0.2,32.3684210526316,19.7368421052632,0.0561293064940038 +"3062",0.260352117694686,32.3684210526316,19.7368421052632,0.0561289447606102 +"3063",0.338916125940539,32.3684210526316,19.7368421052632,0.0561267323555106 +"3064",0.441187655547492,32.3684210526316,19.7368421052632,0.0561132225140659 +"3065",0.574320702112717,32.3684210526316,19.7368421052632,0.0560315166909218 +"3066",0.747628055154725,32.3684210526316,19.7368421052632,0.05556410836403 +"3067",0.973232737037462,32.3684210526316,19.7368421052632,0.053494450429808 +"3068",1.2669160204875,32.3684210526316,19.7368421052632,0.0486218549864327 +"3069",1.64922134437622,32.3684210526316,19.7368421052632,0.0425953471339471 +"3070",2.14689134777813,32.3684210526316,19.7368421052632,0.0369563774690517 +"3071",2.79473854427218,32.3684210526316,19.7368421052632,0.0320077269094686 +"3072",3.63808049202114,32.3684210526316,19.7368421052632,0.0277136351871224 +"3073",4.73590980220715,32.3684210526316,19.7368421052632,0.0239944818048217 +"3074",6.16502073107827,32.3684210526316,19.7368421052632,0.0207742740202641 +"3075",8.02538101483936,32.3684210526316,19.7368421052632,0.0179862150178157 +"3076",10.4471247126008,32.3684210526316,19.7368421052632,0.0155723306002167 +"3077",13.5996552137305,32.3684210526316,19.7368421052632,0.0134824070430769 +"3078",17.7034951740616,32.3684210526316,19.7368421052632,0.0116729668362692 +"3079",23.045712295823,32.3684210526316,19.7368421052632,0.0101063670753206 +"3080",30,32.3684210526316,19.7368421052632,0.00875001675910906 +"3081",0.2,34.4736842105263,19.7368421052632,0.0454487569742761 +"3082",0.260352117694686,34.4736842105263,19.7368421052632,0.045448464073221 +"3083",0.338916125940539,34.4736842105263,19.7368421052632,0.0454466726550122 +"3084",0.441187655547492,34.4736842105263,19.7368421052632,0.0454357335300001 +"3085",0.574320702112717,34.4736842105263,19.7368421052632,0.0453695750767533 +"3086",0.747628055154725,34.4736842105263,19.7368421052632,0.0449911074137165 +"3087",0.973232737037462,34.4736842105263,19.7368421052632,0.0433152737655245 +"3088",1.2669160204875,34.4736842105263,19.7368421052632,0.0393698587947625 +"3089",1.64922134437622,34.4736842105263,19.7368421052632,0.0344901033176403 +"3090",2.14689134777813,34.4736842105263,19.7368421052632,0.0299241434315597 +"3091",2.79473854427218,34.4736842105263,19.7368421052632,0.025917145471285 +"3092",3.63808049202114,34.4736842105263,19.7368421052632,0.022440153801434 +"3093",4.73590980220715,34.4736842105263,19.7368421052632,0.0194286984890421 +"3094",6.16502073107827,34.4736842105263,19.7368421052632,0.0168212470497006 +"3095",8.02538101483936,34.4736842105263,19.7368421052632,0.0145637130813136 +"3096",10.4471247126008,34.4736842105263,19.7368421052632,0.0126091539906686 +"3097",13.5996552137305,34.4736842105263,19.7368421052632,0.0109169109579954 +"3098",17.7034951740616,34.4736842105263,19.7368421052632,0.00945177957912338 +"3099",23.045712295823,34.4736842105263,19.7368421052632,0.00818327981921776 +"3100",30,34.4736842105263,19.7368421052632,0.00708502224676647 +"3101",0.2,36.5789473684211,19.7368421052632,0.0365233760195092 +"3102",0.260352117694686,36.5789473684211,19.7368421052632,0.0365231406393561 +"3103",0.338916125940539,36.5789473684211,19.7368421052632,0.0365217010259277 +"3104",0.441187655547492,36.5789473684211,19.7368421052632,0.0365129101633664 +"3105",0.574320702112717,36.5789473684211,19.7368421052632,0.0364597441314291 +"3106",0.747628055154725,36.5789473684211,19.7368421052632,0.0361556012309723 +"3107",0.973232737037462,36.5789473684211,19.7368421052632,0.0348088734752779 +"3108",1.2669160204875,36.5789473684211,19.7368421052632,0.031638272470465 +"3109",1.64922134437622,36.5789473684211,19.7368421052632,0.0277168199151163 +"3110",2.14689134777813,36.5789473684211,19.7368421052632,0.0240475387089503 +"3111",2.79473854427218,36.5789473684211,19.7368421052632,0.0208274485908564 +"3112",3.63808049202114,36.5789473684211,19.7368421052632,0.0180332803312812 +"3113",4.73590980220715,36.5789473684211,19.7368421052632,0.015613224821233 +"3114",6.16502073107827,36.5789473684211,19.7368421052632,0.0135178335341714 +"3115",8.02538101483936,36.5789473684211,19.7368421052632,0.0117036417389836 +"3116",10.4471247126008,36.5789473684211,19.7368421052632,0.0101329255880363 +"3117",13.5996552137305,36.5789473684211,19.7368421052632,0.00877301097840899 +"3118",17.7034951740616,36.5789473684211,19.7368421052632,0.0075956070661565 +"3119",23.045712295823,36.5789473684211,19.7368421052632,0.00657621958900476 +"3120",30,36.5789473684211,19.7368421052632,0.00569364156145573 +"3121",0.2,38.6842105263158,19.7368421052632,0.0292391022711075 +"3122",0.260352117694686,38.6842105263158,19.7368421052632,0.0292389138355049 +"3123",0.338916125940539,38.6842105263158,19.7368421052632,0.0292377613406139 +"3124",0.441187655547492,38.6842105263158,19.7368421052632,0.0292307237401099 +"3125",0.574320702112717,38.6842105263158,19.7368421052632,0.029188161216746 +"3126",0.747628055154725,38.6842105263158,19.7368421052632,0.0289446770063395 +"3127",0.973232737037462,38.6842105263158,19.7368421052632,0.0278665425381826 +"3128",1.2669160204875,38.6842105263158,19.7368421052632,0.0253282906802196 +"3129",1.64922134437622,38.6842105263158,19.7368421052632,0.0221889381664791 +"3130",2.14689134777813,38.6842105263158,19.7368421052632,0.019251463591532 +"3131",2.79473854427218,38.6842105263158,19.7368421052632,0.0166735927990062 +"3132",3.63808049202114,38.6842105263158,19.7368421052632,0.0144366974073874 +"3133",4.73590980220715,38.6842105263158,19.7368421052632,0.0124993011896264 +"3134",6.16502073107827,38.6842105263158,19.7368421052632,0.0108218177032243 +"3135",8.02538101483936,38.6842105263158,19.7368421052632,0.0093694508844898 +"3136",10.4471247126008,38.6842105263158,19.7368421052632,0.00811200058329373 +"3137",13.5996552137305,38.6842105263158,19.7368421052632,0.00702330926599529 +"3138",17.7034951740616,38.6842105263158,19.7368421052632,0.006080728454562 +"3139",23.045712295823,38.6842105263158,19.7368421052632,0.00526464905701657 +"3140",30,38.6842105263158,19.7368421052632,0.00455809363903018 +"3141",0.2,40.7894736842105,19.7368421052632,0.0233757819365125 +"3142",0.260352117694686,40.7894736842105,19.7368421052632,0.0233756312879217 +"3143",0.338916125940539,40.7894736842105,19.7368421052632,0.0233747099029556 +"3144",0.441187655547492,40.7894736842105,19.7368421052632,0.0233690835532403 +"3145",0.574320702112717,40.7894736842105,19.7368421052632,0.0233350560972809 +"3146",0.747628055154725,40.7894736842105,19.7368421052632,0.0231403978018697 +"3147",0.973232737037462,40.7894736842105,19.7368421052632,0.02227846175499 +"3148",1.2669160204875,40.7894736842105,19.7368421052632,0.0202492058160919 +"3149",1.64922134437622,40.7894736842105,19.7368421052632,0.0177393880008044 +"3150",2.14689134777813,40.7894736842105,19.7368421052632,0.0153909655194526 +"3151",2.79473854427218,40.7894736842105,19.7368421052632,0.0133300354352162 +"3152",3.63808049202114,40.7894736842105,19.7368421052632,0.011541704917937 +"3153",4.73590980220715,40.7894736842105,19.7368421052632,0.00999281497285288 +"3154",6.16502073107827,40.7894736842105,19.7368421052632,0.00865171743105236 +"3155",8.02538101483936,40.7894736842105,19.7368421052632,0.00749059388725215 +"3156",10.4471247126008,40.7894736842105,19.7368421052632,0.00648530023068846 +"3157",13.5996552137305,40.7894736842105,19.7368421052632,0.00561492430076498 +"3158",17.7034951740616,40.7894736842105,19.7368421052632,0.00486135932119383 +"3159",23.045712295823,40.7894736842105,19.7368421052632,0.00420892841332863 +"3160",30,40.7894736842105,19.7368421052632,0.00364405862957908 +"3161",0.2,42.8947368421053,19.7368421052632,0.0186921039115616 +"3162",0.260352117694686,42.8947368421053,19.7368421052632,0.0186919834476079 +"3163",0.338916125940539,42.8947368421053,19.7368421052632,0.0186912466755257 +"3164",0.441187655547492,42.8947368421053,19.7368421052632,0.0186867476468384 +"3165",0.574320702112717,42.8947368421053,19.7368421052632,0.0186595380867746 +"3166",0.747628055154725,42.8947368421053,19.7368421052632,0.0185038824130968 +"3167",0.973232737037462,42.8947368421053,19.7368421052632,0.0178146477942441 +"3168",1.2669160204875,42.8947368421053,19.7368421052632,0.0161919828080607 +"3169",1.64922134437622,42.8947368421053,19.7368421052632,0.0141850435095227 +"3170",2.14689134777813,42.8947368421053,19.7368421052632,0.0123071616414895 +"3171",2.79473854427218,42.8947368421053,19.7368421052632,0.0106591688858402 +"3172",3.63808049202114,42.8947368421053,19.7368421052632,0.00922915640762714 +"3173",4.73590980220715,42.8947368421053,19.7368421052632,0.00799060909914706 +"3174",6.16502073107827,42.8947368421053,19.7368421052632,0.00691821996260573 +"3175",8.02538101483936,42.8947368421053,19.7368421052632,0.00598974441497183 +"3176",10.4471247126008,42.8947368421053,19.7368421052632,0.00518587596936613 +"3177",13.5996552137305,42.8947368421053,19.7368421052632,0.00448989252083645 +"3178",17.7034951740616,42.8947368421053,19.7368421052632,0.00388731524917496 +"3179",23.045712295823,42.8947368421053,19.7368421052632,0.0033656083664682 +"3180",30,42.8947368421053,19.7368421052632,0.00291391846265987 +"3181",0.2,45,19.7368421052632,0.0149647094668531 +"3182",0.260352117694686,45,19.7368421052632,0.0149646130246292 +"3183",0.338916125940539,45,19.7368421052632,0.014964023172347 +"3184",0.441187655547492,45,19.7368421052632,0.0149604212954525 +"3185",0.574320702112717,45,19.7368421052632,0.0149386375966777 +"3186",0.747628055154725,45,19.7368421052632,0.0148140212375736 +"3187",0.973232737037462,45,19.7368421052632,0.0142622269679489 +"3188",1.2669160204875,45,19.7368421052632,0.0129631377806023 +"3189",1.64922134437622,45,19.7368421052632,0.01135640246272 +"3190",2.14689134777813,45,19.7368421052632,0.00985298921929126 +"3191",2.79473854427218,45,19.7368421052632,0.00853362287570295 +"3192",3.63808049202114,45,19.7368421052632,0.00738876933906083 +"3193",4.73590980220715,45,19.7368421052632,0.00639720088213111 +"3194",6.16502073107827,45,19.7368421052632,0.00553865697826246 +"3195",8.02538101483936,45,19.7368421052632,0.00479532883911037 +"3196",10.4471247126008,45,19.7368421052632,0.00415175988641375 +"3197",13.5996552137305,45,19.7368421052632,0.00359456257196147 +"3198",17.7034951740616,45,19.7368421052632,0.0031121452986354 +"3199",23.045712295823,45,19.7368421052632,0.00269447204133367 +"3200",30,45,19.7368421052632,0.00233285366966276 +"3201",0.2,5,21.8421052631579,0.0320836763908571 +"3202",0.260352117694686,5,21.8421052631579,0.0320834696229872 +"3203",0.338916125940539,5,21.8421052631579,0.0320822050057366 +"3204",0.441187655547492,5,21.8421052631579,0.0320744827407011 +"3205",0.574320702112717,5,21.8421052631579,0.0320277794522989 +"3206",0.747628055154725,5,21.8421052631579,0.0317606074803097 +"3207",0.973232737037462,5,21.8421052631579,0.0305775849284732 +"3208",1.2669160204875,5,21.8421052631579,0.0277923950668184 +"3209",1.64922134437622,5,21.8421052631579,0.0243476254841626 +"3210",2.14689134777813,5,21.8421052631579,0.0211243738673679 +"3211",2.79473854427218,5,21.8421052631579,0.0182957106779865 +"3212",3.63808049202114,5,21.8421052631579,0.0158411952417921 +"3213",4.73590980220715,5,21.8421052631579,0.01371531624882 +"3214",6.16502073107827,5,21.8421052631579,0.0118746360244509 +"3215",8.02538101483936,5,21.8421052631579,0.0102809733127492 +"3216",10.4471247126008,5,21.8421052631579,0.00890118989234556 +"3217",13.5996552137305,5,21.8421052631579,0.00770658345094827 +"3218",17.7034951740616,5,21.8421052631579,0.00667230211611603 +"3219",23.045712295823,5,21.8421052631579,0.00577682909313046 +"3220",30,5,21.8421052631579,0.00500153527006113 +"3221",0.2,7.10526315789474,21.8421052631579,0.0404630098878639 +"3222",0.260352117694686,7.10526315789474,21.8421052631579,0.0404627491181734 +"3223",0.338916125940539,7.10526315789474,21.8421052631579,0.0404611542192692 +"3224",0.441187655547492,7.10526315789474,21.8421052631579,0.0404514151207108 +"3225",0.574320702112717,7.10526315789474,21.8421052631579,0.040392514276637 +"3226",0.747628055154725,7.10526315789474,21.8421052631579,0.0400555646698444 +"3227",0.973232737037462,7.10526315789474,21.8421052631579,0.0385635706530314 +"3228",1.2669160204875,7.10526315789474,21.8421052631579,0.0350509693058917 +"3229",1.64922134437622,7.10526315789474,21.8421052631579,0.0307065249851612 +"3230",2.14689134777813,7.10526315789474,21.8421052631579,0.0266414527517745 +"3231",2.79473854427218,7.10526315789474,21.8421052631579,0.0230740240940663 +"3232",3.63808049202114,7.10526315789474,21.8421052631579,0.0199784598216082 +"3233",4.73590980220715,7.10526315789474,21.8421052631579,0.0172973623792481 +"3234",6.16502073107827,7.10526315789474,21.8421052631579,0.0149759494210915 +"3235",8.02538101483936,7.10526315789474,21.8421052631579,0.0129660678453041 +"3236",10.4471247126008,7.10526315789474,21.8421052631579,0.0112259246802019 +"3237",13.5996552137305,7.10526315789474,21.8421052631579,0.00971932139504534 +"3238",17.7034951740616,7.10526315789474,21.8421052631579,0.00841491552308996 +"3239",23.045712295823,7.10526315789474,21.8421052631579,0.00728557070169331 +"3240",30,7.10526315789474,21.8421052631579,0.00630779243069086 +"3241",0.2,9.21052631578947,21.8421052631579,0.0503673723081886 +"3242",0.260352117694686,9.21052631578947,21.8421052631579,0.050367047708409 +"3243",0.338916125940539,9.21052631578947,21.8421052631579,0.0503650624169756 +"3244",0.441187655547492,9.21052631578947,21.8421052631579,0.0503529394235454 +"3245",0.574320702112717,9.21052631578947,21.8421052631579,0.0502796210828942 +"3246",0.747628055154725,9.21052631578947,21.8421052631579,0.0498601943931483 +"3247",0.973232737037462,9.21052631578947,21.8421052631579,0.0480029964650982 +"3248",1.2669160204875,9.21052631578947,21.8421052631579,0.0436305955905233 +"3249",1.64922134437622,9.21052631578947,21.8421052631579,0.0382227367787136 +"3250",2.14689134777813,9.21052631578947,21.8421052631579,0.0331626335583628 +"3251",2.79473854427218,9.21052631578947,21.8421052631579,0.0287219849787429 +"3252",3.63808049202114,9.21052631578947,21.8421052631579,0.0248687017295008 +"3253",4.73590980220715,9.21052631578947,21.8421052631579,0.0215313367275367 +"3254",6.16502073107827,9.21052631578947,21.8421052631579,0.0186416982387401 +"3255",8.02538101483936,9.21052631578947,21.8421052631579,0.0161398464510555 +"3256",10.4471247126008,9.21052631578947,21.8421052631579,0.0139737584880209 +"3257",13.5996552137305,9.21052631578947,21.8421052631579,0.0120983752974348 +"3258",17.7034951740616,9.21052631578947,21.8421052631579,0.0104746825376564 +"3259",23.045712295823,9.21052631578947,21.8421052631579,0.0090689015233115 +"3260",30,9.21052631578947,21.8421052631579,0.00785178687101749 +"3261",0.2,11.3157894736842,21.8421052631579,0.0616469324407538 +"3262",0.260352117694686,11.3157894736842,21.8421052631579,0.0616465351482257 +"3263",0.338916125940539,11.3157894736842,21.8421052631579,0.0616441052591673 +"3264",0.441187655547492,11.3157894736842,21.8421052631579,0.0616292673726006 +"3265",0.574320702112717,11.3157894736842,21.8421052631579,0.0615395296994669 +"3266",0.747628055154725,11.3157894736842,21.8421052631579,0.0610261741754106 +"3267",0.973232737037462,11.3157894736842,21.8421052631579,0.0587530646214901 +"3268",1.2669160204875,11.3157894736842,21.8421052631579,0.0534014830525824 +"3269",1.64922134437622,11.3157894736842,21.8421052631579,0.0467825571181324 +"3270",2.14689134777813,11.3157894736842,21.8421052631579,0.0405892651699342 +"3271",2.79473854427218,11.3157894736842,21.8421052631579,0.0351541521109102 +"3272",3.63808049202114,11.3157894736842,21.8421052631579,0.0304379423652909 +"3273",4.73590980220715,11.3157894736842,21.8421052631579,0.0263531885777131 +"3274",6.16502073107827,11.3157894736842,21.8421052631579,0.0228164277634491 +"3275",8.02538101483936,11.3157894736842,21.8421052631579,0.0197542968428909 +"3276",10.4471247126008,11.3157894736842,21.8421052631579,0.0171031226362862 +"3277",13.5996552137305,11.3157894736842,21.8421052631579,0.0148077553071513 +"3278",17.7034951740616,11.3157894736842,21.8421052631579,0.0128204434169433 +"3279",23.045712295823,11.3157894736842,21.8421052631579,0.011099843686476 +"3280",30,11.3157894736842,21.8421052631579,0.00961016135237452 +"3281",0.2,13.4210526315789,21.8421052631579,0.0738372434292826 +"3282",0.260352117694686,13.4210526315789,21.8421052631579,0.0738367675745409 +"3283",0.338916125940539,13.4210526315789,21.8421052631579,0.0738338571895014 +"3284",0.441187655547492,13.4210526315789,21.8421052631579,0.0738160851998982 +"3285",0.574320702112717,13.4210526315789,21.8421052631579,0.0737086024403576 +"3286",0.747628055154725,13.4210526315789,21.8421052631579,0.0730937339417191 +"3287",0.973232737037462,13.4210526315789,21.8421052631579,0.0703711306129069 +"3288",1.2669160204875,13.4210526315789,21.8421052631579,0.0639613058999765 +"3289",1.64922134437622,13.4210526315789,21.8421052631579,0.0560335270776958 +"3290",2.14689134777813,13.4210526315789,21.8421052631579,0.0486155488085059 +"3291",2.79473854427218,13.4210526315789,21.8421052631579,0.0421056747545047 +"3292",3.63808049202114,13.4210526315789,21.8421052631579,0.0364568628304804 +"3293",4.73590980220715,13.4210526315789,21.8421052631579,0.0315643734912594 +"3294",6.16502073107827,13.4210526315789,21.8421052631579,0.0273282394476891 +"3295",8.02538101483936,13.4210526315789,21.8421052631579,0.0236605905113713 +"3296",10.4471247126008,13.4210526315789,21.8421052631579,0.0204851625133173 +"3297",13.5996552137305,13.4210526315789,21.8421052631579,0.017735900067796 +"3298",17.7034951740616,13.4210526315789,21.8421052631579,0.0153556091758166 +"3299",23.045712295823,13.4210526315789,21.8421052631579,0.013294771172807 +"3300",30,13.4210526315789,21.8421052631579,0.0115105130957151 +"3301",0.2,15.5263157894737,21.8421052631579,0.0860717259536223 +"3302",0.260352117694686,15.5263157894737,21.8421052631579,0.0860711712519973 +"3303",0.338916125940539,15.5263157894737,21.8421052631579,0.0860677786299016 +"3304",0.441187655547492,15.5263157894737,21.8421052631579,0.0860470619055532 +"3305",0.574320702112717,15.5263157894737,21.8421052631579,0.0859217697603666 +"3306",0.747628055154725,15.5263157894737,21.8421052631579,0.0852050204553493 +"3307",0.973232737037462,15.5263157894737,21.8421052631579,0.0820312946130191 +"3308",1.2669160204875,15.5263157894737,21.8421052631579,0.0745593922168997 +"3309",1.64922134437622,15.5263157894737,21.8421052631579,0.0653180178843679 +"3310",2.14689134777813,15.5263157894737,21.8421052631579,0.0566709156489339 +"3311",2.79473854427218,15.5263157894737,21.8421052631579,0.0490823862084324 +"3312",3.63808049202114,15.5263157894737,21.8421052631579,0.0424975928262982 +"3313",4.73590980220715,15.5263157894737,21.8421052631579,0.0367944411093769 +"3314",6.16502073107827,15.5263157894737,21.8421052631579,0.0318563996608198 +"3315",8.02538101483936,15.5263157894737,21.8421052631579,0.0275810386169967 +"3316",10.4471247126008,15.5263157894737,21.8421052631579,0.0238794571962909 +"3317",13.5996552137305,15.5263157894737,21.8421052631579,0.0206746549475162 +"3318",17.7034951740616,15.5263157894737,21.8421052631579,0.0178999610961595 +"3319",23.045712295823,15.5263157894737,21.8421052631579,0.0154976519687916 +"3320",30,15.5263157894737,21.8421052631579,0.0134177507548591 +"3321",0.2,17.6315789473684,21.8421052631579,0.0971087000861452 +"3322",0.260352117694686,17.6315789473684,21.8421052631579,0.097108074255152 +"3323",0.338916125940539,17.6315789473684,21.8421052631579,0.0971042465972545 +"3324",0.441187655547492,17.6315789473684,21.8421052631579,0.0970808733681338 +"3325",0.574320702112717,17.6315789473684,21.8421052631579,0.096939515015954 +"3326",0.747628055154725,17.6315789473684,21.8421052631579,0.0961308569749223 +"3327",0.973232737037462,17.6315789473684,21.8421052631579,0.0925501643890138 +"3328",1.2669160204875,17.6315789473684,21.8421052631579,0.0841201402339425 +"3329",1.64922134437622,17.6315789473684,21.8421052631579,0.0736937448236171 +"3330",2.14689134777813,17.6315789473684,21.8421052631579,0.0639378249987091 +"3331",2.79473854427218,17.6315789473684,21.8421052631579,0.0553762187178079 +"3332",3.63808049202114,17.6315789473684,21.8421052631579,0.0479470575317123 +"3333",4.73590980220715,17.6315789473684,21.8421052631579,0.0415125908878959 +"3334",6.16502073107827,17.6315789473684,21.8421052631579,0.0359413445729414 +"3335",8.02538101483936,17.6315789473684,21.8421052631579,0.0311177541457166 +"3336",10.4471247126008,17.6315789473684,21.8421052631579,0.0269415190807727 +"3337",13.5996552137305,17.6315789473684,21.8421052631579,0.0233257651620078 +"3338",17.7034951740616,17.6315789473684,21.8421052631579,0.0201952724240389 +"3339",23.045712295823,17.6315789473684,21.8421052631579,0.0174849152889968 +"3340",30,17.6315789473684,21.8421052631579,0.0151383084218195 +"3341",0.2,19.7368421052632,21.8421052631579,0.10555600402663 +"3342",0.260352117694686,19.7368421052632,21.8421052631579,0.105555323755771 +"3343",0.338916125940539,19.7368421052632,21.8421052631579,0.105551163137082 +"3344",0.441187655547492,19.7368421052632,21.8421052631579,0.105525756714537 +"3345",0.574320702112717,19.7368421052632,21.8421052631579,0.105372101864059 +"3346",0.747628055154725,19.7368421052632,21.8421052631579,0.104493100174616 +"3347",0.973232737037462,19.7368421052632,21.8421052631579,0.100600929847127 +"3348",1.2669160204875,19.7368421052632,21.8421052631579,0.0914375936798437 +"3349",1.64922134437622,19.7368421052632,21.8421052631579,0.0801042256609202 +"3350",2.14689134777813,19.7368421052632,21.8421052631579,0.0694996566428205 +"3351",2.79473854427218,19.7368421052632,21.8421052631579,0.0601932922670279 +"3352",3.63808049202114,19.7368421052632,21.8421052631579,0.0521178822638218 +"3353",4.73590980220715,19.7368421052632,21.8421052631579,0.0451236934181119 +"3354",6.16502073107827,19.7368421052632,21.8421052631579,0.0390678148209008 +"3355",8.02538101483936,19.7368421052632,21.8421052631579,0.0338246292967688 +"3356",10.4471247126008,19.7368421052632,21.8421052631579,0.0292851113654163 +"3357",13.5996552137305,19.7368421052632,21.8421052631579,0.0253548297853944 +"3358",17.7034951740616,19.7368421052632,21.8421052631579,0.0219520213474146 +"3359",23.045712295823,19.7368421052632,21.8421052631579,0.0190058953215662 +"3360",30,19.7368421052632,21.8421052631579,0.0164551615180969 +"3361",0.2,21.8421052631579,21.8421052631579,0.110273049710927 +"3362",0.260352117694686,21.8421052631579,21.8421052631579,0.110272339040388 +"3363",0.338916125940539,21.8421052631579,21.8421052631579,0.110267992493588 +"3364",0.441187655547492,21.8421052631579,21.8421052631579,0.110241450718707 +"3365",0.574320702112717,21.8421052631579,21.8421052631579,0.110080929399987 +"3366",0.747628055154725,21.8421052631579,21.8421052631579,0.109162647224665 +"3367",0.973232737037462,21.8421052631579,21.8421052631579,0.105096545102248 +"3368",1.2669160204875,21.8421052631579,21.8421052631579,0.0955237213295905 +"3369",1.64922134437622,21.8421052631579,21.8421052631579,0.0836838921652762 +"3370",2.14689134777813,21.8421052631579,21.8421052631579,0.0726054302882914 +"3371",2.79473854427218,21.8421052631579,21.8421052631579,0.0628831867181306 +"3372",3.63808049202114,21.8421052631579,21.8421052631579,0.0544469059311561 +"3373",4.73590980220715,21.8421052631579,21.8421052631579,0.0471401634925545 +"3374",6.16502073107827,21.8421052631579,21.8421052631579,0.0408136621461685 +"3375",8.02538101483936,21.8421052631579,21.8421052631579,0.0353361711850636 +"3376",10.4471247126008,21.8421052631579,21.8421052631579,0.0305937930406486 +"3377",13.5996552137305,21.8421052631579,21.8421052631579,0.0264878765648566 +"3378",17.7034951740616,21.8421052631579,21.8421052631579,0.0229330047458795 +"3379",23.045712295823,21.8421052631579,21.8421052631579,0.0198552233851804 +"3380",30,21.8421052631579,21.8421052631579,0.0171905033808276 +"3381",0.2,23.9473684210526,21.8421052631579,0.11076433532131 +"3382",0.260352117694686,23.9473684210526,21.8421052631579,0.11076362148461 +"3383",0.338916125940539,23.9473684210526,21.8421052631579,0.110759255573188 +"3384",0.441187655547492,23.9473684210526,21.8421052631579,0.110732595550085 +"3385",0.574320702112717,23.9473684210526,21.8421052631579,0.110571359080979 +"3386",0.747628055154725,23.9473684210526,21.8421052631579,0.109648985798898 +"3387",0.973232737037462,23.9473684210526,21.8421052631579,0.105564768484525 +"3388",1.2669160204875,23.9473684210526,21.8421052631579,0.0959492961174687 +"3389",1.64922134437622,23.9473684210526,21.8421052631579,0.0840567184555562 +"3390",2.14689134777813,23.9473684210526,21.8421052631579,0.0729289001046225 +"3391",2.79473854427218,23.9473684210526,21.8421052631579,0.0631633422488844 +"3392",3.63808049202114,23.9473684210526,21.8421052631579,0.0546894763641308 +"3393",4.73590980220715,23.9473684210526,21.8421052631579,0.0473501811174926 +"3394",6.16502073107827,23.9473684210526,21.8421052631579,0.0409954941075769 +"3395",8.02538101483936,23.9473684210526,21.8421052631579,0.0354935999718319 +"3396",10.4471247126008,23.9473684210526,21.8421052631579,0.0307300937081942 +"3397",13.5996552137305,23.9473684210526,21.8421052631579,0.0266058846605792 +"3398",17.7034951740616,23.9473684210526,21.8421052631579,0.0230351752695389 +"3399",23.045712295823,23.9473684210526,21.8421052631579,0.0199436818577232 +"3400",30,23.9473684210526,21.8421052631579,0.0172670900624181 +"3401",0.2,26.0526315789474,21.8421052631579,0.107322137517437 +"3402",0.260352117694686,26.0526315789474,21.8421052631579,0.107321445864476 +"3403",0.338916125940539,26.0526315789474,21.8421052631579,0.107317215631481 +"3404",0.441187655547492,26.0526315789474,21.8421052631579,0.107291384115791 +"3405",0.574320702112717,26.0526315789474,21.8421052631579,0.107135158355396 +"3406",0.747628055154725,26.0526315789474,21.8421052631579,0.106241449455914 +"3407",0.973232737037462,26.0526315789474,21.8421052631579,0.102284156424788 +"3408",1.2669160204875,26.0526315789474,21.8421052631579,0.0929675018836063 +"3409",1.64922134437622,26.0526315789474,21.8421052631579,0.0814445071257168 +"3410",2.14689134777813,26.0526315789474,21.8421052631579,0.07066250542938 +"3411",2.79473854427218,26.0526315789474,21.8421052631579,0.0612004295717698 +"3412",3.63808049202114,26.0526315789474,21.8421052631579,0.0529899040704907 +"3413",4.73590980220715,26.0526315789474,21.8421052631579,0.0458786904162411 +"3414",6.16502073107827,26.0526315789474,21.8421052631579,0.0397214865547267 +"3415",8.02538101483936,26.0526315789474,21.8421052631579,0.0343905735191369 +"3416",10.4471247126008,26.0526315789474,21.8421052631579,0.0297751016453763 +"3417",13.5996552137305,26.0526315789474,21.8421052631579,0.0257790596949161 +"3418",17.7034951740616,26.0526315789474,21.8421052631579,0.0223193164193538 +"3419",23.045712295823,26.0526315789474,21.8421052631579,0.0193238966381158 +"3420",30,26.0526315789474,21.8421052631579,0.0167304846711637 +"3421",0.2,28.1578947368421,21.8421052631579,0.100839914858442 +"3422",0.260352117694686,28.1578947368421,21.8421052631579,0.100839264981098 +"3423",0.338916125940539,28.1578947368421,21.8421052631579,0.100835290252818 +"3424",0.441187655547492,28.1578947368421,21.8421052631579,0.100811018952384 +"3425",0.574320702112717,28.1578947368421,21.8421052631579,0.100664229177774 +"3426",0.747628055154725,28.1578947368421,21.8421052631579,0.0998245000089676 +"3427",0.973232737037462,28.1578947368421,21.8421052631579,0.0961062262067545 +"3428",1.2669160204875,28.1578947368421,21.8421052631579,0.0873522946095044 +"3429",1.64922134437622,28.1578947368421,21.8421052631579,0.0765252850364696 +"3430",2.14689134777813,28.1578947368421,21.8421052631579,0.0663945127819054 +"3431",2.79473854427218,28.1578947368421,21.8421052631579,0.0575039432690636 +"3432",3.63808049202114,28.1578947368421,21.8421052631579,0.0497893308727392 +"3433",4.73590980220715,28.1578947368421,21.8421052631579,0.0431076322407285 +"3434",6.16502073107827,28.1578947368421,21.8421052631579,0.0373223215161793 +"3435",8.02538101483936,28.1578947368421,21.8421052631579,0.0323133939168823 +"3436",10.4471247126008,28.1578947368421,21.8421052631579,0.0279766950628744 +"3437",13.5996552137305,28.1578947368421,21.8421052631579,0.0242220127636171 +"3438",17.7034951740616,28.1578947368421,21.8421052631579,0.0209712368714291 +"3439",23.045712295823,28.1578947368421,21.8421052631579,0.0181567394835416 +"3440",30,28.1578947368421,21.8421052631579,0.0157199687669891 +"3441",0.2,30.2631578947368,21.8421052631579,0.092448642616583 +"3442",0.260352117694686,30.2631578947368,21.8421052631579,0.0924480468180008 +"3443",0.338916125940539,30.2631578947368,21.8421052631579,0.0924444028419543 +"3444",0.441187655547492,30.2631578947368,21.8421052631579,0.092422151248597 +"3445",0.574320702112717,30.2631578947368,21.8421052631579,0.0922875764085472 +"3446",0.747628055154725,30.2631578947368,21.8421052631579,0.0915177242926395 +"3447",0.973232737037462,30.2631578947368,21.8421052631579,0.0881088621731708 +"3448",1.2669160204875,30.2631578947368,21.8421052631579,0.0800833784660468 +"3449",1.64922134437622,30.2631578947368,21.8421052631579,0.0701573254737478 +"3450",2.14689134777813,30.2631578947368,21.8421052631579,0.0608695732487785 +"3451",2.79473854427218,30.2631578947368,21.8421052631579,0.0527188217858841 +"3452",3.63808049202114,30.2631578947368,21.8421052631579,0.0456461715822971 +"3453",4.73590980220715,30.2631578947368,21.8421052631579,0.0395204824663393 +"3454",6.16502073107827,30.2631578947368,21.8421052631579,0.0342165894161464 +"3455",8.02538101483936,30.2631578947368,21.8421052631579,0.0296244737031393 +"3456",10.4471247126008,30.2631578947368,21.8421052631579,0.0256486480288244 +"3457",13.5996552137305,30.2631578947368,21.8421052631579,0.022206407101607 +"3458",17.7034951740616,30.2631578947368,21.8421052631579,0.0192261406158075 +"3459",23.045712295823,30.2631578947368,21.8421052631579,0.0166458482432546 +"3460",30,30.2631578947368,21.8421052631579,0.0144118504713469 +"3461",0.2,32.3684210526316,21.8421052631579,0.0831948044211494 +"3462",0.260352117694686,32.3684210526316,21.8421052631579,0.0831942682602593 +"3463",0.338916125940539,32.3684210526316,21.8421052631579,0.083190989035536 +"3464",0.441187655547492,32.3684210526316,21.8421052631579,0.0831709647614631 +"3465",0.574320702112717,32.3684210526316,21.8421052631579,0.0830498604685165 +"3466",0.747628055154725,32.3684210526316,21.8421052631579,0.0823570682932785 +"3467",0.973232737037462,32.3684210526316,21.8421052631579,0.079289423281939 +"3468",1.2669160204875,32.3684210526316,21.8421052631579,0.0720672669743727 +"3469",1.64922134437622,32.3684210526316,21.8421052631579,0.0631347827972588 +"3470",2.14689134777813,32.3684210526316,21.8421052631579,0.0547767073512727 +"3471",2.79473854427218,32.3684210526316,21.8421052631579,0.0474418222231781 +"3472",3.63808049202114,32.3684210526316,21.8421052631579,0.0410771235778237 +"3473",4.73590980220715,32.3684210526316,21.8421052631579,0.035564597990396 +"3474",6.16502073107827,32.3684210526316,21.8421052631579,0.03079160909091 +"3475",8.02538101483936,32.3684210526316,21.8421052631579,0.0266591507030961 +"3476",10.4471247126008,32.3684210526316,21.8421052631579,0.0230812935272041 +"3477",13.5996552137305,32.3684210526316,21.8421052631579,0.0199836108289515 +"3478",17.7034951740616,32.3684210526316,21.8421052631579,0.0173016602843957 +"3479",23.045712295823,32.3684210526316,21.8421052631579,0.0149796476165167 +"3480",30,32.3684210526316,21.8421052631579,0.0129692664746112 +"3481",0.2,34.4736842105263,21.8421052631579,0.0738721080076276 +"3482",0.260352117694686,34.4736842105263,21.8421052631579,0.0738716319281961 +"3483",0.338916125940539,34.4736842105263,21.8421052631579,0.0738687201689267 +"3484",0.441187655547492,34.4736842105263,21.8421052631579,0.0738509397877193 +"3485",0.574320702112717,34.4736842105263,21.8421052631579,0.073743406276811 +"3486",0.747628055154725,34.4736842105263,21.8421052631579,0.0731282474486592 +"3487",0.973232737037462,34.4736842105263,21.8421052631579,0.0704043585569976 +"3488",1.2669160204875,34.4736842105263,21.8421052631579,0.0639915072435942 +"3489",1.64922134437622,34.4736842105263,21.8421052631579,0.0560599850710337 +"3490",2.14689134777813,34.4736842105263,21.8421052631579,0.04863850416994 +"3491",2.79473854427218,34.4736842105263,21.8421052631579,0.0421255562740207 +"3492",3.63808049202114,34.4736842105263,21.8421052631579,0.0364740770856629 +"3493",4.73590980220715,34.4736842105263,21.8421052631579,0.0315792776036204 +"3494",6.16502073107827,34.4736842105263,21.8421052631579,0.0273411433360387 +"3495",8.02538101483936,34.4736842105263,21.8421052631579,0.0236717626038447 +"3496",10.4471247126008,34.4736842105263,21.8421052631579,0.020494835227522 +"3497",13.5996552137305,34.4736842105263,21.8421052631579,0.0177442746312103 +"3498",17.7034951740616,34.4736842105263,21.8421052631579,0.015362859809972 +"3499",23.045712295823,34.4736842105263,21.8421052631579,0.013301048717439 +"3500",30,34.4736842105263,21.8421052631579,0.0115159481467406 +"3501",0.2,36.5789473684211,21.8421052631579,0.064993499465389 +"3502",0.260352117694686,36.5789473684211,21.8421052631579,0.0649930806054281 +"3503",0.338916125940539,36.5789473684211,21.8421052631579,0.0649905188073472 +"3504",0.441187655547492,36.5789473684211,21.8421052631579,0.0649748754308731 +"3505",0.574320702112717,36.5789473684211,21.8421052631579,0.0648802662560137 +"3506",0.747628055154725,36.5789473684211,21.8421052631579,0.064339042700237 +"3507",0.973232737037462,36.5789473684211,21.8421052631579,0.0619425350602261 +"3508",1.2669160204875,36.5789473684211,21.8421052631579,0.0563004373910183 +"3509",1.64922134437622,36.5789473684211,21.8421052631579,0.0493221962661163 +"3510",2.14689134777813,36.5789473684211,21.8421052631579,0.042792695105437 +"3511",2.79473854427218,36.5789473684211,21.8421052631579,0.0370625313534045 +"3512",3.63808049202114,36.5789473684211,21.8421052631579,0.0320902973192916 +"3513",4.73590980220715,36.5789473684211,21.8421052631579,0.0277837984782613 +"3514",6.16502073107827,36.5789473684211,21.8421052631579,0.0240550409717626 +"3515",8.02538101483936,36.5789473684211,21.8421052631579,0.0208266791300844 +"3516",10.4471247126008,36.5789473684211,21.8421052631579,0.0180315832095336 +"3517",13.5996552137305,36.5789473684211,21.8421052631579,0.0156116095081272 +"3518",17.7034951740616,36.5789473684211,21.8421052631579,0.0135164143514513 +"3519",23.045712295823,36.5789473684211,21.8421052631579,0.0117024100979591 +"3520",30,36.5789473684211,21.8421052631579,0.010131858828793 +"3521",0.2,38.6842105263158,21.8421052631579,0.0568391314778902 +"3522",0.260352117694686,38.6842105263158,21.8421052631579,0.0568387651699274 +"3523",0.338916125940539,38.6842105263158,21.8421052631579,0.05683652478621 +"3524",0.441187655547492,38.6842105263158,21.8421052631579,0.0568228440959951 +"3525",0.574320702112717,38.6842105263158,21.8421052631579,0.0567401050009612 +"3526",0.747628055154725,38.6842105263158,21.8421052631579,0.0562667857136669 +"3527",0.973232737037462,38.6842105263158,21.8421052631579,0.0541709543773209 +"3528",1.2669160204875,38.6842105263158,21.8421052631579,0.0492367388962484 +"3529",1.64922134437622,38.6842105263158,21.8421052631579,0.0431340183465733 +"3530",2.14689134777813,38.6842105263158,21.8421052631579,0.0374237368875094 +"3531",2.79473854427218,38.6842105263158,21.8421052631579,0.0324125044785659 +"3532",3.63808049202114,38.6842105263158,21.8421052631579,0.0280641086185416 +"3533",4.73590980220715,38.6842105263158,21.8421052631579,0.0242979219098992 +"3534",6.16502073107827,38.6842105263158,21.8421052631579,0.0210369905874689 +"3535",8.02538101483936,38.6842105263158,21.8421052631579,0.0182136731066942 +"3536",10.4471247126008,38.6842105263158,21.8421052631579,0.0157692621143902 +"3537",13.5996552137305,38.6842105263158,21.8421052631579,0.0136529088710859 +"3538",17.7034951740616,38.6842105263158,21.8421052631579,0.0118205860393916 +"3539",23.045712295823,38.6842105263158,21.8421052631579,0.0102341746734272 +"3540",30,38.6842105263158,21.8421052631579,0.00886067161827259 +"3541",0.2,40.7894736842105,21.8421052631579,0.0495253595713581 +"3542",0.260352117694686,40.7894736842105,21.8421052631579,0.0495250403980508 +"3543",0.338916125940539,40.7894736842105,21.8421052631579,0.0495230882955768 +"3544",0.441187655547492,40.7894736842105,21.8421052631579,0.0495111679673722 +"3545",0.574320702112717,40.7894736842105,21.8421052631579,0.0494390753205351 +"3546",0.747628055154725,40.7894736842105,21.8421052631579,0.0490266603647502 +"3547",0.973232737037462,40.7894736842105,21.8421052631579,0.0472005100025859 +"3548",1.2669160204875,40.7894736842105,21.8421052631579,0.0429012044089081 +"3549",1.64922134437622,40.7894736842105,21.8421052631579,0.0375837510677405 +"3550",2.14689134777813,40.7894736842105,21.8421052631579,0.0326082397402353 +"3551",2.79473854427218,40.7894736842105,21.8421052631579,0.0282418273673595 +"3552",3.63808049202114,40.7894736842105,21.8421052631579,0.0244529610893786 +"3553",4.73590980220715,40.7894736842105,21.8421052631579,0.0211713882344003 +"3554",6.16502073107827,40.7894736842105,21.8421052631579,0.0183300570584712 +"3555",8.02538101483936,40.7894736842105,21.8421052631579,0.01587002978881 +"3556",10.4471247126008,40.7894736842105,21.8421052631579,0.0137401532374568 +"3557",13.5996552137305,40.7894736842105,21.8421052631579,0.0118961216235075 +"3558",17.7034951740616,40.7894736842105,21.8421052631579,0.0102995728246264 +"3559",23.045712295823,40.7894736842105,21.8421052631579,0.0089172928480571 +"3560",30,40.7894736842105,21.8421052631579,0.00772052521790162 +"3561",0.2,42.8947368421053,21.8421052631579,0.0430661663154471 +"3562",0.260352117694686,42.8947368421053,21.8421052631579,0.0430658887693404 +"3563",0.338916125940539,42.8947368421053,21.8421052631579,0.0430641912638495 +"3564",0.441187655547492,42.8947368421053,21.8421052631579,0.0430538256079222 +"3565",0.574320702112717,42.8947368421053,21.8421052631579,0.0429911354236271 +"3566",0.747628055154725,42.8947368421053,21.8421052631579,0.0426325084246404 +"3567",0.973232737037462,42.8947368421053,21.8421052631579,0.0410445281273815 +"3568",1.2669160204875,42.8947368421053,21.8421052631579,0.0373059462909088 +"3569",1.64922134437622,42.8947368421053,21.8421052631579,0.0326820055068868 +"3570",2.14689134777813,42.8947368421053,21.8421052631579,0.0283554099972472 +"3571",2.79473854427218,42.8947368421053,21.8421052631579,0.0245584735776104 +"3572",3.63808049202114,42.8947368421053,21.8421052631579,0.0212637585732819 +"3573",4.73590980220715,42.8947368421053,21.8421052631579,0.0184101748018179 +"3574",6.16502073107827,42.8947368421053,21.8421052631579,0.0159394155374954 +"3575",8.02538101483936,42.8947368421053,21.8421052631579,0.0138002297859389 +"3576",10.4471247126008,42.8947368421053,21.8421052631579,0.0119481358569734 +"3577",13.5996552137305,42.8947368421053,21.8421052631579,0.0103446064153979 +"3578",17.7034951740616,42.8947368421053,21.8421052631579,0.00895628260112514 +"3579",23.045712295823,42.8947368421053,21.8421052631579,0.00775428225462237 +"3580",30,42.8947368421053,21.8421052631579,0.00671359937523897 +"3581",0.2,45,21.8421052631579,0.0374182130685388 +"3582",0.260352117694686,45,21.8421052631579,0.0374179719214796 +"3583",0.338916125940539,45,21.8421052631579,0.037416497036957 +"3584",0.441187655547492,45,21.8421052631579,0.0374074907948123 +"3585",0.574320702112717,45,21.8421052631579,0.0373530221742233 +"3586",0.747628055154725,45,21.8421052631579,0.0370414276533198 +"3587",0.973232737037462,45,21.8421052631579,0.0356617045389787 +"3588",1.2669160204875,45,21.8421052631579,0.0324134225649892 +"3589",1.64922134437622,45,21.8421052631579,0.0283958928827434 +"3590",2.14689134777813,45,21.8421052631579,0.0246367128467203 +"3591",2.79473854427218,45,21.8421052631579,0.0213377292567484 +"3592",3.63808049202114,45,21.8421052631579,0.0184751027780164 +"3593",4.73590980220715,45,21.8421052631579,0.0159957549580255 +"3594",6.16502073107827,45,21.8421052631579,0.0138490257619252 +"3595",8.02538101483936,45,21.8421052631579,0.0119903855556291 +"3596",10.4471247126008,45,21.8421052631579,0.010381186242429 +"3597",13.5996552137305,45,21.8421052631579,0.00898795319105742 +"3598",17.7034951740616,45,21.8421052631579,0.0077817024207874 +"3599",23.045712295823,45,21.8421052631579,0.00673733955030441 +"3600",30,45,21.8421052631579,0.00583313801464133 +"3601",0.2,5,23.9473684210526,0.027710754164123 +"3602",0.260352117694686,5,23.9473684210526,0.0277105755781798 +"3603",0.338916125940539,5,23.9473684210526,0.0277094833249941 +"3604",0.441187655547492,5,23.9473684210526,0.027702813584738 +"3605",0.574320702112717,5,23.9473684210526,0.0276624758339204 +"3606",0.747628055154725,5,23.9473684210526,0.0274317187116647 +"3607",0.973232737037462,5,23.9473684210526,0.0264099390781469 +"3608",1.2669160204875,5,23.9473684210526,0.0240043634010802 +"3609",1.64922134437622,5,23.9473684210526,0.0210291070154302 +"3610",2.14689134777813,5,23.9473684210526,0.0182451762690285 +"3611",2.79473854427218,5,23.9473684210526,0.0158020525665219 +"3612",3.63808049202114,5,23.9473684210526,0.0136820812447875 +"3613",4.73590980220715,5,23.9473684210526,0.0118459540678623 +"3614",6.16502073107827,5,23.9473684210526,0.0102561538039877 +"3615",8.02538101483936,5,23.9473684210526,0.0088797032037977 +"3616",10.4471247126008,5,23.9473684210526,0.00768798069990678 +"3617",13.5996552137305,5,23.9473684210526,0.00665619603105656 +"3618",17.7034951740616,5,23.9473684210526,0.00576288457083237 +"3619",23.045712295823,5,23.9473684210526,0.0049894622080626 +"3620",30,5,23.9473684210526,0.00431983893065791 +"3621",0.2,7.10526315789474,23.9473684210526,0.0346171770039191 +"3622",0.260352117694686,7.10526315789474,23.9473684210526,0.03461695390854 +"3623",0.338916125940539,7.10526315789474,23.9473684210526,0.0346155894302715 +"3624",0.441187655547492,7.10526315789474,23.9473684210526,0.0346072573734228 +"3625",0.574320702112717,7.10526315789474,23.9473684210526,0.0345568661407727 +"3626",0.747628055154725,7.10526315789474,23.9473684210526,0.03426859682487 +"3627",0.973232737037462,7.10526315789474,23.9473684210526,0.0329921564139381 +"3628",1.2669160204875,7.10526315789474,23.9473684210526,0.0299870328970489 +"3629",1.64922134437622,7.10526315789474,23.9473684210526,0.0262702456770377 +"3630",2.14689134777813,7.10526315789474,23.9473684210526,0.0227924686795566 +"3631",2.79473854427218,7.10526315789474,23.9473684210526,0.0197404389458571 +"3632",3.63808049202114,7.10526315789474,23.9473684210526,0.0170921016955224 +"3633",4.73590980220715,7.10526315789474,23.9473684210526,0.0147983517994038 +"3634",6.16502073107827,7.10526315789474,23.9473684210526,0.0128123215091608 +"3635",8.02538101483936,7.10526315789474,23.9473684210526,0.0110928145703847 +"3636",10.4471247126008,7.10526315789474,23.9473684210526,0.00960407598851831 +"3637",13.5996552137305,7.10526315789474,23.9473684210526,0.00831513696145417 +"3638",17.7034951740616,7.10526315789474,23.9473684210526,0.00719918317849118 +"3639",23.045712295823,7.10526315789474,23.9473684210526,0.00623299876242595 +"3640",30,7.10526315789474,23.9473684210526,0.00539648354589408 +"3641",0.2,9.21052631578947,23.9473684210526,0.0426729857524171 +"3642",0.260352117694686,9.21052631578947,23.9473684210526,0.0426727107402191 +"3643",0.338916125940539,9.21052631578947,23.9473684210526,0.0426710287324198 +"3644",0.441187655547492,9.21052631578947,23.9473684210526,0.0426607577116733 +"3645",0.574320702112717,9.21052631578947,23.9473684210526,0.0425986398690577 +"3646",0.747628055154725,9.21052631578947,23.9473684210526,0.0422432870218575 +"3647",0.973232737037462,9.21052631578947,23.9473684210526,0.0406698044856201 +"3648",1.2669160204875,9.21052631578947,23.9473684210526,0.0369653547263013 +"3649",1.64922134437622,9.21052631578947,23.9473684210526,0.0323836290683614 +"3650",2.14689134777813,9.21052631578947,23.9473684210526,0.0280965340159025 +"3651",2.79473854427218,9.21052631578947,23.9473684210526,0.0243342624324234 +"3652",3.63808049202114,9.21052631578947,23.9473684210526,0.0210696271405758 +"3653",4.73590980220715,9.21052631578947,23.9473684210526,0.0182420956920815 +"3654",6.16502073107827,9.21052631578947,23.9473684210526,0.015793893683298 +"3655",8.02538101483936,9.21052631578947,23.9473684210526,0.0136742380253202 +"3656",10.4471247126008,9.21052631578947,23.9473684210526,0.0118390531318245 +"3657",13.5996552137305,9.21052631578947,23.9473684210526,0.0102501634100712 +"3658",17.7034951740616,9.21052631578947,23.9473684210526,0.00887451455588117 +"3659",23.045712295823,9.21052631578947,23.9473684210526,0.00768348809476069 +"3660",30,9.21052631578947,23.9473684210526,0.00665230632298585 +"3661",0.2,11.3157894736842,23.9473684210526,0.0517856933290574 +"3662",0.260352117694686,11.3157894736842,23.9473684210526,0.0517853595887039 +"3663",0.338916125940539,11.3157894736842,23.9473684210526,0.051783318392417 +"3664",0.441187655547492,11.3157894736842,23.9473684210526,0.0517708540213124 +"3665",0.574320702112717,11.3157894736842,23.9473684210526,0.0516954710713915 +"3666",0.747628055154725,11.3157894736842,23.9473684210526,0.0512642335274454 +"3667",0.973232737037462,11.3157894736842,23.9473684210526,0.0493547377974542 +"3668",1.2669160204875,11.3157894736842,23.9473684210526,0.0448592122136106 +"3669",1.64922134437622,11.3157894736842,23.9473684210526,0.0392990706941832 +"3670",2.14689134777813,11.3157894736842,23.9473684210526,0.0340964773966992 +"3671",2.79473854427218,11.3157894736842,23.9473684210526,0.0295307822852049 +"3672",3.63808049202114,11.3157894736842,23.9473684210526,0.0255689924297749 +"3673",4.73590980220715,11.3157894736842,23.9473684210526,0.022137648831754 +"3674",6.16502073107827,11.3157894736842,23.9473684210526,0.0191666395105404 +"3675",8.02538101483936,11.3157894736842,23.9473684210526,0.0165943367777508 +"3676",10.4471247126008,11.3157894736842,23.9473684210526,0.0143672528176999 +"3677",13.5996552137305,11.3157894736842,23.9473684210526,0.0124390597369111 +"3678",17.7034951740616,11.3157894736842,23.9473684210526,0.0107696445686153 +"3679",23.045712295823,11.3157894736842,23.9473684210526,0.00932427743587645 +"3680",30,11.3157894736842,23.9473684210526,0.0080728894193578 +"3681",0.2,13.4210526315789,23.9473684210526,0.0617110252838339 +"3682",0.260352117694686,13.4210526315789,23.9473684210526,0.0617106275782502 +"3683",0.338916125940539,13.4210526315789,23.9473684210526,0.0617081951628943 +"3684",0.441187655547492,13.4210526315789,23.9473684210526,0.0616933418497313 +"3685",0.574320702112717,13.4210526315789,23.9473684210526,0.0616035108784824 +"3686",0.747628055154725,13.4210526315789,23.9473684210526,0.0610896216309504 +"3687",0.973232737037462,13.4210526315789,23.9473684210526,0.0588141487793252 +"3688",1.2669160204875,13.4210526315789,23.9473684210526,0.0534570032988951 +"3689",1.64922134437622,13.4210526315789,23.9473684210526,0.0468311958252593 +"3690",2.14689134777813,13.4210526315789,23.9473684210526,0.0406314648593636 +"3691",2.79473854427218,13.4210526315789,23.9473684210526,0.0351907010431223 +"3692",3.63808049202114,13.4210526315789,23.9473684210526,0.0304695879668879 +"3693",4.73590980220715,13.4210526315789,23.9473684210526,0.0263805873583709 +"3694",6.16502073107827,13.4210526315789,23.9473684210526,0.022840149458372 +"3695",8.02538101483936,13.4210526315789,23.9473684210526,0.0197748349134417 +"3696",10.4471247126008,13.4210526315789,23.9473684210526,0.0171209043443437 +"3697",13.5996552137305,13.4210526315789,23.9473684210526,0.0148231505766269 +"3698",17.7034951740616,13.4210526315789,23.9473684210526,0.0128337725257182 +"3699",23.045712295823,13.4210526315789,23.9473684210526,0.0111113839288116 +"3700",30,13.4210526315789,23.9473684210526,0.00962015280757181 +"3701",0.2,15.5263157894737,23.9473684210526,0.0720333119279288 +"3702",0.260352117694686,15.5263157894737,23.9473684210526,0.0720328476988833 +"3703",0.338916125940539,15.5263157894737,23.9473684210526,0.0720300084180049 +"3704",0.441187655547492,15.5263157894737,23.9473684210526,0.0720126706192029 +"3705",0.574320702112717,15.5263157894737,23.9473684210526,0.0719078137910593 +"3706",0.747628055154725,15.5263157894737,23.9473684210526,0.0713079672596879 +"3707",0.973232737037462,15.5263157894737,23.9473684210526,0.0686518803619128 +"3708",1.2669160204875,15.5263157894737,23.9473684210526,0.0623986552751437 +"3709",1.64922134437622,15.5263157894737,23.9473684210526,0.0546645614997185 +"3710",2.14689134777813,15.5263157894737,23.9473684210526,0.0474278132447418 +"3711",2.79473854427218,15.5263157894737,23.9473684210526,0.0410769831410623 +"3712",3.63808049202114,15.5263157894737,23.9473684210526,0.0355661783974487 +"3713",4.73590980220715,15.5263157894737,23.9473684210526,0.0307932183801411 +"3714",6.16502073107827,15.5263157894737,23.9473684210526,0.0266605781195215 +"3715",8.02538101483936,15.5263157894737,23.9473684210526,0.0230825342001958 +"3716",10.4471247126008,15.5263157894737,23.9473684210526,0.0199846856773488 +"3717",13.5996552137305,15.5263157894737,23.9473684210526,0.01730259097673 +"3718",17.7034951740616,15.5263157894737,23.9473684210526,0.0149804534166331 +"3719",23.045712295823,15.5263157894737,23.9473684210526,0.0129699641322396 +"3720",30,15.5263157894737,23.9473684210526,0.011229297597875 +"3721",0.2,17.6315789473684,23.9473684210526,0.0821855427376248 +"3722",0.260352117694686,17.6315789473684,23.9473684210526,0.0821850130810668 +"3723",0.338916125940539,17.6315789473684,23.9473684210526,0.0821817736376241 +"3724",0.441187655547492,17.6315789473684,23.9473684210526,0.0821619922841603 +"3725",0.574320702112717,17.6315789473684,23.9473684210526,0.0820423571445273 +"3726",0.747628055154725,17.6315789473684,23.9473684210526,0.0813579694436068 +"3727",0.973232737037462,17.6315789473684,23.9473684210526,0.0783275389745713 +"3728",1.2669160204875,17.6315789473684,23.9473684210526,0.0711929968597946 +"3729",1.64922134437622,17.6315789473684,23.9473684210526,0.0623688753873157 +"3730",2.14689134777813,17.6315789473684,23.9473684210526,0.0541121943175089 +"3731",2.79473854427218,17.6315789473684,23.9473684210526,0.0468662909300933 +"3732",3.63808049202114,17.6315789473684,23.9473684210526,0.040578804395695 +"3733",4.73590980220715,17.6315789473684,23.9473684210526,0.0351331529465449 +"3734",6.16502073107827,17.6315789473684,23.9473684210526,0.0304180666390015 +"3735",8.02538101483936,17.6315789473684,23.9473684210526,0.026335740371079 +"3736",10.4471247126008,17.6315789473684,23.9473684210526,0.022801287277712 +"3737",13.5996552137305,17.6315789473684,23.9473684210526,0.0197411835181542 +"3738",17.7034951740616,17.6315789473684,23.9473684210526,0.0170917685380553 +"3739",23.045712295823,17.6315789473684,23.9473684210526,0.0147979249178789 +"3740",30,17.6315789473684,23.9473684210526,0.0128119323260749 +"3741",0.2,19.7368421052632,23.9473684210526,0.0915204472588765 +"3742",0.260352117694686,19.7368421052632,23.9473684210526,0.0915198574421829 +"3743",0.338916125940539,19.7368421052632,23.9473684210526,0.0915162500520889 +"3744",0.441187655547492,19.7368421052632,23.9473684210526,0.0914942218673731 +"3745",0.574320702112717,19.7368421052632,23.9473684210526,0.0913609981747091 +"3746",0.747628055154725,19.7368421052632,23.9473684210526,0.0905988754655281 +"3747",0.973232737037462,19.7368421052632,23.9473684210526,0.0872242387268199 +"3748",1.2669160204875,19.7368421052632,23.9473684210526,0.079279331829798 +"3749",1.64922134437622,19.7368421052632,23.9473684210526,0.069452937589072 +"3750",2.14689134777813,19.7368421052632,23.9473684210526,0.0602584355001216 +"3751",2.79473854427218,19.7368421052632,23.9473684210526,0.0521895185504828 +"3752",3.63808049202114,19.7368421052632,23.9473684210526,0.0451878785953954 +"3753",4.73590980220715,19.7368421052632,23.9473684210526,0.0391236921260883 +"3754",6.16502073107827,19.7368421052632,23.9473684210526,0.0338730507923903 +"3755",8.02538101483936,19.7368421052632,23.9473684210526,0.0293270404668311 +"3756",10.4471247126008,19.7368421052632,23.9473684210526,0.0253911325547407 +"3757",13.5996552137305,19.7368421052632,23.9473684210526,0.0219834521354802 +"3758",17.7034951740616,19.7368421052632,23.9473684210526,0.0190331078793484 +"3759",23.045712295823,19.7368421052632,23.9473684210526,0.0164787219488367 +"3760",30,19.7368421052632,23.9473684210526,0.0142671537800289 +"3761",0.2,21.8421052631579,23.9473684210526,0.0994222254111273 +"3762",0.260352117694686,21.8421052631579,23.9473684210526,0.0994215846702872 +"3763",0.338916125940539,21.8421052631579,23.9473684210526,0.0994176658219663 +"3764",0.441187655547492,21.8421052631579,23.9473684210526,0.0993937357471928 +"3765",0.574320702112717,21.8421052631579,23.9473684210526,0.0992490096624887 +"3766",0.747628055154725,21.8421052631579,23.9473684210526,0.0984210860885489 +"3767",0.973232737037462,21.8421052631579,23.9473684210526,0.0947550868002427 +"3768",1.2669160204875,21.8421052631579,23.9473684210526,0.0861242250852446 +"3769",1.64922134437622,21.8421052631579,23.9473684210526,0.0754494304088527 +"3770",2.14689134777813,21.8421052631579,23.9473684210526,0.0654610847810723 +"3771",2.79473854427218,21.8421052631579,23.9473684210526,0.0566955061173071 +"3772",3.63808049202114,21.8421052631579,23.9473684210526,0.0490893520095458 +"3773",4.73590980220715,21.8421052631579,23.9473684210526,0.042501590125241 +"3774",6.16502073107827,21.8421052631579,23.9473684210526,0.0367976139989521 +"3775",8.02538101483936,21.8421052631579,23.9473684210526,0.0318591059731927 +"3776",10.4471247126008,21.8421052631579,23.9473684210526,0.0275833759548897 +"3777",13.5996552137305,21.8421052631579,23.9473684210526,0.0238814800297696 +"3778",17.7034951740616,21.8421052631579,23.9473684210526,0.0206764061860652 +"3779",23.045712295823,21.8421052631579,23.9473684210526,0.0179014772890069 +"3780",30,21.8421052631579,23.9473684210526,0.0154989646748658 +"3781",0.2,23.9473684210526,23.9473684210526,0.105424081592245 +"3782",0.260352117694686,23.9473684210526,23.9473684210526,0.105423402171578 +"3783",0.338916125940539,23.9473684210526,23.9473684210526,0.105419246752773 +"3784",0.441187655547492,23.9473684210526,23.9473684210526,0.105393872082824 +"3785",0.574320702112717,23.9473684210526,23.9473684210526,0.105240409268053 +"3786",0.747628055154725,23.9473684210526,23.9473684210526,0.104362506142769 +"3787",0.973232737037462,23.9473684210526,23.9473684210526,0.100475200195941 +"3788",1.2669160204875,23.9473684210526,23.9473684210526,0.0913233162395042 +"3789",1.64922134437622,23.9473684210526,23.9473684210526,0.0800041125072325 +"3790",2.14689134777813,23.9473684210526,23.9473684210526,0.0694127969328699 +"3791",2.79473854427218,23.9473684210526,23.9473684210526,0.0601180635226018 +"3792",3.63808049202114,23.9473684210526,23.9473684210526,0.0520527460551648 +"3793",4.73590980220715,23.9473684210526,23.9473684210526,0.0450672984499707 +"3794",6.16502073107827,23.9473684210526,23.9473684210526,0.0390189884061001 +"3795",8.02538101483936,23.9473684210526,23.9473684210526,0.0337823557427424 +"3796",10.4471247126008,23.9473684210526,23.9473684210526,0.029248511238136 +"3797",13.5996552137305,23.9473684210526,23.9473684210526,0.0253231416696915 +"3798",17.7034951740616,23.9473684210526,23.9473684210526,0.0219245860146494 +"3799",23.045712295823,23.9473684210526,23.9473684210526,0.0189821420163741 +"3800",30,23.9473684210526,23.9473684210526,0.0164345960847452 +"3801",0.2,26.0526315789474,23.9473684210526,0.109288062991127 +"3802",0.260352117694686,26.0526315789474,23.9473684210526,0.109287358668477 +"3803",0.338916125940539,26.0526315789474,23.9473684210526,0.10928305094613 +"3804",0.441187655547492,26.0526315789474,23.9473684210526,0.109256746249083 +"3805",0.574320702112717,26.0526315789474,23.9473684210526,0.109097658747308 +"3806",0.747628055154725,26.0526315789474,23.9473684210526,0.108187578900207 +"3807",0.973232737037462,26.0526315789474,23.9473684210526,0.104157796228484 +"3808",1.2669160204875,26.0526315789474,23.9473684210526,0.0946704793345412 +"3809",1.64922134437622,26.0526315789474,23.9473684210526,0.0829364065134324 +"3810",2.14689134777813,26.0526315789474,23.9473684210526,0.0719569002548262 +"3811",2.79473854427218,26.0526315789474,23.9473684210526,0.0623214982187335 +"3812",3.63808049202114,26.0526315789474,23.9473684210526,0.0539605724215907 +"3813",4.73590980220715,26.0526315789474,23.9473684210526,0.0467190956511273 +"3814",6.16502073107827,26.0526315789474,23.9473684210526,0.04044910421197 +"3815",8.02538101483936,26.0526315789474,23.9473684210526,0.0350205395829894 +"3816",10.4471247126008,26.0526315789474,23.9473684210526,0.0303205215574317 +"3817",13.5996552137305,26.0526315789474,23.9473684210526,0.0262512801641905 +"3818",17.7034951740616,26.0526315789474,23.9473684210526,0.0227281613577714 +"3819",23.045712295823,26.0526315789474,23.9473684210526,0.0196778715172096 +"3820",30,26.0526315789474,23.9473684210526,0.0170369534646769 +"3821",0.2,28.1578947368421,23.9473684210526,0.111020487470355 +"3822",0.260352117694686,28.1578947368421,23.9473684210526,0.111019771982846 +"3823",0.338916125940539,28.1578947368421,23.9473684210526,0.111015395974875 +"3824",0.441187655547492,28.1578947368421,23.9473684210526,0.110988674298152 +"3825",0.574320702112717,28.1578947368421,23.9473684210526,0.110827064955702 +"3826",0.747628055154725,28.1578947368421,23.9473684210526,0.109902558605267 +"3827",0.973232737037462,28.1578947368421,23.9473684210526,0.105808896183503 +"3828",1.2669160204875,28.1578947368421,23.9473684210526,0.09617118720117 +"3829",1.64922134437622,28.1578947368421,23.9473684210526,0.0842511069201433 +"3830",2.14689134777813,28.1578947368421,23.9473684210526,0.073097554522447 +"3831",2.79473854427218,28.1578947368421,23.9473684210526,0.0633094129656997 +"3832",3.63808049202114,28.1578947368421,23.9473684210526,0.0548159505298468 +"3833",4.73590980220715,28.1578947368421,23.9473684210526,0.0474596825252856 +"3834",6.16502073107827,28.1578947368421,23.9473684210526,0.0410902997495408 +"3835",8.02538101483936,28.1578947368421,23.9473684210526,0.035575682005582 +"3836",10.4471247126008,28.1578947368421,23.9473684210526,0.0308011597198386 +"3837",13.5996552137305,28.1578947368421,23.9473684210526,0.0266674130804744 +"3838",17.7034951740616,28.1578947368421,23.9473684210526,0.0230884461137309 +"3839",23.045712295823,28.1578947368421,23.9473684210526,0.0199898033548 +"3840",30,28.1578947368421,23.9473684210526,0.0173070217084161 +"3841",0.2,30.2631578947368,23.9473684210526,0.110827288905264 +"3842",0.260352117694686,30.2631578947368,23.9473684210526,0.110826574662851 +"3843",0.338916125940539,30.2631578947368,23.9473684210526,0.110822206270037 +"3844",0.441187655547492,30.2631578947368,23.9473684210526,0.110795531094547 +"3845",0.574320702112717,30.2631578947368,23.9473684210526,0.110634202985713 +"3846",0.747628055154725,30.2631578947368,23.9473684210526,0.109711305467164 +"3847",0.973232737037462,30.2631578947368,23.9473684210526,0.105624766863029 +"3848",1.2669160204875,30.2631578947368,23.9473684210526,0.0960038294837456 +"3849",1.64922134437622,30.2631578947368,23.9473684210526,0.0841044926029555 +"3850",2.14689134777813,30.2631578947368,23.9473684210526,0.0729703496887519 +"3851",2.79473854427218,30.2631578947368,23.9473684210526,0.0631992415187854 +"3852",3.63808049202114,30.2631578947368,23.9473684210526,0.0547205594607948 +"3853",4.73590980220715,30.2631578947368,23.9473684210526,0.0473770928810452 +"3854",6.16502073107827,30.2631578947368,23.9473684210526,0.0410187941461007 +"3855",8.02538101483936,30.2631578947368,23.9473684210526,0.0355137729753459 +"3856",10.4471247126008,30.2631578947368,23.9473684210526,0.0307475593439385 +"3857",13.5996552137305,30.2631578947368,23.9473684210526,0.0266210062770165 +"3858",17.7034951740616,30.2631578947368,23.9473684210526,0.0230482674515669 +"3859",23.045712295823,30.2631578947368,23.9473684210526,0.0199550169706596 +"3860",30,30.2631578947368,23.9473684210526,0.0172769039181212 +"3861",0.2,32.3684210526316,23.9473684210526,0.10903699961002 +"3862",0.260352117694686,32.3684210526316,23.9473684210526,0.109036296905384 +"3863",0.338916125940539,32.3684210526316,23.9473684210526,0.109031999079007 +"3864",0.441187655547492,32.3684210526316,23.9473684210526,0.109005754810756 +"3865",0.574320702112717,32.3684210526316,23.9473684210526,0.108847032774751 +"3866",0.747628055154725,32.3684210526316,23.9473684210526,0.107939043620058 +"3867",0.973232737037462,32.3684210526316,23.9473684210526,0.103918518417404 +"3868",1.2669160204875,32.3684210526316,23.9473684210526,0.0944529963818541 +"3869",1.64922134437622,32.3684210526316,23.9473684210526,0.0827458798075302 +"3870",2.14689134777813,32.3684210526316,23.9473684210526,0.0717915963581561 +"3871",2.79473854427218,32.3684210526316,23.9473684210526,0.0621783293709178 +"3872",3.63808049202114,32.3684210526316,23.9473684210526,0.053836610816015 +"3873",4.73590980220715,32.3684210526316,23.9473684210526,0.046611769619396 +"3874",6.16502073107827,32.3684210526316,23.9473684210526,0.0403561819971529 +"3875",8.02538101483936,32.3684210526316,23.9473684210526,0.0349400882067342 +"3876",10.4471247126008,32.3684210526316,23.9473684210526,0.030250867356865 +"3877",13.5996552137305,32.3684210526316,23.9473684210526,0.0261909740797378 +"3878",17.7034951740616,32.3684210526316,23.9473684210526,0.0226759488024323 +"3879",23.045712295823,32.3684210526316,23.9473684210526,0.0196326662786787 +"3880",30,32.3684210526316,23.9473684210526,0.0169978151084508 +"3881",0.2,34.4736842105263,23.9473684210526,0.106022760163323 +"3882",0.260352117694686,34.4736842105263,23.9473684210526,0.106022076884386 +"3883",0.338916125940539,34.4736842105263,23.9473684210526,0.106017897867935 +"3884",0.441187655547492,34.4736842105263,23.9473684210526,0.105992379101201 +"3885",0.574320702112717,34.4736842105263,23.9473684210526,0.105838044807189 +"3886",0.747628055154725,34.4736842105263,23.9473684210526,0.104955156276477 +"3887",0.973232737037462,34.4736842105263,23.9473684210526,0.101045775233196 +"3888",1.2669160204875,34.4736842105263,23.9473684210526,0.0918419198796464 +"3889",1.64922134437622,34.4736842105263,23.9473684210526,0.0804584370508549 +"3890",2.14689134777813,34.4736842105263,23.9473684210526,0.0698069758856734 +"3891",2.79473854427218,34.4736842105263,23.9473684210526,0.060459459869832 +"3892",3.63808049202114,34.4736842105263,23.9473684210526,0.0523483413608895 +"3893",4.73590980220715,34.4736842105263,23.9473684210526,0.0453232250412284 +"3894",6.16502073107827,34.4736842105263,23.9473684210526,0.0392405680667532 +"3895",8.02538101483936,34.4736842105263,23.9473684210526,0.0339741977977858 +"3896",10.4471247126008,34.4736842105263,23.9473684210526,0.0294146066562771 +"3897",13.5996552137305,34.4736842105263,23.9473684210526,0.0254669458370227 +"3898",17.7034951740616,34.4736842105263,23.9473684210526,0.0220490905835153 +"3899",23.045712295823,34.4736842105263,23.9473684210526,0.0190899371376284 +"3900",30,34.4736842105263,23.9473684210526,0.0165279242916564 +"3901",0.2,36.5789473684211,23.9473684210526,0.102143455876788 +"3902",0.260352117694686,36.5789473684211,23.9473684210526,0.102142797598587 +"3903",0.338916125940539,36.5789473684211,23.9473684210526,0.102138771489647 +"3904",0.441187655547492,36.5789473684211,23.9473684210526,0.102114186438099 +"3905",0.574320702112717,36.5789473684211,23.9473684210526,0.10196549913618 +"3906",0.747628055154725,36.5789473684211,23.9473684210526,0.101114914926317 +"3907",0.973232737037462,36.5789473684211,23.9473684210526,0.0973485756093185 +"3908",1.2669160204875,36.5789473684211,23.9473684210526,0.0884814833759766 +"3909",1.64922134437622,36.5789473684211,23.9473684210526,0.0775145148283206 +"3910",2.14689134777813,36.5789473684211,23.9473684210526,0.0672527837446073 +"3911",2.79473854427218,36.5789473684211,23.9473684210526,0.0582472872997792 +"3912",3.63808049202114,36.5789473684211,23.9473684210526,0.0504329493759852 +"3913",4.73590980220715,36.5789473684211,23.9473684210526,0.0436648775230997 +"3914",6.16502073107827,36.5789473684211,23.9473684210526,0.037804781036941 +"3915",8.02538101483936,36.5789473684211,23.9473684210526,0.0327311038531885 +"3916",10.4471247126008,36.5789473684211,23.9473684210526,0.0283383452053147 +"3917",13.5996552137305,36.5789473684211,23.9473684210526,0.0245351267446097 +"3918",17.7034951740616,36.5789473684211,23.9473684210526,0.0212423286063413 +"3919",23.045712295823,36.5789473684211,23.9473684210526,0.0183914486729479 +"3920",30,36.5789473684211,23.9473684210526,0.0159231782215355 +"3921",0.2,38.6842105263158,23.9473684210526,0.0977096893140521 +"3922",0.260352117694686,38.6842105263158,23.9473684210526,0.0977090596098974 +"3923",0.338916125940539,38.6842105263158,23.9473684210526,0.0977052082632762 +"3924",0.441187655547492,38.6842105263158,23.9473684210526,0.097681690381216 +"3925",0.574320702112717,38.6842105263158,23.9473684210526,0.0975394571862378 +"3926",0.747628055154725,38.6842105263158,23.9473684210526,0.0967257944981323 +"3927",0.973232737037462,38.6842105263158,23.9473684210526,0.0931229416148388 +"3928",1.2669160204875,38.6842105263158,23.9473684210526,0.0846407454741092 +"3929",1.64922134437622,38.6842105263158,23.9473684210526,0.0741498228759835 +"3930",2.14689134777813,38.6842105263158,23.9473684210526,0.0643335253226341 +"3931",2.79473854427218,38.6842105263158,23.9473684210526,0.0557189327166782 +"3932",3.63808049202114,38.6842105263158,23.9473684210526,0.0482437937156055 +"3933",4.73590980220715,38.6842105263158,23.9473684210526,0.0417695052521495 +"3934",6.16502073107827,38.6842105263158,23.9473684210526,0.0361637794413484 +"3935",8.02538101483936,38.6842105263158,23.9473684210526,0.0313103366333994 +"3936",10.4471247126008,38.6842105263158,23.9473684210526,0.0271082555599618 +"3937",13.5996552137305,38.6842105263158,23.9473684210526,0.0234701243551863 +"3938",17.7034951740616,38.6842105263158,23.9473684210526,0.0203202575301182 +"3939",23.045712295823,38.6842105263158,23.9473684210526,0.0175931264557639 +"3940",30,38.6842105263158,23.9473684210526,0.0152319968378129 +"3941",0.2,40.7894736842105,23.9473684210526,0.0929707382775433 +"3942",0.260352117694686,40.7894736842105,23.9473684210526,0.0929701391142404 +"3943",0.338916125940539,40.7894736842105,23.9473684210526,0.0929664745591564 +"3944",0.441187655547492,40.7894736842105,23.9473684210526,0.0929440973018628 +"3945",0.574320702112717,40.7894736842105,23.9473684210526,0.0928087624621193 +"3946",0.747628055154725,40.7894736842105,23.9473684210526,0.0920345626734074 +"3947",0.973232737037462,40.7894736842105,23.9473684210526,0.0886064493018812 +"3948",1.2669160204875,40.7894736842105,23.9473684210526,0.0805356423741884 +"3949",1.64922134437622,40.7894736842105,23.9473684210526,0.0705535328617387 +"3950",2.14689134777813,40.7894736842105,23.9473684210526,0.0612133288646343 +"3951",2.79473854427218,40.7894736842105,23.9473684210526,0.0530165467424257 +"3952",3.63808049202114,40.7894736842105,23.9473684210526,0.0459039543625311 +"3953",4.73590980220715,40.7894736842105,23.9473684210526,0.0397436709505695 +"3954",6.16502073107827,40.7894736842105,23.9473684210526,0.0344098246261117 +"3955",8.02538101483936,40.7894736842105,23.9473684210526,0.0297917753393871 +"3956",10.4471247126008,40.7894736842105,23.9473684210526,0.0257934965356963 +"3957",13.5996552137305,40.7894736842105,23.9473684210526,0.0223318158525105 +"3958",17.7034951740616,40.7894736842105,23.9473684210526,0.0193347185711827 +"3959",23.045712295823,40.7894736842105,23.9473684210526,0.016739854222086 +"3960",30,40.7894736842105,23.9473684210526,0.0144932401422446 +"3961",0.2,42.8947368421053,23.9473684210526,0.0881152544735355 +"3962",0.260352117694686,42.8947368421053,23.9473684210526,0.0881146866020969 +"3963",0.338916125940539,42.8947368421053,23.9473684210526,0.0881112134318312 +"3964",0.441187655547492,42.8947368421053,23.9473684210526,0.0880900048477393 +"3965",0.574320702112717,42.8947368421053,23.9473684210526,0.0879617379966412 +"3966",0.747628055154725,42.8947368421053,23.9473684210526,0.087227971516353 +"3967",0.973232737037462,42.8947368421053,23.9473684210526,0.0839788945735152 +"3968",1.2669160204875,42.8947368421053,23.9473684210526,0.076329593089887 +"3969",1.64922134437622,42.8947368421053,23.9473684210526,0.0668688085874941 +"3970",2.14689134777813,42.8947368421053,23.9473684210526,0.058016405484244 +"3971",2.79473854427218,42.8947368421053,23.9473684210526,0.0502477079785149 +"3972",3.63808049202114,42.8947368421053,23.9473684210526,0.0435065773912759 +"3973",4.73590980220715,42.8947368421053,23.9473684210526,0.0376680205449954 +"3974",6.16502073107827,42.8947368421053,23.9473684210526,0.0326127393359846 +"3975",8.02538101483936,42.8947368421053,23.9473684210526,0.0282358719946035 +"3976",10.4471247126008,42.8947368421053,23.9473684210526,0.0244464070428289 +"3977",13.5996552137305,42.8947368421053,23.9473684210526,0.0211655158725937 +"3978",17.7034951740616,42.8947368421053,23.9473684210526,0.0183249448013201 +"3979",23.045712295823,42.8947368421053,23.9473684210526,0.0158655996710019 +"3980",30,42.8947368421053,23.9473684210526,0.0137363171137516 +"3981",0.2,45,23.9473684210526,0.0832790299143118 +"3982",0.260352117694686,45,23.9473684210526,0.0832784932106183 +"3983",0.338916125940539,45,23.9473684210526,0.0832752106660444 +"3984",0.441187655547492,45,23.9473684210526,0.0832551661196196 +"3985",0.574320702112717,45,23.9473684210526,0.083133939222036 +"3986",0.747628055154725,45,23.9473684210526,0.0824404456717178 +"3987",0.973232737037462,45,23.9473684210526,0.079369695010744 +"3988",1.2669160204875,45,23.9473684210526,0.0721402270725905 +"3989",1.64922134437622,45,23.9473684210526,0.0631986997480082 +"3990",2.14689134777813,45,23.9473684210526,0.0548321626795539 +"3991",2.79473854427218,45,23.9473684210526,0.0474898517954702 +"3992",3.63808049202114,45,23.9473684210526,0.0411187096001132 +"3993",4.73590980220715,45,23.9473684210526,0.0356006031931932 +"3994",6.16502073107827,45,23.9473684210526,0.030822782172919 +"3995",8.02538101483936,45,23.9473684210526,0.0266861401302711 +"3996",10.4471247126008,45,23.9473684210526,0.0231046607716334 +"3997",13.5996552137305,45,23.9473684210526,0.0200038420139269 +"3998",17.7034951740616,45,23.9473684210526,0.017319176292518 +"3999",23.045712295823,45,23.9473684210526,0.0149948128448825 +"4000",30,45,23.9473684210526,0.0129823964155056 +"4001",0.2,5,26.0526315789474,0.00930244581560227 +"4002",0.260352117694686,5,26.0526315789474,0.00930238586465144 +"4003",0.338916125940539,5,26.0526315789474,0.00930201919739958 +"4004",0.441187655547492,5,26.0526315789474,0.00929978017867893 +"4005",0.574320702112717,5,26.0526315789474,0.00928623887485581 +"4006",0.747628055154725,5,26.0526315789474,0.00920877416156673 +"4007",0.973232737037462,5,26.0526315789474,0.00886576474291326 +"4008",1.2669160204875,5,26.0526315789474,0.00805821770688865 +"4009",1.64922134437622,5,26.0526315789474,0.00705942997447585 +"4010",2.14689134777813,5,26.0526315789474,0.00612486988385514 +"4011",2.79473854427218,5,26.0526315789474,0.00530471804934442 +"4012",3.63808049202114,5,26.0526315789474,0.00459304783516461 +"4013",4.73590980220715,5,26.0526315789474,0.00397666354360984 +"4014",6.16502073107827,5,26.0526315789474,0.00344297071357235 +"4015",8.02538101483936,5,26.0526315789474,0.00298089894712803 +"4016",10.4471247126008,5,26.0526315789474,0.00258084004024949 +"4017",13.5996552137305,5,26.0526315789474,0.00223447195086075 +"4018",17.7034951740616,5,26.0526315789474,0.00193458904597933 +"4019",23.045712295823,5,26.0526315789474,0.00167495267593943 +"4020",30,5,26.0526315789474,0.00145016145524476 +"4021",0.2,7.10526315789474,26.0526315789474,0.0114728854560623 +"4022",0.260352117694686,7.10526315789474,26.0526315789474,0.0114728115174008 +"4023",0.338916125940539,7.10526315789474,26.0526315789474,0.0114723592996223 +"4024",0.441187655547492,7.10526315789474,26.0526315789474,0.0114695978747428 +"4025",0.574320702112717,7.10526315789474,26.0526315789474,0.0114528971241264 +"4026",0.747628055154725,7.10526315789474,26.0526315789474,0.0113573584023677 +"4027",0.973232737037462,7.10526315789474,26.0526315789474,0.0109343182849008 +"4028",1.2669160204875,7.10526315789474,26.0526315789474,0.00993835498359853 +"4029",1.64922134437622,7.10526315789474,26.0526315789474,0.00870653085088787 +"4030",2.14689134777813,7.10526315789474,26.0526315789474,0.00755391990490254 +"4031",2.79473854427218,7.10526315789474,26.0526315789474,0.0065424108630397 +"4032",3.63808049202114,7.10526315789474,26.0526315789474,0.00566469429133101 +"4033",4.73590980220715,7.10526315789474,26.0526315789474,0.00490449568183596 +"4034",6.16502073107827,7.10526315789474,26.0526315789474,0.00424628204328165 +"4035",8.02538101483936,7.10526315789474,26.0526315789474,0.00367640004085122 +"4036",10.4471247126008,7.10526315789474,26.0526315789474,0.00318299969160148 +"4037",13.5996552137305,7.10526315789474,26.0526315789474,0.00275581726087696 +"4038",17.7034951740616,7.10526315789474,26.0526315789474,0.00238596590284322 +"4039",23.045712295823,7.10526315789474,26.0526315789474,0.00206575137080053 +"4040",30,7.10526315789474,26.0526315789474,0.0017885120320631 +"4041",0.2,9.21052631578947,26.0526315789474,0.013993273137112 +"4042",0.260352117694686,9.21052631578947,26.0526315789474,0.0139931829554494 +"4043",0.338916125940539,9.21052631578947,26.0526315789474,0.0139926313935153 +"4044",0.441187655547492,9.21052631578947,26.0526315789474,0.0139892633329925 +"4045",0.574320702112717,9.21052631578947,26.0526315789474,0.0139688937262476 +"4046",0.747628055154725,9.21052631578947,26.0526315789474,0.0138523668565372 +"4047",0.973232737037462,9.21052631578947,26.0526315789474,0.013336392393588 +"4048",1.2669160204875,9.21052631578947,26.0526315789474,0.0121216337730965 +"4049",1.64922134437622,9.21052631578947,26.0526315789474,0.0106191999161632 +"4050",2.14689134777813,9.21052631578947,26.0526315789474,0.00921338096592904 +"4051",2.79473854427218,9.21052631578947,26.0526315789474,0.00797966148379423 +"4052",3.63808049202114,9.21052631578947,26.0526315789474,0.00690912628391569 +"4053",4.73590980220715,9.21052631578947,26.0526315789474,0.00598192564011461 +"4054",6.16502073107827,9.21052631578947,26.0526315789474,0.0051791142408257 +"4055",8.02538101483936,9.21052631578947,26.0526315789474,0.00448403935783542 +"4056",10.4471247126008,9.21052631578947,26.0526315789474,0.00388224777894801 +"4057",13.5996552137305,9.21052631578947,26.0526315789474,0.00336122101062575 +"4058",17.7034951740616,9.21052631578947,26.0526315789474,0.00291011992599292 +"4059",23.045712295823,9.21052631578947,26.0526315789474,0.00251955999000244 +"4060",30,9.21052631578947,26.0526315789474,0.00218141612844621 +"4061",0.2,11.3157894736842,26.0526315789474,0.0168651416065501 +"4062",0.260352117694686,11.3157894736842,26.0526315789474,0.0168650329167178 +"4063",0.338916125940539,11.3157894736842,26.0526315789474,0.016864368156584 +"4064",0.441187655547492,11.3157894736842,26.0526315789474,0.0168603088620144 +"4065",0.574320702112717,11.3157894736842,26.0526315789474,0.0168357587586286 +"4066",0.747628055154725,11.3157894736842,26.0526315789474,0.0166953168377587 +"4067",0.973232737037462,11.3157894736842,26.0526315789474,0.0160734478655935 +"4068",1.2669160204875,11.3157894736842,26.0526315789474,0.0146093818138824 +"4069",1.64922134437622,11.3157894736842,26.0526315789474,0.012798600340286 +"4070",2.14689134777813,11.3157894736842,26.0526315789474,0.0111042622510802 +"4071",2.79473854427218,11.3157894736842,26.0526315789474,0.00961734396076388 +"4072",3.63808049202114,11.3157894736842,26.0526315789474,0.00832710060141256 +"4073",4.73590980220715,11.3157894736842,26.0526315789474,0.00720960864637331 +"4074",6.16502073107827,11.3157894736842,26.0526315789474,0.00624203459849371 +"4075",8.02538101483936,11.3157894736842,26.0526315789474,0.00540430805560951 +"4076",10.4471247126008,11.3157894736842,26.0526315789474,0.0046790095428085 +"4077",13.5996552137305,11.3157894736842,26.0526315789474,0.00405105137015958 +"4078",17.7034951740616,11.3157894736842,26.0526315789474,0.00350736987429683 +"4079",23.045712295823,11.3157894736842,26.0526315789474,0.00303665451258096 +"4080",30,11.3157894736842,26.0526315789474,0.0026291126849719 +"4081",0.2,13.4210526315789,26.0526315789474,0.0200713242621131 +"4082",0.260352117694686,13.4210526315789,26.0526315789474,0.0200711949095753 +"4083",0.338916125940539,13.4210526315789,26.0526315789474,0.0200704037738403 +"4084",0.441187655547492,13.4210526315789,26.0526315789474,0.0200655727786738 +"4085",0.574320702112717,13.4210526315789,26.0526315789474,0.0200363555270657 +"4086",0.747628055154725,13.4210526315789,26.0526315789474,0.0198692146041173 +"4087",0.973232737037462,13.4210526315789,26.0526315789474,0.0191291239437444 +"4088",1.2669160204875,13.4210526315789,26.0526315789474,0.0173867285846902 +"4089",1.64922134437622,13.4210526315789,26.0526315789474,0.0152317047507803 +"4090",2.14689134777813,13.4210526315789,26.0526315789474,0.0132152610118857 +"4091",2.79473854427218,13.4210526315789,26.0526315789474,0.0114456690421026 +"4092",3.63808049202114,13.4210526315789,26.0526315789474,0.00991014129814816 +"4093",4.73590980220715,13.4210526315789,26.0526315789474,0.00858020622181387 +"4094",6.16502073107827,13.4210526315789,26.0526315789474,0.00742868950670642 +"4095",8.02538101483936,13.4210526315789,26.0526315789474,0.0064317052253128 +"4096",10.4471247126008,13.4210526315789,26.0526315789474,0.00556852233738475 +"4097",13.5996552137305,13.4210526315789,26.0526315789474,0.00482118487646563 +"4098",17.7034951740616,13.4210526315789,26.0526315789474,0.00417414568442388 +"4099",23.045712295823,13.4210526315789,26.0526315789474,0.0036139440044992 +"4100",30,13.4210526315789,26.0526315789474,0.00312892559415042 +"4101",0.2,15.5263157894737,26.0526315789474,0.0235739961063685 +"4102",0.260352117694686,15.5263157894737,26.0526315789474,0.023573844180358 +"4103",0.338916125940539,15.5263157894737,26.0526315789474,0.0235729149825385 +"4104",0.441187655547492,15.5263157894737,26.0526315789474,0.0235672409243769 +"4105",0.574320702112717,15.5263157894737,26.0526315789474,0.02353292493373 +"4106",0.747628055154725,15.5263157894737,26.0526315789474,0.0233366160397406 +"4107",0.973232737037462,15.5263157894737,26.0526315789474,0.0224673712346569 +"4108",1.2669160204875,15.5263157894737,26.0526315789474,0.0204209082871357 +"4109",1.64922134437622,15.5263157894737,26.0526315789474,0.0178898085546871 +"4110",2.14689134777813,15.5263157894737,26.0526315789474,0.0155214727025708 +"4111",2.79473854427218,15.5263157894737,26.0526315789474,0.0134430670298435 +"4112",3.63808049202114,15.5263157894737,26.0526315789474,0.0116395724230859 +"4113",4.73590980220715,15.5263157894737,26.0526315789474,0.0100775487169367 +"4114",6.16502073107827,15.5263157894737,26.0526315789474,0.00872507938288277 +"4115",8.02538101483936,15.5263157894737,26.0526315789474,0.00755411013039313 +"4116",10.4471247126008,15.5263157894737,26.0526315789474,0.00654029211951529 +"4117",13.5996552137305,15.5263157894737,26.0526315789474,0.00566253586567875 +"4118",17.7034951740616,15.5263157894737,26.0526315789474,0.00490258105678493 +"4119",23.045712295823,15.5263157894737,26.0526315789474,0.00424461788261342 +"4120",30,15.5263157894737,26.0526315789474,0.00367495830421372 +"4121",0.2,17.6315789473684,26.0526315789474,0.0273152957521607 +"4122",0.260352117694686,17.6315789473684,26.0526315789474,0.0273151197148061 +"4123",0.338916125940539,17.6315789473684,26.0526315789474,0.0273140430490963 +"4124",0.441187655547492,17.6315789473684,26.0526315789474,0.0273074684922796 +"4125",0.574320702112717,17.6315789473684,26.0526315789474,0.0272677063989409 +"4126",0.747628055154725,17.6315789473684,26.0526315789474,0.0270402423969148 +"4127",0.973232737037462,17.6315789473684,26.0526315789474,0.0260330445156241 +"4128",1.2669160204875,17.6315789473684,26.0526315789474,0.0236617986561969 +"4129",1.64922134437622,17.6315789473684,26.0526315789474,0.0207290019653817 +"4130",2.14689134777813,17.6315789473684,26.0526315789474,0.0179848005177737 +"4131",2.79473854427218,17.6315789473684,26.0526315789474,0.0155765424783919 +"4132",3.63808049202114,17.6315789473684,26.0526315789474,0.0134868251326891 +"4133",4.73590980220715,17.6315789473684,26.0526315789474,0.0116769012100401 +"4134",6.16502073107827,17.6315789473684,26.0526315789474,0.0101097888847168 +"4135",8.02538101483936,17.6315789473684,26.0526315789474,0.00875298152358387 +"4136",10.4471247126008,17.6315789473684,26.0526315789474,0.00757826601582511 +"4137",13.5996552137305,17.6315789473684,26.0526315789474,0.00656120588042548 +"4138",17.7034951740616,17.6315789473684,26.0526315789474,0.00568064281129001 +"4139",23.045712295823,17.6315789473684,26.0526315789474,0.00491825790991684 +"4140",30,17.6315789473684,26.0526315789474,0.00425819078375679 +"4141",0.2,19.7368421052632,26.0526315789474,0.0312209080038604 +"4142",0.260352117694686,19.7368421052632,26.0526315789474,0.0312207067962256 +"4143",0.338916125940539,19.7368421052632,26.0526315789474,0.0312194761860436 +"4144",0.441187655547492,19.7368421052632,26.0526315789474,0.0312119615819403 +"4145",0.574320702112717,19.7368421052632,26.0526315789474,0.0311665142007575 +"4146",0.747628055154725,19.7368421052632,26.0526315789474,0.0309065268022728 +"4147",0.973232737037462,19.7368421052632,26.0526315789474,0.0297553171401562 +"4148",1.2669160204875,19.7368421052632,26.0526315789474,0.0270450243612154 +"4149",1.64922134437622,19.7368421052632,26.0526315789474,0.0236928887479401 +"4150",2.14689134777813,19.7368421052632,26.0526315789474,0.0205563142177868 +"4151",2.79473854427218,19.7368421052632,26.0526315789474,0.0178037171608376 +"4152",3.63808049202114,19.7368421052632,26.0526315789474,0.0154152065770157 +"4153",4.73590980220715,19.7368421052632,26.0526315789474,0.0133464950098514 +"4154",6.16502073107827,19.7368421052632,26.0526315789474,0.011555312875689 +"4155",8.02538101483936,19.7368421052632,26.0526315789474,0.0100045056581782 +"4156",10.4471247126008,19.7368421052632,26.0526315789474,0.008661826262311 +"4157",13.5996552137305,19.7368421052632,26.0526315789474,0.00749934421526254 +"4158",17.7034951740616,19.7368421052632,26.0526315789474,0.00649287594113079 +"4159",23.045712295823,19.7368421052632,26.0526315789474,0.00562148325751245 +"4160",30,19.7368421052632,26.0526315789474,0.00486703801155221 +"4161",0.2,21.8421052631579,26.0526315789474,0.0352062709070171 +"4162",0.260352117694686,21.8421052631579,26.0526315789474,0.0352060440151375 +"4163",0.338916125940539,21.8421052631579,26.0526315789474,0.0352046563170141 +"4164",0.441187655547492,21.8421052631579,26.0526315789474,0.0351961824703282 +"4165",0.574320702112717,21.8421052631579,26.0526315789474,0.0351449337105631 +"4166",0.747628055154725,21.8421052631579,26.0526315789474,0.0348517588041084 +"4167",0.973232737037462,21.8421052631579,26.0526315789474,0.0335535967125304 +"4168",1.2669160204875,21.8421052631579,26.0526315789474,0.0304973338453223 +"4169",1.64922134437622,21.8421052631579,26.0526315789474,0.0267172966182359 +"4170",2.14689134777813,21.8421052631579,26.0526315789474,0.0231803369431691 +"4171",2.79473854427218,21.8421052631579,26.0526315789474,0.0200763696378995 +"4172",3.63808049202114,21.8421052631579,26.0526315789474,0.0173829646072735 +"4173",4.73590980220715,21.8421052631579,26.0526315789474,0.0150501810811486 +"4174",6.16502073107827,21.8421052631579,26.0526315789474,0.0130303537445659 +"4175",8.02538101483936,21.8421052631579,26.0526315789474,0.0112815852905064 +"4176",10.4471247126008,21.8421052631579,26.0526315789474,0.009767512267828 +"4177",13.5996552137305,21.8421052631579,26.0526315789474,0.00845663886632823 +"4178",17.7034951740616,21.8421052631579,26.0526315789474,0.00732169446579963 +"4179",23.045712295823,21.8421052631579,26.0526315789474,0.00633906811546841 +"4180",30,21.8421052631579,26.0526315789474,0.00548831759564039 +"4181",0.2,23.9473684210526,26.0526315789474,0.0391843539680811 +"4182",0.260352117694686,23.9473684210526,26.0526315789474,0.0391841014388727 +"4183",0.338916125940539,23.9473684210526,26.0526315789474,0.0391825569397517 +"4184",0.441187655547492,23.9473684210526,26.0526315789474,0.0391731256026787 +"4185",0.574320702112717,23.9473684210526,26.0526315789474,0.0391160860613889 +"4186",0.747628055154725,23.9473684210526,26.0526315789474,0.0387897842687502 +"4187",0.973232737037462,23.9473684210526,26.0526315789474,0.0373449381775899 +"4188",1.2669160204875,23.9473684210526,26.0526315789474,0.0339433371865484 +"4189",1.64922134437622,23.9473684210526,26.0526315789474,0.0297361799698733 +"4190",2.14689134777813,23.9473684210526,26.0526315789474,0.0257995665113027 +"4191",2.79473854427218,23.9473684210526,26.0526315789474,0.0223448707863205 +"4192",3.63808049202114,23.9473684210526,26.0526315789474,0.0193471282427208 +"4193",4.73590980220715,23.9473684210526,26.0526315789474,0.0167507551232841 +"4194",6.16502073107827,23.9473684210526,26.0526315789474,0.0145027002378322 +"4195",8.02538101483936,23.9473684210526,26.0526315789474,0.012556332152071 +"4196",10.4471247126008,23.9473684210526,26.0526315789474,0.0108711785778443 +"4197",13.5996552137305,23.9473684210526,26.0526315789474,0.00941218488017689 +"4198",17.7034951740616,23.9473684210526,26.0526315789474,0.00814899903348898 +"4199",23.045712295823,23.9473684210526,26.0526315789474,0.00705534220083455 +"4200",30,23.9473684210526,26.0526315789474,0.00610846232265847 +"4201",0.2,26.0526315789474,26.0526315789474,0.0430735264295427 +"4202",0.260352117694686,26.0526315789474,26.0526315789474,0.0430732488360027 +"4203",0.338916125940539,26.0526315789474,26.0526315789474,0.0430715510404039 +"4204",0.441187655547492,26.0526315789474,26.0526315789474,0.0430611836129604 +"4205",0.574320702112717,26.0526315789474,26.0526315789474,0.0429984827147582 +"4206",0.747628055154725,26.0526315789474,26.0526315789474,0.0426397944255324 +"4207",0.973232737037462,26.0526315789474,26.0526315789474,0.041051542738522 +"4208",1.2669160204875,26.0526315789474,26.0526315789474,0.037312321969188 +"4209",1.64922134437622,26.0526315789474,26.0526315789474,0.0326875909422757 +"4210",2.14689134777813,26.0526315789474,26.0526315789474,0.028360256006787 +"4211",2.79473854427218,26.0526315789474,26.0526315789474,0.0245626706813466 +"4212",3.63808049202114,26.0526315789474,26.0526315789474,0.0212673926020936 +"4213",4.73590980220715,26.0526315789474,26.0526315789474,0.0184133211461214 +"4214",6.16502073107827,26.0526315789474,26.0526315789474,0.0159421396229437 +"4215",8.02538101483936,26.0526315789474,26.0526315789474,0.0138025882792635 +"4216",10.4471247126008,26.0526315789474,26.0526315789474,0.0119501778228752 +"4217",13.5996552137305,26.0526315789474,26.0526315789474,0.0103463743341612 +"4218",17.7034951740616,26.0526315789474,26.0526315789474,0.00895781325192266 +"4219",23.045712295823,26.0526315789474,26.0526315789474,0.00775560748059455 +"4220",30,26.0526315789474,26.0526315789474,0.00671474674593902 +"4221",0.2,28.1578947368421,26.0526315789474,0.0468040736826896 +"4222",0.260352117694686,28.1578947368421,26.0526315789474,0.0468037720471009 +"4223",0.338916125940539,28.1578947368421,26.0526315789474,0.0468019272074304 +"4224",0.441187655547492,28.1578947368421,26.0526315789474,0.0467906618693402 +"4225",0.574320702112717,28.1578947368421,26.0526315789474,0.046722530520396 +"4226",0.747628055154725,28.1578947368421,26.0526315789474,0.0463327766620603 +"4227",0.973232737037462,28.1578947368421,26.0526315789474,0.0446069683722031 +"4228",1.2669160204875,28.1578947368421,26.0526315789474,0.0405438981081506 +"4229",1.64922134437622,28.1578947368421,26.0526315789474,0.0355186245889209 +"4230",2.14689134777813,28.1578947368421,26.0526315789474,0.0308165042853606 +"4231",2.79473854427218,28.1578947368421,26.0526315789474,0.0266900145799274 +"4232",3.63808049202114,28.1578947368421,26.0526315789474,0.0231093363580365 +"4233",4.73590980220715,28.1578947368421,26.0526315789474,0.0200080771439925 +"4234",6.16502073107827,28.1578947368421,26.0526315789474,0.0173228695076198 +"4235",8.02538101483936,28.1578947368421,26.0526315789474,0.0149980141489273 +"4236",10.4471247126008,28.1578947368421,26.0526315789474,0.0129851686106545 +"4237",13.5996552137305,28.1578947368421,26.0526315789474,0.0112424615959151 +"4238",17.7034951740616,28.1578947368421,26.0526315789474,0.00973363887826939 +"4239",23.045712295823,28.1578947368421,26.0526315789474,0.00842731148492175 +"4240",30,28.1578947368421,26.0526315789474,0.00729630303132035 +"4241",0.2,30.2631578947368,26.0526315789474,0.0503223882307774 +"4242",0.260352117694686,30.2631578947368,26.0526315789474,0.0503220639209043 +"4243",0.338916125940539,30.2631578947368,26.0526315789474,0.0503200804025732 +"4244",0.441187655547492,30.2631578947368,26.0526315789474,0.0503079682364235 +"4245",0.574320702112717,30.2631578947368,26.0526315789474,0.0502347153778049 +"4246",0.747628055154725,30.2631578947368,26.0526315789474,0.0498156632861731 +"4247",0.973232737037462,30.2631578947368,26.0526315789474,0.047960124057625 +"4248",1.2669160204875,30.2631578947368,26.0526315789474,0.0435916282591023 +"4249",1.64922134437622,30.2631578947368,26.0526315789474,0.038188599310918 +"4250",2.14689134777813,30.2631578947368,26.0526315789474,0.0331330153669269 +"4251",2.79473854427218,30.2631578947368,26.0526315789474,0.0286963328167087 +"4252",3.63808049202114,30.2631578947368,26.0526315789474,0.024846491009496 +"4253",4.73590980220715,30.2631578947368,26.0526315789474,0.0215121066729651 +"4254",6.16502073107827,30.2631578947368,26.0526315789474,0.0186250489763661 +"4255",8.02538101483936,30.2631578947368,26.0526315789474,0.0161254316410528 +"4256",10.4471247126008,30.2631578947368,26.0526315789474,0.0139612782532033 +"4257",13.5996552137305,30.2631578947368,26.0526315789474,0.01208757000373 +"4258",17.7034951740616,30.2631578947368,26.0526315789474,0.0104653273954575 +"4259",23.045712295823,30.2631578947368,26.0526315789474,0.00906080191141072 +"4260",30,30.2631578947368,26.0526315789474,0.00784477428782652 +"4261",0.2,32.3684210526316,26.0526315789474,0.0535925377292278 +"4262",0.260352117694686,32.3684210526316,26.0526315789474,0.0535921923444056 +"4263",0.338916125940539,32.3684210526316,26.0526315789474,0.0535900799291421 +"4264",0.441187655547492,32.3684210526316,26.0526315789474,0.0535771806661266 +"4265",0.574320702112717,32.3684210526316,26.0526315789474,0.0534991675445853 +"4266",0.747628055154725,32.3684210526316,26.0526315789474,0.053052883776647 +"4267",0.973232737037462,32.3684210526316,26.0526315789474,0.051076764208196 +"4268",1.2669160204875,32.3684210526316,26.0526315789474,0.0464243861289078 +"4269",1.64922134437622,32.3684210526316,26.0526315789474,0.0406702468096499 +"4270",2.14689134777813,32.3684210526316,26.0526315789474,0.0352861308567446 +"4271",2.79473854427218,32.3684210526316,26.0526315789474,0.0305611349786723 +"4272",3.63808049202114,32.3684210526316,26.0526315789474,0.0264611150957046 +"4273",4.73590980220715,32.3684210526316,26.0526315789474,0.0229100491657696 +"4274",6.16502073107827,32.3684210526316,26.0526315789474,0.0198353789449948 +"4275",8.02538101483936,32.3684210526316,26.0526315789474,0.0171733265054908 +"4276",10.4471247126008,32.3684210526316,26.0526315789474,0.0148685377987572 +"4277",13.5996552137305,32.3684210526316,26.0526315789474,0.0128730685139339 +"4278",17.7034951740616,32.3684210526316,26.0526315789474,0.0111454061106494 +"4279",23.045712295823,32.3684210526316,26.0526315789474,0.00964960895868906 +"4280",30,32.3684210526316,26.0526315789474,0.00835455900998926 +"4281",0.2,34.4736842105263,26.0526315789474,0.0565955277206869 +"4282",0.260352117694686,34.4736842105263,26.0526315789474,0.0565951629826635 +"4283",0.338916125940539,34.4736842105263,26.0526315789474,0.0565929322008854 +"4284",0.441187655547492,34.4736842105263,26.0526315789474,0.0565793101440002 +"4285",0.574320702112717,34.4736842105263,26.0526315789474,0.0564969256559755 +"4286",0.747628055154725,34.4736842105263,26.0526315789474,0.0560256349421964 +"4287",0.973232737037462,34.4736842105263,26.0526315789474,0.0539387860159387 +"4288",1.2669160204875,34.4736842105263,26.0526315789474,0.0490257178219339 +"4289",1.64922134437622,34.4736842105263,26.0526315789474,0.0429491525919551 +"4290",2.14689134777813,34.4736842105263,26.0526315789474,0.0372633445191297 +"4291",2.79473854427218,34.4736842105263,26.0526315789474,0.0322735894799364 +"4292",3.63808049202114,34.4736842105263,26.0526315789474,0.0279438301743733 +"4293",4.73590980220715,34.4736842105263,26.0526315789474,0.024193784761502 +"4294",6.16502073107827,34.4736842105263,26.0526315789474,0.0209468292881297 +"4295",8.02538101483936,34.4736842105263,26.0526315789474,0.0181356121109347 +"4296",10.4471247126008,34.4736842105263,26.0526315789474,0.0157016774873998 +"4297",13.5996552137305,34.4736842105263,26.0526315789474,0.0135943946079141 +"4298",17.7034951740616,34.4736842105263,26.0526315789474,0.0117699248294704 +"4299",23.045712295823,34.4736842105263,26.0526315789474,0.0101903125781154 +"4300",30,34.4736842105263,26.0526315789474,0.00882269614536453 +"4301",0.2,36.5789473684211,26.0526315789474,0.0593269504654957 +"4302",0.260352117694686,36.5789473684211,26.0526315789474,0.0593265681244253 +"4303",0.338916125940539,36.5789473684211,26.0526315789474,0.0593242296802871 +"4304",0.441187655547492,36.5789473684211,26.0526315789474,0.0593099501934334 +"4305",0.574320702112717,36.5789473684211,26.0526315789474,0.0592235896515848 +"4306",0.747628055154725,36.5789473684211,26.0526315789474,0.0587295534272172 +"4307",0.973232737037462,36.5789473684211,26.0526315789474,0.0565419886519919 +"4308",1.2669160204875,36.5789473684211,26.0526315789474,0.0513918051460117 +"4309",1.64922134437622,36.5789473684211,26.0526315789474,0.0450219717171498 +"4310",2.14689134777813,36.5789473684211,26.0526315789474,0.0390617542321642 +"4311",2.79473854427218,36.5789473684211,26.0526315789474,0.0338311828077551 +"4312",3.63808049202114,36.5789473684211,26.0526315789474,0.0292924599405281 +"4313",4.73590980220715,36.5789473684211,26.0526315789474,0.0253614292140233 +"4314",6.16502073107827,36.5789473684211,26.0526315789474,0.0219577686371113 +"4315",8.02538101483936,36.5789473684211,26.0526315789474,0.0190108760302909 +"4316",10.4471247126008,36.5789473684211,26.0526315789474,0.0164594744503047 +"4317",13.5996552137305,36.5789473684211,26.0526315789474,0.0142504895350119 +"4318",17.7034951740616,36.5789473684211,26.0526315789474,0.012337966893546 +"4319",23.045712295823,36.5789473684211,26.0526315789474,0.010682119133749 +"4320",30,36.5789473684211,26.0526315789474,0.00924849856991154 +"4321",0.2,38.6842105263158,26.0526315789474,0.0617938056734254 +"4322",0.260352117694686,38.6842105263158,26.0526315789474,0.0617934074343517 +"4323",0.338916125940539,38.6842105263158,26.0526315789474,0.0617909717561056 +"4324",0.441187655547492,38.6842105263158,26.0526315789474,0.0617760985184147 +"4325",0.574320702112717,38.6842105263158,26.0526315789474,0.0616861470461247 +"4326",0.747628055154725,38.6842105263158,26.0526315789474,0.0611715684573944 +"4327",0.973232737037462,38.6842105263158,26.0526315789474,0.0588930432414907 +"4328",1.2669160204875,38.6842105263158,26.0526315789474,0.0535287115801808 +"4329",1.64922134437622,38.6842105263158,26.0526315789474,0.0468940161173809 +"4330",2.14689134777813,38.6842105263158,26.0526315789474,0.0406859687097738 +"4331",2.79473854427218,38.6842105263158,26.0526315789474,0.0352379065453636 +"4332",3.63808049202114,38.6842105263158,26.0526315789474,0.0305104604746933 +"4333",4.73590980220715,38.6842105263158,26.0526315789474,0.026415974799904 +"4334",6.16502073107827,38.6842105263158,26.0526315789474,0.0228707876864973 +"4335",8.02538101483936,38.6842105263158,26.0526315789474,0.0198013612680229 +"4336",10.4471247126008,38.6842105263158,26.0526315789474,0.0171438706639806 +"4337",13.5996552137305,38.6842105263158,26.0526315789474,0.0148430346439239 +"4338",17.7034951740616,38.6842105263158,26.0526315789474,0.0128509880019596 +"4339",23.045712295823,38.6842105263158,26.0526315789474,0.0111262889589306 +"4340",30,38.6842105263158,26.0526315789474,0.00963305747077711 +"4341",0.2,40.7894736842105,26.0526315789474,0.0640111649053613 +"4342",0.260352117694686,40.7894736842105,26.0526315789474,0.0640107523761968 +"4343",0.338916125940539,40.7894736842105,26.0526315789474,0.0640082292980312 +"4344",0.441187655547492,40.7894736842105,26.0526315789474,0.0639928223610391 +"4345",0.574320702112717,40.7894736842105,26.0526315789474,0.063899643142451 +"4346",0.747628055154725,40.7894736842105,26.0526315789474,0.0633665998294357 +"4347",0.973232737037462,40.7894736842105,26.0526315789474,0.061006313846937 +"4348",1.2669160204875,40.7894736842105,26.0526315789474,0.0554494928219645 +"4349",1.64922134437622,40.7894736842105,26.0526315789474,0.0485767232823992 +"4350",2.14689134777813,40.7894736842105,26.0526315789474,0.0421459112937546 +"4351",2.79473854427218,40.7894736842105,26.0526315789474,0.0365023552476395 +"4352",3.63808049202114,40.7894736842105,26.0526315789474,0.0316052733036961 +"4353",4.73590980220715,40.7894736842105,26.0526315789474,0.027363864397491 +"4354",6.16502073107827,40.7894736842105,26.0526315789474,0.0236914646405323 +"4355",8.02538101483936,40.7894736842105,26.0526315789474,0.0205118973927048 +"4356",10.4471247126008,40.7894736842105,26.0526315789474,0.0177590475328206 +"4357",13.5996552137305,40.7894736842105,26.0526315789474,0.0153756501632137 +"4358",17.7034951740616,40.7894736842105,26.0526315789474,0.0133121225214329 +"4359",23.045712295823,40.7894736842105,26.0526315789474,0.0115255357648427 +"4360",30,40.7894736842105,26.0526315789474,0.00997872235873499 +"4361",0.2,42.8947368421053,26.0526315789474,0.0659991389447994 +"4362",0.260352117694686,42.8947368421053,26.0526315789474,0.0659987136038502 +"4363",0.338916125940539,42.8947368421053,26.0526315789474,0.0659961121672623 +"4364",0.441187655547492,42.8947368421053,26.0526315789474,0.0659802267420125 +"4365",0.574320702112717,42.8947368421053,26.0526315789474,0.0658841536865782 +"4366",0.747628055154725,42.8947368421053,26.0526315789474,0.065334555819842 +"4367",0.973232737037462,42.8947368421053,26.0526315789474,0.0629009671991895 +"4368",1.2669160204875,42.8947368421053,26.0526315789474,0.0571715697813989 +"4369",1.64922134437622,42.8947368421053,26.0526315789474,0.0500853548617363 +"4370",2.14689134777813,42.8947368421053,26.0526315789474,0.0434548232256703 +"4371",2.79473854427218,42.8947368421053,26.0526315789474,0.0376359970852462 +"4372",3.63808049202114,42.8947368421053,26.0526315789474,0.0325868280516841 +"4373",4.73590980220715,42.8947368421053,26.0526315789474,0.0282136950812685 +"4374",6.16502073107827,42.8947368421053,26.0526315789474,0.0244272427931605 +"4375",8.02538101483936,42.8947368421053,26.0526315789474,0.0211489287539776 +"4376",10.4471247126008,42.8947368421053,26.0526315789474,0.0183105845266028 +"4377",13.5996552137305,42.8947368421053,26.0526315789474,0.0158531667559698 +"4378",17.7034951740616,42.8947368421053,26.0526315789474,0.013725552803815 +"4379",23.045712295823,42.8947368421053,26.0526315789474,0.0118834806003257 +"4380",30,42.8947368421053,26.0526315789474,0.0102886283106928 +"4381",0.2,45,26.0526315789474,0.0677803892725847 +"4382",0.260352117694686,45,26.0526315789474,0.0677799524521114 +"4383",0.338916125940539,45,26.0526315789474,0.0677772808053685 +"4384",0.441187655547492,45,26.0526315789474,0.0677609666484809 +"4385",0.574320702112717,45,26.0526315789474,0.0676623006779841 +"4386",0.747628055154725,45,26.0526315789474,0.0670978697180299 +"4387",0.973232737037462,45,26.0526315789474,0.0645986009900679 +"4388",1.2669160204875,45,26.0526315789474,0.0587145729029743 +"4389",1.64922134437622,45,26.0526315789474,0.0514371081753565 +"4390",2.14689134777813,45,26.0526315789474,0.0446276251644852 +"4391",2.79473854427218,45,26.0526315789474,0.03865175476355 +"4392",3.63808049202114,45,26.0526315789474,0.0334663137400821 +"4393",4.73590980220715,45,26.0526315789474,0.0289751543126318 +"4394",6.16502073107827,45,26.0526315789474,0.025086509488573 +"4395",8.02538101483936,45,26.0526315789474,0.0217197170533043 +"4396",10.4471247126008,45,26.0526315789474,0.0188047687722068 +"4397",13.5996552137305,45,26.0526315789474,0.0162810277694918 +"4398",17.7034951740616,45,26.0526315789474,0.0140959916583473 +"4399",23.045712295823,45,26.0526315789474,0.0122042037802487 +"4400",30,45,26.0526315789474,0.0105663080326391 +"4401",0.2,5,28.1578947368421,0.0105823374613747 +"4402",0.260352117694686,5,28.1578947368421,0.0105822692619779 +"4403",0.338916125940539,5,28.1578947368421,0.0105818521462352 +"4404",0.441187655547492,5,28.1578947368421,0.0105793050686006 +"4405",0.574320702112717,5,28.1578947368421,0.0105639006631825 +"4406",0.747628055154725,5,28.1578947368421,0.0104757778454179 +"4407",0.973232737037462,5,28.1578947368421,0.0100855749361429 +"4408",1.2669160204875,5,28.1578947368421,0.00916692027041917 +"4409",1.64922134437622,5,28.1578947368421,0.00803071275616028 +"4410",2.14689134777813,5,28.1578947368421,0.0069675697448574 +"4411",2.79473854427218,5,28.1578947368421,0.00603457602961306 +"4412",3.63808049202114,5,28.1578947368421,0.00522498954913841 +"4413",4.73590980220715,5,28.1578947368421,0.00452379905489413 +"4414",6.16502073107827,5,28.1578947368421,0.00391667725702239 +"4415",8.02538101483936,5,28.1578947368421,0.00339103061948047 +"4416",10.4471247126008,5,28.1578947368421,0.00293592897837047 +"4417",13.5996552137305,5,28.1578947368421,0.00254190529036193 +"4418",17.7034951740616,5,28.1578947368421,0.00220076252411976 +"4419",23.045712295823,5,28.1578947368421,0.00190540367554681 +"4420",30,5,28.1578947368421,0.00164968420102372 +"4421",0.2,7.10526315789474,28.1578947368421,0.0117899000427748 +"4422",0.260352117694686,7.10526315789474,28.1578947368421,0.0117898240610672 +"4423",0.338916125940539,7.10526315789474,28.1578947368421,0.011789359347772 +"4424",0.441187655547492,7.10526315789474,28.1578947368421,0.0117865216202072 +"4425",0.574320702112717,7.10526315789474,28.1578947368421,0.0117693594005407 +"4426",0.747628055154725,7.10526315789474,28.1578947368421,0.0116711807876657 +"4427",0.973232737037462,7.10526315789474,28.1578947368421,0.0112364513799575 +"4428",1.2669160204875,7.10526315789474,28.1578947368421,0.0102129679839456 +"4429",1.64922134437622,7.10526315789474,28.1578947368421,0.0089471065360513 +"4430",2.14689134777813,7.10526315789474,28.1578947368421,0.00776264706476856 +"4431",2.79473854427218,7.10526315789474,28.1578947368421,0.00672318837396255 +"4432",3.63808049202114,7.10526315789474,28.1578947368421,0.00582121905805132 +"4433",4.73590980220715,7.10526315789474,28.1578947368421,0.00504001491782633 +"4434",6.16502073107827,7.10526315789474,28.1578947368421,0.00436361376006475 +"4435",8.02538101483936,7.10526315789474,28.1578947368421,0.00377798498598152 +"4436",10.4471247126008,7.10526315789474,28.1578947368421,0.00327095117822648 +"4437",13.5996552137305,7.10526315789474,28.1578947368421,0.0028319649983714 +"4438",17.7034951740616,7.10526315789474,28.1578947368421,0.00245189404249882 +"4439",23.045712295823,7.10526315789474,28.1578947368421,0.00212283145929031 +"4440",30,7.10526315789474,28.1578947368421,0.00183793154425523 +"4441",0.2,9.21052631578947,28.1578947368421,0.01306446921825 +"4442",0.260352117694686,9.21052631578947,28.1578947368421,0.013064385022398 +"4443",0.338916125940539,9.21052631578947,28.1578947368421,0.0130638700704036 +"4444",0.441187655547492,9.21052631578947,28.1578947368421,0.0130607255649977 +"4445",0.574320702112717,9.21052631578947,28.1578947368421,0.0130417079915037 +"4446",0.747628055154725,9.21052631578947,28.1578947368421,0.0129329155962211 +"4447",0.973232737037462,9.21052631578947,28.1578947368421,0.0124511889535298 +"4448",1.2669160204875,9.21052631578947,28.1578947368421,0.0113170599724464 +"4449",1.64922134437622,9.21052631578947,28.1578947368421,0.00991435020725892 +"4450",2.14689134777813,9.21052631578947,28.1578947368421,0.00860184253147745 +"4451",2.79473854427218,9.21052631578947,28.1578947368421,0.00745001121650376 +"4452",3.63808049202114,9.21052631578947,28.1578947368421,0.00645053282221918 +"4453",4.73590980220715,9.21052631578947,28.1578947368421,0.00558487514860781 +"4454",6.16502073107827,9.21052631578947,28.1578947368421,0.00483535037972054 +"4455",8.02538101483936,9.21052631578947,28.1578947368421,0.00418641111267217 +"4456",10.4471247126008,9.21052631578947,28.1578947368421,0.00362456346765441 +"4457",13.5996552137305,9.21052631578947,28.1578947368421,0.00313811986650882 +"4458",17.7034951740616,9.21052631578947,28.1578947368421,0.00271696062972706 +"4459",23.045712295823,9.21052631578947,28.1578947368421,0.00235232412105369 +"4460",30,9.21052631578947,28.1578947368421,0.00203662456832179 +"4461",0.2,11.3157894736842,28.1578947368421,0.014398776980109 +"4462",0.260352117694686,11.3157894736842,28.1578947368421,0.0143986841851185 +"4463",0.338916125940539,11.3157894736842,28.1578947368421,0.0143981166397557 +"4464",0.441187655547492,11.3157894736842,28.1578947368421,0.0143946509779446 +"4465",0.574320702112717,11.3157894736842,28.1578947368421,0.0143736910908747 +"4466",0.747628055154725,11.3157894736842,28.1578947368421,0.0142537874491242 +"4467",0.973232737037462,11.3157894736842,28.1578947368421,0.0137228608284085 +"4468",1.2669160204875,11.3157894736842,28.1578947368421,0.0124729003445577 +"4469",1.64922134437622,11.3157894736842,28.1578947368421,0.0109269282320021 +"4470",2.14689134777813,11.3157894736842,28.1578947368421,0.00948037077968256 +"4471",2.79473854427218,11.3157894736842,28.1578947368421,0.00821089997716087 +"4472",3.63808049202114,11.3157894736842,28.1578947368421,0.00710934229002287 +"4473",4.73590980220715,11.3157894736842,28.1578947368421,0.00615527277711543 +"4474",6.16502073107827,11.3157894736842,28.1578947368421,0.00532919712046345 +"4475",8.02538101483936,11.3157894736842,28.1578947368421,0.00461398002103378 +"4476",10.4471247126008,11.3157894736842,28.1578947368421,0.00399474943445096 +"4477",13.5996552137305,11.3157894736842,28.1578947368421,0.00345862410021143 +"4478",17.7034951740616,11.3157894736842,28.1578947368421,0.00299445078997374 +"4479",23.045712295823,11.3157894736842,28.1578947368421,0.00259257301909124 +"4480",30,11.3157894736842,28.1578947368421,0.00224463026102214 +"4481",0.2,13.4210526315789,28.1578947368421,0.0157842474347364 +"4482",0.260352117694686,13.4210526315789,28.1578947368421,0.0157841457108822 +"4483",0.338916125940539,13.4210526315789,28.1578947368421,0.015783523555511 +"4484",0.441187655547492,13.4210526315789,28.1578947368421,0.0157797244228745 +"4485",0.574320702112717,13.4210526315789,28.1578947368421,0.0157567477461628 +"4486",0.747628055154725,13.4210526315789,28.1578947368421,0.0156253068083435 +"4487",0.973232737037462,13.4210526315789,28.1578947368421,0.0150432936857956 +"4488",1.2669160204875,13.4210526315789,28.1578947368421,0.013673060256387 +"4489",1.64922134437622,13.4210526315789,28.1578947368421,0.0119783325454508 +"4490",2.14689134777813,13.4210526315789,28.1578947368421,0.0103925853123688 +"4491",2.79473854427218,13.4210526315789,28.1578947368421,0.00900096425414584 +"4492",3.63808049202114,13.4210526315789,28.1578947368421,0.00779341314605925 +"4493",4.73590980220715,13.4210526315789,28.1578947368421,0.00674754173055827 +"4494",6.16502073107827,13.4210526315789,28.1578947368421,0.00584197991913361 +"4495",8.02538101483936,13.4210526315789,28.1578947368421,0.0050579436303191 +"4496",10.4471247126008,13.4210526315789,28.1578947368421,0.00437912981083412 +"4497",13.5996552137305,13.4210526315789,28.1578947368421,0.00379141774727777 +"4498",17.7034951740616,13.4210526315789,28.1578947368421,0.0032825810320822 +"4499",23.045712295823,13.4210526315789,28.1578947368421,0.00284203402014551 +"4500",30,13.4210526315789,28.1578947368421,0.00246061172337168 +"4501",0.2,15.5263157894737,28.1578947368421,0.0172112541174461 +"4502",0.260352117694686,15.5263157894737,28.1578947368421,0.0172111431970419 +"4503",0.338916125940539,15.5263157894737,28.1578947368421,0.0172104647944612 +"4504",0.441187655547492,15.5263157894737,28.1578947368421,0.0172063221935863 +"4505",0.574320702112717,15.5263157894737,28.1578947368421,0.0171812682641357 +"4506",0.747628055154725,15.5263157894737,28.1578947368421,0.0170379441435784 +"4507",0.973232737037462,15.5263157894737,28.1578947368421,0.0164033129523684 +"4508",1.2669160204875,15.5263157894737,28.1578947368421,0.0149092008097856 +"4509",1.64922134437622,15.5263157894737,28.1578947368421,0.0130612578265422 +"4510",2.14689134777813,15.5263157894737,28.1578947368421,0.0113321479207668 +"4511",2.79473854427218,15.5263157894737,28.1578947368421,0.00981471455770671 +"4512",3.63808049202114,15.5263157894737,28.1578947368421,0.00849799235938742 +"4513",4.73590980220715,15.5263157894737,28.1578947368421,0.00735756683192476 +"4514",6.16502073107827,15.5263157894737,28.1578947368421,0.00637013588091313 +"4515",8.02538101483936,15.5263157894737,28.1578947368421,0.00551521721216565 +"4516",10.4471247126008,15.5263157894737,28.1578947368421,0.00477503386203146 +"4517",13.5996552137305,15.5263157894737,28.1578947368421,0.00413418850557206 +"4518",17.7034951740616,15.5263157894737,28.1578947368421,0.00357934938221643 +"4519",23.045712295823,15.5263157894737,28.1578947368421,0.00309897383029513 +"4520",30,15.5263157894737,28.1578947368421,0.00268306828250276 +"4521",0.2,17.6315789473684,28.1578947368421,0.0186694321437014 +"4522",0.260352117694686,17.6315789473684,28.1578947368421,0.0186693118258591 +"4523",0.338916125940539,17.6315789473684,28.1578947368421,0.0186685759474124 +"4524",0.441187655547492,17.6315789473684,28.1578947368421,0.0186640823756247 +"4525",0.574320702112717,17.6315789473684,28.1578947368421,0.0186369058182037 +"4526",0.747628055154725,17.6315789473684,28.1578947368421,0.0184814389402504 +"4527",0.973232737037462,17.6315789473684,28.1578947368421,0.0177930402983082 +"4528",1.2669160204875,17.6315789473684,28.1578947368421,0.016172343452472 +"4529",1.64922134437622,17.6315789473684,28.1578947368421,0.0141678383829593 +"4530",2.14689134777813,17.6315789473684,28.1578947368421,0.0122922342093998 +"4531",2.79473854427218,17.6315789473684,28.1578947368421,0.0106462403143051 +"4532",3.63808049202114,17.6315789473684,28.1578947368421,0.00921796230702673 +"4533",4.73590980220715,17.6315789473684,28.1578947368421,0.00798091724019878 +"4534",6.16502073107827,17.6315789473684,28.1578947368421,0.00690982881104033 +"4535",8.02538101483936,17.6315789473684,28.1578947368421,0.00598247941711173 +"4536",10.4471247126008,17.6315789473684,28.1578947368421,0.00517958598849048 +"4537",13.5996552137305,17.6315789473684,28.1578947368421,0.00448444670256841 +"4538",17.7034951740616,17.6315789473684,28.1578947368421,0.0038826003005878 +"4539",23.045712295823,17.6315789473684,28.1578947368421,0.00336152619936951 +"4540",30,17.6315789473684,28.1578947368421,0.00291038415302508 +"4541",0.2,19.7368421052632,28.1578947368421,0.0201480237771937 +"4542",0.260352117694686,19.7368421052632,28.1578947368421,0.0201478939303548 +"4543",0.338916125940539,19.7368421052632,28.1578947368421,0.0201470997714148 +"4544",0.441187655547492,19.7368421052632,28.1578947368421,0.0201422503153346 +"4545",0.574320702112717,19.7368421052632,28.1578947368421,0.02011292141444 +"4546",0.747628055154725,19.7368421052632,28.1578947368421,0.019945141787858 +"4547",0.973232737037462,19.7368421052632,28.1578947368421,0.0192022229835108 +"4548",1.2669160204875,19.7368421052632,28.1578947368421,0.017453169325414 +"4549",1.64922134437622,19.7368421052632,28.1578947368421,0.0152899103954592 +"4550",2.14689134777813,19.7368421052632,28.1578947368421,0.0132657611232903 +"4551",2.79473854427218,19.7368421052632,28.1578947368421,0.0114894069267503 +"4552",3.63808049202114,19.7368421052632,28.1578947368421,0.00994801139690304 +"4553",4.73590980220715,19.7368421052632,28.1578947368421,0.00861299417580784 +"4554",6.16502073107827,19.7368421052632,28.1578947368421,0.00745707711458956 +"4555",8.02538101483936,19.7368421052632,28.1578947368421,0.00645628300929359 +"4556",10.4471247126008,19.7368421052632,28.1578947368421,0.00558980159915219 +"4557",13.5996552137305,19.7368421052632,28.1578947368421,0.00483960830171199 +"4558",17.7034951740616,19.7368421052632,28.1578947368421,0.00419009654773962 +"4559",23.045712295823,19.7368421052632,28.1578947368421,0.00362775414223866 +"4560",30,19.7368421052632,28.1578947368421,0.0031408823077514 +"4561",0.2,21.8421052631579,28.1578947368421,0.0216362332519967 +"4562",0.260352117694686,21.8421052631579,28.1578947368421,0.0216360938141777 +"4563",0.338916125940539,21.8421052631579,28.1578947368421,0.0216352409956454 +"4564",0.441187655547492,21.8421052631579,28.1578947368421,0.021630033340341 +"4565",0.574320702112717,21.8421052631579,28.1578947368421,0.0215985380955569 +"4566",0.747628055154725,21.8421052631579,28.1578947368421,0.0214183656292244 +"4567",0.973232737037462,21.8421052631579,28.1578947368421,0.0206205720234642 +"4568",1.2669160204875,21.8421052631579,28.1578947368421,0.0187423266265297 +"4569",1.64922134437622,21.8421052631579,28.1578947368421,0.0164192811849243 +"4570",2.14689134777813,21.8421052631579,28.1578947368421,0.0142456205681903 +"4571",2.79473854427218,21.8421052631579,28.1578947368421,0.012338058111469 +"4572",3.63808049202114,21.8421052631579,28.1578947368421,0.0106828092599608 +"4573",4.73590980220715,21.8421052631579,28.1578947368421,0.00924918260205784 +"4574",6.16502073107827,21.8421052631579,28.1578947368421,0.00800788512131976 +"4575",8.02538101483936,21.8421052631579,28.1578947368421,0.00693316856654195 +"4576",10.4471247126008,21.8421052631579,28.1578947368421,0.00600268555214532 +"4577",13.5996552137305,21.8421052631579,28.1578947368421,0.00519708013163388 +"4578",17.7034951740616,21.8421052631579,28.1578947368421,0.00449959297536167 +"4579",23.045712295823,21.8421052631579,28.1578947368421,0.00389571382634657 +"4580",30,21.8421052631579,28.1578947368421,0.00337287979104442 +"4581",0.2,23.9473684210526,28.1578947368421,0.0231235667845707 +"4582",0.260352117694686,23.9473684210526,28.1578947368421,0.0231234177614167 +"4583",0.338916125940539,23.9473684210526,28.1578947368421,0.0231225063178185 +"4584",0.441187655547492,23.9473684210526,28.1578947368421,0.0231169406741217 +"4585",0.574320702112717,23.9473684210526,28.1578947368421,0.023083280360532 +"4586",0.747628055154725,23.9473684210526,28.1578947368421,0.0228907223487257 +"4587",0.973232737037462,23.9473684210526,28.1578947368421,0.0220380862402018 +"4588",1.2669160204875,23.9473684210526,28.1578947368421,0.020030725145136 +"4589",1.64922134437622,23.9473684210526,28.1578947368421,0.0175479872403023 +"4590",2.14689134777813,23.9473684210526,28.1578947368421,0.0152249032795856 +"4591",2.79473854427218,23.9473684210526,28.1578947368421,0.0131862097902896 +"4592",3.63808049202114,23.9473684210526,28.1578947368421,0.0114171746298186 +"4593",4.73590980220715,23.9473684210526,28.1578947368421,0.0098849965754384 +"4594",6.16502073107827,23.9473684210526,28.1578947368421,0.00855836892907037 +"4595",8.02538101483936,23.9473684210526,28.1578947368421,0.00740977343467695 +"4596",10.4471247126008,23.9473684210526,28.1578947368421,0.00641532648660092 +"4597",13.5996552137305,23.9473684210526,28.1578947368421,0.00555434155792858 +"4598",17.7034951740616,23.9473684210526,28.1578947368421,0.00480890723710232 +"4599",23.045712295823,23.9473684210526,28.1578947368421,0.00416351579260161 +"4600",30,23.9473684210526,28.1578947368421,0.0036047407234042 +"4601",0.2,26.0526315789474,28.1578947368421,0.0246001365043004 +"4602",0.260352117694686,26.0526315789474,28.1578947368421,0.0245999779651803 +"4603",0.338916125940539,26.0526315789474,28.1578947368421,0.024599008320785 +"4604",0.441187655547492,26.0526315789474,28.1578947368421,0.024593087279453 +"4605",0.574320702112717,26.0526315789474,28.1578947368421,0.0245572775656316 +"4606",0.747628055154725,26.0526315789474,28.1578947368421,0.0243524236423783 +"4607",0.973232737037462,26.0526315789474,28.1578947368421,0.0234453419255481 +"4608",1.2669160204875,26.0526315789474,28.1578947368421,0.0213097995409282 +"4609",1.64922134437622,26.0526315789474,28.1578947368421,0.0186685248650827 +"4610",2.14689134777813,26.0526315789474,28.1578947368421,0.0161970989351213 +"4611",2.79473854427218,26.0526315789474,28.1578947368421,0.0140282234067762 +"4612",3.63808049202114,26.0526315789474,28.1578947368421,0.0121462254073356 +"4613",4.73590980220715,26.0526315789474,28.1578947368421,0.0105162091716138 +"4614",6.16502073107827,26.0526315789474,28.1578947368421,0.009104868892881 +"4615",8.02538101483936,26.0526315789474,28.1578947368421,0.00788292911976797 +"4616",10.4471247126008,26.0526315789474,28.1578947368421,0.00682498114414343 +"4617",13.5996552137305,26.0526315789474,28.1578947368421,0.00590901748806865 +"4618",17.7034951740616,26.0526315789474,28.1578947368421,0.0051159829956757 +"4619",23.045712295823,26.0526315789474,28.1578947368421,0.00442937967961553 +"4620",30,26.0526315789474,28.1578947368421,0.00383492368130352 +"4621",0.2,28.1578947368421,28.1578947368421,0.0260569119291081 +"4622",0.260352117694686,28.1578947368421,28.1578947368421,0.0260567440015891 +"4623",0.338916125940539,28.1578947368421,28.1578947368421,0.0260557169366131 +"4624",0.441187655547492,28.1578947368421,28.1578947368421,0.0260494452619624 +"4625",0.574320702112717,28.1578947368421,28.1578947368421,0.0260115149618973 +"4626",0.747628055154725,28.1578947368421,28.1578947368421,0.0257945299611998 +"4627",0.973232737037462,28.1578947368421,28.1578947368421,0.024833732511811 +"4628",1.2669160204875,28.1578947368421,28.1578947368421,0.022571727184028 +"4629",1.64922134437622,28.1578947368421,28.1578947368421,0.019774041016837 +"4630",2.14689134777813,28.1578947368421,28.1578947368421,0.0171562617299187 +"4631",2.79473854427218,28.1578947368421,28.1578947368421,0.0148589493301519 +"4632",3.63808049202114,28.1578947368421,28.1578947368421,0.0128655028257551 +"4633",4.73590980220715,28.1578947368421,28.1578947368421,0.011138959987678 +"4634",6.16502073107827,28.1578947368421,28.1578947368421,0.00964404269977946 +"4635",8.02538101483936,28.1578947368421,28.1578947368421,0.00834974187160663 +"4636",10.4471247126008,28.1578947368421,28.1578947368421,0.0072291441374596 +"4637",13.5996552137305,28.1578947368421,28.1578947368421,0.00625893877650835 +"4638",17.7034951740616,28.1578947368421,28.1578947368421,0.00541894222114714 +"4639",23.045712295823,28.1578947368421,28.1578947368421,0.00469167950316646 +"4640",30,28.1578947368421,28.1578947368421,0.00406202089980715 +"4641",0.2,30.2631578947368,28.1578947368421,0.0274859087394832 +"4642",0.260352117694686,30.2631578947368,28.1578947368421,0.0274857316025887 +"4643",0.338916125940539,30.2631578947368,28.1578947368421,0.0274846482119598 +"4644",0.441187655547492,30.2631578947368,28.1578947368421,0.0274780325900641 +"4645",0.574320702112717,30.2631578947368,28.1578947368421,0.0274380221402884 +"4646",0.747628055154725,30.2631578947368,28.1578947368421,0.0272091373843651 +"4647",0.973232737037462,30.2631578947368,28.1578947368421,0.0261956484842653 +"4648",1.2669160204875,30.2631578947368,28.1578947368421,0.0238095916799586 +"4649",1.64922134437622,30.2631578947368,28.1578947368421,0.0208584765638491 +"4650",2.14689134777813,30.2631578947368,28.1578947368421,0.0180971346682284 +"4651",2.79473854427218,30.2631578947368,28.1578947368421,0.0156738345036552 +"4652",3.63808049202114,30.2631578947368,28.1578947368421,0.0135710646571761 +"4653",4.73590980220715,30.2631578947368,28.1578947368421,0.0117498358403729 +"4654",6.16502073107827,30.2631578947368,28.1578947368421,0.0101729352368 +"4655",8.02538101483936,30.2631578947368,28.1578947368421,0.00880765317492775 +"4656",10.4471247126008,30.2631578947368,28.1578947368421,0.00762560032314566 +"4657",13.5996552137305,30.2631578947368,28.1578947368421,0.00660218756870205 +"4658",17.7034951740616,30.2631578947368,28.1578947368421,0.00571612444944396 +"4659",23.045712295823,30.2631578947368,28.1578947368421,0.00494897764592288 +"4660",30,30.2631578947368,28.1578947368421,0.00428478770061969 +"4661",0.2,32.3684210526316,28.1578947368421,0.0288803110000826 +"4662",0.260352117694686,32.3684210526316,28.1578947368421,0.028880124876762 +"4663",0.338916125940539,32.3684210526316,28.1578947368421,0.0288789865240667 +"4664",0.441187655547492,32.3684210526316,28.1578947368421,0.0288720352815366 +"4665",0.574320702112717,32.3684210526316,28.1578947368421,0.0288299950403451 +"4666",0.747628055154725,32.3684210526316,28.1578947368421,0.0285894986100871 +"4667",0.973232737037462,32.3684210526316,28.1578947368421,0.0275245938653527 +"4668",1.2669160204875,32.3684210526316,28.1578947368421,0.0250174887437653 +"4669",1.64922134437622,32.3684210526316,28.1578947368421,0.0219166590365104 +"4670",2.14689134777813,32.3684210526316,28.1578947368421,0.0190152300359649 +"4671",2.79473854427218,32.3684210526316,28.1578947368421,0.0164689921413855 +"4672",3.63808049202114,32.3684210526316,28.1578947368421,0.0142595455590108 +"4673",4.73590980220715,32.3684210526316,28.1578947368421,0.0123459230140871 +"4674",6.16502073107827,32.3684210526316,28.1578947368421,0.0106890238269781 +"4675",8.02538101483936,32.3684210526316,28.1578947368421,0.00925447891440393 +"4676",10.4471247126008,32.3684210526316,28.1578947368421,0.00801245871046712 +"4677",13.5996552137305,32.3684210526316,28.1578947368421,0.00693712665905399 +"4678",17.7034951740616,32.3684210526316,28.1578947368421,0.00600611220024815 +"4679",23.045712295823,32.3684210526316,28.1578947368421,0.00520004686406438 +"4680",30,32.3684210526316,28.1578947368421,0.00450216154525266 +"4681",0.2,34.4736842105263,28.1578947368421,0.0302345287902769 +"4682",0.260352117694686,34.4736842105263,28.1578947368421,0.0302343339395048 +"4683",0.338916125940539,34.4736842105263,28.1578947368421,0.030233142208663 +"4684",0.441187655547492,34.4736842105263,28.1578947368421,0.0302258650175551 +"4685",0.574320702112717,34.4736842105263,28.1578947368421,0.03018185348033 +"4686",0.747628055154725,34.4736842105263,28.1578947368421,0.0299300800058486 +"4687",0.973232737037462,34.4736842105263,28.1578947368421,0.0288152411398999 +"4688",1.2669160204875,34.4736842105263,28.1578947368421,0.0261905761223152 +"4689",1.64922134437622,34.4736842105263,28.1578947368421,0.0229443463619266 +"4690",2.14689134777813,34.4736842105263,28.1578947368421,0.0199068673455239 +"4691",2.79473854427218,34.4736842105263,28.1578947368421,0.0172412345921115 +"4692",3.63808049202114,34.4736842105263,28.1578947368421,0.014928185528852 +"4693",4.73590980220715,34.4736842105263,28.1578947368421,0.0129248318970974 +"4694",6.16502073107827,34.4736842105263,28.1578947368421,0.0111902395592555 +"4695",8.02538101483936,34.4736842105263,28.1578947368421,0.00968842784192164 +"4696",10.4471247126008,34.4736842105263,28.1578947368421,0.00838816845018845 +"4697",13.5996552137305,34.4736842105263,28.1578947368421,0.00726241333392723 +"4698",17.7034951740616,34.4736842105263,28.1578947368421,0.0062877429621695 +"4699",23.045712295823,34.4736842105263,28.1578947368421,0.00544388066395455 +"4700",30,34.4736842105263,28.1578947368421,0.00471327101907004 +"4701",0.2,36.5789473684211,28.1578947368421,0.0315441978227556 +"4702",0.260352117694686,36.5789473684211,28.1578947368421,0.031543994531633 +"4703",0.338916125940539,36.5789473684211,28.1578947368421,0.0315427511785883 +"4704",0.441187655547492,36.5789473684211,28.1578947368421,0.0315351587614055 +"4705",0.574320702112717,36.5789473684211,28.1578947368421,0.0314892407764968 +"4706",0.747628055154725,36.5789473684211,28.1578947368421,0.031226561230847 +"4707",0.973232737037462,36.5789473684211,28.1578947368421,0.0300634308916274 +"4708",1.2669160204875,36.5789473684211,28.1578947368421,0.0273250732639146 +"4709",1.64922134437622,36.5789473684211,28.1578947368421,0.0239382265744849 +"4710",2.14689134777813,36.5789473684211,28.1578947368421,0.0207691730846653 +"4711",2.79473854427218,36.5789473684211,28.1578947368421,0.0179880731217813 +"4712",3.63808049202114,36.5789473684211,28.1578947368421,0.0155748297161601 +"4713",4.73590980220715,36.5789473684211,28.1578947368421,0.0134846968185267 +"4714",6.16502073107827,36.5789473684211,28.1578947368421,0.0116749671473199 +"4715",8.02538101483936,36.5789473684211,28.1578947368421,0.010108101454366 +"4716",10.4471247126008,36.5789473684211,28.1578947368421,0.00875151872876 +"4717",13.5996552137305,36.5789473684211,28.1578947368421,0.00757699928003146 +"4718",17.7034951740616,36.5789473684211,28.1578947368421,0.00656010911342858 +"4719",23.045712295823,36.5789473684211,28.1578947368421,0.0056796932334689 +"4720",30,36.5789473684211,28.1578947368421,0.00491743577183247 +"4721",0.2,38.6842105263158,28.1578947368421,0.0328061307400901 +"4722",0.260352117694686,38.6842105263158,28.1578947368421,0.0328059193162592 +"4723",0.338916125940539,38.6842105263158,28.1578947368421,0.0328046262225889 +"4724",0.441187655547492,38.6842105263158,28.1578947368421,0.0327967300690036 +"4725",0.574320702112717,38.6842105263158,28.1578947368421,0.0327489751245063 +"4726",0.747628055154725,38.6842105263158,28.1578947368421,0.0324757870229812 +"4727",0.973232737037462,38.6842105263158,28.1578947368421,0.0312661253859787 +"4728",1.2669160204875,38.6842105263158,28.1578947368421,0.0284182191290928 +"4729",1.64922134437622,38.6842105263158,28.1578947368421,0.0248958808558426 +"4730",2.14689134777813,38.6842105263158,28.1578947368421,0.0216000486494404 +"4731",2.79473854427218,38.6842105263158,28.1578947368421,0.0187076901403958 +"4732",3.63808049202114,38.6842105263158,28.1578947368421,0.016197904375124 +"4733",4.73590980220715,38.6842105263158,28.1578947368421,0.014024155228317 +"4734",6.16502073107827,38.6842105263158,28.1578947368421,0.0121420269037539 +"4735",8.02538101483936,38.6842105263158,28.1578947368421,0.0105124783869701 +"4736",10.4471247126008,38.6842105263158,28.1578947368421,0.00910162525619639 +"4737",13.5996552137305,38.6842105263158,28.1578947368421,0.00788011888572941 +"4738",17.7034951740616,38.6842105263158,28.1578947368421,0.0068225477932155 +"4739",23.045712295823,38.6842105263158,28.1578947368421,0.00590691067269337 +"4740",30,38.6842105263158,28.1578947368421,0.00511415892530182 +"4741",0.2,40.7894736842105,28.1578947368421,0.0340182313529281 +"4742",0.260352117694686,40.7894736842105,28.1578947368421,0.0340180121175404 +"4743",0.338916125940539,40.7894736842105,28.1578947368421,0.0340166712474455 +"4744",0.441187655547492,40.7894736842105,28.1578947368421,0.034008483351665 +"4745",0.574320702112717,40.7894736842105,28.1578947368421,0.0339589639870369 +"4746",0.747628055154725,40.7894736842105,28.1578947368421,0.0336756823006296 +"4747",0.973232737037462,40.7894736842105,28.1578947368421,0.0324213268341977 +"4748",1.2669160204875,40.7894736842105,28.1578947368421,0.0294681978996781 +"4749",1.64922134437622,40.7894736842105,28.1578947368421,0.0258157184521012 +"4750",2.14689134777813,40.7894736842105,28.1578947368421,0.0223981138773316 +"4751",2.79473854427218,40.7894736842105,28.1578947368421,0.0193988902963547 +"4752",3.63808049202114,40.7894736842105,28.1578947368421,0.0167963745200895 +"4753",4.73590980220715,40.7894736842105,28.1578947368421,0.0145423110352744 +"4754",6.16502073107827,40.7894736842105,28.1578947368421,0.0125906429983411 +"4755",8.02538101483936,40.7894736842105,28.1578947368421,0.0109008869315877 +"4756",10.4471247126008,40.7894736842105,28.1578947368421,0.00943790647260257 +"4757",13.5996552137305,40.7894736842105,28.1578947368421,0.00817126864082554 +"4758",17.7034951740616,40.7894736842105,28.1578947368421,0.00707462306618171 +"4759",23.045712295823,40.7894736842105,28.1578947368421,0.00612515555207506 +"4760",30,40.7894736842105,28.1578947368421,0.00530311370380407 +"4761",0.2,42.8947368421053,28.1578947368421,0.035179383306261 +"4762",0.260352117694686,42.8947368421053,28.1578947368421,0.0351791565876625 +"4763",0.338916125940539,42.8947368421053,28.1578947368421,0.0351777699493466 +"4764",0.441187655547492,42.8947368421053,28.1578947368421,0.0351693025742751 +"4765",0.574320702112717,42.8947368421053,28.1578947368421,0.03511809295402 +"4766",0.747628055154725,42.8947368421053,28.1578947368421,0.0348251419500017 +"4767",0.973232737037462,42.8947368421053,28.1578947368421,0.0335279712858921 +"4768",1.2669160204875,42.8947368421053,28.1578947368421,0.030474042536262 +"4769",1.64922134437622,42.8947368421053,28.1578947368421,0.0266968921849846 +"4770",2.14689134777813,42.8947368421053,28.1578947368421,0.0231626337434532 +"4771",2.79473854427218,42.8947368421053,28.1578947368421,0.0200610369884156 +"4772",3.63808049202114,42.8947368421053,28.1578947368421,0.0173696889549458 +"4773",4.73590980220715,42.8947368421053,28.1578947368421,0.0150386870134785 +"4774",6.16502073107827,42.8947368421053,28.1578947368421,0.0130204022518298 +"4775",8.02538101483936,42.8947368421053,28.1578947368421,0.0112729693606345 +"4776",10.4471247126008,42.8947368421053,28.1578947368421,0.00976005266010838 +"4777",13.5996552137305,42.8947368421053,28.1578947368421,0.00845018039391074 +"4778",17.7034951740616,42.8947368421053,28.1578947368421,0.00731610276884956 +"4779",23.045712295823,42.8947368421053,28.1578947368421,0.00633422686621756 +"4780",30,42.8947368421053,28.1578947368421,0.00548412607837565 +"4781",0.2,45,28.1578947368421,0.0362893238461481 +"4782",0.260352117694686,45,28.1578947368421,0.0362890899743779 +"4783",0.338916125940539,45,28.1578947368421,0.0362876595864015 +"4784",0.441187655547492,45,28.1578947368421,0.0362789250581858 +"4785",0.574320702112717,45,28.1578947368421,0.0362260997292908 +"4786",0.747628055154725,45,28.1578947368421,0.0359239058629765 +"4787",0.973232737037462,45,28.1578947368421,0.0345858083214765 +"4788",1.2669160204875,45,28.1578947368421,0.0314355254289771 +"4789",1.64922134437622,45,28.1578947368421,0.0275392026560676 +"4790",2.14689134777813,45,28.1578947368421,0.0238934352466689 +"4791",2.79473854427218,45,28.1578947368421,0.0206939803811911 +"4792",3.63808049202114,45,28.1578947368421,0.0179177179459171 +"4793",4.73590980220715,45,28.1578947368421,0.0155131708393493 +"4794",6.16502073107827,45,28.1578947368421,0.0134312074151588 +"4795",8.02538101483936,45,28.1578947368421,0.0116286414765822 +"4796",10.4471247126008,45,28.1578947368421,0.0100679909211227 +"4797",13.5996552137305,45,28.1578947368421,0.00871679103079733 +"4798",17.7034951740616,45,28.1578947368421,0.00754693225742904 +"4799",23.045712295823,45,28.1578947368421,0.00653407730493759 +"4800",30,45,28.1578947368421,0.00565715508821498 +"4801",0.2,5,30.2631578947368,-0.0449193698458747 +"4802",0.260352117694686,5,30.2631578947368,-0.0449190803565311 +"4803",0.338916125940539,5,30.2631578947368,-0.044917309804762 +"4804",0.441187655547492,5,30.2631578947368,-0.0449064980986797 +"4805",0.574320702112717,5,30.2631578947368,-0.0448411102591067 +"4806",0.747628055154725,5,30.2631578947368,-0.0444670509874687 +"4807",0.973232737037462,5,30.2631578947368,-0.042810737449875 +"4808",1.2669160204875,5,30.2631578947368,-0.0389112786733145 +"4809",1.64922134437622,5,30.2631578947368,-0.034088362588759 +"4810",2.14689134777813,5,30.2631578947368,-0.0295755870041514 +"4811",2.79473854427218,5,30.2631578947368,-0.0256152625567496 +"4812",3.63808049202114,5,30.2631578947368,-0.0221787708864172 +"4813",4.73590980220715,5,30.2631578947368,-0.0192023930059788 +"4814",6.16502073107827,5,30.2631578947368,-0.0166253131614138 +"4815",8.02538101483936,5,30.2631578947368,-0.0143940749490464 +"4816",10.4471247126008,5,30.2631578947368,-0.0124622825629975 +"4817",13.5996552137305,5,30.2631578947368,-0.0107897507774356 +"4818",17.7034951740616,5,30.2631578947368,-0.00934168524909567 +"4819",23.045712295823,5,30.2631578947368,-0.00808796097459341 +"4820",30,5,30.2631578947368,-0.00700249590651918 +"4821",0.2,7.10526315789474,30.2631578947368,-0.0462231254707567 +"4822",0.260352117694686,7.10526315789474,30.2631578947368,-0.0462228275791724 +"4823",0.338916125940539,7.10526315789474,30.2631578947368,-0.0462210056382845 +"4824",0.441187655547492,7.10526315789474,30.2631578947368,-0.0462098801294337 +"4825",0.574320702112717,7.10526315789474,30.2631578947368,-0.0461425944501552 +"4826",0.747628055154725,7.10526315789474,30.2631578947368,-0.0457576783503579 +"4827",0.973232737037462,7.10526315789474,30.2631578947368,-0.0440532913847839 +"4828",1.2669160204875,7.10526315789474,30.2631578947368,-0.0400406533420988 +"4829",1.64922134437622,7.10526315789474,30.2631578947368,-0.0350777552409846 +"4830",2.14689134777813,7.10526315789474,30.2631578947368,-0.030433999267016 +"4831",2.79473854427218,7.10526315789474,30.2631578947368,-0.0263587289668034 +"4832",3.63808049202114,7.10526315789474,30.2631578947368,-0.0228224953508376 +"4833",4.73590980220715,7.10526315789474,30.2631578947368,-0.0197597300295977 +"4834",6.16502073107827,7.10526315789474,30.2631578947368,-0.0171078521111807 +"4835",8.02538101483936,7.10526315789474,30.2631578947368,-0.0148118536544064 +"4836",10.4471247126008,7.10526315789474,30.2631578947368,-0.0128239922451708 +"4837",13.5996552137305,7.10526315789474,30.2631578947368,-0.0111029163074825 +"4838",17.7034951740616,7.10526315789474,30.2631578947368,-0.00961282161479213 +"4839",23.045712295823,7.10526315789474,30.2631578947368,-0.00832270880499782 +"4840",30,7.10526315789474,30.2631578947368,-0.00720573881615176 +"4841",0.2,9.21052631578947,30.2631578947368,-0.0475311716935409 +"4842",0.260352117694686,9.21052631578947,30.2631578947368,-0.0475308653720644 +"4843",0.338916125940539,9.21052631578947,30.2631578947368,-0.0475289918729387 +"4844",0.441187655547492,9.21052631578947,30.2631578947368,-0.0475175515286093 +"4845",0.574320702112717,9.21052631578947,30.2631578947368,-0.0474483617639248 +"4846",0.747628055154725,9.21052631578947,30.2631578947368,-0.047052553106662 +"4847",0.973232737037462,9.21052631578947,30.2631578947368,-0.0452999345057371 +"4848",1.2669160204875,9.21052631578947,30.2631578947368,-0.0411737447293326 +"4849",1.64922134437622,9.21052631578947,30.2631578947368,-0.0360704039374849 +"4850",2.14689134777813,9.21052631578947,30.2631578947368,-0.0312952365239085 +"4851",2.79473854427218,9.21052631578947,30.2631578947368,-0.0271046420895374 +"4852",3.63808049202114,9.21052631578947,30.2631578947368,-0.0234683382819275 +"4853",4.73590980220715,9.21052631578947,30.2631578947368,-0.0203189012229174 +"4854",6.16502073107827,9.21052631578947,30.2631578947368,-0.0175919790737362 +"4855",8.02538101483936,9.21052631578947,30.2631578947368,-0.0152310072496632 +"4856",10.4471247126008,9.21052631578947,30.2631578947368,-0.0131868922967461 +"4857",13.5996552137305,9.21052631578947,30.2631578947368,-0.01141711245043 +"4858",17.7034951740616,9.21052631578947,30.2631578947368,-0.00988485027740348 +"4859",23.045712295823,9.21052631578947,30.2631578947368,-0.008558229179374 +"4860",30,9.21052631578947,30.2631578947368,-0.00740965058855667 +"4861",0.2,11.3157894736842,30.2631578947368,-0.0488427985178875 +"4862",0.260352117694686,11.3157894736842,30.2631578947368,-0.0488424837434432 +"4863",0.338916125940539,11.3157894736842,30.2631578947368,-0.0488405585449459 +"4864",0.441187655547492,11.3157894736842,30.2631578947368,-0.0488288025033179 +"4865",0.574320702112717,11.3157894736842,30.2631578947368,-0.0487577034410483 +"4866",0.747628055154725,11.3157894736842,30.2631578947368,-0.0483509724094009 +"4867",0.973232737037462,11.3157894736842,30.2631578947368,-0.0465499901454752 +"4868",1.2669160204875,11.3157894736842,30.2631578947368,-0.0423099378026696 +"4869",1.64922134437622,11.3157894736842,30.2631578947368,-0.0370657698770091 +"4870",2.14689134777813,11.3157894736842,30.2631578947368,-0.0321588313025874 +"4871",2.79473854427218,11.3157894736842,30.2631578947368,-0.027852597049667 +"4872",3.63808049202114,11.3157894736842,30.2631578947368,-0.0241159491216494 +"4873",4.73590980220715,11.3157894736842,30.2631578947368,-0.0208796030725807 +"4874",6.16502073107827,11.3157894736842,30.2631578947368,-0.0180774312690919 +"4875",8.02538101483936,11.3157894736842,30.2631578947368,-0.0156513082218186 +"4876",10.4471247126008,11.3157894736842,30.2631578947368,-0.0135507857386688 +"4877",13.5996552137305,11.3157894736842,30.2631578947368,-0.0117321686632901 +"4878",17.7034951740616,11.3157894736842,30.2631578947368,-0.0101576235820905 +"4879",23.045712295823,11.3157894736842,30.2631578947368,-0.00879439425927037 +"4880",30,11.3157894736842,30.2631578947368,-0.00761412054216203 +"4881",0.2,13.4210526315789,30.2631578947368,-0.050157325627289 +"4882",0.260352117694686,13.4210526315789,30.2631578947368,-0.0501570023811856 +"4883",0.338916125940539,13.4210526315789,30.2631578947368,-0.0501550253689984 +"4884",0.441187655547492,13.4210526315789,30.2631578947368,-0.0501429529319981 +"4885",0.574320702112717,13.4210526315789,30.2631578947368,-0.0500699403502817 +"4886",0.747628055154725,13.4210526315789,30.2631578947368,-0.0496522627925637 +"4887",0.973232737037462,13.4210526315789,30.2631578947368,-0.0478028099233222 +"4888",1.2669160204875,13.4210526315789,30.2631578947368,-0.0434486432398352 +"4889",1.64922134437622,13.4210526315789,30.2631578947368,-0.0380633367817048 +"4890",2.14689134777813,13.4210526315789,30.2631578947368,-0.0330243356724576 +"4891",2.79473854427218,13.4210526315789,30.2631578947368,-0.0286022058968262 +"4892",3.63808049202114,13.4210526315789,30.2631578947368,-0.0247649919662715 +"4893",4.73590980220715,13.4210526315789,30.2631578947368,-0.0214415447529371 +"4894",6.16502073107827,13.4210526315789,30.2631578947368,-0.0185639569021975 +"4895",8.02538101483936,13.4210526315789,30.2631578947368,-0.0160725385685532 +"4896",10.4471247126008,13.4210526315789,30.2631578947368,-0.0139154838261596 +"4897",13.5996552137305,13.4210526315789,30.2631578947368,-0.0120479215322482 +"4898",17.7034951740616,13.4210526315789,30.2631578947368,-0.010431000046399 +"4899",23.045712295823,13.4210526315789,30.2631578947368,-0.00903108155024004 +"4900",30,13.4210526315789,30.2631578947368,-0.00781904262219513 +"4901",0.2,15.5263157894737,30.2631578947368,-0.0514741027570687 +"4902",0.260352117694686,15.5263157894737,30.2631578947368,-0.0514737710248055 +"4903",0.338916125940539,15.5263157894737,30.2631578947368,-0.0514717421102411 +"4904",0.441187655547492,15.5263157894737,30.2631578947368,-0.051459352736308 +"4905",0.574320702112717,15.5263157894737,30.2631578947368,-0.0513844233598544 +"4906",0.747628055154725,15.5263157894737,30.2631578947368,-0.0509557805393608 +"4907",0.973232737037462,15.5263157894737,30.2631578947368,-0.0490577740997213 +"4908",1.2669160204875,15.5263157894737,30.2631578947368,-0.0445892977508692 +"4909",1.64922134437622,15.5263157894737,30.2631578947368,-0.0390626111794207 +"4910",2.14689134777813,15.5263157894737,30.2631578947368,-0.0338913214895004 +"4911",2.79473854427218,15.5263157894737,30.2631578947368,-0.0293530978177004 +"4912",3.63808049202114,15.5263157894737,30.2631578947368,-0.0254151457500414 +"4913",4.73590980220715,15.5263157894737,30.2631578947368,-0.0220044482850674 +"4914",6.16502073107827,15.5263157894737,30.2631578947368,-0.0190513153006231 +"4915",8.02538101483936,15.5263157894737,30.2631578947368,-0.0164944899174317 +"4916",10.4471247126008,15.5263157894737,30.2631578947368,-0.0142808061519204 +"4917",13.5996552137305,15.5263157894737,30.2631578947368,-0.0123642148620188 +"4918",17.7034951740616,15.5263157894737,30.2631578947368,-0.010704844437623 +"4919",23.045712295823,15.5263157894737,30.2631578947368,-0.00926817396882108 +"4920",30,15.5263157894737,30.2631578947368,-0.00802431545867341 +"4921",0.2,17.6315789473684,30.2631578947368,-0.0527925098869645 +"4922",0.260352117694686,17.6315789473684,30.2631578947368,-0.0527921696580369 +"4923",0.338916125940539,17.6315789473684,30.2631578947368,-0.0527900887768468 +"4924",0.441187655547492,17.6315789473684,30.2631578947368,-0.0527773820736539 +"4925",0.574320702112717,17.6315789473684,30.2631578947368,-0.0527005335297188 +"4926",0.747628055154725,17.6315789473684,30.2631578947368,-0.0522609118728696 +"4927",0.973232737037462,17.6315789473684,30.2631578947368,-0.0503142917597792 +"4928",1.2669160204875,17.6315789473684,30.2631578947368,-0.0457313642449514 +"4929",1.64922134437622,17.6315789473684,30.2631578947368,-0.040063122549854 +"4930",2.14689134777813,17.6315789473684,30.2631578947368,-0.0347593805230737 +"4931",2.79473854427218,17.6315789473684,30.2631578947368,-0.0301049192458471 +"4932",3.63808049202114,17.6315789473684,30.2631578947368,-0.0260661043402734 +"4933",4.73590980220715,17.6315789473684,30.2631578947368,-0.0225680486191106 +"4934",6.16502073107827,17.6315789473684,30.2631578947368,-0.0195392769858375 +"4935",8.02538101483936,17.6315789473684,30.2631578947368,-0.0169169635876143 +"4936",10.4471247126008,17.6315789473684,30.2631578947368,-0.0146465806995645 +"4937",13.5996552137305,17.6315789473684,30.2631578947368,-0.0126808997221043 +"4938",17.7034951740616,17.6315789473684,30.2631578947368,-0.0109790278128553 +"4939",23.045712295823,17.6315789473684,30.2631578947368,-0.00950555987721228 +"4940",30,17.6315789473684,30.2631578947368,-0.00822984239642651 +"4941",0.2,19.7368421052632,30.2631578947368,-0.0541119572691577 +"4942",0.260352117694686,19.7368421052632,30.2631578947368,-0.0541116085368615 +"4943",0.338916125940539,19.7368421052632,30.2631578947368,-0.054109475648043 +"4944",0.441187655547492,19.7368421052632,30.2631578947368,-0.0540964513652105 +"4945",0.574320702112717,19.7368421052632,30.2631578947368,-0.0540176821395283 +"4946",0.747628055154725,19.7368421052632,30.2631578947368,-0.0535670729837797 +"4947",0.973232737037462,19.7368421052632,30.2631578947368,-0.051571800839978 +"4948",1.2669160204875,19.7368421052632,30.2631578947368,-0.0468743318546809 +"4949",1.64922134437622,19.7368421052632,30.2631578947368,-0.0410644233458205 +"4950",2.14689134777813,19.7368421052632,30.2631578947368,-0.0356281244743657 +"4951",2.79473854427218,19.7368421052632,30.2631578947368,-0.0308573338776787 +"4952",3.63808049202114,19.7368421052632,30.2631578947368,-0.0267175765511872 +"4953",4.73590980220715,19.7368421052632,30.2631578947368,-0.0231320936462452 +"4954",6.16502073107827,19.7368421052632,30.2631578947368,-0.0200276236835814 +"4955",8.02538101483936,19.7368421052632,30.2631578947368,-0.0173397705988386 +"4956",10.4471247126008,19.7368421052632,30.2631578947368,-0.0150126438513923 +"4957",13.5996552137305,19.7368421052632,30.2631578947368,-0.0129978344535276 +"4958",17.7034951740616,19.7368421052632,30.2631578947368,-0.0112534275248167 +"4959",23.045712295823,19.7368421052632,30.2631578947368,-0.00974313308831974 +"4960",30,19.7368421052632,30.2631578947368,-0.00843553149946551 +"4961",0.2,21.8421052631579,30.2631578947368,-0.0554318853065748 +"4962",0.260352117694686,21.8421052631579,30.2631578947368,-0.0554315280678124 +"4963",0.338916125940539,21.8421052631579,30.2631578947368,-0.0554293431524199 +"4964",0.441187655547492,21.8421052631579,30.2631578947368,-0.0554160011742582 +"4965",0.574320702112717,21.8421052631579,30.2631578947368,-0.0553353105671529 +"4966",0.747628055154725,21.8421052631579,30.2631578947368,-0.0548737099099209 +"4967",0.973232737037462,21.8421052631579,30.2631578947368,-0.0528297680121907 +"4968",1.2669160204875,21.8421052631579,30.2631578947368,-0.0480177158306557 +"4969",1.64922134437622,21.8421052631579,30.2631578947368,-0.0420660889009012 +"4970",2.14689134777813,21.8421052631579,30.2631578947368,-0.0364971848962682 +"4971",2.79473854427218,21.8421052631579,30.2631578947368,-0.0316100226030652 +"4972",3.63808049202114,21.8421052631579,30.2631578947368,-0.0273692860838204 +"4973",4.73590980220715,21.8421052631579,30.2631578947368,-0.0236963441466653 +"4974",6.16502073107827,21.8421052631579,30.2631578947368,-0.0205161482788258 +"4975",8.02538101483936,21.8421052631579,30.2631578947368,-0.0177627316324221 +"4976",10.4471247126008,21.8421052631579,30.2631578947368,-0.0153788403546281 +"4977",13.5996552137305,21.8421052631579,30.2631578947368,-0.0133148846395997 +"4978",17.7034951740616,21.8421052631579,30.2631578947368,-0.0115279271965466 +"4979",23.045712295823,21.8421052631579,30.2631578947368,-0.00998079284384459 +"4980",30,21.8421052631579,30.2631578947368,-0.00864129553201153 +"4981",0.2,23.9473684210526,30.2631578947368,-0.0567517642961101 +"4982",0.260352117694686,23.9473684210526,30.2631578947368,-0.0567513985511976 +"4983",0.338916125940539,23.9473684210526,30.2631578947368,-0.0567491616111643 +"4984",0.441187655547492,23.9473684210526,30.2631578947368,-0.0567355019494788 +"4985",0.574320702112717,23.9473684210526,30.2631578947368,-0.056652890032348 +"4986",0.747628055154725,23.9473684210526,30.2631578947368,-0.0561802982820716 +"4987",0.973232737037462,23.9473684210526,30.2631578947368,-0.0540876884389572 +"4988",1.2669160204875,23.9473684210526,30.2631578947368,-0.0491610573190399 +"4989",1.64922134437622,23.9473684210526,30.2631578947368,-0.0430677172345786 +"4990",2.14689134777813,23.9473684210526,30.2631578947368,-0.0373662130243094 +"4991",2.79473854427218,23.9473684210526,30.2631578947368,-0.0323626833589059 +"4992",3.63808049202114,23.9473684210526,30.2631578947368,-0.0280209713992453 +"4993",4.73590980220715,23.9473684210526,30.2631578947368,-0.0242605736798122 +"4994",6.16502073107827,23.9473684210526,30.2631578947368,-0.0210046547207346 +"4995",8.02538101483936,23.9473684210526,30.2631578947368,-0.0181856769489799 +"4996",10.4471247126008,23.9473684210526,30.2631578947368,-0.0157450232501805 +"4997",13.5996552137305,23.9473684210526,30.2631578947368,-0.0136319230442417 +"4998",17.7034951740616,23.9473684210526,30.2631578947368,-0.0118024166680026 +"4999",23.045712295823,23.9473684210526,30.2631578947368,-0.0102184437680489 +"5000",30,23.9473684210526,30.2631578947368,-0.0088470519184665 +"5001",0.2,26.0526315789474,30.2631578947368,-0.0580710940510687 +"5002",0.260352117694686,26.0526315789474,30.2631578947368,-0.0580707198035457 +"5003",0.338916125940539,26.0526315789474,30.2631578947368,-0.0580684308605204 +"5004",0.441187655547492,26.0526315789474,30.2631578947368,-0.0580544536475072 +"5005",0.574320702112717,26.0526315789474,30.2631578947368,-0.0579699212198559 +"5006",0.747628055154725,26.0526315789474,30.2631578947368,-0.057486342950203 +"5007",0.973232737037462,26.0526315789474,30.2631578947368,-0.0553450854136506 +"5008",1.2669160204875,26.0526315789474,30.2631578947368,-0.0503039230345059 +"5009",1.64922134437622,26.0526315789474,30.2631578947368,-0.0440689287657172 +"5010",2.14689134777813,26.0526315789474,30.2631578947368,-0.0382348795280655 +"5011",2.79473854427218,26.0526315789474,30.2631578947368,-0.0331150309138282 +"5012",3.63808049202114,26.0526315789474,30.2631578947368,-0.0286723855321519 +"5013",4.73590980220715,26.0526315789474,30.2631578947368,-0.0248245684229737 +"5014",6.16502073107827,26.0526315789474,30.2631578947368,-0.0214929578829254 +"5015",8.02538101483936,26.0526315789474,30.2631578947368,-0.0186084462674396 +"5016",10.4471247126008,26.0526315789474,30.2631578947368,-0.0161110537678944 +"5017",13.5996552137305,26.0526315789474,30.2631578947368,-0.0139488295212939 +"5018",17.7034951740616,26.0526315789474,30.2631578947368,-0.0120767919175415 +"5019",23.045712295823,26.0526315789474,30.2631578947368,-0.0104559957997746 +"5020",30,26.0526315789474,30.2631578947368,-0.00905272268455573 +"5021",0.2,28.1578947368421,30.2631578947368,-0.0593894034166722 +"5022",0.260352117694686,28.1578947368421,30.2631578947368,-0.0593890206731148 +"5023",0.338916125940539,28.1578947368421,30.2631578947368,-0.0593866797673173 +"5024",0.441187655547492,28.1578947368421,30.2631578947368,-0.0593723852485753 +"5025",0.574320702112717,28.1578947368421,30.2631578947368,-0.0592859337957551 +"5026",0.747628055154725,28.1578947368421,30.2631578947368,-0.058791377503864 +"5027",0.973232737037462,28.1578947368421,30.2631578947368,-0.0566015098987271 +"5028",1.2669160204875,28.1578947368421,30.2631578947368,-0.0514459048405429 +"5029",1.64922134437622,28.1578947368421,30.2631578947368,-0.0450693659448905 +"5030",2.14689134777813,28.1578947368421,30.2631578947368,-0.0391028741921619 +"5031",2.79473854427218,28.1578947368421,30.2631578947368,-0.0338667965919048 +"5032",3.63808049202114,28.1578947368421,30.2631578947368,-0.0293232958516301 +"5033",4.73590980220715,28.1578947368421,30.2631578947368,-0.0253881269641695 +"5034",6.16502073107827,28.1578947368421,30.2631578947368,-0.0219808833841509 +"5035",8.02538101483936,28.1578947368421,30.2631578947368,-0.0190308886097885 +"5036",10.4471247126008,28.1578947368421,30.2631578947368,-0.016476801192134 +"5037",13.5996552137305,28.1578947368421,30.2631578947368,-0.0142654908981392 +"5038",17.7034951740616,28.1578947368421,30.2631578947368,-0.0123509549611607 +"5039",23.045712295823,28.1578947368421,30.2631578947368,-0.0106933641052078 +"5040",30,28.1578947368421,30.2631578947368,-0.0092582343817999 +"5041",0.2,30.2631578947368,30.2631578947368,-0.060706249691905 +"5042",0.260352117694686,30.2631578947368,30.2631578947368,-0.0607058584617422 +"5043",0.338916125940539,30.2631578947368,30.2631578947368,-0.0607034656508421 +"5044",0.441187655547492,30.2631578947368,30.2631578947368,-0.0606888541785246 +"5045",0.574320702112717,30.2631578947368,30.2631578947368,-0.0606004858303142 +"5046",0.747628055154725,30.2631578947368,30.2631578947368,-0.0600949636998492 +"5047",0.973232737037462,30.2631578947368,30.2631578947368,-0.0578565399747114 +"5048",1.2669160204875,30.2631578947368,30.2631578947368,-0.0525866192486326 +"5049",1.64922134437622,30.2631578947368,30.2631578947368,-0.0460686928156328 +"5050",2.14689134777813,30.2631578947368,30.2631578947368,-0.0399699055356085 +"5051",2.79473854427218,30.2631578947368,30.2631578947368,-0.0346177279429612 +"5052",3.63808049202114,30.2631578947368,30.2631578947368,-0.029973483775709 +"5053",4.73590980220715,30.2631578947368,30.2631578947368,-0.0259510600549997 +"5054",6.16502073107827,30.2631578947368,30.2631578947368,-0.022468267374316 +"5055",8.02538101483936,30.2631578947368,30.2631578947368,-0.0194528621158085 +"5056",10.4471247126008,30.2631578947368,30.2631578947368,-0.0168421427013825 +"5057",13.5996552137305,30.2631578947368,30.2631578947368,-0.0145818008368296 +"5058",17.7034951740616,30.2631578947368,30.2631578947368,-0.0126248137322627 +"5059",23.045712295823,30.2631578947368,30.2631578947368,-0.0109304689737793 +"5060",30,30.2631578947368,30.2631578947368,-0.0094635179973865 +"5061",0.2,32.3684210526316,30.2631578947368,-0.0620212179703493 +"5062",0.260352117694686,32.3684210526316,30.2631578947368,-0.0620208182656842 +"5063",0.338916125940539,32.3684210526316,30.2631578947368,-0.062018373623705 +"5064",0.441187655547492,32.3684210526316,30.2631578947368,-0.0620034456498296 +"5065",0.574320702112717,32.3684210526316,30.2631578947368,-0.0619131631399752 +"5066",0.747628055154725,32.3684210526316,30.2631578947368,-0.061396690809671 +"5067",0.973232737037462,32.3684210526316,30.2631578947368,-0.0591097802119754 +"5068",1.2669160204875,32.3684210526316,30.2631578947368,-0.0537257068472494 +"5069",1.64922134437622,32.3684210526316,30.2631578947368,-0.0470665945142124 +"5070",2.14689134777813,32.3684210526316,30.2631578947368,-0.040835700377795 +"5071",2.79473854427218,32.3684210526316,30.2631578947368,-0.0353675883666876 +"5072",3.63808049202114,32.3684210526316,30.2631578947368,-0.0306227444458962 +"5073",4.73590980220715,32.3684210526316,30.2631578947368,-0.0265131903288597 +"5074",6.16502073107827,32.3684210526316,30.2631578947368,-0.0229549562905113 +"5075",8.02538101483936,32.3684210526316,30.2631578947368,-0.019874233831852 +"5076",10.4471247126008,32.3684210526316,30.2631578947368,-0.0172069631853648 +"5077",13.5996552137305,32.3684210526316,30.2631578947368,-0.014897659675752 +"5078",17.7034951740616,32.3684210526316,30.2631578947368,-0.0128982819445711 +"5079",23.045712295823,32.3684210526316,30.2631578947368,-0.0111672356994786 +"5080",30,32.3684210526316,30.2631578947368,-0.00966850885141235 +"5081",0.2,34.4736842105263,30.2631578947368,-0.0633339204119477 +"5082",0.260352117694686,34.4736842105263,30.2631578947368,-0.0633335122473828 +"5083",0.338916125940539,34.4736842105263,30.2631578947368,-0.0633310158636353 +"5084",0.441187655547492,34.4736842105263,30.2631578947368,-0.0633157719335694 +"5085",0.574320702112717,34.4736842105263,30.2631578947368,-0.0632235785603848 +"5086",0.747628055154725,34.4736842105263,30.2631578947368,-0.0626961748986557 +"5087",0.973232737037462,34.4736842105263,30.2631578947368,-0.0603608609766857 +"5088",1.2669160204875,34.4736842105263,30.2631578947368,-0.0548628316710267 +"5089",1.64922134437622,34.4736842105263,30.2631578947368,-0.048062776716988 +"5090",2.14689134777813,34.4736842105263,30.2631578947368,-0.0417000033590093 +"5091",2.79473854427218,34.4736842105263,30.2631578947368,-0.036116156697361 +"5092",3.63808049202114,34.4736842105263,30.2631578947368,-0.0312708863676139 +"5093",4.73590980220715,34.4736842105263,30.2631578947368,-0.0270743519896303 +"5094",6.16502073107827,34.4736842105263,30.2631578947368,-0.0234408065874813 +"5095",8.02538101483936,34.4736842105263,30.2631578947368,-0.0202948794774831 +"5096",10.4471247126008,34.4736842105263,30.2631578947368,-0.0175711550430081 +"5097",13.5996552137305,34.4736842105263,30.2631578947368,-0.0152129742547049 +"5098",17.7034951740616,34.4736842105263,30.2631578947368,-0.0131712789406823 +"5099",23.045712295823,34.4736842105263,30.2631578947368,-0.0114035944497312 +"5100",30,34.4736842105263,30.2631578947368,-0.00987314648335844 +"5101",0.2,36.5789473684211,30.2631578947368,-0.0646439954568998 +"5102",0.260352117694686,36.5789473684211,30.2631578947368,-0.0646435788493678 +"5103",0.338916125940539,36.5789473684211,30.2631578947368,-0.0646410308274139 +"5104",0.441187655547492,36.5789473684211,30.2631578947368,-0.0646254715735494 +"5105",0.574320702112717,36.5789473684211,30.2631578947368,-0.0645313711616605 +"5106",0.747628055154725,36.5789473684211,30.2631578947368,-0.0639930580477555 +"5107",0.973232737037462,36.5789473684211,30.2631578947368,-0.061609437681602 +"5108",1.2669160204875,36.5789473684211,30.2631578947368,-0.0559976805197972 +"5109",1.64922134437622,36.5789473684211,30.2631578947368,-0.0490569650438511 +"5110",2.14689134777813,36.5789473684211,30.2631578947368,-0.0425625764228545 +"5111",2.79473854427218,36.5789473684211,30.2631578947368,-0.0368632267555706 +"5112",3.63808049202114,36.5789473684211,30.2631578947368,-0.0319177310220626 +"5113",4.73590980220715,36.5789473684211,30.2631578947368,-0.027634390475629 +"5114",6.16502073107827,36.5789473684211,30.2631578947368,-0.0239256844466769 +"5115",8.02538101483936,36.5789473684211,30.2631578947368,-0.0207146831935775 +"5116",10.4471247126008,36.5789473684211,30.2631578947368,-0.0179346179643479 +"5117",13.5996552137305,36.5789473684211,30.2631578947368,-0.0155276577260731 +"5118",17.7034951740616,36.5789473684211,30.2631578947368,-0.013443729528583 +"5119",23.045712295823,36.5789473684211,30.2631578947368,-0.0116394801238561 +"5120",30,36.5789473684211,30.2631578947368,-0.010077374529544 +"5121",0.2,38.6842105263158,30.2631578947368,-0.0659511069921298 +"5122",0.260352117694686,38.6842105263158,30.2631578947368,-0.0659506819607294 +"5123",0.338916125940539,38.6842105263158,30.2631578947368,-0.0659480824173795 +"5124",0.441187655547492,38.6842105263158,30.2631578947368,-0.0659322085530077 +"5125",0.574320702112717,38.6842105263158,30.2631578947368,-0.0658362054163107 +"5126",0.747628055154725,38.6842105263158,30.2631578947368,-0.0652870075284097 +"5127",0.973232737037462,38.6842105263158,30.2631578947368,-0.0628551899916731 +"5128",1.2669160204875,38.6842105263158,30.2631578947368,-0.0571299622365477 +"5129",1.64922134437622,38.6842105263158,30.2631578947368,-0.0500489044256757 +"5130",2.14689134777813,38.6842105263158,30.2631578947368,-0.0434231982674389 +"5131",2.79473854427218,38.6842105263158,30.2631578947368,-0.0376086068728953 +"5132",3.63808049202114,38.6842105263158,30.2631578947368,-0.0325631124546679 +"5133",4.73590980220715,38.6842105263158,30.2631578947368,-0.0281931621032866 +"5134",6.16502073107827,38.6842105263158,30.2631578947368,-0.0244094654677522 +"5135",8.02538101483936,38.6842105263158,30.2631578947368,-0.0211335372752225 +"5136",10.4471247126008,38.6842105263158,30.2631578947368,-0.0182972586992754 +"5137",13.5996552137305,38.6842105263158,30.2631578947368,-0.0158416293546118 +"5138",17.7034951740616,38.6842105263158,30.2631578947368,-0.0137155638083042 +"5139",23.045712295823,38.6842105263158,30.2631578947368,-0.0118748322029849 +"5140",30,38.6842105263158,30.2631578947368,-0.0102811405931869 +"5141",0.2,40.7894736842105,30.2631578947368,-0.0672549434799829 +"5142",0.260352117694686,40.7894736842105,30.2631578947368,-0.0672545100458206 +"5143",0.338916125940539,40.7894736842105,30.2631578947368,-0.0672518591101647 +"5144",0.441187655547492,40.7894736842105,30.2631578947368,-0.0672356714235613 +"5145",0.574320702112717,40.7894736842105,30.2631578947368,-0.0671377703294488 +"5146",0.747628055154725,40.7894736842105,30.2631578947368,-0.0665777149400144 +"5147",0.973232737037462,40.7894736842105,30.2631578947368,-0.0640978209936343 +"5148",1.2669160204875,40.7894736842105,30.2631578947368,-0.0582594069526548 +"5149",1.64922134437622,40.7894736842105,30.2631578947368,-0.051038358443105 +"5150",2.14689134777813,40.7894736842105,30.2631578947368,-0.0442816637716967 +"5151",2.79473854427218,40.7894736842105,30.2631578947368,-0.0383521193950438 +"5152",3.63808049202114,40.7894736842105,30.2631578947368,-0.0332068768448778 +"5153",4.73590980220715,40.7894736842105,30.2631578947368,-0.0287505336946779 +"5154",6.16502073107827,40.7894736842105,30.2631578947368,-0.0248920343460827 +"5155",8.02538101483936,40.7894736842105,30.2631578947368,-0.0215513418925146 +"5156",10.4471247126008,40.7894736842105,30.2631578947368,-0.0186589908158061 +"5157",13.5996552137305,40.7894736842105,30.2631578947368,-0.016154814308157 +"5158",17.7034951740616,40.7894736842105,30.2631578947368,-0.0139867169907197 +"5159",23.045712295823,40.7894736842105,30.2631578947368,-0.0121095945931785 +"5160",30,40.7894736842105,30.2631578947368,-0.0104843961085756 +"5161",0.2,42.8947368421053,30.2631578947368,-0.0685552170580289 +"5162",0.260352117694686,42.8947368421053,30.2631578947368,-0.0685547752440664 +"5163",0.338916125940539,42.8947368421053,30.2631578947368,-0.0685520730565409 +"5164",0.441187655547492,42.8947368421053,30.2631578947368,-0.0685355724052677 +"5165",0.574320702112717,42.8947368421053,30.2631578947368,-0.0684357785401655 +"5166",0.747628055154725,42.8947368421053,30.2631578947368,-0.0678648953187912 +"5167",0.973232737037462,42.8947368421053,30.2631578947368,-0.0653370563380688 +"5168",1.2669160204875,42.8947368421053,30.2631578947368,-0.0593857653080925 +"5169",1.64922134437622,42.8947368421053,30.2631578947368,-0.0520251086434105 +"5170",2.14689134777813,42.8947368421053,30.2631578947368,-0.0451377834026855 +"5171",2.79473854427218,42.8947368421053,30.2631578947368,-0.0390936001685171 +"5172",3.63808049202114,42.8947368421053,30.2631578947368,-0.0338488820616939 +"5173",4.73590980220715,42.8947368421053,30.2631578947368,-0.0293063821927 +"5174",6.16502073107827,42.8947368421053,30.2631578947368,-0.0253732845395894 +"5175",8.02538101483936,42.8947368421053,30.2631578947368,-0.0219680048020985 +"5176",10.4471247126008,42.8947368421053,30.2631578947368,-0.0190197344503318 +"5177",13.5996552137305,42.8947368421053,30.2631578947368,-0.0164671434413959 +"5178",17.7034951740616,42.8947368421053,30.2631578947368,-0.0142571292103368 +"5179",23.045712295823,42.8947368421053,30.2631578947368,-0.0123437154633424 +"5180",30,42.8947368421053,30.2631578947368,-0.0106870962007377 +"5181",0.2,45,30.2631578947368,-0.0698516626180748 +"5182",0.260352117694686,45,30.2631578947368,-0.0698512124489822 +"5183",0.338916125940539,45,30.2631578947368,-0.0698484591604732 +"5184",0.441187655547492,45,30.2631578947368,-0.0698316464659012 +"5185",0.574320702112717,45,30.2631578947368,-0.0697299654021453 +"5186",0.747628055154725,45,30.2631578947368,-0.0691482862260733 +"5187",0.973232737037462,45,30.2631578947368,-0.0665726433616539 +"5188",1.2669160204875,45,30.2631578947368,-0.0605088076536288 +"5189",1.64922134437622,45,30.2631578947368,-0.0530089538415748 +"5190",2.14689134777813,45,30.2631578947368,-0.0459913826091936 +"5191",2.79473854427218,45,30.2631578947368,-0.0398328980154159 +"5192",3.63808049202114,45,30.2631578947368,-0.0344889972089373 +"5193",4.73590980220715,45,30.2631578947368,-0.0298605942673635 +"5194",6.16502073107827,45,30.2631578947368,-0.025853117927868 +"5195",8.02538101483936,45,30.2631578947368,-0.0223834410520434 +"5196",10.4471247126008,45,30.2631578947368,-0.0193794160521057 +"5197",13.5996552137305,45,30.2631578947368,-0.0167785530746433 +"5198",17.7034951740616,45,30.2631578947368,-0.0145267453337617 +"5199",23.045712295823,45,30.2631578947368,-0.0125771470793983 +"5200",30,45,30.2631578947368,-0.0108891995418664 +"5201",0.2,5,32.3684210526316,NA +"5202",0.260352117694686,5,32.3684210526316,NA +"5203",0.338916125940539,5,32.3684210526316,NA +"5204",0.441187655547492,5,32.3684210526316,NA +"5205",0.574320702112717,5,32.3684210526316,NA +"5206",0.747628055154725,5,32.3684210526316,NA +"5207",0.973232737037462,5,32.3684210526316,NA +"5208",1.2669160204875,5,32.3684210526316,NA +"5209",1.64922134437622,5,32.3684210526316,NA +"5210",2.14689134777813,5,32.3684210526316,NA +"5211",2.79473854427218,5,32.3684210526316,NA +"5212",3.63808049202114,5,32.3684210526316,NA +"5213",4.73590980220715,5,32.3684210526316,NA +"5214",6.16502073107827,5,32.3684210526316,NA +"5215",8.02538101483936,5,32.3684210526316,NA +"5216",10.4471247126008,5,32.3684210526316,NA +"5217",13.5996552137305,5,32.3684210526316,NA +"5218",17.7034951740616,5,32.3684210526316,NA +"5219",23.045712295823,5,32.3684210526316,NA +"5220",30,5,32.3684210526316,NA +"5221",0.2,7.10526315789474,32.3684210526316,NA +"5222",0.260352117694686,7.10526315789474,32.3684210526316,NA +"5223",0.338916125940539,7.10526315789474,32.3684210526316,NA +"5224",0.441187655547492,7.10526315789474,32.3684210526316,NA +"5225",0.574320702112717,7.10526315789474,32.3684210526316,NA +"5226",0.747628055154725,7.10526315789474,32.3684210526316,NA +"5227",0.973232737037462,7.10526315789474,32.3684210526316,NA +"5228",1.2669160204875,7.10526315789474,32.3684210526316,NA +"5229",1.64922134437622,7.10526315789474,32.3684210526316,NA +"5230",2.14689134777813,7.10526315789474,32.3684210526316,NA +"5231",2.79473854427218,7.10526315789474,32.3684210526316,NA +"5232",3.63808049202114,7.10526315789474,32.3684210526316,NA +"5233",4.73590980220715,7.10526315789474,32.3684210526316,NA +"5234",6.16502073107827,7.10526315789474,32.3684210526316,NA +"5235",8.02538101483936,7.10526315789474,32.3684210526316,NA +"5236",10.4471247126008,7.10526315789474,32.3684210526316,NA +"5237",13.5996552137305,7.10526315789474,32.3684210526316,NA +"5238",17.7034951740616,7.10526315789474,32.3684210526316,NA +"5239",23.045712295823,7.10526315789474,32.3684210526316,NA +"5240",30,7.10526315789474,32.3684210526316,NA +"5241",0.2,9.21052631578947,32.3684210526316,NA +"5242",0.260352117694686,9.21052631578947,32.3684210526316,NA +"5243",0.338916125940539,9.21052631578947,32.3684210526316,NA +"5244",0.441187655547492,9.21052631578947,32.3684210526316,NA +"5245",0.574320702112717,9.21052631578947,32.3684210526316,NA +"5246",0.747628055154725,9.21052631578947,32.3684210526316,NA +"5247",0.973232737037462,9.21052631578947,32.3684210526316,NA +"5248",1.2669160204875,9.21052631578947,32.3684210526316,NA +"5249",1.64922134437622,9.21052631578947,32.3684210526316,NA +"5250",2.14689134777813,9.21052631578947,32.3684210526316,NA +"5251",2.79473854427218,9.21052631578947,32.3684210526316,NA +"5252",3.63808049202114,9.21052631578947,32.3684210526316,NA +"5253",4.73590980220715,9.21052631578947,32.3684210526316,NA +"5254",6.16502073107827,9.21052631578947,32.3684210526316,NA +"5255",8.02538101483936,9.21052631578947,32.3684210526316,NA +"5256",10.4471247126008,9.21052631578947,32.3684210526316,NA +"5257",13.5996552137305,9.21052631578947,32.3684210526316,NA +"5258",17.7034951740616,9.21052631578947,32.3684210526316,NA +"5259",23.045712295823,9.21052631578947,32.3684210526316,NA +"5260",30,9.21052631578947,32.3684210526316,NA +"5261",0.2,11.3157894736842,32.3684210526316,NA +"5262",0.260352117694686,11.3157894736842,32.3684210526316,NA +"5263",0.338916125940539,11.3157894736842,32.3684210526316,NA +"5264",0.441187655547492,11.3157894736842,32.3684210526316,NA +"5265",0.574320702112717,11.3157894736842,32.3684210526316,NA +"5266",0.747628055154725,11.3157894736842,32.3684210526316,NA +"5267",0.973232737037462,11.3157894736842,32.3684210526316,NA +"5268",1.2669160204875,11.3157894736842,32.3684210526316,NA +"5269",1.64922134437622,11.3157894736842,32.3684210526316,NA +"5270",2.14689134777813,11.3157894736842,32.3684210526316,NA +"5271",2.79473854427218,11.3157894736842,32.3684210526316,NA +"5272",3.63808049202114,11.3157894736842,32.3684210526316,NA +"5273",4.73590980220715,11.3157894736842,32.3684210526316,NA +"5274",6.16502073107827,11.3157894736842,32.3684210526316,NA +"5275",8.02538101483936,11.3157894736842,32.3684210526316,NA +"5276",10.4471247126008,11.3157894736842,32.3684210526316,NA +"5277",13.5996552137305,11.3157894736842,32.3684210526316,NA +"5278",17.7034951740616,11.3157894736842,32.3684210526316,NA +"5279",23.045712295823,11.3157894736842,32.3684210526316,NA +"5280",30,11.3157894736842,32.3684210526316,NA +"5281",0.2,13.4210526315789,32.3684210526316,NA +"5282",0.260352117694686,13.4210526315789,32.3684210526316,NA +"5283",0.338916125940539,13.4210526315789,32.3684210526316,NA +"5284",0.441187655547492,13.4210526315789,32.3684210526316,NA +"5285",0.574320702112717,13.4210526315789,32.3684210526316,NA +"5286",0.747628055154725,13.4210526315789,32.3684210526316,NA +"5287",0.973232737037462,13.4210526315789,32.3684210526316,NA +"5288",1.2669160204875,13.4210526315789,32.3684210526316,NA +"5289",1.64922134437622,13.4210526315789,32.3684210526316,NA +"5290",2.14689134777813,13.4210526315789,32.3684210526316,NA +"5291",2.79473854427218,13.4210526315789,32.3684210526316,NA +"5292",3.63808049202114,13.4210526315789,32.3684210526316,NA +"5293",4.73590980220715,13.4210526315789,32.3684210526316,NA +"5294",6.16502073107827,13.4210526315789,32.3684210526316,NA +"5295",8.02538101483936,13.4210526315789,32.3684210526316,NA +"5296",10.4471247126008,13.4210526315789,32.3684210526316,NA +"5297",13.5996552137305,13.4210526315789,32.3684210526316,NA +"5298",17.7034951740616,13.4210526315789,32.3684210526316,NA +"5299",23.045712295823,13.4210526315789,32.3684210526316,NA +"5300",30,13.4210526315789,32.3684210526316,NA +"5301",0.2,15.5263157894737,32.3684210526316,NA +"5302",0.260352117694686,15.5263157894737,32.3684210526316,NA +"5303",0.338916125940539,15.5263157894737,32.3684210526316,NA +"5304",0.441187655547492,15.5263157894737,32.3684210526316,NA +"5305",0.574320702112717,15.5263157894737,32.3684210526316,NA +"5306",0.747628055154725,15.5263157894737,32.3684210526316,NA +"5307",0.973232737037462,15.5263157894737,32.3684210526316,NA +"5308",1.2669160204875,15.5263157894737,32.3684210526316,NA +"5309",1.64922134437622,15.5263157894737,32.3684210526316,NA +"5310",2.14689134777813,15.5263157894737,32.3684210526316,NA +"5311",2.79473854427218,15.5263157894737,32.3684210526316,NA +"5312",3.63808049202114,15.5263157894737,32.3684210526316,NA +"5313",4.73590980220715,15.5263157894737,32.3684210526316,NA +"5314",6.16502073107827,15.5263157894737,32.3684210526316,NA +"5315",8.02538101483936,15.5263157894737,32.3684210526316,NA +"5316",10.4471247126008,15.5263157894737,32.3684210526316,NA +"5317",13.5996552137305,15.5263157894737,32.3684210526316,NA +"5318",17.7034951740616,15.5263157894737,32.3684210526316,NA +"5319",23.045712295823,15.5263157894737,32.3684210526316,NA +"5320",30,15.5263157894737,32.3684210526316,NA +"5321",0.2,17.6315789473684,32.3684210526316,NA +"5322",0.260352117694686,17.6315789473684,32.3684210526316,NA +"5323",0.338916125940539,17.6315789473684,32.3684210526316,NA +"5324",0.441187655547492,17.6315789473684,32.3684210526316,NA +"5325",0.574320702112717,17.6315789473684,32.3684210526316,NA +"5326",0.747628055154725,17.6315789473684,32.3684210526316,NA +"5327",0.973232737037462,17.6315789473684,32.3684210526316,NA +"5328",1.2669160204875,17.6315789473684,32.3684210526316,NA +"5329",1.64922134437622,17.6315789473684,32.3684210526316,NA +"5330",2.14689134777813,17.6315789473684,32.3684210526316,NA +"5331",2.79473854427218,17.6315789473684,32.3684210526316,NA +"5332",3.63808049202114,17.6315789473684,32.3684210526316,NA +"5333",4.73590980220715,17.6315789473684,32.3684210526316,NA +"5334",6.16502073107827,17.6315789473684,32.3684210526316,NA +"5335",8.02538101483936,17.6315789473684,32.3684210526316,NA +"5336",10.4471247126008,17.6315789473684,32.3684210526316,NA +"5337",13.5996552137305,17.6315789473684,32.3684210526316,NA +"5338",17.7034951740616,17.6315789473684,32.3684210526316,NA +"5339",23.045712295823,17.6315789473684,32.3684210526316,NA +"5340",30,17.6315789473684,32.3684210526316,NA +"5341",0.2,19.7368421052632,32.3684210526316,NA +"5342",0.260352117694686,19.7368421052632,32.3684210526316,NA +"5343",0.338916125940539,19.7368421052632,32.3684210526316,NA +"5344",0.441187655547492,19.7368421052632,32.3684210526316,NA +"5345",0.574320702112717,19.7368421052632,32.3684210526316,NA +"5346",0.747628055154725,19.7368421052632,32.3684210526316,NA +"5347",0.973232737037462,19.7368421052632,32.3684210526316,NA +"5348",1.2669160204875,19.7368421052632,32.3684210526316,NA +"5349",1.64922134437622,19.7368421052632,32.3684210526316,NA +"5350",2.14689134777813,19.7368421052632,32.3684210526316,NA +"5351",2.79473854427218,19.7368421052632,32.3684210526316,NA +"5352",3.63808049202114,19.7368421052632,32.3684210526316,NA +"5353",4.73590980220715,19.7368421052632,32.3684210526316,NA +"5354",6.16502073107827,19.7368421052632,32.3684210526316,NA +"5355",8.02538101483936,19.7368421052632,32.3684210526316,NA +"5356",10.4471247126008,19.7368421052632,32.3684210526316,NA +"5357",13.5996552137305,19.7368421052632,32.3684210526316,NA +"5358",17.7034951740616,19.7368421052632,32.3684210526316,NA +"5359",23.045712295823,19.7368421052632,32.3684210526316,NA +"5360",30,19.7368421052632,32.3684210526316,NA +"5361",0.2,21.8421052631579,32.3684210526316,NA +"5362",0.260352117694686,21.8421052631579,32.3684210526316,NA +"5363",0.338916125940539,21.8421052631579,32.3684210526316,NA +"5364",0.441187655547492,21.8421052631579,32.3684210526316,NA +"5365",0.574320702112717,21.8421052631579,32.3684210526316,NA +"5366",0.747628055154725,21.8421052631579,32.3684210526316,NA +"5367",0.973232737037462,21.8421052631579,32.3684210526316,NA +"5368",1.2669160204875,21.8421052631579,32.3684210526316,NA +"5369",1.64922134437622,21.8421052631579,32.3684210526316,NA +"5370",2.14689134777813,21.8421052631579,32.3684210526316,NA +"5371",2.79473854427218,21.8421052631579,32.3684210526316,NA +"5372",3.63808049202114,21.8421052631579,32.3684210526316,NA +"5373",4.73590980220715,21.8421052631579,32.3684210526316,NA +"5374",6.16502073107827,21.8421052631579,32.3684210526316,NA +"5375",8.02538101483936,21.8421052631579,32.3684210526316,NA +"5376",10.4471247126008,21.8421052631579,32.3684210526316,NA +"5377",13.5996552137305,21.8421052631579,32.3684210526316,NA +"5378",17.7034951740616,21.8421052631579,32.3684210526316,NA +"5379",23.045712295823,21.8421052631579,32.3684210526316,NA +"5380",30,21.8421052631579,32.3684210526316,NA +"5381",0.2,23.9473684210526,32.3684210526316,NA +"5382",0.260352117694686,23.9473684210526,32.3684210526316,NA +"5383",0.338916125940539,23.9473684210526,32.3684210526316,NA +"5384",0.441187655547492,23.9473684210526,32.3684210526316,NA +"5385",0.574320702112717,23.9473684210526,32.3684210526316,NA +"5386",0.747628055154725,23.9473684210526,32.3684210526316,NA +"5387",0.973232737037462,23.9473684210526,32.3684210526316,NA +"5388",1.2669160204875,23.9473684210526,32.3684210526316,NA +"5389",1.64922134437622,23.9473684210526,32.3684210526316,NA +"5390",2.14689134777813,23.9473684210526,32.3684210526316,NA +"5391",2.79473854427218,23.9473684210526,32.3684210526316,NA +"5392",3.63808049202114,23.9473684210526,32.3684210526316,NA +"5393",4.73590980220715,23.9473684210526,32.3684210526316,NA +"5394",6.16502073107827,23.9473684210526,32.3684210526316,NA +"5395",8.02538101483936,23.9473684210526,32.3684210526316,NA +"5396",10.4471247126008,23.9473684210526,32.3684210526316,NA +"5397",13.5996552137305,23.9473684210526,32.3684210526316,NA +"5398",17.7034951740616,23.9473684210526,32.3684210526316,NA +"5399",23.045712295823,23.9473684210526,32.3684210526316,NA +"5400",30,23.9473684210526,32.3684210526316,NA +"5401",0.2,26.0526315789474,32.3684210526316,NA +"5402",0.260352117694686,26.0526315789474,32.3684210526316,NA +"5403",0.338916125940539,26.0526315789474,32.3684210526316,NA +"5404",0.441187655547492,26.0526315789474,32.3684210526316,NA +"5405",0.574320702112717,26.0526315789474,32.3684210526316,NA +"5406",0.747628055154725,26.0526315789474,32.3684210526316,NA +"5407",0.973232737037462,26.0526315789474,32.3684210526316,NA +"5408",1.2669160204875,26.0526315789474,32.3684210526316,NA +"5409",1.64922134437622,26.0526315789474,32.3684210526316,NA +"5410",2.14689134777813,26.0526315789474,32.3684210526316,NA +"5411",2.79473854427218,26.0526315789474,32.3684210526316,NA +"5412",3.63808049202114,26.0526315789474,32.3684210526316,NA +"5413",4.73590980220715,26.0526315789474,32.3684210526316,NA +"5414",6.16502073107827,26.0526315789474,32.3684210526316,NA +"5415",8.02538101483936,26.0526315789474,32.3684210526316,NA +"5416",10.4471247126008,26.0526315789474,32.3684210526316,NA +"5417",13.5996552137305,26.0526315789474,32.3684210526316,NA +"5418",17.7034951740616,26.0526315789474,32.3684210526316,NA +"5419",23.045712295823,26.0526315789474,32.3684210526316,NA +"5420",30,26.0526315789474,32.3684210526316,NA +"5421",0.2,28.1578947368421,32.3684210526316,NA +"5422",0.260352117694686,28.1578947368421,32.3684210526316,NA +"5423",0.338916125940539,28.1578947368421,32.3684210526316,NA +"5424",0.441187655547492,28.1578947368421,32.3684210526316,NA +"5425",0.574320702112717,28.1578947368421,32.3684210526316,NA +"5426",0.747628055154725,28.1578947368421,32.3684210526316,NA +"5427",0.973232737037462,28.1578947368421,32.3684210526316,NA +"5428",1.2669160204875,28.1578947368421,32.3684210526316,NA +"5429",1.64922134437622,28.1578947368421,32.3684210526316,NA +"5430",2.14689134777813,28.1578947368421,32.3684210526316,NA +"5431",2.79473854427218,28.1578947368421,32.3684210526316,NA +"5432",3.63808049202114,28.1578947368421,32.3684210526316,NA +"5433",4.73590980220715,28.1578947368421,32.3684210526316,NA +"5434",6.16502073107827,28.1578947368421,32.3684210526316,NA +"5435",8.02538101483936,28.1578947368421,32.3684210526316,NA +"5436",10.4471247126008,28.1578947368421,32.3684210526316,NA +"5437",13.5996552137305,28.1578947368421,32.3684210526316,NA +"5438",17.7034951740616,28.1578947368421,32.3684210526316,NA +"5439",23.045712295823,28.1578947368421,32.3684210526316,NA +"5440",30,28.1578947368421,32.3684210526316,NA +"5441",0.2,30.2631578947368,32.3684210526316,NA +"5442",0.260352117694686,30.2631578947368,32.3684210526316,NA +"5443",0.338916125940539,30.2631578947368,32.3684210526316,NA +"5444",0.441187655547492,30.2631578947368,32.3684210526316,NA +"5445",0.574320702112717,30.2631578947368,32.3684210526316,NA +"5446",0.747628055154725,30.2631578947368,32.3684210526316,NA +"5447",0.973232737037462,30.2631578947368,32.3684210526316,NA +"5448",1.2669160204875,30.2631578947368,32.3684210526316,NA +"5449",1.64922134437622,30.2631578947368,32.3684210526316,NA +"5450",2.14689134777813,30.2631578947368,32.3684210526316,NA +"5451",2.79473854427218,30.2631578947368,32.3684210526316,NA +"5452",3.63808049202114,30.2631578947368,32.3684210526316,NA +"5453",4.73590980220715,30.2631578947368,32.3684210526316,NA +"5454",6.16502073107827,30.2631578947368,32.3684210526316,NA +"5455",8.02538101483936,30.2631578947368,32.3684210526316,NA +"5456",10.4471247126008,30.2631578947368,32.3684210526316,NA +"5457",13.5996552137305,30.2631578947368,32.3684210526316,NA +"5458",17.7034951740616,30.2631578947368,32.3684210526316,NA +"5459",23.045712295823,30.2631578947368,32.3684210526316,NA +"5460",30,30.2631578947368,32.3684210526316,NA +"5461",0.2,32.3684210526316,32.3684210526316,NA +"5462",0.260352117694686,32.3684210526316,32.3684210526316,NA +"5463",0.338916125940539,32.3684210526316,32.3684210526316,NA +"5464",0.441187655547492,32.3684210526316,32.3684210526316,NA +"5465",0.574320702112717,32.3684210526316,32.3684210526316,NA +"5466",0.747628055154725,32.3684210526316,32.3684210526316,NA +"5467",0.973232737037462,32.3684210526316,32.3684210526316,NA +"5468",1.2669160204875,32.3684210526316,32.3684210526316,NA +"5469",1.64922134437622,32.3684210526316,32.3684210526316,NA +"5470",2.14689134777813,32.3684210526316,32.3684210526316,NA +"5471",2.79473854427218,32.3684210526316,32.3684210526316,NA +"5472",3.63808049202114,32.3684210526316,32.3684210526316,NA +"5473",4.73590980220715,32.3684210526316,32.3684210526316,NA +"5474",6.16502073107827,32.3684210526316,32.3684210526316,NA +"5475",8.02538101483936,32.3684210526316,32.3684210526316,NA +"5476",10.4471247126008,32.3684210526316,32.3684210526316,NA +"5477",13.5996552137305,32.3684210526316,32.3684210526316,NA +"5478",17.7034951740616,32.3684210526316,32.3684210526316,NA +"5479",23.045712295823,32.3684210526316,32.3684210526316,NA +"5480",30,32.3684210526316,32.3684210526316,NA +"5481",0.2,34.4736842105263,32.3684210526316,NA +"5482",0.260352117694686,34.4736842105263,32.3684210526316,NA +"5483",0.338916125940539,34.4736842105263,32.3684210526316,NA +"5484",0.441187655547492,34.4736842105263,32.3684210526316,NA +"5485",0.574320702112717,34.4736842105263,32.3684210526316,NA +"5486",0.747628055154725,34.4736842105263,32.3684210526316,NA +"5487",0.973232737037462,34.4736842105263,32.3684210526316,NA +"5488",1.2669160204875,34.4736842105263,32.3684210526316,NA +"5489",1.64922134437622,34.4736842105263,32.3684210526316,NA +"5490",2.14689134777813,34.4736842105263,32.3684210526316,NA +"5491",2.79473854427218,34.4736842105263,32.3684210526316,NA +"5492",3.63808049202114,34.4736842105263,32.3684210526316,NA +"5493",4.73590980220715,34.4736842105263,32.3684210526316,NA +"5494",6.16502073107827,34.4736842105263,32.3684210526316,NA +"5495",8.02538101483936,34.4736842105263,32.3684210526316,NA +"5496",10.4471247126008,34.4736842105263,32.3684210526316,NA +"5497",13.5996552137305,34.4736842105263,32.3684210526316,NA +"5498",17.7034951740616,34.4736842105263,32.3684210526316,NA +"5499",23.045712295823,34.4736842105263,32.3684210526316,NA +"5500",30,34.4736842105263,32.3684210526316,NA +"5501",0.2,36.5789473684211,32.3684210526316,NA +"5502",0.260352117694686,36.5789473684211,32.3684210526316,NA +"5503",0.338916125940539,36.5789473684211,32.3684210526316,NA +"5504",0.441187655547492,36.5789473684211,32.3684210526316,NA +"5505",0.574320702112717,36.5789473684211,32.3684210526316,NA +"5506",0.747628055154725,36.5789473684211,32.3684210526316,NA +"5507",0.973232737037462,36.5789473684211,32.3684210526316,NA +"5508",1.2669160204875,36.5789473684211,32.3684210526316,NA +"5509",1.64922134437622,36.5789473684211,32.3684210526316,NA +"5510",2.14689134777813,36.5789473684211,32.3684210526316,NA +"5511",2.79473854427218,36.5789473684211,32.3684210526316,NA +"5512",3.63808049202114,36.5789473684211,32.3684210526316,NA +"5513",4.73590980220715,36.5789473684211,32.3684210526316,NA +"5514",6.16502073107827,36.5789473684211,32.3684210526316,NA +"5515",8.02538101483936,36.5789473684211,32.3684210526316,NA +"5516",10.4471247126008,36.5789473684211,32.3684210526316,NA +"5517",13.5996552137305,36.5789473684211,32.3684210526316,NA +"5518",17.7034951740616,36.5789473684211,32.3684210526316,NA +"5519",23.045712295823,36.5789473684211,32.3684210526316,NA +"5520",30,36.5789473684211,32.3684210526316,NA +"5521",0.2,38.6842105263158,32.3684210526316,NA +"5522",0.260352117694686,38.6842105263158,32.3684210526316,NA +"5523",0.338916125940539,38.6842105263158,32.3684210526316,NA +"5524",0.441187655547492,38.6842105263158,32.3684210526316,NA +"5525",0.574320702112717,38.6842105263158,32.3684210526316,NA +"5526",0.747628055154725,38.6842105263158,32.3684210526316,NA +"5527",0.973232737037462,38.6842105263158,32.3684210526316,NA +"5528",1.2669160204875,38.6842105263158,32.3684210526316,NA +"5529",1.64922134437622,38.6842105263158,32.3684210526316,NA +"5530",2.14689134777813,38.6842105263158,32.3684210526316,NA +"5531",2.79473854427218,38.6842105263158,32.3684210526316,NA +"5532",3.63808049202114,38.6842105263158,32.3684210526316,NA +"5533",4.73590980220715,38.6842105263158,32.3684210526316,NA +"5534",6.16502073107827,38.6842105263158,32.3684210526316,NA +"5535",8.02538101483936,38.6842105263158,32.3684210526316,NA +"5536",10.4471247126008,38.6842105263158,32.3684210526316,NA +"5537",13.5996552137305,38.6842105263158,32.3684210526316,NA +"5538",17.7034951740616,38.6842105263158,32.3684210526316,NA +"5539",23.045712295823,38.6842105263158,32.3684210526316,NA +"5540",30,38.6842105263158,32.3684210526316,NA +"5541",0.2,40.7894736842105,32.3684210526316,NA +"5542",0.260352117694686,40.7894736842105,32.3684210526316,NA +"5543",0.338916125940539,40.7894736842105,32.3684210526316,NA +"5544",0.441187655547492,40.7894736842105,32.3684210526316,NA +"5545",0.574320702112717,40.7894736842105,32.3684210526316,NA +"5546",0.747628055154725,40.7894736842105,32.3684210526316,NA +"5547",0.973232737037462,40.7894736842105,32.3684210526316,NA +"5548",1.2669160204875,40.7894736842105,32.3684210526316,NA +"5549",1.64922134437622,40.7894736842105,32.3684210526316,NA +"5550",2.14689134777813,40.7894736842105,32.3684210526316,NA +"5551",2.79473854427218,40.7894736842105,32.3684210526316,NA +"5552",3.63808049202114,40.7894736842105,32.3684210526316,NA +"5553",4.73590980220715,40.7894736842105,32.3684210526316,NA +"5554",6.16502073107827,40.7894736842105,32.3684210526316,NA +"5555",8.02538101483936,40.7894736842105,32.3684210526316,NA +"5556",10.4471247126008,40.7894736842105,32.3684210526316,NA +"5557",13.5996552137305,40.7894736842105,32.3684210526316,NA +"5558",17.7034951740616,40.7894736842105,32.3684210526316,NA +"5559",23.045712295823,40.7894736842105,32.3684210526316,NA +"5560",30,40.7894736842105,32.3684210526316,NA +"5561",0.2,42.8947368421053,32.3684210526316,NA +"5562",0.260352117694686,42.8947368421053,32.3684210526316,NA +"5563",0.338916125940539,42.8947368421053,32.3684210526316,NA +"5564",0.441187655547492,42.8947368421053,32.3684210526316,NA +"5565",0.574320702112717,42.8947368421053,32.3684210526316,NA +"5566",0.747628055154725,42.8947368421053,32.3684210526316,NA +"5567",0.973232737037462,42.8947368421053,32.3684210526316,NA +"5568",1.2669160204875,42.8947368421053,32.3684210526316,NA +"5569",1.64922134437622,42.8947368421053,32.3684210526316,NA +"5570",2.14689134777813,42.8947368421053,32.3684210526316,NA +"5571",2.79473854427218,42.8947368421053,32.3684210526316,NA +"5572",3.63808049202114,42.8947368421053,32.3684210526316,NA +"5573",4.73590980220715,42.8947368421053,32.3684210526316,NA +"5574",6.16502073107827,42.8947368421053,32.3684210526316,NA +"5575",8.02538101483936,42.8947368421053,32.3684210526316,NA +"5576",10.4471247126008,42.8947368421053,32.3684210526316,NA +"5577",13.5996552137305,42.8947368421053,32.3684210526316,NA +"5578",17.7034951740616,42.8947368421053,32.3684210526316,NA +"5579",23.045712295823,42.8947368421053,32.3684210526316,NA +"5580",30,42.8947368421053,32.3684210526316,NA +"5581",0.2,45,32.3684210526316,NA +"5582",0.260352117694686,45,32.3684210526316,NA +"5583",0.338916125940539,45,32.3684210526316,NA +"5584",0.441187655547492,45,32.3684210526316,NA +"5585",0.574320702112717,45,32.3684210526316,NA +"5586",0.747628055154725,45,32.3684210526316,NA +"5587",0.973232737037462,45,32.3684210526316,NA +"5588",1.2669160204875,45,32.3684210526316,NA +"5589",1.64922134437622,45,32.3684210526316,NA +"5590",2.14689134777813,45,32.3684210526316,NA +"5591",2.79473854427218,45,32.3684210526316,NA +"5592",3.63808049202114,45,32.3684210526316,NA +"5593",4.73590980220715,45,32.3684210526316,NA +"5594",6.16502073107827,45,32.3684210526316,NA +"5595",8.02538101483936,45,32.3684210526316,NA +"5596",10.4471247126008,45,32.3684210526316,NA +"5597",13.5996552137305,45,32.3684210526316,NA +"5598",17.7034951740616,45,32.3684210526316,NA +"5599",23.045712295823,45,32.3684210526316,NA +"5600",30,45,32.3684210526316,NA +"5601",0.2,5,34.4736842105263,NA +"5602",0.260352117694686,5,34.4736842105263,NA +"5603",0.338916125940539,5,34.4736842105263,NA +"5604",0.441187655547492,5,34.4736842105263,NA +"5605",0.574320702112717,5,34.4736842105263,NA +"5606",0.747628055154725,5,34.4736842105263,NA +"5607",0.973232737037462,5,34.4736842105263,NA +"5608",1.2669160204875,5,34.4736842105263,NA +"5609",1.64922134437622,5,34.4736842105263,NA +"5610",2.14689134777813,5,34.4736842105263,NA +"5611",2.79473854427218,5,34.4736842105263,NA +"5612",3.63808049202114,5,34.4736842105263,NA +"5613",4.73590980220715,5,34.4736842105263,NA +"5614",6.16502073107827,5,34.4736842105263,NA +"5615",8.02538101483936,5,34.4736842105263,NA +"5616",10.4471247126008,5,34.4736842105263,NA +"5617",13.5996552137305,5,34.4736842105263,NA +"5618",17.7034951740616,5,34.4736842105263,NA +"5619",23.045712295823,5,34.4736842105263,NA +"5620",30,5,34.4736842105263,NA +"5621",0.2,7.10526315789474,34.4736842105263,NA +"5622",0.260352117694686,7.10526315789474,34.4736842105263,NA +"5623",0.338916125940539,7.10526315789474,34.4736842105263,NA +"5624",0.441187655547492,7.10526315789474,34.4736842105263,NA +"5625",0.574320702112717,7.10526315789474,34.4736842105263,NA +"5626",0.747628055154725,7.10526315789474,34.4736842105263,NA +"5627",0.973232737037462,7.10526315789474,34.4736842105263,NA +"5628",1.2669160204875,7.10526315789474,34.4736842105263,NA +"5629",1.64922134437622,7.10526315789474,34.4736842105263,NA +"5630",2.14689134777813,7.10526315789474,34.4736842105263,NA +"5631",2.79473854427218,7.10526315789474,34.4736842105263,NA +"5632",3.63808049202114,7.10526315789474,34.4736842105263,NA +"5633",4.73590980220715,7.10526315789474,34.4736842105263,NA +"5634",6.16502073107827,7.10526315789474,34.4736842105263,NA +"5635",8.02538101483936,7.10526315789474,34.4736842105263,NA +"5636",10.4471247126008,7.10526315789474,34.4736842105263,NA +"5637",13.5996552137305,7.10526315789474,34.4736842105263,NA +"5638",17.7034951740616,7.10526315789474,34.4736842105263,NA +"5639",23.045712295823,7.10526315789474,34.4736842105263,NA +"5640",30,7.10526315789474,34.4736842105263,NA +"5641",0.2,9.21052631578947,34.4736842105263,NA +"5642",0.260352117694686,9.21052631578947,34.4736842105263,NA +"5643",0.338916125940539,9.21052631578947,34.4736842105263,NA +"5644",0.441187655547492,9.21052631578947,34.4736842105263,NA +"5645",0.574320702112717,9.21052631578947,34.4736842105263,NA +"5646",0.747628055154725,9.21052631578947,34.4736842105263,NA +"5647",0.973232737037462,9.21052631578947,34.4736842105263,NA +"5648",1.2669160204875,9.21052631578947,34.4736842105263,NA +"5649",1.64922134437622,9.21052631578947,34.4736842105263,NA +"5650",2.14689134777813,9.21052631578947,34.4736842105263,NA +"5651",2.79473854427218,9.21052631578947,34.4736842105263,NA +"5652",3.63808049202114,9.21052631578947,34.4736842105263,NA +"5653",4.73590980220715,9.21052631578947,34.4736842105263,NA +"5654",6.16502073107827,9.21052631578947,34.4736842105263,NA +"5655",8.02538101483936,9.21052631578947,34.4736842105263,NA +"5656",10.4471247126008,9.21052631578947,34.4736842105263,NA +"5657",13.5996552137305,9.21052631578947,34.4736842105263,NA +"5658",17.7034951740616,9.21052631578947,34.4736842105263,NA +"5659",23.045712295823,9.21052631578947,34.4736842105263,NA +"5660",30,9.21052631578947,34.4736842105263,NA +"5661",0.2,11.3157894736842,34.4736842105263,NA +"5662",0.260352117694686,11.3157894736842,34.4736842105263,NA +"5663",0.338916125940539,11.3157894736842,34.4736842105263,NA +"5664",0.441187655547492,11.3157894736842,34.4736842105263,NA +"5665",0.574320702112717,11.3157894736842,34.4736842105263,NA +"5666",0.747628055154725,11.3157894736842,34.4736842105263,NA +"5667",0.973232737037462,11.3157894736842,34.4736842105263,NA +"5668",1.2669160204875,11.3157894736842,34.4736842105263,NA +"5669",1.64922134437622,11.3157894736842,34.4736842105263,NA +"5670",2.14689134777813,11.3157894736842,34.4736842105263,NA +"5671",2.79473854427218,11.3157894736842,34.4736842105263,NA +"5672",3.63808049202114,11.3157894736842,34.4736842105263,NA +"5673",4.73590980220715,11.3157894736842,34.4736842105263,NA +"5674",6.16502073107827,11.3157894736842,34.4736842105263,NA +"5675",8.02538101483936,11.3157894736842,34.4736842105263,NA +"5676",10.4471247126008,11.3157894736842,34.4736842105263,NA +"5677",13.5996552137305,11.3157894736842,34.4736842105263,NA +"5678",17.7034951740616,11.3157894736842,34.4736842105263,NA +"5679",23.045712295823,11.3157894736842,34.4736842105263,NA +"5680",30,11.3157894736842,34.4736842105263,NA +"5681",0.2,13.4210526315789,34.4736842105263,NA +"5682",0.260352117694686,13.4210526315789,34.4736842105263,NA +"5683",0.338916125940539,13.4210526315789,34.4736842105263,NA +"5684",0.441187655547492,13.4210526315789,34.4736842105263,NA +"5685",0.574320702112717,13.4210526315789,34.4736842105263,NA +"5686",0.747628055154725,13.4210526315789,34.4736842105263,NA +"5687",0.973232737037462,13.4210526315789,34.4736842105263,NA +"5688",1.2669160204875,13.4210526315789,34.4736842105263,NA +"5689",1.64922134437622,13.4210526315789,34.4736842105263,NA +"5690",2.14689134777813,13.4210526315789,34.4736842105263,NA +"5691",2.79473854427218,13.4210526315789,34.4736842105263,NA +"5692",3.63808049202114,13.4210526315789,34.4736842105263,NA +"5693",4.73590980220715,13.4210526315789,34.4736842105263,NA +"5694",6.16502073107827,13.4210526315789,34.4736842105263,NA +"5695",8.02538101483936,13.4210526315789,34.4736842105263,NA +"5696",10.4471247126008,13.4210526315789,34.4736842105263,NA +"5697",13.5996552137305,13.4210526315789,34.4736842105263,NA +"5698",17.7034951740616,13.4210526315789,34.4736842105263,NA +"5699",23.045712295823,13.4210526315789,34.4736842105263,NA +"5700",30,13.4210526315789,34.4736842105263,NA +"5701",0.2,15.5263157894737,34.4736842105263,NA +"5702",0.260352117694686,15.5263157894737,34.4736842105263,NA +"5703",0.338916125940539,15.5263157894737,34.4736842105263,NA +"5704",0.441187655547492,15.5263157894737,34.4736842105263,NA +"5705",0.574320702112717,15.5263157894737,34.4736842105263,NA +"5706",0.747628055154725,15.5263157894737,34.4736842105263,NA +"5707",0.973232737037462,15.5263157894737,34.4736842105263,NA +"5708",1.2669160204875,15.5263157894737,34.4736842105263,NA +"5709",1.64922134437622,15.5263157894737,34.4736842105263,NA +"5710",2.14689134777813,15.5263157894737,34.4736842105263,NA +"5711",2.79473854427218,15.5263157894737,34.4736842105263,NA +"5712",3.63808049202114,15.5263157894737,34.4736842105263,NA +"5713",4.73590980220715,15.5263157894737,34.4736842105263,NA +"5714",6.16502073107827,15.5263157894737,34.4736842105263,NA +"5715",8.02538101483936,15.5263157894737,34.4736842105263,NA +"5716",10.4471247126008,15.5263157894737,34.4736842105263,NA +"5717",13.5996552137305,15.5263157894737,34.4736842105263,NA +"5718",17.7034951740616,15.5263157894737,34.4736842105263,NA +"5719",23.045712295823,15.5263157894737,34.4736842105263,NA +"5720",30,15.5263157894737,34.4736842105263,NA +"5721",0.2,17.6315789473684,34.4736842105263,NA +"5722",0.260352117694686,17.6315789473684,34.4736842105263,NA +"5723",0.338916125940539,17.6315789473684,34.4736842105263,NA +"5724",0.441187655547492,17.6315789473684,34.4736842105263,NA +"5725",0.574320702112717,17.6315789473684,34.4736842105263,NA +"5726",0.747628055154725,17.6315789473684,34.4736842105263,NA +"5727",0.973232737037462,17.6315789473684,34.4736842105263,NA +"5728",1.2669160204875,17.6315789473684,34.4736842105263,NA +"5729",1.64922134437622,17.6315789473684,34.4736842105263,NA +"5730",2.14689134777813,17.6315789473684,34.4736842105263,NA +"5731",2.79473854427218,17.6315789473684,34.4736842105263,NA +"5732",3.63808049202114,17.6315789473684,34.4736842105263,NA +"5733",4.73590980220715,17.6315789473684,34.4736842105263,NA +"5734",6.16502073107827,17.6315789473684,34.4736842105263,NA +"5735",8.02538101483936,17.6315789473684,34.4736842105263,NA +"5736",10.4471247126008,17.6315789473684,34.4736842105263,NA +"5737",13.5996552137305,17.6315789473684,34.4736842105263,NA +"5738",17.7034951740616,17.6315789473684,34.4736842105263,NA +"5739",23.045712295823,17.6315789473684,34.4736842105263,NA +"5740",30,17.6315789473684,34.4736842105263,NA +"5741",0.2,19.7368421052632,34.4736842105263,NA +"5742",0.260352117694686,19.7368421052632,34.4736842105263,NA +"5743",0.338916125940539,19.7368421052632,34.4736842105263,NA +"5744",0.441187655547492,19.7368421052632,34.4736842105263,NA +"5745",0.574320702112717,19.7368421052632,34.4736842105263,NA +"5746",0.747628055154725,19.7368421052632,34.4736842105263,NA +"5747",0.973232737037462,19.7368421052632,34.4736842105263,NA +"5748",1.2669160204875,19.7368421052632,34.4736842105263,NA +"5749",1.64922134437622,19.7368421052632,34.4736842105263,NA +"5750",2.14689134777813,19.7368421052632,34.4736842105263,NA +"5751",2.79473854427218,19.7368421052632,34.4736842105263,NA +"5752",3.63808049202114,19.7368421052632,34.4736842105263,NA +"5753",4.73590980220715,19.7368421052632,34.4736842105263,NA +"5754",6.16502073107827,19.7368421052632,34.4736842105263,NA +"5755",8.02538101483936,19.7368421052632,34.4736842105263,NA +"5756",10.4471247126008,19.7368421052632,34.4736842105263,NA +"5757",13.5996552137305,19.7368421052632,34.4736842105263,NA +"5758",17.7034951740616,19.7368421052632,34.4736842105263,NA +"5759",23.045712295823,19.7368421052632,34.4736842105263,NA +"5760",30,19.7368421052632,34.4736842105263,NA +"5761",0.2,21.8421052631579,34.4736842105263,NA +"5762",0.260352117694686,21.8421052631579,34.4736842105263,NA +"5763",0.338916125940539,21.8421052631579,34.4736842105263,NA +"5764",0.441187655547492,21.8421052631579,34.4736842105263,NA +"5765",0.574320702112717,21.8421052631579,34.4736842105263,NA +"5766",0.747628055154725,21.8421052631579,34.4736842105263,NA +"5767",0.973232737037462,21.8421052631579,34.4736842105263,NA +"5768",1.2669160204875,21.8421052631579,34.4736842105263,NA +"5769",1.64922134437622,21.8421052631579,34.4736842105263,NA +"5770",2.14689134777813,21.8421052631579,34.4736842105263,NA +"5771",2.79473854427218,21.8421052631579,34.4736842105263,NA +"5772",3.63808049202114,21.8421052631579,34.4736842105263,NA +"5773",4.73590980220715,21.8421052631579,34.4736842105263,NA +"5774",6.16502073107827,21.8421052631579,34.4736842105263,NA +"5775",8.02538101483936,21.8421052631579,34.4736842105263,NA +"5776",10.4471247126008,21.8421052631579,34.4736842105263,NA +"5777",13.5996552137305,21.8421052631579,34.4736842105263,NA +"5778",17.7034951740616,21.8421052631579,34.4736842105263,NA +"5779",23.045712295823,21.8421052631579,34.4736842105263,NA +"5780",30,21.8421052631579,34.4736842105263,NA +"5781",0.2,23.9473684210526,34.4736842105263,NA +"5782",0.260352117694686,23.9473684210526,34.4736842105263,NA +"5783",0.338916125940539,23.9473684210526,34.4736842105263,NA +"5784",0.441187655547492,23.9473684210526,34.4736842105263,NA +"5785",0.574320702112717,23.9473684210526,34.4736842105263,NA +"5786",0.747628055154725,23.9473684210526,34.4736842105263,NA +"5787",0.973232737037462,23.9473684210526,34.4736842105263,NA +"5788",1.2669160204875,23.9473684210526,34.4736842105263,NA +"5789",1.64922134437622,23.9473684210526,34.4736842105263,NA +"5790",2.14689134777813,23.9473684210526,34.4736842105263,NA +"5791",2.79473854427218,23.9473684210526,34.4736842105263,NA +"5792",3.63808049202114,23.9473684210526,34.4736842105263,NA +"5793",4.73590980220715,23.9473684210526,34.4736842105263,NA +"5794",6.16502073107827,23.9473684210526,34.4736842105263,NA +"5795",8.02538101483936,23.9473684210526,34.4736842105263,NA +"5796",10.4471247126008,23.9473684210526,34.4736842105263,NA +"5797",13.5996552137305,23.9473684210526,34.4736842105263,NA +"5798",17.7034951740616,23.9473684210526,34.4736842105263,NA +"5799",23.045712295823,23.9473684210526,34.4736842105263,NA +"5800",30,23.9473684210526,34.4736842105263,NA +"5801",0.2,26.0526315789474,34.4736842105263,NA +"5802",0.260352117694686,26.0526315789474,34.4736842105263,NA +"5803",0.338916125940539,26.0526315789474,34.4736842105263,NA +"5804",0.441187655547492,26.0526315789474,34.4736842105263,NA +"5805",0.574320702112717,26.0526315789474,34.4736842105263,NA +"5806",0.747628055154725,26.0526315789474,34.4736842105263,NA +"5807",0.973232737037462,26.0526315789474,34.4736842105263,NA +"5808",1.2669160204875,26.0526315789474,34.4736842105263,NA +"5809",1.64922134437622,26.0526315789474,34.4736842105263,NA +"5810",2.14689134777813,26.0526315789474,34.4736842105263,NA +"5811",2.79473854427218,26.0526315789474,34.4736842105263,NA +"5812",3.63808049202114,26.0526315789474,34.4736842105263,NA +"5813",4.73590980220715,26.0526315789474,34.4736842105263,NA +"5814",6.16502073107827,26.0526315789474,34.4736842105263,NA +"5815",8.02538101483936,26.0526315789474,34.4736842105263,NA +"5816",10.4471247126008,26.0526315789474,34.4736842105263,NA +"5817",13.5996552137305,26.0526315789474,34.4736842105263,NA +"5818",17.7034951740616,26.0526315789474,34.4736842105263,NA +"5819",23.045712295823,26.0526315789474,34.4736842105263,NA +"5820",30,26.0526315789474,34.4736842105263,NA +"5821",0.2,28.1578947368421,34.4736842105263,NA +"5822",0.260352117694686,28.1578947368421,34.4736842105263,NA +"5823",0.338916125940539,28.1578947368421,34.4736842105263,NA +"5824",0.441187655547492,28.1578947368421,34.4736842105263,NA +"5825",0.574320702112717,28.1578947368421,34.4736842105263,NA +"5826",0.747628055154725,28.1578947368421,34.4736842105263,NA +"5827",0.973232737037462,28.1578947368421,34.4736842105263,NA +"5828",1.2669160204875,28.1578947368421,34.4736842105263,NA +"5829",1.64922134437622,28.1578947368421,34.4736842105263,NA +"5830",2.14689134777813,28.1578947368421,34.4736842105263,NA +"5831",2.79473854427218,28.1578947368421,34.4736842105263,NA +"5832",3.63808049202114,28.1578947368421,34.4736842105263,NA +"5833",4.73590980220715,28.1578947368421,34.4736842105263,NA +"5834",6.16502073107827,28.1578947368421,34.4736842105263,NA +"5835",8.02538101483936,28.1578947368421,34.4736842105263,NA +"5836",10.4471247126008,28.1578947368421,34.4736842105263,NA +"5837",13.5996552137305,28.1578947368421,34.4736842105263,NA +"5838",17.7034951740616,28.1578947368421,34.4736842105263,NA +"5839",23.045712295823,28.1578947368421,34.4736842105263,NA +"5840",30,28.1578947368421,34.4736842105263,NA +"5841",0.2,30.2631578947368,34.4736842105263,NA +"5842",0.260352117694686,30.2631578947368,34.4736842105263,NA +"5843",0.338916125940539,30.2631578947368,34.4736842105263,NA +"5844",0.441187655547492,30.2631578947368,34.4736842105263,NA +"5845",0.574320702112717,30.2631578947368,34.4736842105263,NA +"5846",0.747628055154725,30.2631578947368,34.4736842105263,NA +"5847",0.973232737037462,30.2631578947368,34.4736842105263,NA +"5848",1.2669160204875,30.2631578947368,34.4736842105263,NA +"5849",1.64922134437622,30.2631578947368,34.4736842105263,NA +"5850",2.14689134777813,30.2631578947368,34.4736842105263,NA +"5851",2.79473854427218,30.2631578947368,34.4736842105263,NA +"5852",3.63808049202114,30.2631578947368,34.4736842105263,NA +"5853",4.73590980220715,30.2631578947368,34.4736842105263,NA +"5854",6.16502073107827,30.2631578947368,34.4736842105263,NA +"5855",8.02538101483936,30.2631578947368,34.4736842105263,NA +"5856",10.4471247126008,30.2631578947368,34.4736842105263,NA +"5857",13.5996552137305,30.2631578947368,34.4736842105263,NA +"5858",17.7034951740616,30.2631578947368,34.4736842105263,NA +"5859",23.045712295823,30.2631578947368,34.4736842105263,NA +"5860",30,30.2631578947368,34.4736842105263,NA +"5861",0.2,32.3684210526316,34.4736842105263,NA +"5862",0.260352117694686,32.3684210526316,34.4736842105263,NA +"5863",0.338916125940539,32.3684210526316,34.4736842105263,NA +"5864",0.441187655547492,32.3684210526316,34.4736842105263,NA +"5865",0.574320702112717,32.3684210526316,34.4736842105263,NA +"5866",0.747628055154725,32.3684210526316,34.4736842105263,NA +"5867",0.973232737037462,32.3684210526316,34.4736842105263,NA +"5868",1.2669160204875,32.3684210526316,34.4736842105263,NA +"5869",1.64922134437622,32.3684210526316,34.4736842105263,NA +"5870",2.14689134777813,32.3684210526316,34.4736842105263,NA +"5871",2.79473854427218,32.3684210526316,34.4736842105263,NA +"5872",3.63808049202114,32.3684210526316,34.4736842105263,NA +"5873",4.73590980220715,32.3684210526316,34.4736842105263,NA +"5874",6.16502073107827,32.3684210526316,34.4736842105263,NA +"5875",8.02538101483936,32.3684210526316,34.4736842105263,NA +"5876",10.4471247126008,32.3684210526316,34.4736842105263,NA +"5877",13.5996552137305,32.3684210526316,34.4736842105263,NA +"5878",17.7034951740616,32.3684210526316,34.4736842105263,NA +"5879",23.045712295823,32.3684210526316,34.4736842105263,NA +"5880",30,32.3684210526316,34.4736842105263,NA +"5881",0.2,34.4736842105263,34.4736842105263,NA +"5882",0.260352117694686,34.4736842105263,34.4736842105263,NA +"5883",0.338916125940539,34.4736842105263,34.4736842105263,NA +"5884",0.441187655547492,34.4736842105263,34.4736842105263,NA +"5885",0.574320702112717,34.4736842105263,34.4736842105263,NA +"5886",0.747628055154725,34.4736842105263,34.4736842105263,NA +"5887",0.973232737037462,34.4736842105263,34.4736842105263,NA +"5888",1.2669160204875,34.4736842105263,34.4736842105263,NA +"5889",1.64922134437622,34.4736842105263,34.4736842105263,NA +"5890",2.14689134777813,34.4736842105263,34.4736842105263,NA +"5891",2.79473854427218,34.4736842105263,34.4736842105263,NA +"5892",3.63808049202114,34.4736842105263,34.4736842105263,NA +"5893",4.73590980220715,34.4736842105263,34.4736842105263,NA +"5894",6.16502073107827,34.4736842105263,34.4736842105263,NA +"5895",8.02538101483936,34.4736842105263,34.4736842105263,NA +"5896",10.4471247126008,34.4736842105263,34.4736842105263,NA +"5897",13.5996552137305,34.4736842105263,34.4736842105263,NA +"5898",17.7034951740616,34.4736842105263,34.4736842105263,NA +"5899",23.045712295823,34.4736842105263,34.4736842105263,NA +"5900",30,34.4736842105263,34.4736842105263,NA +"5901",0.2,36.5789473684211,34.4736842105263,NA +"5902",0.260352117694686,36.5789473684211,34.4736842105263,NA +"5903",0.338916125940539,36.5789473684211,34.4736842105263,NA +"5904",0.441187655547492,36.5789473684211,34.4736842105263,NA +"5905",0.574320702112717,36.5789473684211,34.4736842105263,NA +"5906",0.747628055154725,36.5789473684211,34.4736842105263,NA +"5907",0.973232737037462,36.5789473684211,34.4736842105263,NA +"5908",1.2669160204875,36.5789473684211,34.4736842105263,NA +"5909",1.64922134437622,36.5789473684211,34.4736842105263,NA +"5910",2.14689134777813,36.5789473684211,34.4736842105263,NA +"5911",2.79473854427218,36.5789473684211,34.4736842105263,NA +"5912",3.63808049202114,36.5789473684211,34.4736842105263,NA +"5913",4.73590980220715,36.5789473684211,34.4736842105263,NA +"5914",6.16502073107827,36.5789473684211,34.4736842105263,NA +"5915",8.02538101483936,36.5789473684211,34.4736842105263,NA +"5916",10.4471247126008,36.5789473684211,34.4736842105263,NA +"5917",13.5996552137305,36.5789473684211,34.4736842105263,NA +"5918",17.7034951740616,36.5789473684211,34.4736842105263,NA +"5919",23.045712295823,36.5789473684211,34.4736842105263,NA +"5920",30,36.5789473684211,34.4736842105263,NA +"5921",0.2,38.6842105263158,34.4736842105263,NA +"5922",0.260352117694686,38.6842105263158,34.4736842105263,NA +"5923",0.338916125940539,38.6842105263158,34.4736842105263,NA +"5924",0.441187655547492,38.6842105263158,34.4736842105263,NA +"5925",0.574320702112717,38.6842105263158,34.4736842105263,NA +"5926",0.747628055154725,38.6842105263158,34.4736842105263,NA +"5927",0.973232737037462,38.6842105263158,34.4736842105263,NA +"5928",1.2669160204875,38.6842105263158,34.4736842105263,NA +"5929",1.64922134437622,38.6842105263158,34.4736842105263,NA +"5930",2.14689134777813,38.6842105263158,34.4736842105263,NA +"5931",2.79473854427218,38.6842105263158,34.4736842105263,NA +"5932",3.63808049202114,38.6842105263158,34.4736842105263,NA +"5933",4.73590980220715,38.6842105263158,34.4736842105263,NA +"5934",6.16502073107827,38.6842105263158,34.4736842105263,NA +"5935",8.02538101483936,38.6842105263158,34.4736842105263,NA +"5936",10.4471247126008,38.6842105263158,34.4736842105263,NA +"5937",13.5996552137305,38.6842105263158,34.4736842105263,NA +"5938",17.7034951740616,38.6842105263158,34.4736842105263,NA +"5939",23.045712295823,38.6842105263158,34.4736842105263,NA +"5940",30,38.6842105263158,34.4736842105263,NA +"5941",0.2,40.7894736842105,34.4736842105263,NA +"5942",0.260352117694686,40.7894736842105,34.4736842105263,NA +"5943",0.338916125940539,40.7894736842105,34.4736842105263,NA +"5944",0.441187655547492,40.7894736842105,34.4736842105263,NA +"5945",0.574320702112717,40.7894736842105,34.4736842105263,NA +"5946",0.747628055154725,40.7894736842105,34.4736842105263,NA +"5947",0.973232737037462,40.7894736842105,34.4736842105263,NA +"5948",1.2669160204875,40.7894736842105,34.4736842105263,NA +"5949",1.64922134437622,40.7894736842105,34.4736842105263,NA +"5950",2.14689134777813,40.7894736842105,34.4736842105263,NA +"5951",2.79473854427218,40.7894736842105,34.4736842105263,NA +"5952",3.63808049202114,40.7894736842105,34.4736842105263,NA +"5953",4.73590980220715,40.7894736842105,34.4736842105263,NA +"5954",6.16502073107827,40.7894736842105,34.4736842105263,NA +"5955",8.02538101483936,40.7894736842105,34.4736842105263,NA +"5956",10.4471247126008,40.7894736842105,34.4736842105263,NA +"5957",13.5996552137305,40.7894736842105,34.4736842105263,NA +"5958",17.7034951740616,40.7894736842105,34.4736842105263,NA +"5959",23.045712295823,40.7894736842105,34.4736842105263,NA +"5960",30,40.7894736842105,34.4736842105263,NA +"5961",0.2,42.8947368421053,34.4736842105263,NA +"5962",0.260352117694686,42.8947368421053,34.4736842105263,NA +"5963",0.338916125940539,42.8947368421053,34.4736842105263,NA +"5964",0.441187655547492,42.8947368421053,34.4736842105263,NA +"5965",0.574320702112717,42.8947368421053,34.4736842105263,NA +"5966",0.747628055154725,42.8947368421053,34.4736842105263,NA +"5967",0.973232737037462,42.8947368421053,34.4736842105263,NA +"5968",1.2669160204875,42.8947368421053,34.4736842105263,NA +"5969",1.64922134437622,42.8947368421053,34.4736842105263,NA +"5970",2.14689134777813,42.8947368421053,34.4736842105263,NA +"5971",2.79473854427218,42.8947368421053,34.4736842105263,NA +"5972",3.63808049202114,42.8947368421053,34.4736842105263,NA +"5973",4.73590980220715,42.8947368421053,34.4736842105263,NA +"5974",6.16502073107827,42.8947368421053,34.4736842105263,NA +"5975",8.02538101483936,42.8947368421053,34.4736842105263,NA +"5976",10.4471247126008,42.8947368421053,34.4736842105263,NA +"5977",13.5996552137305,42.8947368421053,34.4736842105263,NA +"5978",17.7034951740616,42.8947368421053,34.4736842105263,NA +"5979",23.045712295823,42.8947368421053,34.4736842105263,NA +"5980",30,42.8947368421053,34.4736842105263,NA +"5981",0.2,45,34.4736842105263,NA +"5982",0.260352117694686,45,34.4736842105263,NA +"5983",0.338916125940539,45,34.4736842105263,NA +"5984",0.441187655547492,45,34.4736842105263,NA +"5985",0.574320702112717,45,34.4736842105263,NA +"5986",0.747628055154725,45,34.4736842105263,NA +"5987",0.973232737037462,45,34.4736842105263,NA +"5988",1.2669160204875,45,34.4736842105263,NA +"5989",1.64922134437622,45,34.4736842105263,NA +"5990",2.14689134777813,45,34.4736842105263,NA +"5991",2.79473854427218,45,34.4736842105263,NA +"5992",3.63808049202114,45,34.4736842105263,NA +"5993",4.73590980220715,45,34.4736842105263,NA +"5994",6.16502073107827,45,34.4736842105263,NA +"5995",8.02538101483936,45,34.4736842105263,NA +"5996",10.4471247126008,45,34.4736842105263,NA +"5997",13.5996552137305,45,34.4736842105263,NA +"5998",17.7034951740616,45,34.4736842105263,NA +"5999",23.045712295823,45,34.4736842105263,NA +"6000",30,45,34.4736842105263,NA +"6001",0.2,5,36.5789473684211,NA +"6002",0.260352117694686,5,36.5789473684211,NA +"6003",0.338916125940539,5,36.5789473684211,NA +"6004",0.441187655547492,5,36.5789473684211,NA +"6005",0.574320702112717,5,36.5789473684211,NA +"6006",0.747628055154725,5,36.5789473684211,NA +"6007",0.973232737037462,5,36.5789473684211,NA +"6008",1.2669160204875,5,36.5789473684211,NA +"6009",1.64922134437622,5,36.5789473684211,NA +"6010",2.14689134777813,5,36.5789473684211,NA +"6011",2.79473854427218,5,36.5789473684211,NA +"6012",3.63808049202114,5,36.5789473684211,NA +"6013",4.73590980220715,5,36.5789473684211,NA +"6014",6.16502073107827,5,36.5789473684211,NA +"6015",8.02538101483936,5,36.5789473684211,NA +"6016",10.4471247126008,5,36.5789473684211,NA +"6017",13.5996552137305,5,36.5789473684211,NA +"6018",17.7034951740616,5,36.5789473684211,NA +"6019",23.045712295823,5,36.5789473684211,NA +"6020",30,5,36.5789473684211,NA +"6021",0.2,7.10526315789474,36.5789473684211,NA +"6022",0.260352117694686,7.10526315789474,36.5789473684211,NA +"6023",0.338916125940539,7.10526315789474,36.5789473684211,NA +"6024",0.441187655547492,7.10526315789474,36.5789473684211,NA +"6025",0.574320702112717,7.10526315789474,36.5789473684211,NA +"6026",0.747628055154725,7.10526315789474,36.5789473684211,NA +"6027",0.973232737037462,7.10526315789474,36.5789473684211,NA +"6028",1.2669160204875,7.10526315789474,36.5789473684211,NA +"6029",1.64922134437622,7.10526315789474,36.5789473684211,NA +"6030",2.14689134777813,7.10526315789474,36.5789473684211,NA +"6031",2.79473854427218,7.10526315789474,36.5789473684211,NA +"6032",3.63808049202114,7.10526315789474,36.5789473684211,NA +"6033",4.73590980220715,7.10526315789474,36.5789473684211,NA +"6034",6.16502073107827,7.10526315789474,36.5789473684211,NA +"6035",8.02538101483936,7.10526315789474,36.5789473684211,NA +"6036",10.4471247126008,7.10526315789474,36.5789473684211,NA +"6037",13.5996552137305,7.10526315789474,36.5789473684211,NA +"6038",17.7034951740616,7.10526315789474,36.5789473684211,NA +"6039",23.045712295823,7.10526315789474,36.5789473684211,NA +"6040",30,7.10526315789474,36.5789473684211,NA +"6041",0.2,9.21052631578947,36.5789473684211,NA +"6042",0.260352117694686,9.21052631578947,36.5789473684211,NA +"6043",0.338916125940539,9.21052631578947,36.5789473684211,NA +"6044",0.441187655547492,9.21052631578947,36.5789473684211,NA +"6045",0.574320702112717,9.21052631578947,36.5789473684211,NA +"6046",0.747628055154725,9.21052631578947,36.5789473684211,NA +"6047",0.973232737037462,9.21052631578947,36.5789473684211,NA +"6048",1.2669160204875,9.21052631578947,36.5789473684211,NA +"6049",1.64922134437622,9.21052631578947,36.5789473684211,NA +"6050",2.14689134777813,9.21052631578947,36.5789473684211,NA +"6051",2.79473854427218,9.21052631578947,36.5789473684211,NA +"6052",3.63808049202114,9.21052631578947,36.5789473684211,NA +"6053",4.73590980220715,9.21052631578947,36.5789473684211,NA +"6054",6.16502073107827,9.21052631578947,36.5789473684211,NA +"6055",8.02538101483936,9.21052631578947,36.5789473684211,NA +"6056",10.4471247126008,9.21052631578947,36.5789473684211,NA +"6057",13.5996552137305,9.21052631578947,36.5789473684211,NA +"6058",17.7034951740616,9.21052631578947,36.5789473684211,NA +"6059",23.045712295823,9.21052631578947,36.5789473684211,NA +"6060",30,9.21052631578947,36.5789473684211,NA +"6061",0.2,11.3157894736842,36.5789473684211,NA +"6062",0.260352117694686,11.3157894736842,36.5789473684211,NA +"6063",0.338916125940539,11.3157894736842,36.5789473684211,NA +"6064",0.441187655547492,11.3157894736842,36.5789473684211,NA +"6065",0.574320702112717,11.3157894736842,36.5789473684211,NA +"6066",0.747628055154725,11.3157894736842,36.5789473684211,NA +"6067",0.973232737037462,11.3157894736842,36.5789473684211,NA +"6068",1.2669160204875,11.3157894736842,36.5789473684211,NA +"6069",1.64922134437622,11.3157894736842,36.5789473684211,NA +"6070",2.14689134777813,11.3157894736842,36.5789473684211,NA +"6071",2.79473854427218,11.3157894736842,36.5789473684211,NA +"6072",3.63808049202114,11.3157894736842,36.5789473684211,NA +"6073",4.73590980220715,11.3157894736842,36.5789473684211,NA +"6074",6.16502073107827,11.3157894736842,36.5789473684211,NA +"6075",8.02538101483936,11.3157894736842,36.5789473684211,NA +"6076",10.4471247126008,11.3157894736842,36.5789473684211,NA +"6077",13.5996552137305,11.3157894736842,36.5789473684211,NA +"6078",17.7034951740616,11.3157894736842,36.5789473684211,NA +"6079",23.045712295823,11.3157894736842,36.5789473684211,NA +"6080",30,11.3157894736842,36.5789473684211,NA +"6081",0.2,13.4210526315789,36.5789473684211,NA +"6082",0.260352117694686,13.4210526315789,36.5789473684211,NA +"6083",0.338916125940539,13.4210526315789,36.5789473684211,NA +"6084",0.441187655547492,13.4210526315789,36.5789473684211,NA +"6085",0.574320702112717,13.4210526315789,36.5789473684211,NA +"6086",0.747628055154725,13.4210526315789,36.5789473684211,NA +"6087",0.973232737037462,13.4210526315789,36.5789473684211,NA +"6088",1.2669160204875,13.4210526315789,36.5789473684211,NA +"6089",1.64922134437622,13.4210526315789,36.5789473684211,NA +"6090",2.14689134777813,13.4210526315789,36.5789473684211,NA +"6091",2.79473854427218,13.4210526315789,36.5789473684211,NA +"6092",3.63808049202114,13.4210526315789,36.5789473684211,NA +"6093",4.73590980220715,13.4210526315789,36.5789473684211,NA +"6094",6.16502073107827,13.4210526315789,36.5789473684211,NA +"6095",8.02538101483936,13.4210526315789,36.5789473684211,NA +"6096",10.4471247126008,13.4210526315789,36.5789473684211,NA +"6097",13.5996552137305,13.4210526315789,36.5789473684211,NA +"6098",17.7034951740616,13.4210526315789,36.5789473684211,NA +"6099",23.045712295823,13.4210526315789,36.5789473684211,NA +"6100",30,13.4210526315789,36.5789473684211,NA +"6101",0.2,15.5263157894737,36.5789473684211,NA +"6102",0.260352117694686,15.5263157894737,36.5789473684211,NA +"6103",0.338916125940539,15.5263157894737,36.5789473684211,NA +"6104",0.441187655547492,15.5263157894737,36.5789473684211,NA +"6105",0.574320702112717,15.5263157894737,36.5789473684211,NA +"6106",0.747628055154725,15.5263157894737,36.5789473684211,NA +"6107",0.973232737037462,15.5263157894737,36.5789473684211,NA +"6108",1.2669160204875,15.5263157894737,36.5789473684211,NA +"6109",1.64922134437622,15.5263157894737,36.5789473684211,NA +"6110",2.14689134777813,15.5263157894737,36.5789473684211,NA +"6111",2.79473854427218,15.5263157894737,36.5789473684211,NA +"6112",3.63808049202114,15.5263157894737,36.5789473684211,NA +"6113",4.73590980220715,15.5263157894737,36.5789473684211,NA +"6114",6.16502073107827,15.5263157894737,36.5789473684211,NA +"6115",8.02538101483936,15.5263157894737,36.5789473684211,NA +"6116",10.4471247126008,15.5263157894737,36.5789473684211,NA +"6117",13.5996552137305,15.5263157894737,36.5789473684211,NA +"6118",17.7034951740616,15.5263157894737,36.5789473684211,NA +"6119",23.045712295823,15.5263157894737,36.5789473684211,NA +"6120",30,15.5263157894737,36.5789473684211,NA +"6121",0.2,17.6315789473684,36.5789473684211,NA +"6122",0.260352117694686,17.6315789473684,36.5789473684211,NA +"6123",0.338916125940539,17.6315789473684,36.5789473684211,NA +"6124",0.441187655547492,17.6315789473684,36.5789473684211,NA +"6125",0.574320702112717,17.6315789473684,36.5789473684211,NA +"6126",0.747628055154725,17.6315789473684,36.5789473684211,NA +"6127",0.973232737037462,17.6315789473684,36.5789473684211,NA +"6128",1.2669160204875,17.6315789473684,36.5789473684211,NA +"6129",1.64922134437622,17.6315789473684,36.5789473684211,NA +"6130",2.14689134777813,17.6315789473684,36.5789473684211,NA +"6131",2.79473854427218,17.6315789473684,36.5789473684211,NA +"6132",3.63808049202114,17.6315789473684,36.5789473684211,NA +"6133",4.73590980220715,17.6315789473684,36.5789473684211,NA +"6134",6.16502073107827,17.6315789473684,36.5789473684211,NA +"6135",8.02538101483936,17.6315789473684,36.5789473684211,NA +"6136",10.4471247126008,17.6315789473684,36.5789473684211,NA +"6137",13.5996552137305,17.6315789473684,36.5789473684211,NA +"6138",17.7034951740616,17.6315789473684,36.5789473684211,NA +"6139",23.045712295823,17.6315789473684,36.5789473684211,NA +"6140",30,17.6315789473684,36.5789473684211,NA +"6141",0.2,19.7368421052632,36.5789473684211,NA +"6142",0.260352117694686,19.7368421052632,36.5789473684211,NA +"6143",0.338916125940539,19.7368421052632,36.5789473684211,NA +"6144",0.441187655547492,19.7368421052632,36.5789473684211,NA +"6145",0.574320702112717,19.7368421052632,36.5789473684211,NA +"6146",0.747628055154725,19.7368421052632,36.5789473684211,NA +"6147",0.973232737037462,19.7368421052632,36.5789473684211,NA +"6148",1.2669160204875,19.7368421052632,36.5789473684211,NA +"6149",1.64922134437622,19.7368421052632,36.5789473684211,NA +"6150",2.14689134777813,19.7368421052632,36.5789473684211,NA +"6151",2.79473854427218,19.7368421052632,36.5789473684211,NA +"6152",3.63808049202114,19.7368421052632,36.5789473684211,NA +"6153",4.73590980220715,19.7368421052632,36.5789473684211,NA +"6154",6.16502073107827,19.7368421052632,36.5789473684211,NA +"6155",8.02538101483936,19.7368421052632,36.5789473684211,NA +"6156",10.4471247126008,19.7368421052632,36.5789473684211,NA +"6157",13.5996552137305,19.7368421052632,36.5789473684211,NA +"6158",17.7034951740616,19.7368421052632,36.5789473684211,NA +"6159",23.045712295823,19.7368421052632,36.5789473684211,NA +"6160",30,19.7368421052632,36.5789473684211,NA +"6161",0.2,21.8421052631579,36.5789473684211,NA +"6162",0.260352117694686,21.8421052631579,36.5789473684211,NA +"6163",0.338916125940539,21.8421052631579,36.5789473684211,NA +"6164",0.441187655547492,21.8421052631579,36.5789473684211,NA +"6165",0.574320702112717,21.8421052631579,36.5789473684211,NA +"6166",0.747628055154725,21.8421052631579,36.5789473684211,NA +"6167",0.973232737037462,21.8421052631579,36.5789473684211,NA +"6168",1.2669160204875,21.8421052631579,36.5789473684211,NA +"6169",1.64922134437622,21.8421052631579,36.5789473684211,NA +"6170",2.14689134777813,21.8421052631579,36.5789473684211,NA +"6171",2.79473854427218,21.8421052631579,36.5789473684211,NA +"6172",3.63808049202114,21.8421052631579,36.5789473684211,NA +"6173",4.73590980220715,21.8421052631579,36.5789473684211,NA +"6174",6.16502073107827,21.8421052631579,36.5789473684211,NA +"6175",8.02538101483936,21.8421052631579,36.5789473684211,NA +"6176",10.4471247126008,21.8421052631579,36.5789473684211,NA +"6177",13.5996552137305,21.8421052631579,36.5789473684211,NA +"6178",17.7034951740616,21.8421052631579,36.5789473684211,NA +"6179",23.045712295823,21.8421052631579,36.5789473684211,NA +"6180",30,21.8421052631579,36.5789473684211,NA +"6181",0.2,23.9473684210526,36.5789473684211,NA +"6182",0.260352117694686,23.9473684210526,36.5789473684211,NA +"6183",0.338916125940539,23.9473684210526,36.5789473684211,NA +"6184",0.441187655547492,23.9473684210526,36.5789473684211,NA +"6185",0.574320702112717,23.9473684210526,36.5789473684211,NA +"6186",0.747628055154725,23.9473684210526,36.5789473684211,NA +"6187",0.973232737037462,23.9473684210526,36.5789473684211,NA +"6188",1.2669160204875,23.9473684210526,36.5789473684211,NA +"6189",1.64922134437622,23.9473684210526,36.5789473684211,NA +"6190",2.14689134777813,23.9473684210526,36.5789473684211,NA +"6191",2.79473854427218,23.9473684210526,36.5789473684211,NA +"6192",3.63808049202114,23.9473684210526,36.5789473684211,NA +"6193",4.73590980220715,23.9473684210526,36.5789473684211,NA +"6194",6.16502073107827,23.9473684210526,36.5789473684211,NA +"6195",8.02538101483936,23.9473684210526,36.5789473684211,NA +"6196",10.4471247126008,23.9473684210526,36.5789473684211,NA +"6197",13.5996552137305,23.9473684210526,36.5789473684211,NA +"6198",17.7034951740616,23.9473684210526,36.5789473684211,NA +"6199",23.045712295823,23.9473684210526,36.5789473684211,NA +"6200",30,23.9473684210526,36.5789473684211,NA +"6201",0.2,26.0526315789474,36.5789473684211,NA +"6202",0.260352117694686,26.0526315789474,36.5789473684211,NA +"6203",0.338916125940539,26.0526315789474,36.5789473684211,NA +"6204",0.441187655547492,26.0526315789474,36.5789473684211,NA +"6205",0.574320702112717,26.0526315789474,36.5789473684211,NA +"6206",0.747628055154725,26.0526315789474,36.5789473684211,NA +"6207",0.973232737037462,26.0526315789474,36.5789473684211,NA +"6208",1.2669160204875,26.0526315789474,36.5789473684211,NA +"6209",1.64922134437622,26.0526315789474,36.5789473684211,NA +"6210",2.14689134777813,26.0526315789474,36.5789473684211,NA +"6211",2.79473854427218,26.0526315789474,36.5789473684211,NA +"6212",3.63808049202114,26.0526315789474,36.5789473684211,NA +"6213",4.73590980220715,26.0526315789474,36.5789473684211,NA +"6214",6.16502073107827,26.0526315789474,36.5789473684211,NA +"6215",8.02538101483936,26.0526315789474,36.5789473684211,NA +"6216",10.4471247126008,26.0526315789474,36.5789473684211,NA +"6217",13.5996552137305,26.0526315789474,36.5789473684211,NA +"6218",17.7034951740616,26.0526315789474,36.5789473684211,NA +"6219",23.045712295823,26.0526315789474,36.5789473684211,NA +"6220",30,26.0526315789474,36.5789473684211,NA +"6221",0.2,28.1578947368421,36.5789473684211,NA +"6222",0.260352117694686,28.1578947368421,36.5789473684211,NA +"6223",0.338916125940539,28.1578947368421,36.5789473684211,NA +"6224",0.441187655547492,28.1578947368421,36.5789473684211,NA +"6225",0.574320702112717,28.1578947368421,36.5789473684211,NA +"6226",0.747628055154725,28.1578947368421,36.5789473684211,NA +"6227",0.973232737037462,28.1578947368421,36.5789473684211,NA +"6228",1.2669160204875,28.1578947368421,36.5789473684211,NA +"6229",1.64922134437622,28.1578947368421,36.5789473684211,NA +"6230",2.14689134777813,28.1578947368421,36.5789473684211,NA +"6231",2.79473854427218,28.1578947368421,36.5789473684211,NA +"6232",3.63808049202114,28.1578947368421,36.5789473684211,NA +"6233",4.73590980220715,28.1578947368421,36.5789473684211,NA +"6234",6.16502073107827,28.1578947368421,36.5789473684211,NA +"6235",8.02538101483936,28.1578947368421,36.5789473684211,NA +"6236",10.4471247126008,28.1578947368421,36.5789473684211,NA +"6237",13.5996552137305,28.1578947368421,36.5789473684211,NA +"6238",17.7034951740616,28.1578947368421,36.5789473684211,NA +"6239",23.045712295823,28.1578947368421,36.5789473684211,NA +"6240",30,28.1578947368421,36.5789473684211,NA +"6241",0.2,30.2631578947368,36.5789473684211,NA +"6242",0.260352117694686,30.2631578947368,36.5789473684211,NA +"6243",0.338916125940539,30.2631578947368,36.5789473684211,NA +"6244",0.441187655547492,30.2631578947368,36.5789473684211,NA +"6245",0.574320702112717,30.2631578947368,36.5789473684211,NA +"6246",0.747628055154725,30.2631578947368,36.5789473684211,NA +"6247",0.973232737037462,30.2631578947368,36.5789473684211,NA +"6248",1.2669160204875,30.2631578947368,36.5789473684211,NA +"6249",1.64922134437622,30.2631578947368,36.5789473684211,NA +"6250",2.14689134777813,30.2631578947368,36.5789473684211,NA +"6251",2.79473854427218,30.2631578947368,36.5789473684211,NA +"6252",3.63808049202114,30.2631578947368,36.5789473684211,NA +"6253",4.73590980220715,30.2631578947368,36.5789473684211,NA +"6254",6.16502073107827,30.2631578947368,36.5789473684211,NA +"6255",8.02538101483936,30.2631578947368,36.5789473684211,NA +"6256",10.4471247126008,30.2631578947368,36.5789473684211,NA +"6257",13.5996552137305,30.2631578947368,36.5789473684211,NA +"6258",17.7034951740616,30.2631578947368,36.5789473684211,NA +"6259",23.045712295823,30.2631578947368,36.5789473684211,NA +"6260",30,30.2631578947368,36.5789473684211,NA +"6261",0.2,32.3684210526316,36.5789473684211,NA +"6262",0.260352117694686,32.3684210526316,36.5789473684211,NA +"6263",0.338916125940539,32.3684210526316,36.5789473684211,NA +"6264",0.441187655547492,32.3684210526316,36.5789473684211,NA +"6265",0.574320702112717,32.3684210526316,36.5789473684211,NA +"6266",0.747628055154725,32.3684210526316,36.5789473684211,NA +"6267",0.973232737037462,32.3684210526316,36.5789473684211,NA +"6268",1.2669160204875,32.3684210526316,36.5789473684211,NA +"6269",1.64922134437622,32.3684210526316,36.5789473684211,NA +"6270",2.14689134777813,32.3684210526316,36.5789473684211,NA +"6271",2.79473854427218,32.3684210526316,36.5789473684211,NA +"6272",3.63808049202114,32.3684210526316,36.5789473684211,NA +"6273",4.73590980220715,32.3684210526316,36.5789473684211,NA +"6274",6.16502073107827,32.3684210526316,36.5789473684211,NA +"6275",8.02538101483936,32.3684210526316,36.5789473684211,NA +"6276",10.4471247126008,32.3684210526316,36.5789473684211,NA +"6277",13.5996552137305,32.3684210526316,36.5789473684211,NA +"6278",17.7034951740616,32.3684210526316,36.5789473684211,NA +"6279",23.045712295823,32.3684210526316,36.5789473684211,NA +"6280",30,32.3684210526316,36.5789473684211,NA +"6281",0.2,34.4736842105263,36.5789473684211,NA +"6282",0.260352117694686,34.4736842105263,36.5789473684211,NA +"6283",0.338916125940539,34.4736842105263,36.5789473684211,NA +"6284",0.441187655547492,34.4736842105263,36.5789473684211,NA +"6285",0.574320702112717,34.4736842105263,36.5789473684211,NA +"6286",0.747628055154725,34.4736842105263,36.5789473684211,NA +"6287",0.973232737037462,34.4736842105263,36.5789473684211,NA +"6288",1.2669160204875,34.4736842105263,36.5789473684211,NA +"6289",1.64922134437622,34.4736842105263,36.5789473684211,NA +"6290",2.14689134777813,34.4736842105263,36.5789473684211,NA +"6291",2.79473854427218,34.4736842105263,36.5789473684211,NA +"6292",3.63808049202114,34.4736842105263,36.5789473684211,NA +"6293",4.73590980220715,34.4736842105263,36.5789473684211,NA +"6294",6.16502073107827,34.4736842105263,36.5789473684211,NA +"6295",8.02538101483936,34.4736842105263,36.5789473684211,NA +"6296",10.4471247126008,34.4736842105263,36.5789473684211,NA +"6297",13.5996552137305,34.4736842105263,36.5789473684211,NA +"6298",17.7034951740616,34.4736842105263,36.5789473684211,NA +"6299",23.045712295823,34.4736842105263,36.5789473684211,NA +"6300",30,34.4736842105263,36.5789473684211,NA +"6301",0.2,36.5789473684211,36.5789473684211,NA +"6302",0.260352117694686,36.5789473684211,36.5789473684211,NA +"6303",0.338916125940539,36.5789473684211,36.5789473684211,NA +"6304",0.441187655547492,36.5789473684211,36.5789473684211,NA +"6305",0.574320702112717,36.5789473684211,36.5789473684211,NA +"6306",0.747628055154725,36.5789473684211,36.5789473684211,NA +"6307",0.973232737037462,36.5789473684211,36.5789473684211,NA +"6308",1.2669160204875,36.5789473684211,36.5789473684211,NA +"6309",1.64922134437622,36.5789473684211,36.5789473684211,NA +"6310",2.14689134777813,36.5789473684211,36.5789473684211,NA +"6311",2.79473854427218,36.5789473684211,36.5789473684211,NA +"6312",3.63808049202114,36.5789473684211,36.5789473684211,NA +"6313",4.73590980220715,36.5789473684211,36.5789473684211,NA +"6314",6.16502073107827,36.5789473684211,36.5789473684211,NA +"6315",8.02538101483936,36.5789473684211,36.5789473684211,NA +"6316",10.4471247126008,36.5789473684211,36.5789473684211,NA +"6317",13.5996552137305,36.5789473684211,36.5789473684211,NA +"6318",17.7034951740616,36.5789473684211,36.5789473684211,NA +"6319",23.045712295823,36.5789473684211,36.5789473684211,NA +"6320",30,36.5789473684211,36.5789473684211,NA +"6321",0.2,38.6842105263158,36.5789473684211,NA +"6322",0.260352117694686,38.6842105263158,36.5789473684211,NA +"6323",0.338916125940539,38.6842105263158,36.5789473684211,NA +"6324",0.441187655547492,38.6842105263158,36.5789473684211,NA +"6325",0.574320702112717,38.6842105263158,36.5789473684211,NA +"6326",0.747628055154725,38.6842105263158,36.5789473684211,NA +"6327",0.973232737037462,38.6842105263158,36.5789473684211,NA +"6328",1.2669160204875,38.6842105263158,36.5789473684211,NA +"6329",1.64922134437622,38.6842105263158,36.5789473684211,NA +"6330",2.14689134777813,38.6842105263158,36.5789473684211,NA +"6331",2.79473854427218,38.6842105263158,36.5789473684211,NA +"6332",3.63808049202114,38.6842105263158,36.5789473684211,NA +"6333",4.73590980220715,38.6842105263158,36.5789473684211,NA +"6334",6.16502073107827,38.6842105263158,36.5789473684211,NA +"6335",8.02538101483936,38.6842105263158,36.5789473684211,NA +"6336",10.4471247126008,38.6842105263158,36.5789473684211,NA +"6337",13.5996552137305,38.6842105263158,36.5789473684211,NA +"6338",17.7034951740616,38.6842105263158,36.5789473684211,NA +"6339",23.045712295823,38.6842105263158,36.5789473684211,NA +"6340",30,38.6842105263158,36.5789473684211,NA +"6341",0.2,40.7894736842105,36.5789473684211,NA +"6342",0.260352117694686,40.7894736842105,36.5789473684211,NA +"6343",0.338916125940539,40.7894736842105,36.5789473684211,NA +"6344",0.441187655547492,40.7894736842105,36.5789473684211,NA +"6345",0.574320702112717,40.7894736842105,36.5789473684211,NA +"6346",0.747628055154725,40.7894736842105,36.5789473684211,NA +"6347",0.973232737037462,40.7894736842105,36.5789473684211,NA +"6348",1.2669160204875,40.7894736842105,36.5789473684211,NA +"6349",1.64922134437622,40.7894736842105,36.5789473684211,NA +"6350",2.14689134777813,40.7894736842105,36.5789473684211,NA +"6351",2.79473854427218,40.7894736842105,36.5789473684211,NA +"6352",3.63808049202114,40.7894736842105,36.5789473684211,NA +"6353",4.73590980220715,40.7894736842105,36.5789473684211,NA +"6354",6.16502073107827,40.7894736842105,36.5789473684211,NA +"6355",8.02538101483936,40.7894736842105,36.5789473684211,NA +"6356",10.4471247126008,40.7894736842105,36.5789473684211,NA +"6357",13.5996552137305,40.7894736842105,36.5789473684211,NA +"6358",17.7034951740616,40.7894736842105,36.5789473684211,NA +"6359",23.045712295823,40.7894736842105,36.5789473684211,NA +"6360",30,40.7894736842105,36.5789473684211,NA +"6361",0.2,42.8947368421053,36.5789473684211,NA +"6362",0.260352117694686,42.8947368421053,36.5789473684211,NA +"6363",0.338916125940539,42.8947368421053,36.5789473684211,NA +"6364",0.441187655547492,42.8947368421053,36.5789473684211,NA +"6365",0.574320702112717,42.8947368421053,36.5789473684211,NA +"6366",0.747628055154725,42.8947368421053,36.5789473684211,NA +"6367",0.973232737037462,42.8947368421053,36.5789473684211,NA +"6368",1.2669160204875,42.8947368421053,36.5789473684211,NA +"6369",1.64922134437622,42.8947368421053,36.5789473684211,NA +"6370",2.14689134777813,42.8947368421053,36.5789473684211,NA +"6371",2.79473854427218,42.8947368421053,36.5789473684211,NA +"6372",3.63808049202114,42.8947368421053,36.5789473684211,NA +"6373",4.73590980220715,42.8947368421053,36.5789473684211,NA +"6374",6.16502073107827,42.8947368421053,36.5789473684211,NA +"6375",8.02538101483936,42.8947368421053,36.5789473684211,NA +"6376",10.4471247126008,42.8947368421053,36.5789473684211,NA +"6377",13.5996552137305,42.8947368421053,36.5789473684211,NA +"6378",17.7034951740616,42.8947368421053,36.5789473684211,NA +"6379",23.045712295823,42.8947368421053,36.5789473684211,NA +"6380",30,42.8947368421053,36.5789473684211,NA +"6381",0.2,45,36.5789473684211,NA +"6382",0.260352117694686,45,36.5789473684211,NA +"6383",0.338916125940539,45,36.5789473684211,NA +"6384",0.441187655547492,45,36.5789473684211,NA +"6385",0.574320702112717,45,36.5789473684211,NA +"6386",0.747628055154725,45,36.5789473684211,NA +"6387",0.973232737037462,45,36.5789473684211,NA +"6388",1.2669160204875,45,36.5789473684211,NA +"6389",1.64922134437622,45,36.5789473684211,NA +"6390",2.14689134777813,45,36.5789473684211,NA +"6391",2.79473854427218,45,36.5789473684211,NA +"6392",3.63808049202114,45,36.5789473684211,NA +"6393",4.73590980220715,45,36.5789473684211,NA +"6394",6.16502073107827,45,36.5789473684211,NA +"6395",8.02538101483936,45,36.5789473684211,NA +"6396",10.4471247126008,45,36.5789473684211,NA +"6397",13.5996552137305,45,36.5789473684211,NA +"6398",17.7034951740616,45,36.5789473684211,NA +"6399",23.045712295823,45,36.5789473684211,NA +"6400",30,45,36.5789473684211,NA +"6401",0.2,5,38.6842105263158,NA +"6402",0.260352117694686,5,38.6842105263158,NA +"6403",0.338916125940539,5,38.6842105263158,NA +"6404",0.441187655547492,5,38.6842105263158,NA +"6405",0.574320702112717,5,38.6842105263158,NA +"6406",0.747628055154725,5,38.6842105263158,NA +"6407",0.973232737037462,5,38.6842105263158,NA +"6408",1.2669160204875,5,38.6842105263158,NA +"6409",1.64922134437622,5,38.6842105263158,NA +"6410",2.14689134777813,5,38.6842105263158,NA +"6411",2.79473854427218,5,38.6842105263158,NA +"6412",3.63808049202114,5,38.6842105263158,NA +"6413",4.73590980220715,5,38.6842105263158,NA +"6414",6.16502073107827,5,38.6842105263158,NA +"6415",8.02538101483936,5,38.6842105263158,NA +"6416",10.4471247126008,5,38.6842105263158,NA +"6417",13.5996552137305,5,38.6842105263158,NA +"6418",17.7034951740616,5,38.6842105263158,NA +"6419",23.045712295823,5,38.6842105263158,NA +"6420",30,5,38.6842105263158,NA +"6421",0.2,7.10526315789474,38.6842105263158,NA +"6422",0.260352117694686,7.10526315789474,38.6842105263158,NA +"6423",0.338916125940539,7.10526315789474,38.6842105263158,NA +"6424",0.441187655547492,7.10526315789474,38.6842105263158,NA +"6425",0.574320702112717,7.10526315789474,38.6842105263158,NA +"6426",0.747628055154725,7.10526315789474,38.6842105263158,NA +"6427",0.973232737037462,7.10526315789474,38.6842105263158,NA +"6428",1.2669160204875,7.10526315789474,38.6842105263158,NA +"6429",1.64922134437622,7.10526315789474,38.6842105263158,NA +"6430",2.14689134777813,7.10526315789474,38.6842105263158,NA +"6431",2.79473854427218,7.10526315789474,38.6842105263158,NA +"6432",3.63808049202114,7.10526315789474,38.6842105263158,NA +"6433",4.73590980220715,7.10526315789474,38.6842105263158,NA +"6434",6.16502073107827,7.10526315789474,38.6842105263158,NA +"6435",8.02538101483936,7.10526315789474,38.6842105263158,NA +"6436",10.4471247126008,7.10526315789474,38.6842105263158,NA +"6437",13.5996552137305,7.10526315789474,38.6842105263158,NA +"6438",17.7034951740616,7.10526315789474,38.6842105263158,NA +"6439",23.045712295823,7.10526315789474,38.6842105263158,NA +"6440",30,7.10526315789474,38.6842105263158,NA +"6441",0.2,9.21052631578947,38.6842105263158,NA +"6442",0.260352117694686,9.21052631578947,38.6842105263158,NA +"6443",0.338916125940539,9.21052631578947,38.6842105263158,NA +"6444",0.441187655547492,9.21052631578947,38.6842105263158,NA +"6445",0.574320702112717,9.21052631578947,38.6842105263158,NA +"6446",0.747628055154725,9.21052631578947,38.6842105263158,NA +"6447",0.973232737037462,9.21052631578947,38.6842105263158,NA +"6448",1.2669160204875,9.21052631578947,38.6842105263158,NA +"6449",1.64922134437622,9.21052631578947,38.6842105263158,NA +"6450",2.14689134777813,9.21052631578947,38.6842105263158,NA +"6451",2.79473854427218,9.21052631578947,38.6842105263158,NA +"6452",3.63808049202114,9.21052631578947,38.6842105263158,NA +"6453",4.73590980220715,9.21052631578947,38.6842105263158,NA +"6454",6.16502073107827,9.21052631578947,38.6842105263158,NA +"6455",8.02538101483936,9.21052631578947,38.6842105263158,NA +"6456",10.4471247126008,9.21052631578947,38.6842105263158,NA +"6457",13.5996552137305,9.21052631578947,38.6842105263158,NA +"6458",17.7034951740616,9.21052631578947,38.6842105263158,NA +"6459",23.045712295823,9.21052631578947,38.6842105263158,NA +"6460",30,9.21052631578947,38.6842105263158,NA +"6461",0.2,11.3157894736842,38.6842105263158,NA +"6462",0.260352117694686,11.3157894736842,38.6842105263158,NA +"6463",0.338916125940539,11.3157894736842,38.6842105263158,NA +"6464",0.441187655547492,11.3157894736842,38.6842105263158,NA +"6465",0.574320702112717,11.3157894736842,38.6842105263158,NA +"6466",0.747628055154725,11.3157894736842,38.6842105263158,NA +"6467",0.973232737037462,11.3157894736842,38.6842105263158,NA +"6468",1.2669160204875,11.3157894736842,38.6842105263158,NA +"6469",1.64922134437622,11.3157894736842,38.6842105263158,NA +"6470",2.14689134777813,11.3157894736842,38.6842105263158,NA +"6471",2.79473854427218,11.3157894736842,38.6842105263158,NA +"6472",3.63808049202114,11.3157894736842,38.6842105263158,NA +"6473",4.73590980220715,11.3157894736842,38.6842105263158,NA +"6474",6.16502073107827,11.3157894736842,38.6842105263158,NA +"6475",8.02538101483936,11.3157894736842,38.6842105263158,NA +"6476",10.4471247126008,11.3157894736842,38.6842105263158,NA +"6477",13.5996552137305,11.3157894736842,38.6842105263158,NA +"6478",17.7034951740616,11.3157894736842,38.6842105263158,NA +"6479",23.045712295823,11.3157894736842,38.6842105263158,NA +"6480",30,11.3157894736842,38.6842105263158,NA +"6481",0.2,13.4210526315789,38.6842105263158,NA +"6482",0.260352117694686,13.4210526315789,38.6842105263158,NA +"6483",0.338916125940539,13.4210526315789,38.6842105263158,NA +"6484",0.441187655547492,13.4210526315789,38.6842105263158,NA +"6485",0.574320702112717,13.4210526315789,38.6842105263158,NA +"6486",0.747628055154725,13.4210526315789,38.6842105263158,NA +"6487",0.973232737037462,13.4210526315789,38.6842105263158,NA +"6488",1.2669160204875,13.4210526315789,38.6842105263158,NA +"6489",1.64922134437622,13.4210526315789,38.6842105263158,NA +"6490",2.14689134777813,13.4210526315789,38.6842105263158,NA +"6491",2.79473854427218,13.4210526315789,38.6842105263158,NA +"6492",3.63808049202114,13.4210526315789,38.6842105263158,NA +"6493",4.73590980220715,13.4210526315789,38.6842105263158,NA +"6494",6.16502073107827,13.4210526315789,38.6842105263158,NA +"6495",8.02538101483936,13.4210526315789,38.6842105263158,NA +"6496",10.4471247126008,13.4210526315789,38.6842105263158,NA +"6497",13.5996552137305,13.4210526315789,38.6842105263158,NA +"6498",17.7034951740616,13.4210526315789,38.6842105263158,NA +"6499",23.045712295823,13.4210526315789,38.6842105263158,NA +"6500",30,13.4210526315789,38.6842105263158,NA +"6501",0.2,15.5263157894737,38.6842105263158,NA +"6502",0.260352117694686,15.5263157894737,38.6842105263158,NA +"6503",0.338916125940539,15.5263157894737,38.6842105263158,NA +"6504",0.441187655547492,15.5263157894737,38.6842105263158,NA +"6505",0.574320702112717,15.5263157894737,38.6842105263158,NA +"6506",0.747628055154725,15.5263157894737,38.6842105263158,NA +"6507",0.973232737037462,15.5263157894737,38.6842105263158,NA +"6508",1.2669160204875,15.5263157894737,38.6842105263158,NA +"6509",1.64922134437622,15.5263157894737,38.6842105263158,NA +"6510",2.14689134777813,15.5263157894737,38.6842105263158,NA +"6511",2.79473854427218,15.5263157894737,38.6842105263158,NA +"6512",3.63808049202114,15.5263157894737,38.6842105263158,NA +"6513",4.73590980220715,15.5263157894737,38.6842105263158,NA +"6514",6.16502073107827,15.5263157894737,38.6842105263158,NA +"6515",8.02538101483936,15.5263157894737,38.6842105263158,NA +"6516",10.4471247126008,15.5263157894737,38.6842105263158,NA +"6517",13.5996552137305,15.5263157894737,38.6842105263158,NA +"6518",17.7034951740616,15.5263157894737,38.6842105263158,NA +"6519",23.045712295823,15.5263157894737,38.6842105263158,NA +"6520",30,15.5263157894737,38.6842105263158,NA +"6521",0.2,17.6315789473684,38.6842105263158,NA +"6522",0.260352117694686,17.6315789473684,38.6842105263158,NA +"6523",0.338916125940539,17.6315789473684,38.6842105263158,NA +"6524",0.441187655547492,17.6315789473684,38.6842105263158,NA +"6525",0.574320702112717,17.6315789473684,38.6842105263158,NA +"6526",0.747628055154725,17.6315789473684,38.6842105263158,NA +"6527",0.973232737037462,17.6315789473684,38.6842105263158,NA +"6528",1.2669160204875,17.6315789473684,38.6842105263158,NA +"6529",1.64922134437622,17.6315789473684,38.6842105263158,NA +"6530",2.14689134777813,17.6315789473684,38.6842105263158,NA +"6531",2.79473854427218,17.6315789473684,38.6842105263158,NA +"6532",3.63808049202114,17.6315789473684,38.6842105263158,NA +"6533",4.73590980220715,17.6315789473684,38.6842105263158,NA +"6534",6.16502073107827,17.6315789473684,38.6842105263158,NA +"6535",8.02538101483936,17.6315789473684,38.6842105263158,NA +"6536",10.4471247126008,17.6315789473684,38.6842105263158,NA +"6537",13.5996552137305,17.6315789473684,38.6842105263158,NA +"6538",17.7034951740616,17.6315789473684,38.6842105263158,NA +"6539",23.045712295823,17.6315789473684,38.6842105263158,NA +"6540",30,17.6315789473684,38.6842105263158,NA +"6541",0.2,19.7368421052632,38.6842105263158,NA +"6542",0.260352117694686,19.7368421052632,38.6842105263158,NA +"6543",0.338916125940539,19.7368421052632,38.6842105263158,NA +"6544",0.441187655547492,19.7368421052632,38.6842105263158,NA +"6545",0.574320702112717,19.7368421052632,38.6842105263158,NA +"6546",0.747628055154725,19.7368421052632,38.6842105263158,NA +"6547",0.973232737037462,19.7368421052632,38.6842105263158,NA +"6548",1.2669160204875,19.7368421052632,38.6842105263158,NA +"6549",1.64922134437622,19.7368421052632,38.6842105263158,NA +"6550",2.14689134777813,19.7368421052632,38.6842105263158,NA +"6551",2.79473854427218,19.7368421052632,38.6842105263158,NA +"6552",3.63808049202114,19.7368421052632,38.6842105263158,NA +"6553",4.73590980220715,19.7368421052632,38.6842105263158,NA +"6554",6.16502073107827,19.7368421052632,38.6842105263158,NA +"6555",8.02538101483936,19.7368421052632,38.6842105263158,NA +"6556",10.4471247126008,19.7368421052632,38.6842105263158,NA +"6557",13.5996552137305,19.7368421052632,38.6842105263158,NA +"6558",17.7034951740616,19.7368421052632,38.6842105263158,NA +"6559",23.045712295823,19.7368421052632,38.6842105263158,NA +"6560",30,19.7368421052632,38.6842105263158,NA +"6561",0.2,21.8421052631579,38.6842105263158,NA +"6562",0.260352117694686,21.8421052631579,38.6842105263158,NA +"6563",0.338916125940539,21.8421052631579,38.6842105263158,NA +"6564",0.441187655547492,21.8421052631579,38.6842105263158,NA +"6565",0.574320702112717,21.8421052631579,38.6842105263158,NA +"6566",0.747628055154725,21.8421052631579,38.6842105263158,NA +"6567",0.973232737037462,21.8421052631579,38.6842105263158,NA +"6568",1.2669160204875,21.8421052631579,38.6842105263158,NA +"6569",1.64922134437622,21.8421052631579,38.6842105263158,NA +"6570",2.14689134777813,21.8421052631579,38.6842105263158,NA +"6571",2.79473854427218,21.8421052631579,38.6842105263158,NA +"6572",3.63808049202114,21.8421052631579,38.6842105263158,NA +"6573",4.73590980220715,21.8421052631579,38.6842105263158,NA +"6574",6.16502073107827,21.8421052631579,38.6842105263158,NA +"6575",8.02538101483936,21.8421052631579,38.6842105263158,NA +"6576",10.4471247126008,21.8421052631579,38.6842105263158,NA +"6577",13.5996552137305,21.8421052631579,38.6842105263158,NA +"6578",17.7034951740616,21.8421052631579,38.6842105263158,NA +"6579",23.045712295823,21.8421052631579,38.6842105263158,NA +"6580",30,21.8421052631579,38.6842105263158,NA +"6581",0.2,23.9473684210526,38.6842105263158,NA +"6582",0.260352117694686,23.9473684210526,38.6842105263158,NA +"6583",0.338916125940539,23.9473684210526,38.6842105263158,NA +"6584",0.441187655547492,23.9473684210526,38.6842105263158,NA +"6585",0.574320702112717,23.9473684210526,38.6842105263158,NA +"6586",0.747628055154725,23.9473684210526,38.6842105263158,NA +"6587",0.973232737037462,23.9473684210526,38.6842105263158,NA +"6588",1.2669160204875,23.9473684210526,38.6842105263158,NA +"6589",1.64922134437622,23.9473684210526,38.6842105263158,NA +"6590",2.14689134777813,23.9473684210526,38.6842105263158,NA +"6591",2.79473854427218,23.9473684210526,38.6842105263158,NA +"6592",3.63808049202114,23.9473684210526,38.6842105263158,NA +"6593",4.73590980220715,23.9473684210526,38.6842105263158,NA +"6594",6.16502073107827,23.9473684210526,38.6842105263158,NA +"6595",8.02538101483936,23.9473684210526,38.6842105263158,NA +"6596",10.4471247126008,23.9473684210526,38.6842105263158,NA +"6597",13.5996552137305,23.9473684210526,38.6842105263158,NA +"6598",17.7034951740616,23.9473684210526,38.6842105263158,NA +"6599",23.045712295823,23.9473684210526,38.6842105263158,NA +"6600",30,23.9473684210526,38.6842105263158,NA +"6601",0.2,26.0526315789474,38.6842105263158,NA +"6602",0.260352117694686,26.0526315789474,38.6842105263158,NA +"6603",0.338916125940539,26.0526315789474,38.6842105263158,NA +"6604",0.441187655547492,26.0526315789474,38.6842105263158,NA +"6605",0.574320702112717,26.0526315789474,38.6842105263158,NA +"6606",0.747628055154725,26.0526315789474,38.6842105263158,NA +"6607",0.973232737037462,26.0526315789474,38.6842105263158,NA +"6608",1.2669160204875,26.0526315789474,38.6842105263158,NA +"6609",1.64922134437622,26.0526315789474,38.6842105263158,NA +"6610",2.14689134777813,26.0526315789474,38.6842105263158,NA +"6611",2.79473854427218,26.0526315789474,38.6842105263158,NA +"6612",3.63808049202114,26.0526315789474,38.6842105263158,NA +"6613",4.73590980220715,26.0526315789474,38.6842105263158,NA +"6614",6.16502073107827,26.0526315789474,38.6842105263158,NA +"6615",8.02538101483936,26.0526315789474,38.6842105263158,NA +"6616",10.4471247126008,26.0526315789474,38.6842105263158,NA +"6617",13.5996552137305,26.0526315789474,38.6842105263158,NA +"6618",17.7034951740616,26.0526315789474,38.6842105263158,NA +"6619",23.045712295823,26.0526315789474,38.6842105263158,NA +"6620",30,26.0526315789474,38.6842105263158,NA +"6621",0.2,28.1578947368421,38.6842105263158,NA +"6622",0.260352117694686,28.1578947368421,38.6842105263158,NA +"6623",0.338916125940539,28.1578947368421,38.6842105263158,NA +"6624",0.441187655547492,28.1578947368421,38.6842105263158,NA +"6625",0.574320702112717,28.1578947368421,38.6842105263158,NA +"6626",0.747628055154725,28.1578947368421,38.6842105263158,NA +"6627",0.973232737037462,28.1578947368421,38.6842105263158,NA +"6628",1.2669160204875,28.1578947368421,38.6842105263158,NA +"6629",1.64922134437622,28.1578947368421,38.6842105263158,NA +"6630",2.14689134777813,28.1578947368421,38.6842105263158,NA +"6631",2.79473854427218,28.1578947368421,38.6842105263158,NA +"6632",3.63808049202114,28.1578947368421,38.6842105263158,NA +"6633",4.73590980220715,28.1578947368421,38.6842105263158,NA +"6634",6.16502073107827,28.1578947368421,38.6842105263158,NA +"6635",8.02538101483936,28.1578947368421,38.6842105263158,NA +"6636",10.4471247126008,28.1578947368421,38.6842105263158,NA +"6637",13.5996552137305,28.1578947368421,38.6842105263158,NA +"6638",17.7034951740616,28.1578947368421,38.6842105263158,NA +"6639",23.045712295823,28.1578947368421,38.6842105263158,NA +"6640",30,28.1578947368421,38.6842105263158,NA +"6641",0.2,30.2631578947368,38.6842105263158,NA +"6642",0.260352117694686,30.2631578947368,38.6842105263158,NA +"6643",0.338916125940539,30.2631578947368,38.6842105263158,NA +"6644",0.441187655547492,30.2631578947368,38.6842105263158,NA +"6645",0.574320702112717,30.2631578947368,38.6842105263158,NA +"6646",0.747628055154725,30.2631578947368,38.6842105263158,NA +"6647",0.973232737037462,30.2631578947368,38.6842105263158,NA +"6648",1.2669160204875,30.2631578947368,38.6842105263158,NA +"6649",1.64922134437622,30.2631578947368,38.6842105263158,NA +"6650",2.14689134777813,30.2631578947368,38.6842105263158,NA +"6651",2.79473854427218,30.2631578947368,38.6842105263158,NA +"6652",3.63808049202114,30.2631578947368,38.6842105263158,NA +"6653",4.73590980220715,30.2631578947368,38.6842105263158,NA +"6654",6.16502073107827,30.2631578947368,38.6842105263158,NA +"6655",8.02538101483936,30.2631578947368,38.6842105263158,NA +"6656",10.4471247126008,30.2631578947368,38.6842105263158,NA +"6657",13.5996552137305,30.2631578947368,38.6842105263158,NA +"6658",17.7034951740616,30.2631578947368,38.6842105263158,NA +"6659",23.045712295823,30.2631578947368,38.6842105263158,NA +"6660",30,30.2631578947368,38.6842105263158,NA +"6661",0.2,32.3684210526316,38.6842105263158,NA +"6662",0.260352117694686,32.3684210526316,38.6842105263158,NA +"6663",0.338916125940539,32.3684210526316,38.6842105263158,NA +"6664",0.441187655547492,32.3684210526316,38.6842105263158,NA +"6665",0.574320702112717,32.3684210526316,38.6842105263158,NA +"6666",0.747628055154725,32.3684210526316,38.6842105263158,NA +"6667",0.973232737037462,32.3684210526316,38.6842105263158,NA +"6668",1.2669160204875,32.3684210526316,38.6842105263158,NA +"6669",1.64922134437622,32.3684210526316,38.6842105263158,NA +"6670",2.14689134777813,32.3684210526316,38.6842105263158,NA +"6671",2.79473854427218,32.3684210526316,38.6842105263158,NA +"6672",3.63808049202114,32.3684210526316,38.6842105263158,NA +"6673",4.73590980220715,32.3684210526316,38.6842105263158,NA +"6674",6.16502073107827,32.3684210526316,38.6842105263158,NA +"6675",8.02538101483936,32.3684210526316,38.6842105263158,NA +"6676",10.4471247126008,32.3684210526316,38.6842105263158,NA +"6677",13.5996552137305,32.3684210526316,38.6842105263158,NA +"6678",17.7034951740616,32.3684210526316,38.6842105263158,NA +"6679",23.045712295823,32.3684210526316,38.6842105263158,NA +"6680",30,32.3684210526316,38.6842105263158,NA +"6681",0.2,34.4736842105263,38.6842105263158,NA +"6682",0.260352117694686,34.4736842105263,38.6842105263158,NA +"6683",0.338916125940539,34.4736842105263,38.6842105263158,NA +"6684",0.441187655547492,34.4736842105263,38.6842105263158,NA +"6685",0.574320702112717,34.4736842105263,38.6842105263158,NA +"6686",0.747628055154725,34.4736842105263,38.6842105263158,NA +"6687",0.973232737037462,34.4736842105263,38.6842105263158,NA +"6688",1.2669160204875,34.4736842105263,38.6842105263158,NA +"6689",1.64922134437622,34.4736842105263,38.6842105263158,NA +"6690",2.14689134777813,34.4736842105263,38.6842105263158,NA +"6691",2.79473854427218,34.4736842105263,38.6842105263158,NA +"6692",3.63808049202114,34.4736842105263,38.6842105263158,NA +"6693",4.73590980220715,34.4736842105263,38.6842105263158,NA +"6694",6.16502073107827,34.4736842105263,38.6842105263158,NA +"6695",8.02538101483936,34.4736842105263,38.6842105263158,NA +"6696",10.4471247126008,34.4736842105263,38.6842105263158,NA +"6697",13.5996552137305,34.4736842105263,38.6842105263158,NA +"6698",17.7034951740616,34.4736842105263,38.6842105263158,NA +"6699",23.045712295823,34.4736842105263,38.6842105263158,NA +"6700",30,34.4736842105263,38.6842105263158,NA +"6701",0.2,36.5789473684211,38.6842105263158,NA +"6702",0.260352117694686,36.5789473684211,38.6842105263158,NA +"6703",0.338916125940539,36.5789473684211,38.6842105263158,NA +"6704",0.441187655547492,36.5789473684211,38.6842105263158,NA +"6705",0.574320702112717,36.5789473684211,38.6842105263158,NA +"6706",0.747628055154725,36.5789473684211,38.6842105263158,NA +"6707",0.973232737037462,36.5789473684211,38.6842105263158,NA +"6708",1.2669160204875,36.5789473684211,38.6842105263158,NA +"6709",1.64922134437622,36.5789473684211,38.6842105263158,NA +"6710",2.14689134777813,36.5789473684211,38.6842105263158,NA +"6711",2.79473854427218,36.5789473684211,38.6842105263158,NA +"6712",3.63808049202114,36.5789473684211,38.6842105263158,NA +"6713",4.73590980220715,36.5789473684211,38.6842105263158,NA +"6714",6.16502073107827,36.5789473684211,38.6842105263158,NA +"6715",8.02538101483936,36.5789473684211,38.6842105263158,NA +"6716",10.4471247126008,36.5789473684211,38.6842105263158,NA +"6717",13.5996552137305,36.5789473684211,38.6842105263158,NA +"6718",17.7034951740616,36.5789473684211,38.6842105263158,NA +"6719",23.045712295823,36.5789473684211,38.6842105263158,NA +"6720",30,36.5789473684211,38.6842105263158,NA +"6721",0.2,38.6842105263158,38.6842105263158,NA +"6722",0.260352117694686,38.6842105263158,38.6842105263158,NA +"6723",0.338916125940539,38.6842105263158,38.6842105263158,NA +"6724",0.441187655547492,38.6842105263158,38.6842105263158,NA +"6725",0.574320702112717,38.6842105263158,38.6842105263158,NA +"6726",0.747628055154725,38.6842105263158,38.6842105263158,NA +"6727",0.973232737037462,38.6842105263158,38.6842105263158,NA +"6728",1.2669160204875,38.6842105263158,38.6842105263158,NA +"6729",1.64922134437622,38.6842105263158,38.6842105263158,NA +"6730",2.14689134777813,38.6842105263158,38.6842105263158,NA +"6731",2.79473854427218,38.6842105263158,38.6842105263158,NA +"6732",3.63808049202114,38.6842105263158,38.6842105263158,NA +"6733",4.73590980220715,38.6842105263158,38.6842105263158,NA +"6734",6.16502073107827,38.6842105263158,38.6842105263158,NA +"6735",8.02538101483936,38.6842105263158,38.6842105263158,NA +"6736",10.4471247126008,38.6842105263158,38.6842105263158,NA +"6737",13.5996552137305,38.6842105263158,38.6842105263158,NA +"6738",17.7034951740616,38.6842105263158,38.6842105263158,NA +"6739",23.045712295823,38.6842105263158,38.6842105263158,NA +"6740",30,38.6842105263158,38.6842105263158,NA +"6741",0.2,40.7894736842105,38.6842105263158,NA +"6742",0.260352117694686,40.7894736842105,38.6842105263158,NA +"6743",0.338916125940539,40.7894736842105,38.6842105263158,NA +"6744",0.441187655547492,40.7894736842105,38.6842105263158,NA +"6745",0.574320702112717,40.7894736842105,38.6842105263158,NA +"6746",0.747628055154725,40.7894736842105,38.6842105263158,NA +"6747",0.973232737037462,40.7894736842105,38.6842105263158,NA +"6748",1.2669160204875,40.7894736842105,38.6842105263158,NA +"6749",1.64922134437622,40.7894736842105,38.6842105263158,NA +"6750",2.14689134777813,40.7894736842105,38.6842105263158,NA +"6751",2.79473854427218,40.7894736842105,38.6842105263158,NA +"6752",3.63808049202114,40.7894736842105,38.6842105263158,NA +"6753",4.73590980220715,40.7894736842105,38.6842105263158,NA +"6754",6.16502073107827,40.7894736842105,38.6842105263158,NA +"6755",8.02538101483936,40.7894736842105,38.6842105263158,NA +"6756",10.4471247126008,40.7894736842105,38.6842105263158,NA +"6757",13.5996552137305,40.7894736842105,38.6842105263158,NA +"6758",17.7034951740616,40.7894736842105,38.6842105263158,NA +"6759",23.045712295823,40.7894736842105,38.6842105263158,NA +"6760",30,40.7894736842105,38.6842105263158,NA +"6761",0.2,42.8947368421053,38.6842105263158,NA +"6762",0.260352117694686,42.8947368421053,38.6842105263158,NA +"6763",0.338916125940539,42.8947368421053,38.6842105263158,NA +"6764",0.441187655547492,42.8947368421053,38.6842105263158,NA +"6765",0.574320702112717,42.8947368421053,38.6842105263158,NA +"6766",0.747628055154725,42.8947368421053,38.6842105263158,NA +"6767",0.973232737037462,42.8947368421053,38.6842105263158,NA +"6768",1.2669160204875,42.8947368421053,38.6842105263158,NA +"6769",1.64922134437622,42.8947368421053,38.6842105263158,NA +"6770",2.14689134777813,42.8947368421053,38.6842105263158,NA +"6771",2.79473854427218,42.8947368421053,38.6842105263158,NA +"6772",3.63808049202114,42.8947368421053,38.6842105263158,NA +"6773",4.73590980220715,42.8947368421053,38.6842105263158,NA +"6774",6.16502073107827,42.8947368421053,38.6842105263158,NA +"6775",8.02538101483936,42.8947368421053,38.6842105263158,NA +"6776",10.4471247126008,42.8947368421053,38.6842105263158,NA +"6777",13.5996552137305,42.8947368421053,38.6842105263158,NA +"6778",17.7034951740616,42.8947368421053,38.6842105263158,NA +"6779",23.045712295823,42.8947368421053,38.6842105263158,NA +"6780",30,42.8947368421053,38.6842105263158,NA +"6781",0.2,45,38.6842105263158,NA +"6782",0.260352117694686,45,38.6842105263158,NA +"6783",0.338916125940539,45,38.6842105263158,NA +"6784",0.441187655547492,45,38.6842105263158,NA +"6785",0.574320702112717,45,38.6842105263158,NA +"6786",0.747628055154725,45,38.6842105263158,NA +"6787",0.973232737037462,45,38.6842105263158,NA +"6788",1.2669160204875,45,38.6842105263158,NA +"6789",1.64922134437622,45,38.6842105263158,NA +"6790",2.14689134777813,45,38.6842105263158,NA +"6791",2.79473854427218,45,38.6842105263158,NA +"6792",3.63808049202114,45,38.6842105263158,NA +"6793",4.73590980220715,45,38.6842105263158,NA +"6794",6.16502073107827,45,38.6842105263158,NA +"6795",8.02538101483936,45,38.6842105263158,NA +"6796",10.4471247126008,45,38.6842105263158,NA +"6797",13.5996552137305,45,38.6842105263158,NA +"6798",17.7034951740616,45,38.6842105263158,NA +"6799",23.045712295823,45,38.6842105263158,NA +"6800",30,45,38.6842105263158,NA +"6801",0.2,5,40.7894736842105,NA +"6802",0.260352117694686,5,40.7894736842105,NA +"6803",0.338916125940539,5,40.7894736842105,NA +"6804",0.441187655547492,5,40.7894736842105,NA +"6805",0.574320702112717,5,40.7894736842105,NA +"6806",0.747628055154725,5,40.7894736842105,NA +"6807",0.973232737037462,5,40.7894736842105,NA +"6808",1.2669160204875,5,40.7894736842105,NA +"6809",1.64922134437622,5,40.7894736842105,NA +"6810",2.14689134777813,5,40.7894736842105,NA +"6811",2.79473854427218,5,40.7894736842105,NA +"6812",3.63808049202114,5,40.7894736842105,NA +"6813",4.73590980220715,5,40.7894736842105,NA +"6814",6.16502073107827,5,40.7894736842105,NA +"6815",8.02538101483936,5,40.7894736842105,NA +"6816",10.4471247126008,5,40.7894736842105,NA +"6817",13.5996552137305,5,40.7894736842105,NA +"6818",17.7034951740616,5,40.7894736842105,NA +"6819",23.045712295823,5,40.7894736842105,NA +"6820",30,5,40.7894736842105,NA +"6821",0.2,7.10526315789474,40.7894736842105,NA +"6822",0.260352117694686,7.10526315789474,40.7894736842105,NA +"6823",0.338916125940539,7.10526315789474,40.7894736842105,NA +"6824",0.441187655547492,7.10526315789474,40.7894736842105,NA +"6825",0.574320702112717,7.10526315789474,40.7894736842105,NA +"6826",0.747628055154725,7.10526315789474,40.7894736842105,NA +"6827",0.973232737037462,7.10526315789474,40.7894736842105,NA +"6828",1.2669160204875,7.10526315789474,40.7894736842105,NA +"6829",1.64922134437622,7.10526315789474,40.7894736842105,NA +"6830",2.14689134777813,7.10526315789474,40.7894736842105,NA +"6831",2.79473854427218,7.10526315789474,40.7894736842105,NA +"6832",3.63808049202114,7.10526315789474,40.7894736842105,NA +"6833",4.73590980220715,7.10526315789474,40.7894736842105,NA +"6834",6.16502073107827,7.10526315789474,40.7894736842105,NA +"6835",8.02538101483936,7.10526315789474,40.7894736842105,NA +"6836",10.4471247126008,7.10526315789474,40.7894736842105,NA +"6837",13.5996552137305,7.10526315789474,40.7894736842105,NA +"6838",17.7034951740616,7.10526315789474,40.7894736842105,NA +"6839",23.045712295823,7.10526315789474,40.7894736842105,NA +"6840",30,7.10526315789474,40.7894736842105,NA +"6841",0.2,9.21052631578947,40.7894736842105,NA +"6842",0.260352117694686,9.21052631578947,40.7894736842105,NA +"6843",0.338916125940539,9.21052631578947,40.7894736842105,NA +"6844",0.441187655547492,9.21052631578947,40.7894736842105,NA +"6845",0.574320702112717,9.21052631578947,40.7894736842105,NA +"6846",0.747628055154725,9.21052631578947,40.7894736842105,NA +"6847",0.973232737037462,9.21052631578947,40.7894736842105,NA +"6848",1.2669160204875,9.21052631578947,40.7894736842105,NA +"6849",1.64922134437622,9.21052631578947,40.7894736842105,NA +"6850",2.14689134777813,9.21052631578947,40.7894736842105,NA +"6851",2.79473854427218,9.21052631578947,40.7894736842105,NA +"6852",3.63808049202114,9.21052631578947,40.7894736842105,NA +"6853",4.73590980220715,9.21052631578947,40.7894736842105,NA +"6854",6.16502073107827,9.21052631578947,40.7894736842105,NA +"6855",8.02538101483936,9.21052631578947,40.7894736842105,NA +"6856",10.4471247126008,9.21052631578947,40.7894736842105,NA +"6857",13.5996552137305,9.21052631578947,40.7894736842105,NA +"6858",17.7034951740616,9.21052631578947,40.7894736842105,NA +"6859",23.045712295823,9.21052631578947,40.7894736842105,NA +"6860",30,9.21052631578947,40.7894736842105,NA +"6861",0.2,11.3157894736842,40.7894736842105,NA +"6862",0.260352117694686,11.3157894736842,40.7894736842105,NA +"6863",0.338916125940539,11.3157894736842,40.7894736842105,NA +"6864",0.441187655547492,11.3157894736842,40.7894736842105,NA +"6865",0.574320702112717,11.3157894736842,40.7894736842105,NA +"6866",0.747628055154725,11.3157894736842,40.7894736842105,NA +"6867",0.973232737037462,11.3157894736842,40.7894736842105,NA +"6868",1.2669160204875,11.3157894736842,40.7894736842105,NA +"6869",1.64922134437622,11.3157894736842,40.7894736842105,NA +"6870",2.14689134777813,11.3157894736842,40.7894736842105,NA +"6871",2.79473854427218,11.3157894736842,40.7894736842105,NA +"6872",3.63808049202114,11.3157894736842,40.7894736842105,NA +"6873",4.73590980220715,11.3157894736842,40.7894736842105,NA +"6874",6.16502073107827,11.3157894736842,40.7894736842105,NA +"6875",8.02538101483936,11.3157894736842,40.7894736842105,NA +"6876",10.4471247126008,11.3157894736842,40.7894736842105,NA +"6877",13.5996552137305,11.3157894736842,40.7894736842105,NA +"6878",17.7034951740616,11.3157894736842,40.7894736842105,NA +"6879",23.045712295823,11.3157894736842,40.7894736842105,NA +"6880",30,11.3157894736842,40.7894736842105,NA +"6881",0.2,13.4210526315789,40.7894736842105,NA +"6882",0.260352117694686,13.4210526315789,40.7894736842105,NA +"6883",0.338916125940539,13.4210526315789,40.7894736842105,NA +"6884",0.441187655547492,13.4210526315789,40.7894736842105,NA +"6885",0.574320702112717,13.4210526315789,40.7894736842105,NA +"6886",0.747628055154725,13.4210526315789,40.7894736842105,NA +"6887",0.973232737037462,13.4210526315789,40.7894736842105,NA +"6888",1.2669160204875,13.4210526315789,40.7894736842105,NA +"6889",1.64922134437622,13.4210526315789,40.7894736842105,NA +"6890",2.14689134777813,13.4210526315789,40.7894736842105,NA +"6891",2.79473854427218,13.4210526315789,40.7894736842105,NA +"6892",3.63808049202114,13.4210526315789,40.7894736842105,NA +"6893",4.73590980220715,13.4210526315789,40.7894736842105,NA +"6894",6.16502073107827,13.4210526315789,40.7894736842105,NA +"6895",8.02538101483936,13.4210526315789,40.7894736842105,NA +"6896",10.4471247126008,13.4210526315789,40.7894736842105,NA +"6897",13.5996552137305,13.4210526315789,40.7894736842105,NA +"6898",17.7034951740616,13.4210526315789,40.7894736842105,NA +"6899",23.045712295823,13.4210526315789,40.7894736842105,NA +"6900",30,13.4210526315789,40.7894736842105,NA +"6901",0.2,15.5263157894737,40.7894736842105,NA +"6902",0.260352117694686,15.5263157894737,40.7894736842105,NA +"6903",0.338916125940539,15.5263157894737,40.7894736842105,NA +"6904",0.441187655547492,15.5263157894737,40.7894736842105,NA +"6905",0.574320702112717,15.5263157894737,40.7894736842105,NA +"6906",0.747628055154725,15.5263157894737,40.7894736842105,NA +"6907",0.973232737037462,15.5263157894737,40.7894736842105,NA +"6908",1.2669160204875,15.5263157894737,40.7894736842105,NA +"6909",1.64922134437622,15.5263157894737,40.7894736842105,NA +"6910",2.14689134777813,15.5263157894737,40.7894736842105,NA +"6911",2.79473854427218,15.5263157894737,40.7894736842105,NA +"6912",3.63808049202114,15.5263157894737,40.7894736842105,NA +"6913",4.73590980220715,15.5263157894737,40.7894736842105,NA +"6914",6.16502073107827,15.5263157894737,40.7894736842105,NA +"6915",8.02538101483936,15.5263157894737,40.7894736842105,NA +"6916",10.4471247126008,15.5263157894737,40.7894736842105,NA +"6917",13.5996552137305,15.5263157894737,40.7894736842105,NA +"6918",17.7034951740616,15.5263157894737,40.7894736842105,NA +"6919",23.045712295823,15.5263157894737,40.7894736842105,NA +"6920",30,15.5263157894737,40.7894736842105,NA +"6921",0.2,17.6315789473684,40.7894736842105,NA +"6922",0.260352117694686,17.6315789473684,40.7894736842105,NA +"6923",0.338916125940539,17.6315789473684,40.7894736842105,NA +"6924",0.441187655547492,17.6315789473684,40.7894736842105,NA +"6925",0.574320702112717,17.6315789473684,40.7894736842105,NA +"6926",0.747628055154725,17.6315789473684,40.7894736842105,NA +"6927",0.973232737037462,17.6315789473684,40.7894736842105,NA +"6928",1.2669160204875,17.6315789473684,40.7894736842105,NA +"6929",1.64922134437622,17.6315789473684,40.7894736842105,NA +"6930",2.14689134777813,17.6315789473684,40.7894736842105,NA +"6931",2.79473854427218,17.6315789473684,40.7894736842105,NA +"6932",3.63808049202114,17.6315789473684,40.7894736842105,NA +"6933",4.73590980220715,17.6315789473684,40.7894736842105,NA +"6934",6.16502073107827,17.6315789473684,40.7894736842105,NA +"6935",8.02538101483936,17.6315789473684,40.7894736842105,NA +"6936",10.4471247126008,17.6315789473684,40.7894736842105,NA +"6937",13.5996552137305,17.6315789473684,40.7894736842105,NA +"6938",17.7034951740616,17.6315789473684,40.7894736842105,NA +"6939",23.045712295823,17.6315789473684,40.7894736842105,NA +"6940",30,17.6315789473684,40.7894736842105,NA +"6941",0.2,19.7368421052632,40.7894736842105,NA +"6942",0.260352117694686,19.7368421052632,40.7894736842105,NA +"6943",0.338916125940539,19.7368421052632,40.7894736842105,NA +"6944",0.441187655547492,19.7368421052632,40.7894736842105,NA +"6945",0.574320702112717,19.7368421052632,40.7894736842105,NA +"6946",0.747628055154725,19.7368421052632,40.7894736842105,NA +"6947",0.973232737037462,19.7368421052632,40.7894736842105,NA +"6948",1.2669160204875,19.7368421052632,40.7894736842105,NA +"6949",1.64922134437622,19.7368421052632,40.7894736842105,NA +"6950",2.14689134777813,19.7368421052632,40.7894736842105,NA +"6951",2.79473854427218,19.7368421052632,40.7894736842105,NA +"6952",3.63808049202114,19.7368421052632,40.7894736842105,NA +"6953",4.73590980220715,19.7368421052632,40.7894736842105,NA +"6954",6.16502073107827,19.7368421052632,40.7894736842105,NA +"6955",8.02538101483936,19.7368421052632,40.7894736842105,NA +"6956",10.4471247126008,19.7368421052632,40.7894736842105,NA +"6957",13.5996552137305,19.7368421052632,40.7894736842105,NA +"6958",17.7034951740616,19.7368421052632,40.7894736842105,NA +"6959",23.045712295823,19.7368421052632,40.7894736842105,NA +"6960",30,19.7368421052632,40.7894736842105,NA +"6961",0.2,21.8421052631579,40.7894736842105,NA +"6962",0.260352117694686,21.8421052631579,40.7894736842105,NA +"6963",0.338916125940539,21.8421052631579,40.7894736842105,NA +"6964",0.441187655547492,21.8421052631579,40.7894736842105,NA +"6965",0.574320702112717,21.8421052631579,40.7894736842105,NA +"6966",0.747628055154725,21.8421052631579,40.7894736842105,NA +"6967",0.973232737037462,21.8421052631579,40.7894736842105,NA +"6968",1.2669160204875,21.8421052631579,40.7894736842105,NA +"6969",1.64922134437622,21.8421052631579,40.7894736842105,NA +"6970",2.14689134777813,21.8421052631579,40.7894736842105,NA +"6971",2.79473854427218,21.8421052631579,40.7894736842105,NA +"6972",3.63808049202114,21.8421052631579,40.7894736842105,NA +"6973",4.73590980220715,21.8421052631579,40.7894736842105,NA +"6974",6.16502073107827,21.8421052631579,40.7894736842105,NA +"6975",8.02538101483936,21.8421052631579,40.7894736842105,NA +"6976",10.4471247126008,21.8421052631579,40.7894736842105,NA +"6977",13.5996552137305,21.8421052631579,40.7894736842105,NA +"6978",17.7034951740616,21.8421052631579,40.7894736842105,NA +"6979",23.045712295823,21.8421052631579,40.7894736842105,NA +"6980",30,21.8421052631579,40.7894736842105,NA +"6981",0.2,23.9473684210526,40.7894736842105,NA +"6982",0.260352117694686,23.9473684210526,40.7894736842105,NA +"6983",0.338916125940539,23.9473684210526,40.7894736842105,NA +"6984",0.441187655547492,23.9473684210526,40.7894736842105,NA +"6985",0.574320702112717,23.9473684210526,40.7894736842105,NA +"6986",0.747628055154725,23.9473684210526,40.7894736842105,NA +"6987",0.973232737037462,23.9473684210526,40.7894736842105,NA +"6988",1.2669160204875,23.9473684210526,40.7894736842105,NA +"6989",1.64922134437622,23.9473684210526,40.7894736842105,NA +"6990",2.14689134777813,23.9473684210526,40.7894736842105,NA +"6991",2.79473854427218,23.9473684210526,40.7894736842105,NA +"6992",3.63808049202114,23.9473684210526,40.7894736842105,NA +"6993",4.73590980220715,23.9473684210526,40.7894736842105,NA +"6994",6.16502073107827,23.9473684210526,40.7894736842105,NA +"6995",8.02538101483936,23.9473684210526,40.7894736842105,NA +"6996",10.4471247126008,23.9473684210526,40.7894736842105,NA +"6997",13.5996552137305,23.9473684210526,40.7894736842105,NA +"6998",17.7034951740616,23.9473684210526,40.7894736842105,NA +"6999",23.045712295823,23.9473684210526,40.7894736842105,NA +"7000",30,23.9473684210526,40.7894736842105,NA +"7001",0.2,26.0526315789474,40.7894736842105,NA +"7002",0.260352117694686,26.0526315789474,40.7894736842105,NA +"7003",0.338916125940539,26.0526315789474,40.7894736842105,NA +"7004",0.441187655547492,26.0526315789474,40.7894736842105,NA +"7005",0.574320702112717,26.0526315789474,40.7894736842105,NA +"7006",0.747628055154725,26.0526315789474,40.7894736842105,NA +"7007",0.973232737037462,26.0526315789474,40.7894736842105,NA +"7008",1.2669160204875,26.0526315789474,40.7894736842105,NA +"7009",1.64922134437622,26.0526315789474,40.7894736842105,NA +"7010",2.14689134777813,26.0526315789474,40.7894736842105,NA +"7011",2.79473854427218,26.0526315789474,40.7894736842105,NA +"7012",3.63808049202114,26.0526315789474,40.7894736842105,NA +"7013",4.73590980220715,26.0526315789474,40.7894736842105,NA +"7014",6.16502073107827,26.0526315789474,40.7894736842105,NA +"7015",8.02538101483936,26.0526315789474,40.7894736842105,NA +"7016",10.4471247126008,26.0526315789474,40.7894736842105,NA +"7017",13.5996552137305,26.0526315789474,40.7894736842105,NA +"7018",17.7034951740616,26.0526315789474,40.7894736842105,NA +"7019",23.045712295823,26.0526315789474,40.7894736842105,NA +"7020",30,26.0526315789474,40.7894736842105,NA +"7021",0.2,28.1578947368421,40.7894736842105,NA +"7022",0.260352117694686,28.1578947368421,40.7894736842105,NA +"7023",0.338916125940539,28.1578947368421,40.7894736842105,NA +"7024",0.441187655547492,28.1578947368421,40.7894736842105,NA +"7025",0.574320702112717,28.1578947368421,40.7894736842105,NA +"7026",0.747628055154725,28.1578947368421,40.7894736842105,NA +"7027",0.973232737037462,28.1578947368421,40.7894736842105,NA +"7028",1.2669160204875,28.1578947368421,40.7894736842105,NA +"7029",1.64922134437622,28.1578947368421,40.7894736842105,NA +"7030",2.14689134777813,28.1578947368421,40.7894736842105,NA +"7031",2.79473854427218,28.1578947368421,40.7894736842105,NA +"7032",3.63808049202114,28.1578947368421,40.7894736842105,NA +"7033",4.73590980220715,28.1578947368421,40.7894736842105,NA +"7034",6.16502073107827,28.1578947368421,40.7894736842105,NA +"7035",8.02538101483936,28.1578947368421,40.7894736842105,NA +"7036",10.4471247126008,28.1578947368421,40.7894736842105,NA +"7037",13.5996552137305,28.1578947368421,40.7894736842105,NA +"7038",17.7034951740616,28.1578947368421,40.7894736842105,NA +"7039",23.045712295823,28.1578947368421,40.7894736842105,NA +"7040",30,28.1578947368421,40.7894736842105,NA +"7041",0.2,30.2631578947368,40.7894736842105,NA +"7042",0.260352117694686,30.2631578947368,40.7894736842105,NA +"7043",0.338916125940539,30.2631578947368,40.7894736842105,NA +"7044",0.441187655547492,30.2631578947368,40.7894736842105,NA +"7045",0.574320702112717,30.2631578947368,40.7894736842105,NA +"7046",0.747628055154725,30.2631578947368,40.7894736842105,NA +"7047",0.973232737037462,30.2631578947368,40.7894736842105,NA +"7048",1.2669160204875,30.2631578947368,40.7894736842105,NA +"7049",1.64922134437622,30.2631578947368,40.7894736842105,NA +"7050",2.14689134777813,30.2631578947368,40.7894736842105,NA +"7051",2.79473854427218,30.2631578947368,40.7894736842105,NA +"7052",3.63808049202114,30.2631578947368,40.7894736842105,NA +"7053",4.73590980220715,30.2631578947368,40.7894736842105,NA +"7054",6.16502073107827,30.2631578947368,40.7894736842105,NA +"7055",8.02538101483936,30.2631578947368,40.7894736842105,NA +"7056",10.4471247126008,30.2631578947368,40.7894736842105,NA +"7057",13.5996552137305,30.2631578947368,40.7894736842105,NA +"7058",17.7034951740616,30.2631578947368,40.7894736842105,NA +"7059",23.045712295823,30.2631578947368,40.7894736842105,NA +"7060",30,30.2631578947368,40.7894736842105,NA +"7061",0.2,32.3684210526316,40.7894736842105,NA +"7062",0.260352117694686,32.3684210526316,40.7894736842105,NA +"7063",0.338916125940539,32.3684210526316,40.7894736842105,NA +"7064",0.441187655547492,32.3684210526316,40.7894736842105,NA +"7065",0.574320702112717,32.3684210526316,40.7894736842105,NA +"7066",0.747628055154725,32.3684210526316,40.7894736842105,NA +"7067",0.973232737037462,32.3684210526316,40.7894736842105,NA +"7068",1.2669160204875,32.3684210526316,40.7894736842105,NA +"7069",1.64922134437622,32.3684210526316,40.7894736842105,NA +"7070",2.14689134777813,32.3684210526316,40.7894736842105,NA +"7071",2.79473854427218,32.3684210526316,40.7894736842105,NA +"7072",3.63808049202114,32.3684210526316,40.7894736842105,NA +"7073",4.73590980220715,32.3684210526316,40.7894736842105,NA +"7074",6.16502073107827,32.3684210526316,40.7894736842105,NA +"7075",8.02538101483936,32.3684210526316,40.7894736842105,NA +"7076",10.4471247126008,32.3684210526316,40.7894736842105,NA +"7077",13.5996552137305,32.3684210526316,40.7894736842105,NA +"7078",17.7034951740616,32.3684210526316,40.7894736842105,NA +"7079",23.045712295823,32.3684210526316,40.7894736842105,NA +"7080",30,32.3684210526316,40.7894736842105,NA +"7081",0.2,34.4736842105263,40.7894736842105,NA +"7082",0.260352117694686,34.4736842105263,40.7894736842105,NA +"7083",0.338916125940539,34.4736842105263,40.7894736842105,NA +"7084",0.441187655547492,34.4736842105263,40.7894736842105,NA +"7085",0.574320702112717,34.4736842105263,40.7894736842105,NA +"7086",0.747628055154725,34.4736842105263,40.7894736842105,NA +"7087",0.973232737037462,34.4736842105263,40.7894736842105,NA +"7088",1.2669160204875,34.4736842105263,40.7894736842105,NA +"7089",1.64922134437622,34.4736842105263,40.7894736842105,NA +"7090",2.14689134777813,34.4736842105263,40.7894736842105,NA +"7091",2.79473854427218,34.4736842105263,40.7894736842105,NA +"7092",3.63808049202114,34.4736842105263,40.7894736842105,NA +"7093",4.73590980220715,34.4736842105263,40.7894736842105,NA +"7094",6.16502073107827,34.4736842105263,40.7894736842105,NA +"7095",8.02538101483936,34.4736842105263,40.7894736842105,NA +"7096",10.4471247126008,34.4736842105263,40.7894736842105,NA +"7097",13.5996552137305,34.4736842105263,40.7894736842105,NA +"7098",17.7034951740616,34.4736842105263,40.7894736842105,NA +"7099",23.045712295823,34.4736842105263,40.7894736842105,NA +"7100",30,34.4736842105263,40.7894736842105,NA +"7101",0.2,36.5789473684211,40.7894736842105,NA +"7102",0.260352117694686,36.5789473684211,40.7894736842105,NA +"7103",0.338916125940539,36.5789473684211,40.7894736842105,NA +"7104",0.441187655547492,36.5789473684211,40.7894736842105,NA +"7105",0.574320702112717,36.5789473684211,40.7894736842105,NA +"7106",0.747628055154725,36.5789473684211,40.7894736842105,NA +"7107",0.973232737037462,36.5789473684211,40.7894736842105,NA +"7108",1.2669160204875,36.5789473684211,40.7894736842105,NA +"7109",1.64922134437622,36.5789473684211,40.7894736842105,NA +"7110",2.14689134777813,36.5789473684211,40.7894736842105,NA +"7111",2.79473854427218,36.5789473684211,40.7894736842105,NA +"7112",3.63808049202114,36.5789473684211,40.7894736842105,NA +"7113",4.73590980220715,36.5789473684211,40.7894736842105,NA +"7114",6.16502073107827,36.5789473684211,40.7894736842105,NA +"7115",8.02538101483936,36.5789473684211,40.7894736842105,NA +"7116",10.4471247126008,36.5789473684211,40.7894736842105,NA +"7117",13.5996552137305,36.5789473684211,40.7894736842105,NA +"7118",17.7034951740616,36.5789473684211,40.7894736842105,NA +"7119",23.045712295823,36.5789473684211,40.7894736842105,NA +"7120",30,36.5789473684211,40.7894736842105,NA +"7121",0.2,38.6842105263158,40.7894736842105,NA +"7122",0.260352117694686,38.6842105263158,40.7894736842105,NA +"7123",0.338916125940539,38.6842105263158,40.7894736842105,NA +"7124",0.441187655547492,38.6842105263158,40.7894736842105,NA +"7125",0.574320702112717,38.6842105263158,40.7894736842105,NA +"7126",0.747628055154725,38.6842105263158,40.7894736842105,NA +"7127",0.973232737037462,38.6842105263158,40.7894736842105,NA +"7128",1.2669160204875,38.6842105263158,40.7894736842105,NA +"7129",1.64922134437622,38.6842105263158,40.7894736842105,NA +"7130",2.14689134777813,38.6842105263158,40.7894736842105,NA +"7131",2.79473854427218,38.6842105263158,40.7894736842105,NA +"7132",3.63808049202114,38.6842105263158,40.7894736842105,NA +"7133",4.73590980220715,38.6842105263158,40.7894736842105,NA +"7134",6.16502073107827,38.6842105263158,40.7894736842105,NA +"7135",8.02538101483936,38.6842105263158,40.7894736842105,NA +"7136",10.4471247126008,38.6842105263158,40.7894736842105,NA +"7137",13.5996552137305,38.6842105263158,40.7894736842105,NA +"7138",17.7034951740616,38.6842105263158,40.7894736842105,NA +"7139",23.045712295823,38.6842105263158,40.7894736842105,NA +"7140",30,38.6842105263158,40.7894736842105,NA +"7141",0.2,40.7894736842105,40.7894736842105,NA +"7142",0.260352117694686,40.7894736842105,40.7894736842105,NA +"7143",0.338916125940539,40.7894736842105,40.7894736842105,NA +"7144",0.441187655547492,40.7894736842105,40.7894736842105,NA +"7145",0.574320702112717,40.7894736842105,40.7894736842105,NA +"7146",0.747628055154725,40.7894736842105,40.7894736842105,NA +"7147",0.973232737037462,40.7894736842105,40.7894736842105,NA +"7148",1.2669160204875,40.7894736842105,40.7894736842105,NA +"7149",1.64922134437622,40.7894736842105,40.7894736842105,NA +"7150",2.14689134777813,40.7894736842105,40.7894736842105,NA +"7151",2.79473854427218,40.7894736842105,40.7894736842105,NA +"7152",3.63808049202114,40.7894736842105,40.7894736842105,NA +"7153",4.73590980220715,40.7894736842105,40.7894736842105,NA +"7154",6.16502073107827,40.7894736842105,40.7894736842105,NA +"7155",8.02538101483936,40.7894736842105,40.7894736842105,NA +"7156",10.4471247126008,40.7894736842105,40.7894736842105,NA +"7157",13.5996552137305,40.7894736842105,40.7894736842105,NA +"7158",17.7034951740616,40.7894736842105,40.7894736842105,NA +"7159",23.045712295823,40.7894736842105,40.7894736842105,NA +"7160",30,40.7894736842105,40.7894736842105,NA +"7161",0.2,42.8947368421053,40.7894736842105,NA +"7162",0.260352117694686,42.8947368421053,40.7894736842105,NA +"7163",0.338916125940539,42.8947368421053,40.7894736842105,NA +"7164",0.441187655547492,42.8947368421053,40.7894736842105,NA +"7165",0.574320702112717,42.8947368421053,40.7894736842105,NA +"7166",0.747628055154725,42.8947368421053,40.7894736842105,NA +"7167",0.973232737037462,42.8947368421053,40.7894736842105,NA +"7168",1.2669160204875,42.8947368421053,40.7894736842105,NA +"7169",1.64922134437622,42.8947368421053,40.7894736842105,NA +"7170",2.14689134777813,42.8947368421053,40.7894736842105,NA +"7171",2.79473854427218,42.8947368421053,40.7894736842105,NA +"7172",3.63808049202114,42.8947368421053,40.7894736842105,NA +"7173",4.73590980220715,42.8947368421053,40.7894736842105,NA +"7174",6.16502073107827,42.8947368421053,40.7894736842105,NA +"7175",8.02538101483936,42.8947368421053,40.7894736842105,NA +"7176",10.4471247126008,42.8947368421053,40.7894736842105,NA +"7177",13.5996552137305,42.8947368421053,40.7894736842105,NA +"7178",17.7034951740616,42.8947368421053,40.7894736842105,NA +"7179",23.045712295823,42.8947368421053,40.7894736842105,NA +"7180",30,42.8947368421053,40.7894736842105,NA +"7181",0.2,45,40.7894736842105,NA +"7182",0.260352117694686,45,40.7894736842105,NA +"7183",0.338916125940539,45,40.7894736842105,NA +"7184",0.441187655547492,45,40.7894736842105,NA +"7185",0.574320702112717,45,40.7894736842105,NA +"7186",0.747628055154725,45,40.7894736842105,NA +"7187",0.973232737037462,45,40.7894736842105,NA +"7188",1.2669160204875,45,40.7894736842105,NA +"7189",1.64922134437622,45,40.7894736842105,NA +"7190",2.14689134777813,45,40.7894736842105,NA +"7191",2.79473854427218,45,40.7894736842105,NA +"7192",3.63808049202114,45,40.7894736842105,NA +"7193",4.73590980220715,45,40.7894736842105,NA +"7194",6.16502073107827,45,40.7894736842105,NA +"7195",8.02538101483936,45,40.7894736842105,NA +"7196",10.4471247126008,45,40.7894736842105,NA +"7197",13.5996552137305,45,40.7894736842105,NA +"7198",17.7034951740616,45,40.7894736842105,NA +"7199",23.045712295823,45,40.7894736842105,NA +"7200",30,45,40.7894736842105,NA +"7201",0.2,5,42.8947368421053,NA +"7202",0.260352117694686,5,42.8947368421053,NA +"7203",0.338916125940539,5,42.8947368421053,NA +"7204",0.441187655547492,5,42.8947368421053,NA +"7205",0.574320702112717,5,42.8947368421053,NA +"7206",0.747628055154725,5,42.8947368421053,NA +"7207",0.973232737037462,5,42.8947368421053,NA +"7208",1.2669160204875,5,42.8947368421053,NA +"7209",1.64922134437622,5,42.8947368421053,NA +"7210",2.14689134777813,5,42.8947368421053,NA +"7211",2.79473854427218,5,42.8947368421053,NA +"7212",3.63808049202114,5,42.8947368421053,NA +"7213",4.73590980220715,5,42.8947368421053,NA +"7214",6.16502073107827,5,42.8947368421053,NA +"7215",8.02538101483936,5,42.8947368421053,NA +"7216",10.4471247126008,5,42.8947368421053,NA +"7217",13.5996552137305,5,42.8947368421053,NA +"7218",17.7034951740616,5,42.8947368421053,NA +"7219",23.045712295823,5,42.8947368421053,NA +"7220",30,5,42.8947368421053,NA +"7221",0.2,7.10526315789474,42.8947368421053,NA +"7222",0.260352117694686,7.10526315789474,42.8947368421053,NA +"7223",0.338916125940539,7.10526315789474,42.8947368421053,NA +"7224",0.441187655547492,7.10526315789474,42.8947368421053,NA +"7225",0.574320702112717,7.10526315789474,42.8947368421053,NA +"7226",0.747628055154725,7.10526315789474,42.8947368421053,NA +"7227",0.973232737037462,7.10526315789474,42.8947368421053,NA +"7228",1.2669160204875,7.10526315789474,42.8947368421053,NA +"7229",1.64922134437622,7.10526315789474,42.8947368421053,NA +"7230",2.14689134777813,7.10526315789474,42.8947368421053,NA +"7231",2.79473854427218,7.10526315789474,42.8947368421053,NA +"7232",3.63808049202114,7.10526315789474,42.8947368421053,NA +"7233",4.73590980220715,7.10526315789474,42.8947368421053,NA +"7234",6.16502073107827,7.10526315789474,42.8947368421053,NA +"7235",8.02538101483936,7.10526315789474,42.8947368421053,NA +"7236",10.4471247126008,7.10526315789474,42.8947368421053,NA +"7237",13.5996552137305,7.10526315789474,42.8947368421053,NA +"7238",17.7034951740616,7.10526315789474,42.8947368421053,NA +"7239",23.045712295823,7.10526315789474,42.8947368421053,NA +"7240",30,7.10526315789474,42.8947368421053,NA +"7241",0.2,9.21052631578947,42.8947368421053,NA +"7242",0.260352117694686,9.21052631578947,42.8947368421053,NA +"7243",0.338916125940539,9.21052631578947,42.8947368421053,NA +"7244",0.441187655547492,9.21052631578947,42.8947368421053,NA +"7245",0.574320702112717,9.21052631578947,42.8947368421053,NA +"7246",0.747628055154725,9.21052631578947,42.8947368421053,NA +"7247",0.973232737037462,9.21052631578947,42.8947368421053,NA +"7248",1.2669160204875,9.21052631578947,42.8947368421053,NA +"7249",1.64922134437622,9.21052631578947,42.8947368421053,NA +"7250",2.14689134777813,9.21052631578947,42.8947368421053,NA +"7251",2.79473854427218,9.21052631578947,42.8947368421053,NA +"7252",3.63808049202114,9.21052631578947,42.8947368421053,NA +"7253",4.73590980220715,9.21052631578947,42.8947368421053,NA +"7254",6.16502073107827,9.21052631578947,42.8947368421053,NA +"7255",8.02538101483936,9.21052631578947,42.8947368421053,NA +"7256",10.4471247126008,9.21052631578947,42.8947368421053,NA +"7257",13.5996552137305,9.21052631578947,42.8947368421053,NA +"7258",17.7034951740616,9.21052631578947,42.8947368421053,NA +"7259",23.045712295823,9.21052631578947,42.8947368421053,NA +"7260",30,9.21052631578947,42.8947368421053,NA +"7261",0.2,11.3157894736842,42.8947368421053,NA +"7262",0.260352117694686,11.3157894736842,42.8947368421053,NA +"7263",0.338916125940539,11.3157894736842,42.8947368421053,NA +"7264",0.441187655547492,11.3157894736842,42.8947368421053,NA +"7265",0.574320702112717,11.3157894736842,42.8947368421053,NA +"7266",0.747628055154725,11.3157894736842,42.8947368421053,NA +"7267",0.973232737037462,11.3157894736842,42.8947368421053,NA +"7268",1.2669160204875,11.3157894736842,42.8947368421053,NA +"7269",1.64922134437622,11.3157894736842,42.8947368421053,NA +"7270",2.14689134777813,11.3157894736842,42.8947368421053,NA +"7271",2.79473854427218,11.3157894736842,42.8947368421053,NA +"7272",3.63808049202114,11.3157894736842,42.8947368421053,NA +"7273",4.73590980220715,11.3157894736842,42.8947368421053,NA +"7274",6.16502073107827,11.3157894736842,42.8947368421053,NA +"7275",8.02538101483936,11.3157894736842,42.8947368421053,NA +"7276",10.4471247126008,11.3157894736842,42.8947368421053,NA +"7277",13.5996552137305,11.3157894736842,42.8947368421053,NA +"7278",17.7034951740616,11.3157894736842,42.8947368421053,NA +"7279",23.045712295823,11.3157894736842,42.8947368421053,NA +"7280",30,11.3157894736842,42.8947368421053,NA +"7281",0.2,13.4210526315789,42.8947368421053,NA +"7282",0.260352117694686,13.4210526315789,42.8947368421053,NA +"7283",0.338916125940539,13.4210526315789,42.8947368421053,NA +"7284",0.441187655547492,13.4210526315789,42.8947368421053,NA +"7285",0.574320702112717,13.4210526315789,42.8947368421053,NA +"7286",0.747628055154725,13.4210526315789,42.8947368421053,NA +"7287",0.973232737037462,13.4210526315789,42.8947368421053,NA +"7288",1.2669160204875,13.4210526315789,42.8947368421053,NA +"7289",1.64922134437622,13.4210526315789,42.8947368421053,NA +"7290",2.14689134777813,13.4210526315789,42.8947368421053,NA +"7291",2.79473854427218,13.4210526315789,42.8947368421053,NA +"7292",3.63808049202114,13.4210526315789,42.8947368421053,NA +"7293",4.73590980220715,13.4210526315789,42.8947368421053,NA +"7294",6.16502073107827,13.4210526315789,42.8947368421053,NA +"7295",8.02538101483936,13.4210526315789,42.8947368421053,NA +"7296",10.4471247126008,13.4210526315789,42.8947368421053,NA +"7297",13.5996552137305,13.4210526315789,42.8947368421053,NA +"7298",17.7034951740616,13.4210526315789,42.8947368421053,NA +"7299",23.045712295823,13.4210526315789,42.8947368421053,NA +"7300",30,13.4210526315789,42.8947368421053,NA +"7301",0.2,15.5263157894737,42.8947368421053,NA +"7302",0.260352117694686,15.5263157894737,42.8947368421053,NA +"7303",0.338916125940539,15.5263157894737,42.8947368421053,NA +"7304",0.441187655547492,15.5263157894737,42.8947368421053,NA +"7305",0.574320702112717,15.5263157894737,42.8947368421053,NA +"7306",0.747628055154725,15.5263157894737,42.8947368421053,NA +"7307",0.973232737037462,15.5263157894737,42.8947368421053,NA +"7308",1.2669160204875,15.5263157894737,42.8947368421053,NA +"7309",1.64922134437622,15.5263157894737,42.8947368421053,NA +"7310",2.14689134777813,15.5263157894737,42.8947368421053,NA +"7311",2.79473854427218,15.5263157894737,42.8947368421053,NA +"7312",3.63808049202114,15.5263157894737,42.8947368421053,NA +"7313",4.73590980220715,15.5263157894737,42.8947368421053,NA +"7314",6.16502073107827,15.5263157894737,42.8947368421053,NA +"7315",8.02538101483936,15.5263157894737,42.8947368421053,NA +"7316",10.4471247126008,15.5263157894737,42.8947368421053,NA +"7317",13.5996552137305,15.5263157894737,42.8947368421053,NA +"7318",17.7034951740616,15.5263157894737,42.8947368421053,NA +"7319",23.045712295823,15.5263157894737,42.8947368421053,NA +"7320",30,15.5263157894737,42.8947368421053,NA +"7321",0.2,17.6315789473684,42.8947368421053,NA +"7322",0.260352117694686,17.6315789473684,42.8947368421053,NA +"7323",0.338916125940539,17.6315789473684,42.8947368421053,NA +"7324",0.441187655547492,17.6315789473684,42.8947368421053,NA +"7325",0.574320702112717,17.6315789473684,42.8947368421053,NA +"7326",0.747628055154725,17.6315789473684,42.8947368421053,NA +"7327",0.973232737037462,17.6315789473684,42.8947368421053,NA +"7328",1.2669160204875,17.6315789473684,42.8947368421053,NA +"7329",1.64922134437622,17.6315789473684,42.8947368421053,NA +"7330",2.14689134777813,17.6315789473684,42.8947368421053,NA +"7331",2.79473854427218,17.6315789473684,42.8947368421053,NA +"7332",3.63808049202114,17.6315789473684,42.8947368421053,NA +"7333",4.73590980220715,17.6315789473684,42.8947368421053,NA +"7334",6.16502073107827,17.6315789473684,42.8947368421053,NA +"7335",8.02538101483936,17.6315789473684,42.8947368421053,NA +"7336",10.4471247126008,17.6315789473684,42.8947368421053,NA +"7337",13.5996552137305,17.6315789473684,42.8947368421053,NA +"7338",17.7034951740616,17.6315789473684,42.8947368421053,NA +"7339",23.045712295823,17.6315789473684,42.8947368421053,NA +"7340",30,17.6315789473684,42.8947368421053,NA +"7341",0.2,19.7368421052632,42.8947368421053,NA +"7342",0.260352117694686,19.7368421052632,42.8947368421053,NA +"7343",0.338916125940539,19.7368421052632,42.8947368421053,NA +"7344",0.441187655547492,19.7368421052632,42.8947368421053,NA +"7345",0.574320702112717,19.7368421052632,42.8947368421053,NA +"7346",0.747628055154725,19.7368421052632,42.8947368421053,NA +"7347",0.973232737037462,19.7368421052632,42.8947368421053,NA +"7348",1.2669160204875,19.7368421052632,42.8947368421053,NA +"7349",1.64922134437622,19.7368421052632,42.8947368421053,NA +"7350",2.14689134777813,19.7368421052632,42.8947368421053,NA +"7351",2.79473854427218,19.7368421052632,42.8947368421053,NA +"7352",3.63808049202114,19.7368421052632,42.8947368421053,NA +"7353",4.73590980220715,19.7368421052632,42.8947368421053,NA +"7354",6.16502073107827,19.7368421052632,42.8947368421053,NA +"7355",8.02538101483936,19.7368421052632,42.8947368421053,NA +"7356",10.4471247126008,19.7368421052632,42.8947368421053,NA +"7357",13.5996552137305,19.7368421052632,42.8947368421053,NA +"7358",17.7034951740616,19.7368421052632,42.8947368421053,NA +"7359",23.045712295823,19.7368421052632,42.8947368421053,NA +"7360",30,19.7368421052632,42.8947368421053,NA +"7361",0.2,21.8421052631579,42.8947368421053,NA +"7362",0.260352117694686,21.8421052631579,42.8947368421053,NA +"7363",0.338916125940539,21.8421052631579,42.8947368421053,NA +"7364",0.441187655547492,21.8421052631579,42.8947368421053,NA +"7365",0.574320702112717,21.8421052631579,42.8947368421053,NA +"7366",0.747628055154725,21.8421052631579,42.8947368421053,NA +"7367",0.973232737037462,21.8421052631579,42.8947368421053,NA +"7368",1.2669160204875,21.8421052631579,42.8947368421053,NA +"7369",1.64922134437622,21.8421052631579,42.8947368421053,NA +"7370",2.14689134777813,21.8421052631579,42.8947368421053,NA +"7371",2.79473854427218,21.8421052631579,42.8947368421053,NA +"7372",3.63808049202114,21.8421052631579,42.8947368421053,NA +"7373",4.73590980220715,21.8421052631579,42.8947368421053,NA +"7374",6.16502073107827,21.8421052631579,42.8947368421053,NA +"7375",8.02538101483936,21.8421052631579,42.8947368421053,NA +"7376",10.4471247126008,21.8421052631579,42.8947368421053,NA +"7377",13.5996552137305,21.8421052631579,42.8947368421053,NA +"7378",17.7034951740616,21.8421052631579,42.8947368421053,NA +"7379",23.045712295823,21.8421052631579,42.8947368421053,NA +"7380",30,21.8421052631579,42.8947368421053,NA +"7381",0.2,23.9473684210526,42.8947368421053,NA +"7382",0.260352117694686,23.9473684210526,42.8947368421053,NA +"7383",0.338916125940539,23.9473684210526,42.8947368421053,NA +"7384",0.441187655547492,23.9473684210526,42.8947368421053,NA +"7385",0.574320702112717,23.9473684210526,42.8947368421053,NA +"7386",0.747628055154725,23.9473684210526,42.8947368421053,NA +"7387",0.973232737037462,23.9473684210526,42.8947368421053,NA +"7388",1.2669160204875,23.9473684210526,42.8947368421053,NA +"7389",1.64922134437622,23.9473684210526,42.8947368421053,NA +"7390",2.14689134777813,23.9473684210526,42.8947368421053,NA +"7391",2.79473854427218,23.9473684210526,42.8947368421053,NA +"7392",3.63808049202114,23.9473684210526,42.8947368421053,NA +"7393",4.73590980220715,23.9473684210526,42.8947368421053,NA +"7394",6.16502073107827,23.9473684210526,42.8947368421053,NA +"7395",8.02538101483936,23.9473684210526,42.8947368421053,NA +"7396",10.4471247126008,23.9473684210526,42.8947368421053,NA +"7397",13.5996552137305,23.9473684210526,42.8947368421053,NA +"7398",17.7034951740616,23.9473684210526,42.8947368421053,NA +"7399",23.045712295823,23.9473684210526,42.8947368421053,NA +"7400",30,23.9473684210526,42.8947368421053,NA +"7401",0.2,26.0526315789474,42.8947368421053,NA +"7402",0.260352117694686,26.0526315789474,42.8947368421053,NA +"7403",0.338916125940539,26.0526315789474,42.8947368421053,NA +"7404",0.441187655547492,26.0526315789474,42.8947368421053,NA +"7405",0.574320702112717,26.0526315789474,42.8947368421053,NA +"7406",0.747628055154725,26.0526315789474,42.8947368421053,NA +"7407",0.973232737037462,26.0526315789474,42.8947368421053,NA +"7408",1.2669160204875,26.0526315789474,42.8947368421053,NA +"7409",1.64922134437622,26.0526315789474,42.8947368421053,NA +"7410",2.14689134777813,26.0526315789474,42.8947368421053,NA +"7411",2.79473854427218,26.0526315789474,42.8947368421053,NA +"7412",3.63808049202114,26.0526315789474,42.8947368421053,NA +"7413",4.73590980220715,26.0526315789474,42.8947368421053,NA +"7414",6.16502073107827,26.0526315789474,42.8947368421053,NA +"7415",8.02538101483936,26.0526315789474,42.8947368421053,NA +"7416",10.4471247126008,26.0526315789474,42.8947368421053,NA +"7417",13.5996552137305,26.0526315789474,42.8947368421053,NA +"7418",17.7034951740616,26.0526315789474,42.8947368421053,NA +"7419",23.045712295823,26.0526315789474,42.8947368421053,NA +"7420",30,26.0526315789474,42.8947368421053,NA +"7421",0.2,28.1578947368421,42.8947368421053,NA +"7422",0.260352117694686,28.1578947368421,42.8947368421053,NA +"7423",0.338916125940539,28.1578947368421,42.8947368421053,NA +"7424",0.441187655547492,28.1578947368421,42.8947368421053,NA +"7425",0.574320702112717,28.1578947368421,42.8947368421053,NA +"7426",0.747628055154725,28.1578947368421,42.8947368421053,NA +"7427",0.973232737037462,28.1578947368421,42.8947368421053,NA +"7428",1.2669160204875,28.1578947368421,42.8947368421053,NA +"7429",1.64922134437622,28.1578947368421,42.8947368421053,NA +"7430",2.14689134777813,28.1578947368421,42.8947368421053,NA +"7431",2.79473854427218,28.1578947368421,42.8947368421053,NA +"7432",3.63808049202114,28.1578947368421,42.8947368421053,NA +"7433",4.73590980220715,28.1578947368421,42.8947368421053,NA +"7434",6.16502073107827,28.1578947368421,42.8947368421053,NA +"7435",8.02538101483936,28.1578947368421,42.8947368421053,NA +"7436",10.4471247126008,28.1578947368421,42.8947368421053,NA +"7437",13.5996552137305,28.1578947368421,42.8947368421053,NA +"7438",17.7034951740616,28.1578947368421,42.8947368421053,NA +"7439",23.045712295823,28.1578947368421,42.8947368421053,NA +"7440",30,28.1578947368421,42.8947368421053,NA +"7441",0.2,30.2631578947368,42.8947368421053,NA +"7442",0.260352117694686,30.2631578947368,42.8947368421053,NA +"7443",0.338916125940539,30.2631578947368,42.8947368421053,NA +"7444",0.441187655547492,30.2631578947368,42.8947368421053,NA +"7445",0.574320702112717,30.2631578947368,42.8947368421053,NA +"7446",0.747628055154725,30.2631578947368,42.8947368421053,NA +"7447",0.973232737037462,30.2631578947368,42.8947368421053,NA +"7448",1.2669160204875,30.2631578947368,42.8947368421053,NA +"7449",1.64922134437622,30.2631578947368,42.8947368421053,NA +"7450",2.14689134777813,30.2631578947368,42.8947368421053,NA +"7451",2.79473854427218,30.2631578947368,42.8947368421053,NA +"7452",3.63808049202114,30.2631578947368,42.8947368421053,NA +"7453",4.73590980220715,30.2631578947368,42.8947368421053,NA +"7454",6.16502073107827,30.2631578947368,42.8947368421053,NA +"7455",8.02538101483936,30.2631578947368,42.8947368421053,NA +"7456",10.4471247126008,30.2631578947368,42.8947368421053,NA +"7457",13.5996552137305,30.2631578947368,42.8947368421053,NA +"7458",17.7034951740616,30.2631578947368,42.8947368421053,NA +"7459",23.045712295823,30.2631578947368,42.8947368421053,NA +"7460",30,30.2631578947368,42.8947368421053,NA +"7461",0.2,32.3684210526316,42.8947368421053,NA +"7462",0.260352117694686,32.3684210526316,42.8947368421053,NA +"7463",0.338916125940539,32.3684210526316,42.8947368421053,NA +"7464",0.441187655547492,32.3684210526316,42.8947368421053,NA +"7465",0.574320702112717,32.3684210526316,42.8947368421053,NA +"7466",0.747628055154725,32.3684210526316,42.8947368421053,NA +"7467",0.973232737037462,32.3684210526316,42.8947368421053,NA +"7468",1.2669160204875,32.3684210526316,42.8947368421053,NA +"7469",1.64922134437622,32.3684210526316,42.8947368421053,NA +"7470",2.14689134777813,32.3684210526316,42.8947368421053,NA +"7471",2.79473854427218,32.3684210526316,42.8947368421053,NA +"7472",3.63808049202114,32.3684210526316,42.8947368421053,NA +"7473",4.73590980220715,32.3684210526316,42.8947368421053,NA +"7474",6.16502073107827,32.3684210526316,42.8947368421053,NA +"7475",8.02538101483936,32.3684210526316,42.8947368421053,NA +"7476",10.4471247126008,32.3684210526316,42.8947368421053,NA +"7477",13.5996552137305,32.3684210526316,42.8947368421053,NA +"7478",17.7034951740616,32.3684210526316,42.8947368421053,NA +"7479",23.045712295823,32.3684210526316,42.8947368421053,NA +"7480",30,32.3684210526316,42.8947368421053,NA +"7481",0.2,34.4736842105263,42.8947368421053,NA +"7482",0.260352117694686,34.4736842105263,42.8947368421053,NA +"7483",0.338916125940539,34.4736842105263,42.8947368421053,NA +"7484",0.441187655547492,34.4736842105263,42.8947368421053,NA +"7485",0.574320702112717,34.4736842105263,42.8947368421053,NA +"7486",0.747628055154725,34.4736842105263,42.8947368421053,NA +"7487",0.973232737037462,34.4736842105263,42.8947368421053,NA +"7488",1.2669160204875,34.4736842105263,42.8947368421053,NA +"7489",1.64922134437622,34.4736842105263,42.8947368421053,NA +"7490",2.14689134777813,34.4736842105263,42.8947368421053,NA +"7491",2.79473854427218,34.4736842105263,42.8947368421053,NA +"7492",3.63808049202114,34.4736842105263,42.8947368421053,NA +"7493",4.73590980220715,34.4736842105263,42.8947368421053,NA +"7494",6.16502073107827,34.4736842105263,42.8947368421053,NA +"7495",8.02538101483936,34.4736842105263,42.8947368421053,NA +"7496",10.4471247126008,34.4736842105263,42.8947368421053,NA +"7497",13.5996552137305,34.4736842105263,42.8947368421053,NA +"7498",17.7034951740616,34.4736842105263,42.8947368421053,NA +"7499",23.045712295823,34.4736842105263,42.8947368421053,NA +"7500",30,34.4736842105263,42.8947368421053,NA +"7501",0.2,36.5789473684211,42.8947368421053,NA +"7502",0.260352117694686,36.5789473684211,42.8947368421053,NA +"7503",0.338916125940539,36.5789473684211,42.8947368421053,NA +"7504",0.441187655547492,36.5789473684211,42.8947368421053,NA +"7505",0.574320702112717,36.5789473684211,42.8947368421053,NA +"7506",0.747628055154725,36.5789473684211,42.8947368421053,NA +"7507",0.973232737037462,36.5789473684211,42.8947368421053,NA +"7508",1.2669160204875,36.5789473684211,42.8947368421053,NA +"7509",1.64922134437622,36.5789473684211,42.8947368421053,NA +"7510",2.14689134777813,36.5789473684211,42.8947368421053,NA +"7511",2.79473854427218,36.5789473684211,42.8947368421053,NA +"7512",3.63808049202114,36.5789473684211,42.8947368421053,NA +"7513",4.73590980220715,36.5789473684211,42.8947368421053,NA +"7514",6.16502073107827,36.5789473684211,42.8947368421053,NA +"7515",8.02538101483936,36.5789473684211,42.8947368421053,NA +"7516",10.4471247126008,36.5789473684211,42.8947368421053,NA +"7517",13.5996552137305,36.5789473684211,42.8947368421053,NA +"7518",17.7034951740616,36.5789473684211,42.8947368421053,NA +"7519",23.045712295823,36.5789473684211,42.8947368421053,NA +"7520",30,36.5789473684211,42.8947368421053,NA +"7521",0.2,38.6842105263158,42.8947368421053,NA +"7522",0.260352117694686,38.6842105263158,42.8947368421053,NA +"7523",0.338916125940539,38.6842105263158,42.8947368421053,NA +"7524",0.441187655547492,38.6842105263158,42.8947368421053,NA +"7525",0.574320702112717,38.6842105263158,42.8947368421053,NA +"7526",0.747628055154725,38.6842105263158,42.8947368421053,NA +"7527",0.973232737037462,38.6842105263158,42.8947368421053,NA +"7528",1.2669160204875,38.6842105263158,42.8947368421053,NA +"7529",1.64922134437622,38.6842105263158,42.8947368421053,NA +"7530",2.14689134777813,38.6842105263158,42.8947368421053,NA +"7531",2.79473854427218,38.6842105263158,42.8947368421053,NA +"7532",3.63808049202114,38.6842105263158,42.8947368421053,NA +"7533",4.73590980220715,38.6842105263158,42.8947368421053,NA +"7534",6.16502073107827,38.6842105263158,42.8947368421053,NA +"7535",8.02538101483936,38.6842105263158,42.8947368421053,NA +"7536",10.4471247126008,38.6842105263158,42.8947368421053,NA +"7537",13.5996552137305,38.6842105263158,42.8947368421053,NA +"7538",17.7034951740616,38.6842105263158,42.8947368421053,NA +"7539",23.045712295823,38.6842105263158,42.8947368421053,NA +"7540",30,38.6842105263158,42.8947368421053,NA +"7541",0.2,40.7894736842105,42.8947368421053,NA +"7542",0.260352117694686,40.7894736842105,42.8947368421053,NA +"7543",0.338916125940539,40.7894736842105,42.8947368421053,NA +"7544",0.441187655547492,40.7894736842105,42.8947368421053,NA +"7545",0.574320702112717,40.7894736842105,42.8947368421053,NA +"7546",0.747628055154725,40.7894736842105,42.8947368421053,NA +"7547",0.973232737037462,40.7894736842105,42.8947368421053,NA +"7548",1.2669160204875,40.7894736842105,42.8947368421053,NA +"7549",1.64922134437622,40.7894736842105,42.8947368421053,NA +"7550",2.14689134777813,40.7894736842105,42.8947368421053,NA +"7551",2.79473854427218,40.7894736842105,42.8947368421053,NA +"7552",3.63808049202114,40.7894736842105,42.8947368421053,NA +"7553",4.73590980220715,40.7894736842105,42.8947368421053,NA +"7554",6.16502073107827,40.7894736842105,42.8947368421053,NA +"7555",8.02538101483936,40.7894736842105,42.8947368421053,NA +"7556",10.4471247126008,40.7894736842105,42.8947368421053,NA +"7557",13.5996552137305,40.7894736842105,42.8947368421053,NA +"7558",17.7034951740616,40.7894736842105,42.8947368421053,NA +"7559",23.045712295823,40.7894736842105,42.8947368421053,NA +"7560",30,40.7894736842105,42.8947368421053,NA +"7561",0.2,42.8947368421053,42.8947368421053,NA +"7562",0.260352117694686,42.8947368421053,42.8947368421053,NA +"7563",0.338916125940539,42.8947368421053,42.8947368421053,NA +"7564",0.441187655547492,42.8947368421053,42.8947368421053,NA +"7565",0.574320702112717,42.8947368421053,42.8947368421053,NA +"7566",0.747628055154725,42.8947368421053,42.8947368421053,NA +"7567",0.973232737037462,42.8947368421053,42.8947368421053,NA +"7568",1.2669160204875,42.8947368421053,42.8947368421053,NA +"7569",1.64922134437622,42.8947368421053,42.8947368421053,NA +"7570",2.14689134777813,42.8947368421053,42.8947368421053,NA +"7571",2.79473854427218,42.8947368421053,42.8947368421053,NA +"7572",3.63808049202114,42.8947368421053,42.8947368421053,NA +"7573",4.73590980220715,42.8947368421053,42.8947368421053,NA +"7574",6.16502073107827,42.8947368421053,42.8947368421053,NA +"7575",8.02538101483936,42.8947368421053,42.8947368421053,NA +"7576",10.4471247126008,42.8947368421053,42.8947368421053,NA +"7577",13.5996552137305,42.8947368421053,42.8947368421053,NA +"7578",17.7034951740616,42.8947368421053,42.8947368421053,NA +"7579",23.045712295823,42.8947368421053,42.8947368421053,NA +"7580",30,42.8947368421053,42.8947368421053,NA +"7581",0.2,45,42.8947368421053,NA +"7582",0.260352117694686,45,42.8947368421053,NA +"7583",0.338916125940539,45,42.8947368421053,NA +"7584",0.441187655547492,45,42.8947368421053,NA +"7585",0.574320702112717,45,42.8947368421053,NA +"7586",0.747628055154725,45,42.8947368421053,NA +"7587",0.973232737037462,45,42.8947368421053,NA +"7588",1.2669160204875,45,42.8947368421053,NA +"7589",1.64922134437622,45,42.8947368421053,NA +"7590",2.14689134777813,45,42.8947368421053,NA +"7591",2.79473854427218,45,42.8947368421053,NA +"7592",3.63808049202114,45,42.8947368421053,NA +"7593",4.73590980220715,45,42.8947368421053,NA +"7594",6.16502073107827,45,42.8947368421053,NA +"7595",8.02538101483936,45,42.8947368421053,NA +"7596",10.4471247126008,45,42.8947368421053,NA +"7597",13.5996552137305,45,42.8947368421053,NA +"7598",17.7034951740616,45,42.8947368421053,NA +"7599",23.045712295823,45,42.8947368421053,NA +"7600",30,45,42.8947368421053,NA +"7601",0.2,5,45,NA +"7602",0.260352117694686,5,45,NA +"7603",0.338916125940539,5,45,NA +"7604",0.441187655547492,5,45,NA +"7605",0.574320702112717,5,45,NA +"7606",0.747628055154725,5,45,NA +"7607",0.973232737037462,5,45,NA +"7608",1.2669160204875,5,45,NA +"7609",1.64922134437622,5,45,NA +"7610",2.14689134777813,5,45,NA +"7611",2.79473854427218,5,45,NA +"7612",3.63808049202114,5,45,NA +"7613",4.73590980220715,5,45,NA +"7614",6.16502073107827,5,45,NA +"7615",8.02538101483936,5,45,NA +"7616",10.4471247126008,5,45,NA +"7617",13.5996552137305,5,45,NA +"7618",17.7034951740616,5,45,NA +"7619",23.045712295823,5,45,NA +"7620",30,5,45,NA +"7621",0.2,7.10526315789474,45,NA +"7622",0.260352117694686,7.10526315789474,45,NA +"7623",0.338916125940539,7.10526315789474,45,NA +"7624",0.441187655547492,7.10526315789474,45,NA +"7625",0.574320702112717,7.10526315789474,45,NA +"7626",0.747628055154725,7.10526315789474,45,NA +"7627",0.973232737037462,7.10526315789474,45,NA +"7628",1.2669160204875,7.10526315789474,45,NA +"7629",1.64922134437622,7.10526315789474,45,NA +"7630",2.14689134777813,7.10526315789474,45,NA +"7631",2.79473854427218,7.10526315789474,45,NA +"7632",3.63808049202114,7.10526315789474,45,NA +"7633",4.73590980220715,7.10526315789474,45,NA +"7634",6.16502073107827,7.10526315789474,45,NA +"7635",8.02538101483936,7.10526315789474,45,NA +"7636",10.4471247126008,7.10526315789474,45,NA +"7637",13.5996552137305,7.10526315789474,45,NA +"7638",17.7034951740616,7.10526315789474,45,NA +"7639",23.045712295823,7.10526315789474,45,NA +"7640",30,7.10526315789474,45,NA +"7641",0.2,9.21052631578947,45,NA +"7642",0.260352117694686,9.21052631578947,45,NA +"7643",0.338916125940539,9.21052631578947,45,NA +"7644",0.441187655547492,9.21052631578947,45,NA +"7645",0.574320702112717,9.21052631578947,45,NA +"7646",0.747628055154725,9.21052631578947,45,NA +"7647",0.973232737037462,9.21052631578947,45,NA +"7648",1.2669160204875,9.21052631578947,45,NA +"7649",1.64922134437622,9.21052631578947,45,NA +"7650",2.14689134777813,9.21052631578947,45,NA +"7651",2.79473854427218,9.21052631578947,45,NA +"7652",3.63808049202114,9.21052631578947,45,NA +"7653",4.73590980220715,9.21052631578947,45,NA +"7654",6.16502073107827,9.21052631578947,45,NA +"7655",8.02538101483936,9.21052631578947,45,NA +"7656",10.4471247126008,9.21052631578947,45,NA +"7657",13.5996552137305,9.21052631578947,45,NA +"7658",17.7034951740616,9.21052631578947,45,NA +"7659",23.045712295823,9.21052631578947,45,NA +"7660",30,9.21052631578947,45,NA +"7661",0.2,11.3157894736842,45,NA +"7662",0.260352117694686,11.3157894736842,45,NA +"7663",0.338916125940539,11.3157894736842,45,NA +"7664",0.441187655547492,11.3157894736842,45,NA +"7665",0.574320702112717,11.3157894736842,45,NA +"7666",0.747628055154725,11.3157894736842,45,NA +"7667",0.973232737037462,11.3157894736842,45,NA +"7668",1.2669160204875,11.3157894736842,45,NA +"7669",1.64922134437622,11.3157894736842,45,NA +"7670",2.14689134777813,11.3157894736842,45,NA +"7671",2.79473854427218,11.3157894736842,45,NA +"7672",3.63808049202114,11.3157894736842,45,NA +"7673",4.73590980220715,11.3157894736842,45,NA +"7674",6.16502073107827,11.3157894736842,45,NA +"7675",8.02538101483936,11.3157894736842,45,NA +"7676",10.4471247126008,11.3157894736842,45,NA +"7677",13.5996552137305,11.3157894736842,45,NA +"7678",17.7034951740616,11.3157894736842,45,NA +"7679",23.045712295823,11.3157894736842,45,NA +"7680",30,11.3157894736842,45,NA +"7681",0.2,13.4210526315789,45,NA +"7682",0.260352117694686,13.4210526315789,45,NA +"7683",0.338916125940539,13.4210526315789,45,NA +"7684",0.441187655547492,13.4210526315789,45,NA +"7685",0.574320702112717,13.4210526315789,45,NA +"7686",0.747628055154725,13.4210526315789,45,NA +"7687",0.973232737037462,13.4210526315789,45,NA +"7688",1.2669160204875,13.4210526315789,45,NA +"7689",1.64922134437622,13.4210526315789,45,NA +"7690",2.14689134777813,13.4210526315789,45,NA +"7691",2.79473854427218,13.4210526315789,45,NA +"7692",3.63808049202114,13.4210526315789,45,NA +"7693",4.73590980220715,13.4210526315789,45,NA +"7694",6.16502073107827,13.4210526315789,45,NA +"7695",8.02538101483936,13.4210526315789,45,NA +"7696",10.4471247126008,13.4210526315789,45,NA +"7697",13.5996552137305,13.4210526315789,45,NA +"7698",17.7034951740616,13.4210526315789,45,NA +"7699",23.045712295823,13.4210526315789,45,NA +"7700",30,13.4210526315789,45,NA +"7701",0.2,15.5263157894737,45,NA +"7702",0.260352117694686,15.5263157894737,45,NA +"7703",0.338916125940539,15.5263157894737,45,NA +"7704",0.441187655547492,15.5263157894737,45,NA +"7705",0.574320702112717,15.5263157894737,45,NA +"7706",0.747628055154725,15.5263157894737,45,NA +"7707",0.973232737037462,15.5263157894737,45,NA +"7708",1.2669160204875,15.5263157894737,45,NA +"7709",1.64922134437622,15.5263157894737,45,NA +"7710",2.14689134777813,15.5263157894737,45,NA +"7711",2.79473854427218,15.5263157894737,45,NA +"7712",3.63808049202114,15.5263157894737,45,NA +"7713",4.73590980220715,15.5263157894737,45,NA +"7714",6.16502073107827,15.5263157894737,45,NA +"7715",8.02538101483936,15.5263157894737,45,NA +"7716",10.4471247126008,15.5263157894737,45,NA +"7717",13.5996552137305,15.5263157894737,45,NA +"7718",17.7034951740616,15.5263157894737,45,NA +"7719",23.045712295823,15.5263157894737,45,NA +"7720",30,15.5263157894737,45,NA +"7721",0.2,17.6315789473684,45,NA +"7722",0.260352117694686,17.6315789473684,45,NA +"7723",0.338916125940539,17.6315789473684,45,NA +"7724",0.441187655547492,17.6315789473684,45,NA +"7725",0.574320702112717,17.6315789473684,45,NA +"7726",0.747628055154725,17.6315789473684,45,NA +"7727",0.973232737037462,17.6315789473684,45,NA +"7728",1.2669160204875,17.6315789473684,45,NA +"7729",1.64922134437622,17.6315789473684,45,NA +"7730",2.14689134777813,17.6315789473684,45,NA +"7731",2.79473854427218,17.6315789473684,45,NA +"7732",3.63808049202114,17.6315789473684,45,NA +"7733",4.73590980220715,17.6315789473684,45,NA +"7734",6.16502073107827,17.6315789473684,45,NA +"7735",8.02538101483936,17.6315789473684,45,NA +"7736",10.4471247126008,17.6315789473684,45,NA +"7737",13.5996552137305,17.6315789473684,45,NA +"7738",17.7034951740616,17.6315789473684,45,NA +"7739",23.045712295823,17.6315789473684,45,NA +"7740",30,17.6315789473684,45,NA +"7741",0.2,19.7368421052632,45,NA +"7742",0.260352117694686,19.7368421052632,45,NA +"7743",0.338916125940539,19.7368421052632,45,NA +"7744",0.441187655547492,19.7368421052632,45,NA +"7745",0.574320702112717,19.7368421052632,45,NA +"7746",0.747628055154725,19.7368421052632,45,NA +"7747",0.973232737037462,19.7368421052632,45,NA +"7748",1.2669160204875,19.7368421052632,45,NA +"7749",1.64922134437622,19.7368421052632,45,NA +"7750",2.14689134777813,19.7368421052632,45,NA +"7751",2.79473854427218,19.7368421052632,45,NA +"7752",3.63808049202114,19.7368421052632,45,NA +"7753",4.73590980220715,19.7368421052632,45,NA +"7754",6.16502073107827,19.7368421052632,45,NA +"7755",8.02538101483936,19.7368421052632,45,NA +"7756",10.4471247126008,19.7368421052632,45,NA +"7757",13.5996552137305,19.7368421052632,45,NA +"7758",17.7034951740616,19.7368421052632,45,NA +"7759",23.045712295823,19.7368421052632,45,NA +"7760",30,19.7368421052632,45,NA +"7761",0.2,21.8421052631579,45,NA +"7762",0.260352117694686,21.8421052631579,45,NA +"7763",0.338916125940539,21.8421052631579,45,NA +"7764",0.441187655547492,21.8421052631579,45,NA +"7765",0.574320702112717,21.8421052631579,45,NA +"7766",0.747628055154725,21.8421052631579,45,NA +"7767",0.973232737037462,21.8421052631579,45,NA +"7768",1.2669160204875,21.8421052631579,45,NA +"7769",1.64922134437622,21.8421052631579,45,NA +"7770",2.14689134777813,21.8421052631579,45,NA +"7771",2.79473854427218,21.8421052631579,45,NA +"7772",3.63808049202114,21.8421052631579,45,NA +"7773",4.73590980220715,21.8421052631579,45,NA +"7774",6.16502073107827,21.8421052631579,45,NA +"7775",8.02538101483936,21.8421052631579,45,NA +"7776",10.4471247126008,21.8421052631579,45,NA +"7777",13.5996552137305,21.8421052631579,45,NA +"7778",17.7034951740616,21.8421052631579,45,NA +"7779",23.045712295823,21.8421052631579,45,NA +"7780",30,21.8421052631579,45,NA +"7781",0.2,23.9473684210526,45,NA +"7782",0.260352117694686,23.9473684210526,45,NA +"7783",0.338916125940539,23.9473684210526,45,NA +"7784",0.441187655547492,23.9473684210526,45,NA +"7785",0.574320702112717,23.9473684210526,45,NA +"7786",0.747628055154725,23.9473684210526,45,NA +"7787",0.973232737037462,23.9473684210526,45,NA +"7788",1.2669160204875,23.9473684210526,45,NA +"7789",1.64922134437622,23.9473684210526,45,NA +"7790",2.14689134777813,23.9473684210526,45,NA +"7791",2.79473854427218,23.9473684210526,45,NA +"7792",3.63808049202114,23.9473684210526,45,NA +"7793",4.73590980220715,23.9473684210526,45,NA +"7794",6.16502073107827,23.9473684210526,45,NA +"7795",8.02538101483936,23.9473684210526,45,NA +"7796",10.4471247126008,23.9473684210526,45,NA +"7797",13.5996552137305,23.9473684210526,45,NA +"7798",17.7034951740616,23.9473684210526,45,NA +"7799",23.045712295823,23.9473684210526,45,NA +"7800",30,23.9473684210526,45,NA +"7801",0.2,26.0526315789474,45,NA +"7802",0.260352117694686,26.0526315789474,45,NA +"7803",0.338916125940539,26.0526315789474,45,NA +"7804",0.441187655547492,26.0526315789474,45,NA +"7805",0.574320702112717,26.0526315789474,45,NA +"7806",0.747628055154725,26.0526315789474,45,NA +"7807",0.973232737037462,26.0526315789474,45,NA +"7808",1.2669160204875,26.0526315789474,45,NA +"7809",1.64922134437622,26.0526315789474,45,NA +"7810",2.14689134777813,26.0526315789474,45,NA +"7811",2.79473854427218,26.0526315789474,45,NA +"7812",3.63808049202114,26.0526315789474,45,NA +"7813",4.73590980220715,26.0526315789474,45,NA +"7814",6.16502073107827,26.0526315789474,45,NA +"7815",8.02538101483936,26.0526315789474,45,NA +"7816",10.4471247126008,26.0526315789474,45,NA +"7817",13.5996552137305,26.0526315789474,45,NA +"7818",17.7034951740616,26.0526315789474,45,NA +"7819",23.045712295823,26.0526315789474,45,NA +"7820",30,26.0526315789474,45,NA +"7821",0.2,28.1578947368421,45,NA +"7822",0.260352117694686,28.1578947368421,45,NA +"7823",0.338916125940539,28.1578947368421,45,NA +"7824",0.441187655547492,28.1578947368421,45,NA +"7825",0.574320702112717,28.1578947368421,45,NA +"7826",0.747628055154725,28.1578947368421,45,NA +"7827",0.973232737037462,28.1578947368421,45,NA +"7828",1.2669160204875,28.1578947368421,45,NA +"7829",1.64922134437622,28.1578947368421,45,NA +"7830",2.14689134777813,28.1578947368421,45,NA +"7831",2.79473854427218,28.1578947368421,45,NA +"7832",3.63808049202114,28.1578947368421,45,NA +"7833",4.73590980220715,28.1578947368421,45,NA +"7834",6.16502073107827,28.1578947368421,45,NA +"7835",8.02538101483936,28.1578947368421,45,NA +"7836",10.4471247126008,28.1578947368421,45,NA +"7837",13.5996552137305,28.1578947368421,45,NA +"7838",17.7034951740616,28.1578947368421,45,NA +"7839",23.045712295823,28.1578947368421,45,NA +"7840",30,28.1578947368421,45,NA +"7841",0.2,30.2631578947368,45,NA +"7842",0.260352117694686,30.2631578947368,45,NA +"7843",0.338916125940539,30.2631578947368,45,NA +"7844",0.441187655547492,30.2631578947368,45,NA +"7845",0.574320702112717,30.2631578947368,45,NA +"7846",0.747628055154725,30.2631578947368,45,NA +"7847",0.973232737037462,30.2631578947368,45,NA +"7848",1.2669160204875,30.2631578947368,45,NA +"7849",1.64922134437622,30.2631578947368,45,NA +"7850",2.14689134777813,30.2631578947368,45,NA +"7851",2.79473854427218,30.2631578947368,45,NA +"7852",3.63808049202114,30.2631578947368,45,NA +"7853",4.73590980220715,30.2631578947368,45,NA +"7854",6.16502073107827,30.2631578947368,45,NA +"7855",8.02538101483936,30.2631578947368,45,NA +"7856",10.4471247126008,30.2631578947368,45,NA +"7857",13.5996552137305,30.2631578947368,45,NA +"7858",17.7034951740616,30.2631578947368,45,NA +"7859",23.045712295823,30.2631578947368,45,NA +"7860",30,30.2631578947368,45,NA +"7861",0.2,32.3684210526316,45,NA +"7862",0.260352117694686,32.3684210526316,45,NA +"7863",0.338916125940539,32.3684210526316,45,NA +"7864",0.441187655547492,32.3684210526316,45,NA +"7865",0.574320702112717,32.3684210526316,45,NA +"7866",0.747628055154725,32.3684210526316,45,NA +"7867",0.973232737037462,32.3684210526316,45,NA +"7868",1.2669160204875,32.3684210526316,45,NA +"7869",1.64922134437622,32.3684210526316,45,NA +"7870",2.14689134777813,32.3684210526316,45,NA +"7871",2.79473854427218,32.3684210526316,45,NA +"7872",3.63808049202114,32.3684210526316,45,NA +"7873",4.73590980220715,32.3684210526316,45,NA +"7874",6.16502073107827,32.3684210526316,45,NA +"7875",8.02538101483936,32.3684210526316,45,NA +"7876",10.4471247126008,32.3684210526316,45,NA +"7877",13.5996552137305,32.3684210526316,45,NA +"7878",17.7034951740616,32.3684210526316,45,NA +"7879",23.045712295823,32.3684210526316,45,NA +"7880",30,32.3684210526316,45,NA +"7881",0.2,34.4736842105263,45,NA +"7882",0.260352117694686,34.4736842105263,45,NA +"7883",0.338916125940539,34.4736842105263,45,NA +"7884",0.441187655547492,34.4736842105263,45,NA +"7885",0.574320702112717,34.4736842105263,45,NA +"7886",0.747628055154725,34.4736842105263,45,NA +"7887",0.973232737037462,34.4736842105263,45,NA +"7888",1.2669160204875,34.4736842105263,45,NA +"7889",1.64922134437622,34.4736842105263,45,NA +"7890",2.14689134777813,34.4736842105263,45,NA +"7891",2.79473854427218,34.4736842105263,45,NA +"7892",3.63808049202114,34.4736842105263,45,NA +"7893",4.73590980220715,34.4736842105263,45,NA +"7894",6.16502073107827,34.4736842105263,45,NA +"7895",8.02538101483936,34.4736842105263,45,NA +"7896",10.4471247126008,34.4736842105263,45,NA +"7897",13.5996552137305,34.4736842105263,45,NA +"7898",17.7034951740616,34.4736842105263,45,NA +"7899",23.045712295823,34.4736842105263,45,NA +"7900",30,34.4736842105263,45,NA +"7901",0.2,36.5789473684211,45,NA +"7902",0.260352117694686,36.5789473684211,45,NA +"7903",0.338916125940539,36.5789473684211,45,NA +"7904",0.441187655547492,36.5789473684211,45,NA +"7905",0.574320702112717,36.5789473684211,45,NA +"7906",0.747628055154725,36.5789473684211,45,NA +"7907",0.973232737037462,36.5789473684211,45,NA +"7908",1.2669160204875,36.5789473684211,45,NA +"7909",1.64922134437622,36.5789473684211,45,NA +"7910",2.14689134777813,36.5789473684211,45,NA +"7911",2.79473854427218,36.5789473684211,45,NA +"7912",3.63808049202114,36.5789473684211,45,NA +"7913",4.73590980220715,36.5789473684211,45,NA +"7914",6.16502073107827,36.5789473684211,45,NA +"7915",8.02538101483936,36.5789473684211,45,NA +"7916",10.4471247126008,36.5789473684211,45,NA +"7917",13.5996552137305,36.5789473684211,45,NA +"7918",17.7034951740616,36.5789473684211,45,NA +"7919",23.045712295823,36.5789473684211,45,NA +"7920",30,36.5789473684211,45,NA +"7921",0.2,38.6842105263158,45,NA +"7922",0.260352117694686,38.6842105263158,45,NA +"7923",0.338916125940539,38.6842105263158,45,NA +"7924",0.441187655547492,38.6842105263158,45,NA +"7925",0.574320702112717,38.6842105263158,45,NA +"7926",0.747628055154725,38.6842105263158,45,NA +"7927",0.973232737037462,38.6842105263158,45,NA +"7928",1.2669160204875,38.6842105263158,45,NA +"7929",1.64922134437622,38.6842105263158,45,NA +"7930",2.14689134777813,38.6842105263158,45,NA +"7931",2.79473854427218,38.6842105263158,45,NA +"7932",3.63808049202114,38.6842105263158,45,NA +"7933",4.73590980220715,38.6842105263158,45,NA +"7934",6.16502073107827,38.6842105263158,45,NA +"7935",8.02538101483936,38.6842105263158,45,NA +"7936",10.4471247126008,38.6842105263158,45,NA +"7937",13.5996552137305,38.6842105263158,45,NA +"7938",17.7034951740616,38.6842105263158,45,NA +"7939",23.045712295823,38.6842105263158,45,NA +"7940",30,38.6842105263158,45,NA +"7941",0.2,40.7894736842105,45,NA +"7942",0.260352117694686,40.7894736842105,45,NA +"7943",0.338916125940539,40.7894736842105,45,NA +"7944",0.441187655547492,40.7894736842105,45,NA +"7945",0.574320702112717,40.7894736842105,45,NA +"7946",0.747628055154725,40.7894736842105,45,NA +"7947",0.973232737037462,40.7894736842105,45,NA +"7948",1.2669160204875,40.7894736842105,45,NA +"7949",1.64922134437622,40.7894736842105,45,NA +"7950",2.14689134777813,40.7894736842105,45,NA +"7951",2.79473854427218,40.7894736842105,45,NA +"7952",3.63808049202114,40.7894736842105,45,NA +"7953",4.73590980220715,40.7894736842105,45,NA +"7954",6.16502073107827,40.7894736842105,45,NA +"7955",8.02538101483936,40.7894736842105,45,NA +"7956",10.4471247126008,40.7894736842105,45,NA +"7957",13.5996552137305,40.7894736842105,45,NA +"7958",17.7034951740616,40.7894736842105,45,NA +"7959",23.045712295823,40.7894736842105,45,NA +"7960",30,40.7894736842105,45,NA +"7961",0.2,42.8947368421053,45,NA +"7962",0.260352117694686,42.8947368421053,45,NA +"7963",0.338916125940539,42.8947368421053,45,NA +"7964",0.441187655547492,42.8947368421053,45,NA +"7965",0.574320702112717,42.8947368421053,45,NA +"7966",0.747628055154725,42.8947368421053,45,NA +"7967",0.973232737037462,42.8947368421053,45,NA +"7968",1.2669160204875,42.8947368421053,45,NA +"7969",1.64922134437622,42.8947368421053,45,NA +"7970",2.14689134777813,42.8947368421053,45,NA +"7971",2.79473854427218,42.8947368421053,45,NA +"7972",3.63808049202114,42.8947368421053,45,NA +"7973",4.73590980220715,42.8947368421053,45,NA +"7974",6.16502073107827,42.8947368421053,45,NA +"7975",8.02538101483936,42.8947368421053,45,NA +"7976",10.4471247126008,42.8947368421053,45,NA +"7977",13.5996552137305,42.8947368421053,45,NA +"7978",17.7034951740616,42.8947368421053,45,NA +"7979",23.045712295823,42.8947368421053,45,NA +"7980",30,42.8947368421053,45,NA +"7981",0.2,45,45,NA +"7982",0.260352117694686,45,45,NA +"7983",0.338916125940539,45,45,NA +"7984",0.441187655547492,45,45,NA +"7985",0.574320702112717,45,45,NA +"7986",0.747628055154725,45,45,NA +"7987",0.973232737037462,45,45,NA +"7988",1.2669160204875,45,45,NA +"7989",1.64922134437622,45,45,NA +"7990",2.14689134777813,45,45,NA +"7991",2.79473854427218,45,45,NA +"7992",3.63808049202114,45,45,NA +"7993",4.73590980220715,45,45,NA +"7994",6.16502073107827,45,45,NA +"7995",8.02538101483936,45,45,NA +"7996",10.4471247126008,45,45,NA +"7997",13.5996552137305,45,45,NA +"7998",17.7034951740616,45,45,NA +"7999",23.045712295823,45,45,NA +"8000",30,45,45,NA From d2ad700d0685c4d41f2b2b89b0a57ac7d9f53008 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 25 Jul 2024 18:09:46 +0100 Subject: [PATCH 019/241] Fixing typing and other issues --- pyrealm/pmodel/functions.py | 16 ++++++++------- pyrealm/pmodel/pmodel_environment.py | 30 ++++++++++++++++++++++++++-- pyrealm/pmodel/quantum_yield.py | 2 +- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index f666794a..3fed726f 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -13,7 +13,7 @@ def calc_ftemp_arrh( tk: NDArray, - ha: float, + ha: float | NDArray, tk_ref: NDArray | None = None, pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), @@ -199,9 +199,9 @@ def calc_ftemp_inst_vcmax( def calc_modified_arrhenius_factor( tk: NDArray, - Ha: NDArray, - Hd: NDArray, - deltaS: NDArray, + Ha: float | NDArray, + Hd: float | NDArray, + deltaS: float | NDArray, mode: str = "M2002", tk_ref: NDArray | None = None, pmodel_const: PModelConst = PModelConst(), @@ -250,7 +250,7 @@ def calc_modified_arrhenius_factor( # Convert temperatures to Kelvin if tk_ref is None: - tk_ref = pmodel_const.plant_T_ref + core_const.k_CtoK + tk_ref = np.array([pmodel_const.plant_T_ref + core_const.k_CtoK]) # Calculate Arrhenius components fva = calc_ftemp_arrh(tk=tk, ha=Ha, tk_ref=tk_ref) @@ -260,9 +260,11 @@ def calc_modified_arrhenius_factor( ) if mode == "M2002": + # Medlyn et al. 2002 simplification return fva * fvb - elif mode == "J1942": - return fva * (tk / tk_ref) * fvb + + # Johnson et al 1942 + return fva * (tk / tk_ref) * fvb def calc_ftemp_kphio( diff --git a/pyrealm/pmodel/pmodel_environment.py b/pyrealm/pmodel/pmodel_environment.py index 3b8be62d..14ff2f9b 100644 --- a/pyrealm/pmodel/pmodel_environment.py +++ b/pyrealm/pmodel/pmodel_environment.py @@ -81,6 +81,8 @@ def __init__( patm: NDArray, theta: NDArray | None = None, rootzonestress: NDArray | None = None, + aridity_index: NDArray | None = None, + mean_growth_temperature: NDArray | None = None, pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), ): @@ -132,10 +134,20 @@ def __init__( temperature and pressure, unitless""" # Optional variables - self.theta: NDArray | None = None + + # TODO - could this be done flexibly using kwargs and then setting the requires + # attributes for the downstream classes that use the PModelEnvironment. + # Easy to add the attributes dynamically, but bounds checking less + # obvious. + + self.theta: NDArray """Volumetric soil moisture (m3/m3)""" - self.rootzonestress: NDArray | None = None + self.rootzonestress: NDArray """Rootzone stress factor (experimental) (-)""" + self.aridity_index: NDArray + """Climatological aridity index as PET/P (-)""" + self.mean_growth_temperature: NDArray + """Mean temperature > 0°C during growing degree days (°C)""" if theta is not None: # Is the input congruent with the other variables and in bounds. @@ -149,6 +161,20 @@ def __init__( rootzonestress, 0, 1, "[]", "rootzonestress", "-" ) + if aridity_index is not None: + # Is the input congruent with the other variables and in bounds. + _ = check_input_shapes(tc, aridity_index) + self.aridity_index = bounds_checker( + aridity_index, 0, 50, "[]", "aridity_index", "-" + ) + + if mean_growth_temperature is not None: + # Is the input congruent with the other variables and in bounds. + _ = check_input_shapes(tc, mean_growth_temperature) + self.mean_growth_temperature = bounds_checker( + mean_growth_temperature, 0, 50, "[]", "mean_growth_temperature", "-" + ) + # Store constant settings self.pmodel_const = pmodel_const """PModel constants used to calculate environment""" diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index 04fc9338..c3fc7b1d 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -226,7 +226,7 @@ def _calculate_kphio(self, **kwargs: Any) -> None: # Calculate deaactivation energy J/mol Hd = 294.804 * deltaS # activation energy J/mol - Ha = 75000 + Ha = 75000.0 # theoretical maximum phi0 and curvature parameters (Long, 1993;Sandoval et al., # in.prep.) From 07a9912868b9fe72c745ce05b216c22a249e696f Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 25 Jul 2024 19:58:19 +0100 Subject: [PATCH 020/241] Regression test for QuantumYieldSandoval --- tests/regression/pmodel/test_quantum_yield.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tests/regression/pmodel/test_quantum_yield.py diff --git a/tests/regression/pmodel/test_quantum_yield.py b/tests/regression/pmodel/test_quantum_yield.py new file mode 100644 index 00000000..231567b2 --- /dev/null +++ b/tests/regression/pmodel/test_quantum_yield.py @@ -0,0 +1,45 @@ +"""Test quantum yield calculations against benchmarks.""" + +from importlib import resources + +import numpy as np +import pandas as pd +import pytest + + +@pytest.fixture(scope="module") +def values(): + """Fixture to load test inputs and expected rpmodel outputs from file.""" + + datapath = ( + resources.files("pyrealm_build_data.sandoval_kphio") / "sandoval_kphio.csv" + ) + + with open(str(datapath)) as infile: + values = pd.read_csv(infile) + + return values + + +def test_QuantumYieldSandoval(values): + """Check implementation against values from original R code.""" + from pyrealm.pmodel import PModelEnvironment + from pyrealm.pmodel.quantum_yield import QuantumYieldSandoval + + env = PModelEnvironment( + tc=values["temp"].to_numpy(), + patm=101325, + vpd=820, + co2=400, + mean_growth_temperature=values["mean_gdd_temp"].to_numpy(), + aridity_index=values["aridity_index"].to_numpy(), + ) + + # Calculate kphio for that environment + qy = QuantumYieldSandoval(env) + + # Get expected kphio, masking negative values from the reference implementation + expected = values["phio"].to_numpy() + expected = np.where(expected < 0, np.nan, expected) + + assert np.allclose(expected, qy.kphio, equal_nan=True) From 425b24855df3e2250f1e736acb081ca818b9dd1b Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 25 Jul 2024 20:33:05 +0100 Subject: [PATCH 021/241] Simpler sandoval test data set and test fixes --- pyrealm/pmodel/functions.py | 16 +- pyrealm/pmodel/optimal_chi.py | 2 +- pyrealm_build_data/sandoval_kphio/calc_phi0.R | 11 +- .../sandoval_kphio/sandoval_kphio.csv | 9838 +++-------------- 4 files changed, 1852 insertions(+), 8015 deletions(-) diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index 3fed726f..84692690 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -62,8 +62,8 @@ def calc_ftemp_arrh( Examples: >>> # Relative rate change from 25 to 10 degrees Celsius (percent change) - >>> round((1.0-calc_ftemp_arrh( 283.15, 100000)) * 100, 4) - np.float64(88.1991) + >>> np.round((1.0-calc_ftemp_arrh( 283.15, 100000)) * 100, 4) + array([88.1991]) """ # Note that the following forms are equivalent: @@ -174,8 +174,8 @@ def calc_ftemp_inst_vcmax( >>> # Relative change in Vcmax going (instantaneously, i.e. not >>> # not acclimatedly) from 10 to 25 degrees (percent change): >>> val = ((calc_ftemp_inst_vcmax(25)/calc_ftemp_inst_vcmax(10)-1) * 100) - >>> round(val, 4) - np.float64(283.1775) + >>> np.round(val, 4) + array([283.1775]) """ # Convert temperatures to Kelvin @@ -239,8 +239,8 @@ def calc_modified_arrhenius_factor( >>> # Relative change in Vcmax going (instantaneously, i.e. not >>> # not acclimatedly) from 10 to 25 degrees (percent change): >>> val = ((calc_ftemp_inst_vcmax(25)/calc_ftemp_inst_vcmax(10)-1) * 100) - >>> round(val, 4) - np.float64(283.1775) + >>> np.round(val, 4) + array([283.1775]) """ if mode not in ["M2002", "J1942"]: @@ -477,8 +477,8 @@ def calc_kmm( Examples: >>> # Michaelis-Menten coefficient at 20 degrees Celsius and standard >>> # atmosphere (in Pa): - >>> round(calc_kmm(20, 101325), 5) - np.float64(46.09928) + >>> np.round(calc_kmm(20, 101325), 5) + array([46.09928]) """ # Check inputs, return shape not used diff --git a/pyrealm/pmodel/optimal_chi.py b/pyrealm/pmodel/optimal_chi.py index 2a028a0f..3b5b5ba7 100644 --- a/pyrealm/pmodel/optimal_chi.py +++ b/pyrealm/pmodel/optimal_chi.py @@ -151,7 +151,7 @@ def _check_requires(self) -> None: """Check additional required variables are present.""" for required_var in self.requires: - if getattr(self.env, required_var) is None: + if not hasattr(self.env, required_var): raise ValueError( f"{self.__class__.__name__} (method {self.method}) requires " f"{required_var} to be provided in the PModelEnvironment." diff --git a/pyrealm_build_data/sandoval_kphio/calc_phi0.R b/pyrealm_build_data/sandoval_kphio/calc_phi0.R index 125f504d..836c74e1 100644 --- a/pyrealm_build_data/sandoval_kphio/calc_phi0.R +++ b/pyrealm_build_data/sandoval_kphio/calc_phi0.R @@ -69,16 +69,17 @@ calc_phi0 <- function(AI, tc, mGDD0 = NA) { } -aridity_index <- exp(seq(log(0.2), log(30), length = 20)) -temp <- seq(5, 45, length = 20) -mean_gdd_temp <- seq(5, 45, length = 20) +aridity_index <- c(0.2, 0.5, 0.8, 1.0, 5.0, 10.0) +temp <- seq(0, 50, by = 1) +mean_gdd_temp <- seq(5, 30, by = 5) data <- expand.grid( - aridity_index = aridity_index, temp = temp, + aridity_index = aridity_index, mean_gdd_temp = mean_gdd_temp ) +# Function is not parallelised so loop over inputs data$phio <- NA for (row_idx in seq_along(data$aridity_index)) { @@ -88,4 +89,4 @@ for (row_idx in seq_along(data$aridity_index)) { ) } -write.csv(data, "sandoval_kphio.csv") +write.csv(data, "sandoval_kphio.csv", row.names = FALSE) diff --git a/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv b/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv index 1555dbdb..bb4af59e 100644 --- a/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv +++ b/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv @@ -1,8001 +1,1837 @@ -"","aridity_index","temp","mean_gdd_temp","phio" -"1",0.2,5,5,0.0276881368424111 -"2",0.260352117694686,5,5,0.0276879584022285 -"3",0.338916125940539,5,5,0.0276868670405322 -"4",0.441187655547492,5,5,0.0276802027440709 -"5",0.574320702112717,5,5,0.0276398979166404 -"6",0.747628055154725,5,5,0.0274093291367171 -"7",0.973232737037462,5,5,0.0263883834725151 -"8",1.2669160204875,5,5,0.0239847712093153 -"9",1.64922134437622,5,5,0.0210119432069007 -"10",2.14689134777813,5,5,0.0182302846850997 -"11",2.79473854427218,5,5,0.0157891550428931 -"12",3.63808049202114,5,5,0.0136709140267692 -"13",4.73590980220715,5,5,0.0118362854838696 -"14",6.16502073107827,5,5,0.0102477828037349 -"15",8.02538101483936,5,5,0.00887245565279721 -"16",10.4471247126008,5,5,0.00768170582439186 -"17",13.5996552137305,5,5,0.00665076329089655 -"18",17.7034951740616,5,5,0.005758180945173 -"19",23.045712295823,5,5,0.0049853898442698 -"20",30,5,5,0.00431631310865178 -"21",0.2,7.10526315789474,5,0.0355860341585567 -"22",0.260352117694686,7.10526315789474,5,0.0355858048192382 -"23",0.338916125940539,7.10526315789474,5,0.0355844021522828 -"24",0.441187655547492,7.10526315789474,5,0.0355758368998477 -"25",0.574320702112717,7.10526315789474,5,0.0355240353295991 -"26",0.747628055154725,7.10526315789474,5,0.0352276980019938 -"27",0.973232737037462,7.10526315789474,5,0.0339155328864028 -"28",1.2669160204875,7.10526315789474,5,0.0308263027013246 -"29",1.64922134437622,7.10526315789474,5,0.027005490941994 -"30",2.14689134777813,7.10526315789474,5,0.0234303787653369 -"31",2.79473854427218,7.10526315789474,5,0.020292929563628 -"32",3.63808049202114,7.10526315789474,5,0.0175704712926049 -"33",4.73590980220715,7.10526315789474,5,0.0152125244806734 -"34",6.16502073107827,7.10526315789474,5,0.0131709096563185 -"35",8.02538101483936,7.10526315789474,5,0.0114032775743544 -"36",10.4471247126008,7.10526315789474,5,0.00987287253810712 -"37",13.5996552137305,7.10526315789474,5,0.00854785899814665 -"38",17.7034951740616,7.10526315789474,5,0.0074006721713469 -"39",23.045712295823,7.10526315789474,5,0.0064074464201636 -"40",30,7.10526315789474,5,0.00554751901862288 -"41",0.2,9.21052631578947,5,0.0455460855578743 -"42",0.260352117694686,9.21052631578947,5,0.0455457920295711 -"43",0.338916125940539,9.21052631578947,5,0.0455439967750375 -"44",0.441187655547492,9.21052631578947,5,0.0455330342238721 -"45",0.574320702112717,9.21052631578947,5,0.0454667340921951 -"46",0.747628055154725,9.21052631578947,5,0.0450874559400705 -"47",0.973232737037462,9.21052631578947,5,0.0434080334915199 -"48",1.2669160204875,9.21052631578947,5,0.0394541694084747 -"49",1.64922134437622,9.21052631578947,5,0.0345639639274247 -"50",2.14689134777813,9.21052631578947,5,0.0299882260311615 -"51",2.79473854427218,9.21052631578947,5,0.0259726470785359 -"52",3.63808049202114,9.21052631578947,5,0.0224882094256276 -"53",4.73590980220715,9.21052631578947,5,0.0194703050770102 -"54",6.16502073107827,9.21052631578947,5,0.0168572697763646 -"55",8.02538101483936,9.21052631578947,5,0.0145949012954805 -"56",10.4471247126008,9.21052631578947,5,0.0126361565135094 -"57",13.5996552137305,9.21052631578947,5,0.0109402895397553 -"58",17.7034951740616,9.21052631578947,5,0.0094720205797615 -"59",23.045712295823,9.21052631578947,5,0.0082008043256513 -"60",30,9.21052631578947,5,0.00710019483290408 -"61",0.2,11.3157894736842,5,0.0579899207005014 -"62",0.260352117694686,11.3157894736842,5,0.0579895469761118 -"63",0.338916125940539,11.3157894736842,5,0.0579872612326331 -"64",0.441187655547492,11.3157894736842,5,0.0579733035573474 -"65",0.574320702112717,11.3157894736842,5,0.0578888892914166 -"66",0.747628055154725,11.3157894736842,5,0.0574059869805871 -"67",0.973232737037462,11.3157894736842,5,0.0552677225519055 -"68",1.2669160204875,11.3157894736842,5,0.0502336068462867 -"69",1.64922134437622,11.3157894736842,5,0.0440073280216245 -"70",2.14689134777813,11.3157894736842,5,0.0381814337762583 -"71",2.79473854427218,11.3157894736842,5,0.0330687418253008 -"72",3.63808049202114,11.3157894736842,5,0.0286323064938552 -"73",4.73590980220715,11.3157894736842,5,0.0247898679678125 -"74",6.16502073107827,11.3157894736842,5,0.0214629144433541 -"75",8.02538101483936,11.3157894736842,5,0.0185824348764531 -"76",10.4471247126008,11.3157894736842,5,0.0160885332998908 -"77",13.5996552137305,11.3157894736842,5,0.0139293314689972 -"78",17.7034951740616,11.3157894736842,5,0.0120599106501903 -"79",23.045712295823,11.3157894736842,5,0.0104413801252044 -"80",30,11.3157894736842,5,0.00904006854321278 -"81",0.2,13.4210526315789,5,0.0731885108045797 -"82",0.260352117694686,13.4210526315789,5,0.0731880391306888 -"83",0.338916125940539,13.4210526315789,5,0.0731851543162372 -"84",0.441187655547492,13.4210526315789,5,0.0731675384709986 -"85",0.574320702112717,13.4210526315789,5,0.0730610000529511 -"86",0.747628055154725,13.4210526315789,5,0.0724515337773161 -"87",0.973232737037462,13.4210526315789,5,0.0697528511898737 -"88",1.2669160204875,13.4210526315789,5,0.0633993430756782 -"89",1.64922134437622,13.4210526315789,5,0.0555412175682368 -"90",2.14689134777813,13.4210526315789,5,0.0481884135158657 -"91",2.79473854427218,13.4210526315789,5,0.0417357350922185 -"92",3.63808049202114,13.4210526315789,5,0.0361365535229546 -"93",4.73590980220715,13.4210526315789,5,0.031287049502564 -"94",6.16502073107827,13.4210526315789,5,0.0270881340526063 -"95",8.02538101483936,13.4210526315789,5,0.0234527090104975 -"96",10.4471247126008,13.4210526315789,5,0.0203051802627955 -"97",13.5996552137305,13.4210526315789,5,0.0175800727851393 -"98",17.7034951740616,13.4210526315789,5,0.0152206950839318 -"99",23.045712295823,13.4210526315789,5,0.0131779635646516 -"100",30,13.4210526315789,5,0.0114093819452895 -"101",0.2,15.5263157894737,5,0.0905487587090105 -"102",0.260352117694686,15.5263157894737,5,0.0905481751545036 -"103",0.338916125940539,15.5263157894737,5,0.0905446060646994 -"104",0.441187655547492,15.5263157894737,5,0.0905228117570625 -"105",0.574320702112717,15.5263157894737,5,0.090391002523578 -"106",0.747628055154725,15.5263157894737,5,0.0896369714041157 -"107",0.973232737037462,15.5263157894737,5,0.0862981637722047 -"108",1.2669160204875,15.5263157894737,5,0.0784376093373134 -"109",1.64922134437622,15.5263157894737,5,0.0687155436379809 -"110",2.14689134777813,15.5263157894737,5,0.0596186611812453 -"111",2.79473854427218,15.5263157894737,5,0.0516354133300934 -"112",3.63808049202114,15.5263157894737,5,0.0447081110075068 -"113",4.73590980220715,15.5263157894737,5,0.0387083090635486 -"114",6.16502073107827,15.5263157894737,5,0.033513414704611 -"115",8.02538101483936,15.5263157894737,5,0.02901567016351 -"116",10.4471247126008,15.5263157894737,5,0.0251215504721512 -"117",13.5996552137305,15.5263157894737,5,0.0217500499902071 -"118",17.7034951740616,15.5263157894737,5,0.0188310300535877 -"119",23.045712295823,15.5263157894737,5,0.0163037644839893 -"120",30,15.5263157894737,5,0.0141156769201309 -"121",0.2,17.6315789473684,5,0.106348964803431 -"122",0.260352117694686,17.6315789473684,5,0.106348279422222 -"123",0.338916125940539,17.6315789473684,5,0.106344087548016 -"124",0.441187655547492,17.6315789473684,5,0.106318490266631 -"125",0.574320702112717,17.6315789473684,5,0.106163681125871 -"126",0.747628055154725,17.6315789473684,5,0.10527807617526 -"127",0.973232737037462,17.6315789473684,5,0.101356666976569 -"128",1.2669160204875,17.6315789473684,5,0.0921244937380803 -"129",1.64922134437622,17.6315789473684,5,0.0807059868737551 -"130",2.14689134777813,17.6315789473684,5,0.0700217539145677 -"131",2.79473854427218,17.6315789473684,5,0.0606454780070469 -"132",3.63808049202114,17.6315789473684,5,0.0525094036821078 -"133",4.73590980220715,17.6315789473684,5,0.0454626728945981 -"134",6.16502073107827,17.6315789473684,5,0.0393613011561779 -"135",8.02538101483936,17.6315789473684,5,0.0340787276265557 -"136",10.4471247126008,17.6315789473684,5,0.0295051078011581 -"137",13.5996552137305,17.6315789473684,5,0.025545301049513 -"138",17.7034951740616,17.6315789473684,5,0.022116929938456 -"139",23.045712295823,17.6315789473684,5,0.0191486719419673 -"140",30,17.6315789473684,5,0.016578776444411 -"141",0.2,19.7368421052632,5,0.109842441357903 -"142",0.260352117694686,19.7368421052632,5,0.109841733462481 -"143",0.338916125940539,19.7368421052632,5,0.109837403888635 -"144",0.441187655547492,19.7368421052632,5,0.109810965757481 -"145",0.574320702112717,19.7368421052632,5,0.109651071263003 -"146",0.747628055154725,19.7368421052632,5,0.108736374913738 -"147",0.973232737037462,19.7368421052632,5,0.104686150628587 -"148",1.2669160204875,19.7368421052632,5,0.0951507080464326 -"149",1.64922134437622,19.7368421052632,5,0.0833571125661408 -"150",2.14689134777813,19.7368421052632,5,0.0723219112885083 -"151",2.79473854427218,19.7368421052632,5,0.0626376323824464 -"152",3.63808049202114,19.7368421052632,5,0.0542342946671006 -"153",4.73590980220715,19.7368421052632,5,0.0469560845338602 -"154",6.16502073107827,19.7368421052632,5,0.0406542877216493 -"155",8.02538101483936,19.7368421052632,5,0.0351981859700352 -"156",10.4471247126008,19.7368421052632,5,0.0304743264722664 -"157",13.5996552137305,19.7368421052632,5,0.0263844433059361 -"158",17.7034951740616,19.7368421052632,5,0.0228434530065433 -"159",23.045712295823,19.7368421052632,5,0.0197776901613942 -"160",30,19.7368421052632,5,0.0171233756976096 -"161",0.2,21.8421052631579,5,0.0888418552461558 -"162",0.260352117694686,21.8421052631579,5,0.0888412826920339 -"163",0.338916125940539,21.8421052631579,5,0.0888377808819122 -"164",0.441187655547492,21.8421052631579,5,0.088816397411262 -"165",0.574320702112717,21.8421052631579,5,0.0886870728682391 -"166",0.747628055154725,21.8421052631579,5,0.0879472557297001 -"167",0.973232737037462,21.8421052631579,5,0.0846713868104779 -"168",1.2669160204875,21.8421052631579,5,0.0769590089798401 -"169",1.64922134437622,21.8421052631579,5,0.0674202105924496 -"170",2.14689134777813,21.8421052631579,5,0.0584948103336808 -"171",2.79473854427218,21.8421052631579,5,0.0506620519381133 -"172",3.63808049202114,21.8421052631579,5,0.0438653338056497 -"173",4.73590980220715,21.8421052631579,5,0.0379786320616346 -"174",6.16502073107827,21.8421052631579,5,0.0328816648669879 -"175",8.02538101483936,21.8421052631579,5,0.0284687057590801 -"176",10.4471247126008,21.8421052631579,5,0.0246479927767774 -"177",13.5996552137305,21.8421052631579,5,0.0213400472891778 -"178",17.7034951740616,21.8421052631579,5,0.01847605279199 -"179",23.045712295823,21.8421052631579,5,0.015996427835182 -"180",30,21.8421052631579,5,0.0138495871563503 -"181",0.2,23.9473684210526,5,0.0535735001038172 -"182",0.260352117694686,23.9473684210526,5,0.0535731548416857 -"183",0.338916125940539,23.9473684210526,5,0.0535710431768134 -"184",0.441187655547492,23.9473684210526,5,0.0535581484959907 -"185",0.574320702112717,23.9473684210526,5,0.0534801630869752 -"186",0.747628055154725,23.9473684210526,5,0.0530340378519887 -"187",0.973232737037462,23.9473684210526,5,0.0510586202585832 -"188",1.2669160204875,23.9473684210526,5,0.0464078948390662 -"189",1.64922134437622,23.9473684210526,5,0.0406557995571605 -"190",2.14689134777813,23.9473684210526,5,0.0352735961985645 -"191",2.79473854427218,23.9473684210526,5,0.030550278776214 -"192",3.63808049202114,23.9473684210526,5,0.0264517153393489 -"193",4.73590980220715,23.9473684210526,5,0.0229019108511341 -"194",6.16502073107827,23.9473684210526,5,0.0198283328424919 -"195",8.02538101483936,23.9473684210526,5,0.0171672260413046 -"196",10.4471247126008,23.9473684210526,5,0.014863256062437 -"197",13.5996552137305,23.9473684210526,5,0.0128684956262403 -"198",17.7034951740616,23.9473684210526,5,0.0111414469388024 -"199",23.045712295823,23.9473684210526,5,0.00964618113741957 -"200",30,23.9473684210526,5,0.00835159122806211 -"201",0.2,26.0526315789474,5,0.0262903125252139 -"202",0.260352117694686,26.0526315789474,5,0.0262901430935113 -"203",0.338916125940539,26.0526315789474,5,0.0262891068287659 -"204",0.441187655547492,26.0526315789474,5,0.0262827789765986 -"205",0.574320702112717,26.0526315789474,5,0.0262445089219736 -"206",0.747628055154725,26.0526315789474,5,0.0260255803130448 -"207",0.973232737037462,26.0526315789474,5,0.0250561766750933 -"208",1.2669160204875,26.0526315789474,5,0.0227739097985382 -"209",1.64922134437622,26.0526315789474,5,0.0199511638076461 -"210",2.14689134777813,26.0526315789474,5,0.0173099361839601 -"211",2.79473854427218,26.0526315789474,5,0.0149920459780048 -"212",3.63808049202114,26.0526315789474,5,0.012980743497286 -"213",4.73590980220715,26.0526315789474,5,0.0112387354295338 -"214",6.16502073107827,26.0526315789474,5,0.00973042766055773 -"215",8.02538101483936,26.0526315789474,5,0.00842453334096666 -"216",10.4471247126008,26.0526315789474,5,0.00729389803291769 -"217",13.5996552137305,26.0526315789474,5,0.0063150022135496 -"218",17.7034951740616,26.0526315789474,5,0.00546748152419732 -"219",23.045712295823,26.0526315789474,5,0.00473370446743528 -"220",30,26.0526315789474,5,0.00409840579844705 -"221",0.2,28.1578947368421,5,0.0117694227293028 -"222",0.260352117694686,28.1578947368421,5,0.0117693468795642 -"223",0.338916125940539,28.1578947368421,5,0.0117688829734073 -"224",0.441187655547492,28.1578947368421,5,0.0117660501745558 -"225",0.574320702112717,28.1578947368421,5,0.0117489177631278 -"226",0.747628055154725,28.1578947368421,5,0.0116509096719896 -"227",0.973232737037462,28.1578947368421,5,0.0112169353249965 -"228",1.2669160204875,28.1578947368421,5,0.0101952295683418 -"229",1.64922134437622,28.1578947368421,5,0.00893156673465001 -"230",2.14689134777813,28.1578947368421,5,0.0077491644943701 -"231",2.79473854427218,28.1578947368421,5,0.00671151118964672 -"232",3.63808049202114,28.1578947368421,5,0.00581110846109899 -"233",4.73590980220715,28.1578947368421,5,0.00503126115698007 -"234",6.16502073107827,28.1578947368421,5,0.00435603480803706 -"235",8.02538101483936,28.1578947368421,5,0.00377142318456084 -"236",10.4471247126008,28.1578947368421,5,0.003265270019575 -"237",13.5996552137305,28.1578947368421,5,0.00282704629381896 -"238",17.7034951740616,28.1578947368421,5,0.00244763546501079 -"239",23.045712295823,28.1578947368421,5,0.00211914441486395 -"240",30,28.1578947368421,5,0.0018347393288645 -"241",0.2,30.2631578947368,5,0.00512403416617755 -"242",0.260352117694686,30.2631578947368,5,0.00512400114360193 -"243",0.338916125940539,30.2631578947368,5,0.00512379917354337 -"244",0.441187655547492,30.2631578947368,5,0.00512256586257863 -"245",0.574320702112717,30.2631578947368,5,0.0051151069528661 -"246",0.747628055154725,30.2631578947368,5,0.00507243733184013 -"247",0.973232737037462,30.2631578947368,5,0.00488349863600239 -"248",1.2669160204875,30.2631578947368,5,0.00443868028549447 -"249",1.64922134437622,30.2631578947368,5,0.00388852148133799 -"250",2.14689134777813,30.2631578947368,5,0.00337374096773857 -"251",2.79473854427218,30.2631578947368,5,0.00292197955952509 -"252",3.63808049202114,30.2631578947368,5,0.00252997270833848 -"253",4.73590980220715,30.2631578947368,5,0.00219045187349261 -"254",6.16502073107827,30.2631578947368,5,0.00189647969138439 -"255",8.02538101483936,30.2631578947368,5,0.00164195829288126 -"256",10.4471247126008,30.2631578947368,5,0.00142159522407508 -"257",13.5996552137305,30.2631578947368,5,0.00123080648321246 -"258",17.7034951740616,30.2631578947368,5,0.00106562301631306 -"259",23.045712295823,30.2631578947368,5,0.000922608409484029 -"260",30,30.2631578947368,5,0.000798787436169208 -"261",0.2,32.3684210526316,5,0.00222578274938186 -"262",0.260352117694686,32.3684210526316,5,0.0022257684050046 -"263",0.338916125940539,32.3684210526316,5,0.00222568067306183 -"264",0.441187655547492,32.3684210526316,5,0.00222514494629247 -"265",0.574320702112717,32.3684210526316,5,0.00222190493812138 -"266",0.747628055154725,32.3684210526316,5,0.00220337006826646 -"267",0.973232737037462,32.3684210526316,5,0.00212129870101013 -"268",1.2669160204875,32.3684210526316,5,0.00192807809024523 -"269",1.64922134437622,32.3684210526316,5,0.00168909959478654 -"270",2.14689134777813,32.3684210526316,5,0.00146548875424012 -"271",2.79473854427218,32.3684210526316,5,0.00126925221158098 -"272",3.63808049202114,32.3684210526316,5,0.00109897190924226 -"273",4.73590980220715,32.3684210526316,5,0.000951490531728452 -"274",6.16502073107827,32.3684210526316,5,0.000823794620554866 -"275",8.02538101483936,32.3684210526316,5,0.0007132353776294 -"276",10.4471247126008,32.3684210526316,5,0.000617513861877773 -"277",13.5996552137305,32.3684210526316,5,0.000534638870334714 -"278",17.7034951740616,32.3684210526316,5,0.000462886321623268 -"279",23.045712295823,32.3684210526316,5,0.000400763503065414 -"280",30,32.3684210526316,5,0.000346978032969419 -"281",0.2,34.4736842105263,5,0.00097334128672763 -"282",0.260352117694686,34.4736842105263,5,0.000973335013889629 -"283",0.338916125940539,34.4736842105263,5,0.000973296648455226 -"284",0.441187655547492,34.4736842105263,5,0.000973062373576795 -"285",0.574320702112717,34.4736842105263,5,0.000971645508555656 -"286",0.747628055154725,34.4736842105263,5,0.000963540155920081 -"287",0.973232737037462,34.4736842105263,5,0.00092765010769729 -"288",1.2669160204875,34.4736842105263,5,0.000843154171174989 -"289",1.64922134437622,34.4736842105263,5,0.000738648178245267 -"290",2.14689134777813,34.4736842105263,5,0.000640862505621045 -"291",2.79473854427218,34.4736842105263,5,0.000555047693286875 -"292",3.63808049202114,34.4736842105263,5,0.000480583620533697 -"293",4.73590980220715,34.4736842105263,5,0.000416089584088533 -"294",6.16502073107827,34.4736842105263,5,0.000360247789768727 -"295",8.02538101483936,34.4736842105263,5,0.000311899910444659 -"296",10.4471247126008,34.4736842105263,5,0.000270040612480793 -"297",13.5996552137305,34.4736842105263,5,0.000233799137014032 -"298",17.7034951740616,34.4736842105263,5,0.000202421538230781 -"299",23.045712295823,34.4736842105263,5,0.000175255048524163 -"300",30,34.4736842105263,5,0.000151734505611777 -"301",0.2,36.5789473684211,5,0.000429770626656847 -"302",0.260352117694686,36.5789473684211,5,0.000429767856938193 -"303",0.338916125940539,36.5789473684211,5,0.000429750917004574 -"304",0.441187655547492,36.5789473684211,5,0.000429647474910125 -"305",0.574320702112717,36.5789473684211,5,0.000429021870123472 -"306",0.747628055154725,36.5789473684211,5,0.000425443020105534 -"307",0.973232737037462,36.5789473684211,5,0.000409596072353722 -"308",1.2669160204875,36.5789473684211,5,0.000372287605031604 -"309",1.64922134437622,36.5789473684211,5,0.000326143866259563 -"310",2.14689134777813,36.5789473684211,5,0.000282967428174764 -"311",2.79473854427218,36.5789473684211,5,0.000245076622373966 -"312",3.63808049202114,36.5789473684211,5,0.000212197639794128 -"313",4.73590980220715,36.5789473684211,5,0.000183720842563165 -"314",6.16502073107827,36.5789473684211,5,0.000159064369786642 -"315",8.02538101483936,36.5789473684211,5,0.000137716771900918 -"316",10.4471247126008,36.5789473684211,5,0.000119234152327851 -"317",13.5996552137305,36.5789473684211,5,0.000103232034843774 -"318",17.7034951740616,36.5789473684211,5,8.93775210407048e-05 -"319",23.045712295823,36.5789473684211,5,7.7382386893532e-05 -"320",30,36.5789473684211,5,6.69970897684607e-05 -"321",0.2,38.6842105263158,5,0.00019176639425231 -"322",0.260352117694686,38.6842105263158,5,0.000191765158386184 -"323",0.338916125940539,38.6842105263158,5,0.000191757599679778 -"324",0.441187655547492,38.6842105263158,5,0.000191711443157586 -"325",0.574320702112717,38.6842105263158,5,0.000191432294312314 -"326",0.747628055154725,38.6842105263158,5,0.00018983538861206 -"327",0.973232737037462,38.6842105263158,5,0.000182764379469557 -"328",1.2669160204875,38.6842105263158,5,0.000166117103435136 -"329",1.64922134437622,38.6842105263158,5,0.000145527472937424 -"330",2.14689134777813,38.6842105263158,5,0.000126261870928771 -"331",2.79473854427218,38.6842105263158,5,0.000109354751751603 -"332",3.63808049202114,38.6842105263158,5,9.46839400559162e-05 -"333",4.73590980220715,38.6842105263158,5,8.19774115355382e-05 -"334",6.16502073107827,38.6842105263158,5,7.09755361488579e-05 -"335",8.02538101483936,38.6842105263158,5,6.14501018390763e-05 -"336",10.4471247126008,38.6842105263158,5,5.32030391223072e-05 -"337",13.5996552137305,38.6842105263158,5,4.60627922557534e-05 -"338",17.7034951740616,38.6842105263158,5,3.98808198468881e-05 -"339",23.045712295823,38.6842105263158,5,3.45285144977076e-05 -"340",30,38.6842105263158,5,2.98945286936848e-05 -"341",0.2,40.7894736842105,5,8.64848587374021e-05 -"342",0.260352117694686,40.7894736842105,5,8.64843013732834e-05 -"343",0.338916125940539,40.7894736842105,5,8.6480892467055e-05 -"344",0.441187655547492,40.7894736842105,5,8.64600763051977e-05 -"345",0.574320702112717,40.7894736842105,5,8.63341827744556e-05 -"346",0.747628055154725,40.7894736842105,5,8.56139931685455e-05 -"347",0.973232737037462,40.7894736842105,5,8.24250338662414e-05 -"348",1.2669160204875,40.7894736842105,5,7.4917267337007e-05 -"349",1.64922134437622,40.7894736842105,5,6.56315356425e-05 -"350",2.14689134777813,40.7894736842105,5,5.69429284717511e-05 -"351",2.79473854427218,40.7894736842105,5,4.93179751039051e-05 -"352",3.63808049202114,40.7894736842105,5,4.27015755933886e-05 -"353",4.73590980220715,40.7894736842105,5,3.69710495102742e-05 -"354",6.16502073107827,40.7894736842105,5,3.2009306122579e-05 -"355",8.02538101483936,40.7894736842105,5,2.7713423917014e-05 -"356",10.4471247126008,40.7894736842105,5,2.39940754000895e-05 -"357",13.5996552137305,40.7894736842105,5,2.07738905287424e-05 -"358",17.7034951740616,40.7894736842105,5,1.79858785176504e-05 -"359",23.045712295823,40.7894736842105,5,1.55720386274647e-05 -"360",30,40.7894736842105,5,1.34821541656192e-05 -"361",0.2,42.8947368421053,5,3.94187457033001e-05 -"362",0.260352117694686,42.8947368421053,5,3.94184916635205e-05 -"363",0.338916125940539,42.8947368421053,5,3.94169379255632e-05 -"364",0.441187655547492,42.8947368421053,5,3.94074501724149e-05 -"365",0.574320702112717,42.8947368421053,5,3.93500694337924e-05 -"366",0.747628055154725,42.8947368421053,5,3.90218157793611e-05 -"367",0.973232737037462,42.8947368421053,5,3.75683269533299e-05 -"368",1.2669160204875,42.8947368421053,5,3.41463783725473e-05 -"369",1.64922134437622,42.8947368421053,5,2.99140549152558e-05 -"370",2.14689134777813,42.8947368421053,5,2.59538935462056e-05 -"371",2.79473854427218,42.8947368421053,5,2.24785326310741e-05 -"372",3.63808049202114,42.8947368421053,5,1.94628582854825e-05 -"373",4.73590980220715,42.8947368421053,5,1.68509542630421e-05 -"374",6.16502073107827,42.8947368421053,5,1.4589452033635e-05 -"375",8.02538101483936,42.8947368421053,5,1.26314412245214e-05 -"376",10.4471247126008,42.8947368421053,5,1.09362074516854e-05 -"377",13.5996552137305,42.8947368421053,5,9.46848639143988e-06 -"378",17.7034951740616,42.8947368421053,5,8.19774445941366e-06 -"379",23.045712295823,42.8947368421053,5,7.09754562474105e-06 -"380",30,42.8947368421053,5,6.14500173031322e-06 -"381",0.2,45,5,1.81547071246715e-05 -"382",0.260352117694686,45,5,1.81545901240487e-05 -"383",0.338916125940539,45,5,1.81538745341166e-05 -"384",0.441187655547492,45,5,1.81495048522151e-05 -"385",0.574320702112717,45,5,1.81230775652555e-05 -"386",0.747628055154725,45,5,1.79718969821984e-05 -"387",0.973232737037462,45,5,1.73024778143691e-05 -"388",1.2669160204875,45,5,1.57264643423171e-05 -"389",1.64922134437622,45,5,1.37772244197091e-05 -"390",2.14689134777813,45,5,1.19533315347682e-05 -"391",2.79473854427218,45,5,1.03527184649956e-05 -"392",3.63808049202114,45,5,8.96381875368349e-06 -"393",4.73590980220715,45,5,7.76087960077208e-06 -"394",6.16502073107827,45,5,6.71932158302827e-06 -"395",8.02538101483936,45,5,5.81753964775418e-06 -"396",10.4471247126008,45,5,5.03678236832831e-06 -"397",13.5996552137305,45,5,4.36080839924183e-06 -"398",17.7034951740616,45,5,3.77555518543793e-06 -"399",23.045712295823,45,5,3.26884734210049e-06 -"400",30,45,5,2.83014349401525e-06 -"401",0.2,5,7.10526315789474,0.0283427684942027 -"402",0.260352117694686,5,7.10526315789474,0.0283425858351522 -"403",0.338916125940539,5,7.10526315789474,0.0283414686703506 -"404",0.441187655547492,5,7.10526315789474,0.0283346468096796 -"405",0.574320702112717,5,7.10526315789474,0.0282933890537113 -"406",0.747628055154725,5,7.10526315789474,0.0280573689275269 -"407",0.973232737037462,5,7.10526315789474,0.0270122850069175 -"408",1.2669160204875,5,7.10526315789474,0.0245518440493538 -"409",1.64922134437622,5,7.10526315789474,0.0215087293636282 -"410",2.14689134777813,5,7.10526315789474,0.0186613039856746 -"411",2.79473854427218,5,7.10526315789474,0.0161624586243132 -"412",3.63808049202114,5,7.10526315789474,0.0139941359568609 -"413",4.73590980220715,5,7.10526315789474,0.0121161312229124 -"414",6.16502073107827,5,7.10526315789474,0.0104900715146797 -"415",8.02538101483936,5,7.10526315789474,0.00908222745262962 -"416",10.4471247126008,5,7.10526315789474,0.00786332468163098 -"417",13.5996552137305,5,7.10526315789474,0.00680800753537478 -"418",17.7034951740616,5,7.10526315789474,0.00589432183196895 -"419",23.045712295823,5,7.10526315789474,0.00510325960225152 -"420",30,5,7.10526315789474,0.00441836386042496 -"421",0.2,7.10526315789474,7.10526315789474,0.0364210918339983 -"422",0.260352117694686,7.10526315789474,7.10526315789474,0.0364208571130304 -"423",0.338916125940539,7.10526315789474,7.10526315789474,0.0364194215312579 -"424",0.441187655547492,7.10526315789474,7.10526315789474,0.0364106552876205 -"425",0.574320702112717,7.10526315789474,7.10526315789474,0.0363576381478413 -"426",0.747628055154725,7.10526315789474,7.10526315789474,0.0360543470034991 -"427",0.973232737037462,7.10526315789474,7.10526315789474,0.0347113907762506 -"428",1.2669160204875,7.10526315789474,7.10526315789474,0.0315496690804365 -"429",1.64922134437622,7.10526315789474,7.10526315789474,0.0276391986035362 -"430",2.14689134777813,7.10526315789474,7.10526315789474,0.0239801932667034 -"431",2.79473854427218,7.10526315789474,7.10526315789474,0.0207691210525081 -"432",3.63808049202114,7.10526315789474,7.10526315789474,0.0179827778971746 -"433",4.73590980220715,7.10526315789474,7.10526315789474,0.0155694997837889 -"434",6.16502073107827,7.10526315789474,7.10526315789474,0.0134799766670467 -"435",8.02538101483936,7.10526315789474,7.10526315789474,0.0116708655393753 -"436",10.4471247126008,7.10526315789474,7.10526315789474,0.0101045481992631 -"437",13.5996552137305,7.10526315789474,7.10526315789474,0.00874844204803614 -"438",17.7034951740616,7.10526315789474,7.10526315789474,0.00757433547062252 -"439",23.045712295823,7.10526315789474,7.10526315789474,0.00655780280124552 -"440",30,7.10526315789474,7.10526315789474,0.00567769644484347 -"441",0.2,9.21052631578947,7.10526315789474,0.0465931014786481 -"442",0.260352117694686,9.21052631578947,7.10526315789474,0.0465928012027002 -"443",0.338916125940539,9.21052631578947,7.10526315789474,0.0465909646787565 -"444",0.441187655547492,9.21052631578947,7.10526315789474,0.0465797501198618 -"445",0.574320702112717,9.21052631578947,7.10526315789474,0.0465119258771099 -"446",0.747628055154725,9.21052631578947,7.10526315789474,0.0461239288579562 -"447",0.973232737037462,9.21052631578947,7.10526315789474,0.0444058997537556 -"448",1.2669160204875,9.21052631578947,7.10526315789474,0.0403611440256257 -"449",1.64922134437622,9.21052631578947,7.10526315789474,0.0353585222319157 -"450",2.14689134777813,9.21052631578947,7.10526315789474,0.0306775970211337 -"451",2.79473854427218,9.21052631578947,7.10526315789474,0.0265697077186059 -"452",3.63808049202114,9.21052631578947,7.10526315789474,0.0230051696212169 -"453",4.73590980220715,9.21052631578947,7.10526315789474,0.0199178895213869 -"454",6.16502073107827,9.21052631578947,7.10526315789474,0.0172447856214795 -"455",8.02538101483936,9.21052631578947,7.10526315789474,0.0149304096894801 -"456",10.4471247126008,9.21052631578947,7.10526315789474,0.0129266371746899 -"457",13.5996552137305,9.21052631578947,7.10526315789474,0.0111917855176356 -"458",17.7034951740616,9.21052631578947,7.10526315789474,0.00968976391000458 -"459",23.045712295823,9.21052631578947,7.10526315789474,0.00838932486670191 -"460",30,9.21052631578947,7.10526315789474,0.00726341450237931 -"461",0.2,11.3157894736842,7.10526315789474,0.0592522492172405 -"462",0.260352117694686,11.3157894736842,7.10526315789474,0.0592518673575931 -"463",0.338916125940539,11.3157894736842,7.10526315789474,0.0592495318578957 -"464",0.441187655547492,11.3157894736842,7.10526315789474,0.0592352703509902 -"465",0.574320702112717,11.3157894736842,7.10526315789474,0.0591490185496082 -"466",0.747628055154725,11.3157894736842,7.10526315789474,0.0586556043886089 -"467",0.973232737037462,11.3157894736842,7.10526315789474,0.0564707940751934 -"468",1.2669160204875,11.3157894736842,7.10526315789474,0.0513270953983443 -"469",1.64922134437622,11.3157894736842,7.10526315789474,0.0449652825150285 -"470",2.14689134777813,11.3157894736842,7.10526315789474,0.0390125698096162 -"471",2.79473854427218,11.3157894736842,7.10526315789474,0.0337885844344044 -"472",3.63808049202114,11.3157894736842,7.10526315789474,0.0292555764785458 -"473",4.73590980220715,11.3157894736842,7.10526315789474,0.025329495490733 -"474",6.16502073107827,11.3157894736842,7.10526315789474,0.0219301206168908 -"475",8.02538101483936,11.3157894736842,7.10526315789474,0.0189869385759174 -"476",10.4471247126008,11.3157894736842,7.10526315789474,0.0164387495811278 -"477",13.5996552137305,11.3157894736842,7.10526315789474,0.0142325460987125 -"478",17.7034951740616,11.3157894736842,7.10526315789474,0.0123224316010584 -"479",23.045712295823,11.3157894736842,7.10526315789474,0.0106686687941135 -"480",30,11.3157894736842,7.10526315789474,0.00923685336680843 -"481",0.2,13.4210526315789,7.10526315789474,0.0745711441746302 -"482",0.260352117694686,13.4210526315789,7.10526315789474,0.0745706635901596 -"483",0.338916125940539,13.4210526315789,7.10526315789474,0.0745677242775267 -"484",0.441187655547492,13.4210526315789,7.10526315789474,0.0745497756443245 -"485",0.574320702112717,13.4210526315789,7.10526315789474,0.074441224566498 -"486",0.747628055154725,13.4210526315789,7.10526315789474,0.0738202446201878 -"487",0.973232737037462,13.4210526315789,7.10526315789474,0.0710705801428346 -"488",1.2669160204875,13.4210526315789,7.10526315789474,0.0645970453709164 -"489",1.64922134437622,13.4210526315789,7.10526315789474,0.056590468878024 -"490",2.14689134777813,13.4210526315789,7.10526315789474,0.0490987600695034 -"491",2.79473854427218,13.4210526315789,7.10526315789474,0.0425241815222349 -"492",3.63808049202114,13.4210526315789,7.10526315789474,0.0368192235790903 -"493",4.73590980220715,13.4210526315789,7.10526315789474,0.0318781056426209 -"494",6.16502073107827,13.4210526315789,7.10526315789474,0.0275998668049442 -"495",8.02538101483936,13.4210526315789,7.10526315789474,0.0238957634973223 -"496",10.4471247126008,13.4210526315789,7.10526315789474,0.0206887735277438 -"497",13.5996552137305,13.4210526315789,7.10526315789474,0.0179121849570286 -"498",17.7034951740616,13.4210526315789,7.10526315789474,0.0155082353099463 -"499",23.045712295823,13.4210526315789,7.10526315789474,0.0134269137342001 -"500",30,13.4210526315789,7.10526315789474,0.0116249211335554 -"501",0.2,15.5263157894737,7.10526315789474,0.0917241652255641 -"502",0.260352117694686,15.5263157894737,7.10526315789474,0.0917235740959807 -"503",0.338916125940539,15.5263157894737,7.10526315789474,0.0917199586760945 -"504",0.441187655547492,15.5263157894737,7.10526315789474,0.0916978814582158 -"505",0.574320702112717,15.5263157894737,7.10526315789474,0.091564361219145 -"506",0.747628055154725,15.5263157894737,7.10526315789474,0.0908005420793484 -"507",0.973232737037462,15.5263157894737,7.10526315789474,0.0874183936407381 -"508",1.2669160204875,15.5263157894737,7.10526315789474,0.0794558019494755 -"509",1.64922134437622,15.5263157894737,7.10526315789474,0.0696075348583151 -"510",2.14689134777813,15.5263157894737,7.10526315789474,0.0603925664656438 -"511",2.79473854427218,15.5263157894737,7.10526315789474,0.0523056886842611 -"512",3.63808049202114,15.5263157894737,7.10526315789474,0.0452884635796486 -"513",4.73590980220715,15.5263157894737,7.10526315789474,0.0392107786651946 -"514",6.16502073107827,15.5263157894737,7.10526315789474,0.0339484497796069 -"515",8.02538101483936,15.5263157894737,7.10526315789474,0.029392320360361 -"516",10.4471247126008,15.5263157894737,7.10526315789474,0.0254476513988992 -"517",13.5996552137305,15.5263157894737,7.10526315789474,0.0220323857268682 -"518",17.7034951740616,15.5263157894737,7.10526315789474,0.0190754742155395 -"519",23.045712295823,15.5263157894737,7.10526315789474,0.0165154024047301 -"520",30,15.5263157894737,7.10526315789474,0.0142989114434313 -"521",0.2,17.6315789473684,7.10526315789474,0.10677969121116 -"522",0.260352117694686,17.6315789473684,7.10526315789474,0.106779003054073 -"523",0.338916125940539,17.6315789473684,7.10526315789474,0.10677479420226 -"524",0.441187655547492,17.6315789473684,7.10526315789474,0.106749093248732 -"525",0.574320702112717,17.6315789473684,7.10526315789474,0.106593657111882 -"526",0.747628055154725,17.6315789473684,7.10526315789474,0.105704465352131 -"527",0.973232737037462,17.6315789473684,7.10526315789474,0.101767173963139 -"528",1.2669160204875,17.6315789473684,7.10526315789474,0.0924976092857967 -"529",1.64922134437622,17.6315789473684,7.10526315789474,0.0810328560621168 -"530",2.14689134777813,17.6315789473684,7.10526315789474,0.0703053506433397 -"531",2.79473854427218,17.6315789473684,7.10526315789474,0.0608910996634052 -"532",3.63808049202114,17.6315789473684,7.10526315789474,0.0527220732352324 -"533",4.73590980220715,17.6315789473684,7.10526315789474,0.0456468023200031 -"534",6.16502073107827,17.6315789473684,7.10526315789474,0.0395207192744633 -"535",8.02538101483936,17.6315789473684,7.10526315789474,0.0342167506713282 -"536",10.4471247126008,17.6315789473684,7.10526315789474,0.0296246071222503 -"537",13.5996552137305,17.6315789473684,7.10526315789474,0.0256487626654842 -"538",17.7034951740616,17.6315789473684,7.10526315789474,0.0222065062291138 -"539",23.045712295823,17.6315789473684,7.10526315789474,0.0192262264221036 -"540",30,17.6315789473684,7.10526315789474,0.0166459225312173 -"541",0.2,19.7368421052632,7.10526315789474,0.109938439774541 -"542",0.260352117694686,19.7368421052632,7.10526315789474,0.109937731260444 -"543",0.338916125940539,19.7368421052632,7.10526315789474,0.109933397902703 -"544",0.441187655547492,19.7368421052632,7.10526315789474,0.109906936665556 -"545",0.574320702112717,19.7368421052632,7.10526315789474,0.109746902428933 -"546",0.747628055154725,19.7368421052632,7.10526315789474,0.108831406667346 -"547",0.973232737037462,19.7368421052632,7.10526315789474,0.10477764262913 -"548",1.2669160204875,19.7368421052632,7.10526315789474,0.0952338664067311 -"549",1.64922134437622,19.7368421052632,7.10526315789474,0.083429963740268 -"550",2.14689134777813,19.7368421052632,7.10526315789474,0.0723851180862283 -"551",2.79473854427218,19.7368421052632,7.10526315789474,0.0626923754622285 -"552",3.63808049202114,19.7368421052632,7.10526315789474,0.054281693526332 -"553",4.73590980220715,19.7368421052632,7.10526315789474,0.0469971224943341 -"554",6.16502073107827,19.7368421052632,7.10526315789474,0.0406898181341438 -"555",8.02538101483936,19.7368421052632,7.10526315789474,0.0352289479421828 -"556",10.4471247126008,19.7368421052632,7.10526315789474,0.030500959957951 -"557",13.5996552137305,19.7368421052632,7.10526315789474,0.0264075023780939 -"558",17.7034951740616,19.7368421052632,7.10526315789474,0.0228634173781657 -"559",23.045712295823,19.7368421052632,7.10526315789474,0.0197949751645022 -"560",30,19.7368421052632,7.10526315789474,0.0171383409235656 -"561",0.2,21.8421052631579,7.10526315789474,0.0913380947515251 -"562",0.260352117694686,21.8421052631579,7.10526315789474,0.0913375061100285 -"563",0.338916125940539,21.8421052631579,7.10526315789474,0.091333905907581 -"564",0.441187655547492,21.8421052631579,7.10526315789474,0.0913119216135458 -"565",0.574320702112717,21.8421052631579,7.10526315789474,0.0911789633662017 -"566",0.747628055154725,21.8421052631579,7.10526315789474,0.0904183591699988 -"567",0.973232737037462,21.8421052631579,7.10526315789474,0.0870504463218433 -"568",1.2669160204875,21.8421052631579,7.10526315789474,0.0791213694795986 -"569",1.64922134437622,21.8421052631579,7.10526315789474,0.0693145541163988 -"570",2.14689134777813,21.8421052631579,7.10526315789474,0.0601383718735591 -"571",2.79473854427218,21.8421052631579,7.10526315789474,0.0520855320660394 -"572",3.63808049202114,21.8421052631579,7.10526315789474,0.0450978427267938 -"573",4.73590980220715,21.8421052631579,7.10526315789474,0.0390457390175785 -"574",6.16502073107827,21.8421052631579,7.10526315789474,0.0338055594729242 -"575",8.02538101483936,21.8421052631579,7.10526315789474,0.0292686069743986 -"576",10.4471247126008,21.8421052631579,7.10526315789474,0.0253405412735076 -"577",13.5996552137305,21.8421052631579,7.10526315789474,0.0219396505836171 -"578",17.7034951740616,21.8421052631579,7.10526315789474,0.0189951848244635 -"579",23.045712295823,21.8421052631579,7.10526315789474,0.016445888452549 -"580",30,21.8421052631579,7.10526315789474,0.0142387267853793 -"581",0.2,23.9473684210526,7.10526315789474,0.0591062000636878 -"582",0.260352117694686,23.9473684210526,7.10526315789474,0.0591058191452751 -"583",0.338916125940539,23.9473684210526,7.10526315789474,0.0591034894022834 -"584",0.441187655547492,23.9473684210526,7.10526315789474,0.0590892630481533 -"585",0.574320702112717,23.9473684210526,7.10526315789474,0.0590032238463392 -"586",0.747628055154725,23.9473684210526,7.10526315789474,0.0585110258876195 -"587",0.973232737037462,23.9473684210526,7.10526315789474,0.0563316008498883 -"588",1.2669160204875,23.9473684210526,7.10526315789474,0.0512005807269812 -"589",1.64922134437622,23.9473684210526,7.10526315789474,0.0448544488920465 -"590",2.14689134777813,23.9473684210526,7.10526315789474,0.0389164088558316 -"591",2.79473854427218,23.9473684210526,7.10526315789474,0.0337052999309201 -"592",3.63808049202114,23.9473684210526,7.10526315789474,0.0291834652551267 -"593",4.73590980220715,23.9473684210526,7.10526315789474,0.0252670615506681 -"594",6.16502073107827,23.9473684210526,7.10526315789474,0.0218760656975297 -"595",8.02538101483936,23.9473684210526,7.10526315789474,0.0189401382207544 -"596",10.4471247126008,23.9473684210526,7.10526315789474,0.0163982301832398 -"597",13.5996552137305,23.9473684210526,7.10526315789474,0.0141974647079117 -"598",17.7034951740616,23.9473684210526,7.10526315789474,0.0122920583961789 -"599",23.045712295823,23.9473684210526,7.10526315789474,0.0106423719012951 -"600",30,23.9473684210526,7.10526315789474,0.00921408571438114 -"601",0.2,26.0526315789474,7.10526315789474,0.0318569743435326 -"602",0.260352117694686,26.0526315789474,7.10526315789474,0.0318567690366767 -"603",0.338916125940539,26.0526315789474,7.10526315789474,0.0318555133551639 -"604",0.441187655547492,26.0526315789474,7.10526315789474,0.0318478456553619 -"605",0.574320702112717,26.0526315789474,7.10526315789474,0.0318014723706341 -"606",0.747628055154725,26.0526315789474,7.10526315789474,0.0315361882257224 -"607",0.973232737037462,26.0526315789474,7.10526315789474,0.0303615248666189 -"608",1.2669160204875,26.0526315789474,7.10526315789474,0.0275960150514816 -"609",1.64922134437622,26.0526315789474,7.10526315789474,0.0241755860807755 -"610",2.14689134777813,26.0526315789474,7.10526315789474,0.0209751098383384 -"611",2.79473854427218,26.0526315789474,7.10526315789474,0.0181664338763685 -"612",3.63808049202114,26.0526315789474,7.10526315789474,0.0157292619536729 -"613",4.73590980220715,26.0526315789474,7.10526315789474,0.0136184043414864 -"614",6.16502073107827,26.0526315789474,7.10526315789474,0.0117907302941605 -"615",8.02538101483936,26.0526315789474,7.10526315789474,0.0102083283430738 -"616",10.4471247126008,26.0526315789474,7.10526315789474,0.00883829442027947 -"617",13.5996552137305,26.0526315789474,7.10526315789474,0.00765212902294186 -"618",17.7034951740616,26.0526315789474,7.10526315789474,0.00662515588101306 -"619",23.045712295823,26.0526315789474,7.10526315789474,0.00573601023663465 -"620",30,26.0526315789474,7.10526315789474,0.0049661946104785 -"621",0.2,28.1578947368421,7.10526315789474,0.015693767801349 -"622",0.260352117694686,28.1578947368421,7.10526315789474,0.0156936666606038 -"623",0.338916125940539,28.1578947368421,7.10526315789474,0.0156930480715978 -"624",0.441187655547492,28.1578947368421,7.10526315789474,0.015689270716631 -"625",0.574320702112717,28.1578947368421,7.10526315789474,0.015666425748529 -"626",0.747628055154725,28.1578947368421,7.10526315789474,0.0155357382661985 -"627",0.973232737037462,28.1578947368421,7.10526315789474,0.014957061402422 -"628",1.2669160204875,28.1578947368421,7.10526315789474,0.0135946825266664 -"629",1.64922134437622,28.1578947368421,7.10526315789474,0.0119096694595618 -"630",2.14689134777813,28.1578947368421,7.10526315789474,0.0103330121643363 -"631",2.79473854427218,28.1578947368421,7.10526315789474,0.00894936825951792 -"632",3.63808049202114,28.1578947368421,7.10526315789474,0.00774873916542079 -"633",4.73590980220715,28.1578947368421,7.10526315789474,0.00670886297158851 -"634",6.16502073107827,28.1578947368421,7.10526315789474,0.00580849208871753 -"635",8.02538101483936,28.1578947368421,7.10526315789474,0.00502895011084612 -"636",10.4471247126008,28.1578947368421,7.10526315789474,0.00435402743826435 -"637",13.5996552137305,28.1578947368421,7.10526315789474,0.00376968430137161 -"638",17.7034951740616,28.1578947368421,7.10526315789474,0.00326376437771997 -"639",23.045712295823,28.1578947368421,7.10526315789474,0.0028257427020272 -"640",30,28.1578947368421,7.10526315789474,0.00244650682242154 -"641",0.2,30.2631578947368,7.10526315789474,0.00748790720975263 -"642",0.260352117694686,30.2631578947368,7.10526315789474,0.00748785895285698 -"643",0.338916125940539,30.2631578947368,7.10526315789474,0.00748756380785822 -"644",0.441187655547492,30.2631578947368,7.10526315789474,0.00748576153297767 -"645",0.574320702112717,30.2631578947368,7.10526315789474,0.00747486160100961 -"646",0.747628055154725,30.2631578947368,7.10526315789474,0.00741250718404909 -"647",0.973232737037462,30.2631578947368,7.10526315789474,0.00713640531257776 -"648",1.2669160204875,30.2631578947368,7.10526315789474,0.00648637870741108 -"649",1.64922134437622,30.2631578947368,7.10526315789474,0.0056824148885622 -"650",2.14689134777813,30.2631578947368,7.10526315789474,0.00493015044335911 -"651",2.79473854427218,30.2631578947368,7.10526315789474,0.00426997773647546 -"652",3.63808049202114,30.2631578947368,7.10526315789474,0.00369712618395306 -"653",4.73590980220715,30.2631578947368,7.10526315789474,0.00320097404588094 -"654",6.16502073107827,30.2631578947368,7.10526315789474,0.00277138354150751 -"655",8.02538101483936,30.2631578947368,7.10526315789474,0.00239944366892277 -"656",10.4471247126008,30.2631578947368,7.10526315789474,0.00207742040401783 -"657",13.5996552137305,30.2631578947368,7.10526315789474,0.00179861500539759 -"658",17.7034951740616,30.2631578947368,7.10526315789474,0.00155722737357962 -"659",23.045712295823,30.2631578947368,7.10526315789474,0.00134823577226602 -"660",30,30.2631578947368,7.10526315789474,0.00116729241226218 -"661",0.2,32.3684210526316,7.10526315789474,0.0035512116737005 -"662",0.260352117694686,32.3684210526316,7.10526315789474,0.00355118878740579 -"663",0.338916125940539,32.3684210526316,7.10526315789474,0.00355104881206479 -"664",0.441187655547492,32.3684210526316,7.10526315789474,0.00355019406595006 -"665",0.574320702112717,32.3684210526316,7.10526315789474,0.00354502466887245 -"666",0.747628055154725,32.3684210526316,7.10526315789474,0.00351545248972891 -"667",0.973232737037462,32.3684210526316,7.10526315789474,0.00338450853414376 -"668",1.2669160204875,32.3684210526316,7.10526315789474,0.003076227194135 -"669",1.64922134437622,32.3684210526316,7.10526315789474,0.00269493965694298 -"670",2.14689134777813,32.3684210526316,7.10526315789474,0.00233817104260497 -"671",2.79473854427218,32.3684210526316,7.10526315789474,0.00202507781673136 -"672",3.63808049202114,32.3684210526316,7.10526315789474,0.00175339748421263 -"673",4.73590980220715,32.3684210526316,7.10526315789474,0.00151809258321728 -"674",6.16502073107827,32.3684210526316,7.10526315789474,0.00131435517417797 -"675",8.02538101483936,32.3684210526316,7.10526315789474,0.00113795912913654 -"676",10.4471247126008,32.3684210526316,7.10526315789474,0.000985236513123862 -"677",13.5996552137305,32.3684210526316,7.10526315789474,0.000853010383908297 -"678",17.7034951740616,32.3684210526316,7.10526315789474,0.000738529988787697 -"679",23.045712295823,32.3684210526316,7.10526315789474,0.000639413721251211 -"680",30,32.3684210526316,7.10526315789474,0.000553599600653227 -"681",0.2,34.4736842105263,7.10526315789474,0.00169112122481658 -"682",0.260352117694686,34.4736842105263,7.10526315789474,0.00169111032614247 -"683",0.338916125940539,34.4736842105263,7.10526315789474,0.00169104366853603 -"684",0.441187655547492,34.4736842105263,7.10526315789474,0.00169063663019834 -"685",0.574320702112717,34.4736842105263,7.10526315789474,0.00168817491348846 -"686",0.747628055154725,34.4736842105263,7.10526315789474,0.00167409235677013 -"687",0.973232737037462,34.4736842105263,7.10526315789474,0.00161173558311131 -"688",1.2669160204875,34.4736842105263,7.10526315789474,0.0014649290378511 -"689",1.64922134437622,34.4736842105263,7.10526315789474,0.00128335623787447 -"690",2.14689134777813,34.4736842105263,7.10526315789474,0.00111345958526894 -"691",2.79473854427218,34.4736842105263,7.10526315789474,0.000964361573583984 -"692",3.63808049202114,34.4736842105263,7.10526315789474,0.000834984780843018 -"693",4.73590980220715,34.4736842105263,7.10526315789474,0.000722930319171929 -"694",6.16502073107827,34.4736842105263,7.10526315789474,0.000625908601410877 -"695",8.02538101483936,34.4736842105263,7.10526315789474,0.000541907104695695 -"696",10.4471247126008,34.4736842105263,7.10526315789474,0.000469179123043332 -"697",13.5996552137305,34.4736842105263,7.10526315789474,0.000406211765944404 -"698",17.7034951740616,34.4736842105263,7.10526315789474,0.000351695098450997 -"699",23.045712295823,34.4736842105263,7.10526315789474,0.000304494976589242 -"700",30,34.4736842105263,7.10526315789474,0.000263629465302781 -"701",0.2,36.5789473684211,7.10526315789474,0.000811642162220618 -"702",0.260352117694686,36.5789473684211,7.10526315789474,0.000811636931475895 -"703",0.338916125940539,36.5789473684211,7.10526315789474,0.000811604939609776 -"704",0.441187655547492,36.5789473684211,7.10526315789474,0.000811409584320242 -"705",0.574320702112717,36.5789473684211,7.10526315789474,0.000810228100081349 -"706",0.747628055154725,36.5789473684211,7.10526315789474,0.000803469272495996 -"707",0.973232737037462,36.5789473684211,7.10526315789474,0.000773541561898531 -"708",1.2669160204875,36.5789473684211,7.10526315789474,0.000703082756181594 -"709",1.64922134437622,36.5789473684211,7.10526315789474,0.000615938122307424 -"710",2.14689134777813,36.5789473684211,7.10526315789474,0.000534397376173298 -"711",2.79473854427218,36.5789473684211,7.10526315789474,0.000462838796687136 -"712",3.63808049202114,36.5789473684211,7.10526315789474,0.000400745282478635 -"713",4.73590980220715,36.5789473684211,7.10526315789474,0.000346965503582504 -"714",6.16502073107827,36.5789473684211,7.10526315789474,0.000300400588169962 -"715",8.02538101483936,36.5789473684211,7.10526315789474,0.000260084639541813 -"716",10.4471247126008,36.5789473684211,7.10526315789474,0.000225179338008111 -"717",13.5996552137305,36.5789473684211,7.10526315789474,0.000194958582029701 -"718",17.7034951740616,36.5789473684211,7.10526315789474,0.000168793677212655 -"719",23.045712295823,36.5789473684211,7.10526315789474,0.000146140298848779 -"720",30,36.5789473684211,7.10526315789474,0.000126527173867516 -"721",0.2,38.6842105263158,7.10526315789474,0.000393093382630405 -"722",0.260352117694686,38.6842105263158,7.10526315789474,0.000393090849283528 -"723",0.338916125940539,38.6842105263158,7.10526315789474,0.000393075355028233 -"724",0.441187655547492,38.6842105263158,7.10526315789474,0.000392980740831051 -"725",0.574320702112717,38.6842105263158,7.10526315789474,0.000392408526057585 -"726",0.747628055154725,38.6842105263158,7.10526315789474,0.000389135100252704 -"727",0.973232737037462,38.6842105263158,7.10526315789474,0.000374640553837133 -"728",1.2669160204875,38.6842105263158,7.10526315789474,0.000340516044829873 -"729",1.64922134437622,38.6842105263158,7.10526315789474,0.000298310279158505 -"730",2.14689134777813,38.6842105263158,7.10526315789474,0.000258818580461662 -"731",2.79473854427218,38.6842105263158,7.10526315789474,0.000224161430579895 -"732",3.63808049202114,38.6842105263158,7.10526315789474,0.00019408838770981 -"733",4.73590980220715,38.6842105263158,7.10526315789474,0.000168041841353031 -"734",6.16502073107827,38.6842105263158,7.10526315789474,0.000145489587461569 -"735",8.02538101483936,38.6842105263158,7.10526315789474,0.000125963824313886 -"736",10.4471247126008,38.6842105263158,7.10526315789474,0.000109058538104904 -"737",13.5996552137305,38.6842105263158,7.10526315789474,9.44220643654181e-05 -"738",17.7034951740616,38.6842105263158,7.10526315789474,8.17499147168649e-05 -"739",23.045712295823,38.6842105263158,7.10526315789474,7.07784625873956e-05 -"740",30,38.6842105263158,7.10526315789474,6.12794616708538e-05 -"741",0.2,40.7894736842105,7.10526315789474,0.000192186214212522 -"742",0.260352117694686,40.7894736842105,7.10526315789474,0.000192184975640806 -"743",0.338916125940539,40.7894736842105,7.10526315789474,0.000192177400386684 -"744",0.441187655547492,40.7894736842105,7.10526315789474,0.000192131142817438 -"745",0.574320702112717,40.7894736842105,7.10526315789474,0.000191851382852278 -"746",0.747628055154725,40.7894736842105,7.10526315789474,0.00019025098116468 -"747",0.973232737037462,40.7894736842105,7.10526315789474,0.000183164491985706 -"748",1.2669160204875,40.7894736842105,7.10526315789474,0.000166480771303151 -"749",1.64922134437622,40.7894736842105,7.10526315789474,0.000145846065452742 -"750",2.14689134777813,40.7894736842105,7.10526315789474,0.000126538286688875 -"751",2.79473854427218,40.7894736842105,7.10526315789474,0.000109594154008231 -"752",3.63808049202114,40.7894736842105,7.10526315789474,9.48912245913635e-05 -"753",4.73590980220715,40.7894736842105,7.10526315789474,8.21568786094399e-05 -"754",6.16502073107827,40.7894736842105,7.10526315789474,7.11309176320329e-05 -"755",8.02538101483936,40.7894736842105,7.10526315789474,6.15846299945944e-05 -"756",10.4471247126008,40.7894736842105,7.10526315789474,5.33195125943906e-05 -"757",13.5996552137305,40.7894736842105,7.10526315789474,4.61636341143464e-05 -"758",17.7034951740616,40.7894736842105,7.10526315789474,3.99681279712684e-05 -"759",23.045712295823,40.7894736842105,7.10526315789474,3.46041052165045e-05 -"760",30,40.7894736842105,7.10526315789474,2.99599745706628e-05 -"761",0.2,42.8947368421053,7.10526315789474,9.48530216347067e-05 -"762",0.260352117694686,42.8947368421053,7.10526315789474,9.48524103407579e-05 -"763",0.338916125940539,42.8947368421053,7.10526315789474,9.48486715931788e-05 -"764",0.441187655547492,42.8947368421053,7.10526315789474,9.48258412864659e-05 -"765",0.574320702112717,42.8947368421053,7.10526315789474,9.4687766460774e-05 -"766",0.747628055154725,42.8947368421053,7.10526315789474,9.38978922415433e-05 -"767",0.973232737037462,42.8947368421053,7.10526315789474,9.04003733681867e-05 -"768",1.2669160204875,42.8947368421053,7.10526315789474,8.21661650752867e-05 -"769",1.64922134437622,42.8947368421053,7.10526315789474,7.19819580109322e-05 -"770",2.14689134777813,42.8947368421053,7.10526315789474,6.24526524657281e-05 -"771",2.79473854427218,42.8947368421053,7.10526315789474,5.40899184875186e-05 -"772",3.63808049202114,42.8947368421053,7.10526315789474,4.68333247313739e-05 -"773",4.73590980220715,42.8947368421053,7.10526315789474,4.05483203678895e-05 -"774",6.16502073107827,42.8947368421053,7.10526315789474,3.51064851175374e-05 -"775",8.02538101483936,42.8947368421053,7.10526315789474,3.03949389147292e-05 -"776",10.4471247126008,42.8947368421053,7.10526315789474,2.63157110534218e-05 -"777",13.5996552137305,42.8947368421053,7.10526315789474,2.27839452654117e-05 -"778",17.7034951740616,42.8947368421053,7.10526315789474,1.97261688237701e-05 -"779",23.045712295823,42.8947368421053,7.10526315789474,1.70787689127439e-05 -"780",30,42.8947368421053,7.10526315789474,1.47866699376462e-05 -"781",0.2,45,7.10526315789474,4.72536466185546e-05 -"782",0.260352117694686,45,7.10526315789474,4.72533420856284e-05 -"783",0.338916125940539,45,7.10526315789474,4.72514795254922e-05 -"784",0.441187655547492,45,7.10526315789474,4.7240105979062e-05 -"785",0.574320702112717,45,7.10526315789474,4.71713201996771e-05 -"786",0.747628055154725,45,7.10526315789474,4.67778225905827e-05 -"787",0.973232737037462,45,7.10526315789474,4.5035437181715e-05 -"788",1.2669160204875,45,7.10526315789474,4.09333394082278e-05 -"789",1.64922134437622,45,7.10526315789474,3.58597960100794e-05 -"790",2.14689134777813,45,7.10526315789474,3.11125098509999e-05 -"791",2.79473854427218,45,7.10526315789474,2.69463834655575e-05 -"792",3.63808049202114,45,7.10526315789474,2.33313113139519e-05 -"793",4.73590980220715,45,7.10526315789474,2.02002631926605e-05 -"794",6.16502073107827,45,7.10526315789474,1.74892630005228e-05 -"795",8.02538101483936,45,7.10526315789474,1.51420764221984e-05 -"796",10.4471247126008,45,7.10526315789474,1.31098966506659e-05 -"797",13.5996552137305,45,7.10526315789474,1.13504501975119e-05 -"798",17.7034951740616,45,7.10526315789474,9.82713459910816e-06 -"799",23.045712295823,45,7.10526315789474,8.50825937829127e-06 -"800",30,45,7.10526315789474,7.36638710983433e-06 -"801",0.2,5,9.21052631578947,0.0290720151230221 -"802",0.260352117694686,5,9.21052631578947,0.0290718277642367 -"803",0.338916125940539,5,9.21052631578947,0.0290706818552895 -"804",0.441187655547492,5,9.21052631578947,0.0290636844712254 -"805",0.574320702112717,5,9.21052631578947,0.0290213651718352 -"806",0.747628055154725,5,9.21052631578947,0.0287792723544319 -"807",0.973232737037462,5,9.21052631578947,0.0277072988966873 -"808",1.2669160204875,5,9.21052631578947,0.0251835519048497 -"809",1.64922134437622,5,9.21052631578947,0.0220621392530616 -"810",2.14689134777813,5,9.21052631578947,0.0191414509065271 -"811",2.79473854427218,5,9.21052631578947,0.0165783113829322 -"812",3.63808049202114,5,9.21052631578947,0.0143541987528389 -"813",4.73590980220715,5,9.21052631578947,0.0124278738055204 -"814",6.16502073107827,5,9.21052631578947,0.010759976315607 -"815",8.02538101483936,5,9.21052631578947,0.00931590906186816 -"816",10.4471247126008,5,9.21052631578947,0.00806564447324076 -"817",13.5996552137305,5,9.21052631578947,0.00698317449357663 -"818",17.7034951740616,5,9.21052631578947,0.00604598006980196 -"819",23.045712295823,5,9.21052631578947,0.00523456416629554 -"820",30,5,9.21052631578947,0.00453204636645013 -"821",0.2,7.10526315789474,9.21052631578947,0.0373464009349278 -"822",0.260352117694686,7.10526315789474,9.21052631578947,0.0373461602506722 -"823",0.338916125940539,7.10526315789474,9.21052631578947,0.0373446881967125 -"824",0.441187655547492,7.10526315789474,9.21052631578947,0.0373356992391309 -"825",0.574320702112717,7.10526315789474,9.21052631578947,0.0372813351534071 -"826",0.747628055154725,7.10526315789474,9.21052631578947,0.0369703386372059 -"827",0.973232737037462,7.10526315789474,9.21052631578947,0.0355932634542466 -"828",1.2669160204875,7.10526315789474,9.21052631578947,0.0323512155048133 -"829",1.64922134437622,7.10526315789474,9.21052631578947,0.0283413961688045 -"830",2.14689134777813,7.10526315789474,9.21052631578947,0.0245894306605976 -"831",2.79473854427218,7.10526315789474,9.21052631578947,0.0212967784005026 -"832",3.63808049202114,7.10526315789474,9.21052631578947,0.0184396458055858 -"833",4.73590980220715,7.10526315789474,9.21052631578947,0.0159650562902364 -"834",6.16502073107827,7.10526315789474,9.21052631578947,0.0138224470451229 -"835",8.02538101483936,7.10526315789474,9.21052631578947,0.0119673738963606 -"836",10.4471247126008,7.10526315789474,9.21052631578947,0.0103612629197381 -"837",13.5996552137305,7.10526315789474,9.21052631578947,0.00897070372769412 -"838",17.7034951740616,7.10526315789474,9.21052631578947,0.00776676796485977 -"839",23.045712295823,7.10526315789474,9.21052631578947,0.00672440941045292 -"840",30,7.10526315789474,9.21052631578947,0.00582194319660682 -"841",0.2,9.21052631578947,9.21052631578947,0.0477401634356467 -"842",0.260352117694686,9.21052631578947,9.21052631578947,0.0477398557672929 -"843",0.338916125940539,9.21052631578947,9.21052631578947,0.0477379740305027 -"844",0.441187655547492,9.21052631578947,9.21052631578947,0.0477264833836579 -"845",0.574320702112717,9.21052631578947,9.21052631578947,0.0476569893956829 -"846",0.747628055154725,9.21052631578947,9.21052631578947,0.0472594403912358 -"847",0.973232737037462,9.21052631578947,9.21052631578947,0.0454991156302984 -"848",1.2669160204875,9.21052631578947,9.21052631578947,0.041354783242237 -"849",1.64922134437622,9.21052631578947,9.21052631578947,0.036229003363688 -"850",2.14689134777813,9.21052631578947,9.21052631578947,0.0314328398222854 -"851",2.79473854427218,9.21052631578947,9.21052631578947,0.0272238195927972 -"852",3.63808049202114,9.21052631578947,9.21052631578947,0.0235715271730723 -"853",4.73590980220715,9.21052631578947,9.21052631578947,0.020408242226157 -"854",6.16502073107827,9.21052631578947,9.21052631578947,0.017669329962063 -"855",8.02538101483936,9.21052631578947,9.21052631578947,0.0152979770849464 -"856",10.4471247126008,9.21052631578947,9.21052631578947,0.0132448742798503 -"857",13.5996552137305,9.21052631578947,9.21052631578947,0.0114673128165438 -"858",17.7034951740616,9.21052631578947,9.21052631578947,0.00992831337764536 -"859",23.045712295823,9.21052631578947,9.21052631578947,0.00859585920535086 -"860",30,9.21052631578947,9.21052631578947,0.00744223038261019 -"861",0.2,11.3157894736842,9.21052631578947,0.0606037267353759 -"862",0.260352117694686,11.3157894736842,9.21052631578947,0.0606033361659371 -"863",0.338916125940539,11.3157894736842,9.21052631578947,0.0606009473961044 -"864",0.441187655547492,11.3157894736842,9.21052631578947,0.0605863606001809 -"865",0.574320702112717,11.3157894736842,9.21052631578947,0.0604981414917007 -"866",0.747628055154725,11.3157894736842,9.21052631578947,0.05999347310568 -"867",0.973232737037462,11.3157894736842,9.21052631578947,0.0577588297132004 -"868",1.2669160204875,11.3157894736842,9.21052631578947,0.0524978090238765 -"869",1.64922134437622,11.3157894736842,9.21052631578947,0.0459908903057617 -"870",2.14689134777813,11.3157894736842,9.21052631578947,0.039902402882941 -"871",2.79473854427218,11.3157894736842,9.21052631578947,0.0345592642454829 -"872",3.63808049202114,11.3157894736842,9.21052631578947,0.029922863449305 -"873",4.73590980220715,11.3157894736842,9.21052631578947,0.0259072329463345 -"874",6.16502073107827,11.3157894736842,9.21052631578947,0.0224303221345591 -"875",8.02538101483936,11.3157894736842,9.21052631578947,0.0194200094038194 -"876",10.4471247126008,11.3157894736842,9.21052631578947,0.0168136990687615 -"877",13.5996552137305,11.3157894736842,9.21052631578947,0.0145571745530302 -"878",17.7034951740616,11.3157894736842,9.21052631578947,0.0126034924805625 -"879",23.045712295823,11.3157894736842,9.21052631578947,0.010912009194084 -"880",30,11.3157894736842,9.21052631578947,0.00944753565867866 -"881",0.2,13.4210526315789,9.21052631578947,0.0759866374247321 -"882",0.260352117694686,13.4210526315789,9.21052631578947,0.0759861477179115 -"883",0.338916125940539,13.4210526315789,9.21052631578947,0.0759831526118852 -"884",0.441187655547492,13.4210526315789,9.21052631578947,0.0759648632816288 -"885",0.574320702112717,13.4210526315789,9.21052631578947,0.0758542517108374 -"886",0.747628055154725,13.4210526315789,9.21052631578947,0.0752214844581612 -"887",0.973232737037462,13.4210526315789,9.21052631578947,0.0724196264473599 -"888",1.2669160204875,13.4210526315789,9.21052631578947,0.0658232124454746 -"889",1.64922134437622,13.4210526315789,9.21052631578947,0.057664656857886 -"890",2.14689134777813,13.4210526315789,9.21052631578947,0.0500307420611436 -"891",2.79473854427218,13.4210526315789,9.21052631578947,0.0433313662929268 -"892",3.63808049202114,13.4210526315789,9.21052631578947,0.0375181180781226 -"893",4.73590980220715,13.4210526315789,9.21052631578947,0.0324832089149737 -"894",6.16502073107827,13.4210526315789,9.21052631578947,0.0281237614775889 -"895",8.02538101483936,13.4210526315789,9.21052631578947,0.0243493476860976 -"896",10.4471247126008,13.4210526315789,9.21052631578947,0.0210814833299808 -"897",13.5996552137305,13.4210526315789,9.21052631578947,0.0182521901585295 -"898",17.7034951740616,13.4210526315789,9.21052631578947,0.0158026092617635 -"899",23.045712295823,13.4210526315789,9.21052631578947,0.013681780492258 -"900",30,13.4210526315789,9.21052631578947,0.0118455828597451 -"901",0.2,15.5263157894737,9.21052631578947,0.0928252531132363 -"902",0.260352117694686,15.5263157894737,9.21052631578947,0.0928246548875336 -"903",0.338916125940539,15.5263157894737,9.21052631578947,0.0928209960669248 -"904",0.441187655547492,15.5263157894737,9.21052631578947,0.0927986538266593 -"905",0.574320702112717,15.5263157894737,9.21052631578947,0.0926635307655008 -"906",0.747628055154725,15.5263157894737,9.21052631578947,0.091890542482533 -"907",0.973232737037462,15.5263157894737,9.21052631578947,0.0884677935906954 -"908",1.2669160204875,15.5263157894737,9.21052631578947,0.0804096162569342 -"909",1.64922134437622,15.5263157894737,9.21052631578947,0.0704431272383028 -"910",2.14689134777813,15.5263157894737,9.21052631578947,0.0611175392498303 -"911",2.79473854427218,15.5263157894737,9.21052631578947,0.052933583853707 -"912",3.63808049202114,15.5263157894737,9.21052631578947,0.0458321216066931 -"913",4.73590980220715,15.5263157894737,9.21052631578947,0.0396814781079017 -"914",6.16502073107827,15.5263157894737,9.21052631578947,0.0343559784473866 -"915",8.02538101483936,15.5263157894737,9.21052631578947,0.0297451557103452 -"916",10.4471247126008,15.5263157894737,9.21052631578947,0.0257531336091339 -"917",13.5996552137305,15.5263157894737,9.21052631578947,0.0222968699334098 -"918",17.7034951740616,15.5263157894737,9.21052631578947,0.0193044626566846 -"919",23.045712295823,15.5263157894737,9.21052631578947,0.0167136588783994 -"920",30,15.5263157894737,9.21052631578947,0.0144705604102934 -"921",0.2,17.6315789473684,9.21052631578947,0.107093176344978 -"922",0.260352117694686,17.6315789473684,9.21052631578947,0.107092486167591 -"923",0.338916125940539,17.6315789473684,9.21052631578947,0.107088264959379 -"924",0.441187655547492,17.6315789473684,9.21052631578947,0.107062488552675 -"925",0.574320702112717,17.6315789473684,9.21052631578947,0.106906596084499 -"926",0.747628055154725,17.6315789473684,9.21052631578947,0.106014793824617 -"927",0.973232737037462,17.6315789473684,9.21052631578947,0.102065943287027 -"928",1.2669160204875,17.6315789473684,9.21052631578947,0.0927691649074315 -"929",1.64922134437622,17.6315789473684,9.21052631578947,0.0812707533199021 -"930",2.14689134777813,17.6315789473684,9.21052631578947,0.0705117539584699 -"931",2.79473854427218,17.6315789473684,9.21052631578947,0.0610698645044513 -"932",3.63808049202114,17.6315789473684,9.21052631578947,0.0528768553477844 -"933",4.73590980220715,17.6315789473684,9.21052631578947,0.0457808127649796 -"934",6.16502073107827,17.6315789473684,9.21052631578947,0.0396367446893134 -"935",8.02538101483936,17.6315789473684,9.21052631578947,0.0343172046297669 -"936",10.4471247126008,17.6315789473684,9.21052631578947,0.0297115794090465 -"937",13.5996552137305,17.6315789473684,9.21052631578947,0.0257240626191108 -"938",17.7034951740616,17.6315789473684,9.21052631578947,0.022271700363859 -"939",23.045712295823,17.6315789473684,9.21052631578947,0.019282671014651 -"940",30,17.6315789473684,9.21052631578947,0.0166947918357924 -"941",0.2,19.7368421052632,9.21052631578947,0.110116698646416 -"942",0.260352117694686,19.7368421052632,9.21052631578947,0.110115988983504 -"943",0.338916125940539,19.7368421052632,9.21052631578947,0.110111648599472 -"944",0.441187655547492,19.7368421052632,9.21052631578947,0.110085144456947 -"945",0.574320702112717,19.7368421052632,9.21052631578947,0.109924850733992 -"946",0.747628055154725,19.7368421052632,9.21052631578947,0.109007870548558 -"947",0.973232737037462,19.7368421052632,9.21052631578947,0.104947533564558 -"948",1.2669160204875,19.7368421052632,9.21052631578947,0.0953882826566318 -"949",1.64922134437622,19.7368421052632,9.21052631578947,0.0835652406392979 -"950",2.14689134777813,19.7368421052632,9.21052631578947,0.0725024864017785 -"951",2.79473854427218,19.7368421052632,9.21052631578947,0.0627940275517793 -"952",3.63808049202114,19.7368421052632,9.21052631578947,0.054369708177725 -"953",4.73590980220715,19.7368421052632,9.21052631578947,0.0470733256317842 -"954",6.16502073107827,19.7368421052632,9.21052631578947,0.0407557943394843 -"955",8.02538101483936,19.7368421052632,9.21052631578947,0.0352860696598494 -"956",10.4471247126008,19.7368421052632,9.21052631578947,0.030550415514391 -"957",13.5996552137305,19.7368421052632,9.21052631578947,0.026450320627949 -"958",17.7034951740616,19.7368421052632,9.21052631578947,0.0229004890975515 -"959",23.045712295823,19.7368421052632,9.21052631578947,0.0198270715809044 -"960",30,19.7368421052632,9.21052631578947,0.0171661297599826 -"961",0.2,21.8421052631579,9.21052631578947,0.0941042978546259 -"962",0.260352117694686,21.8421052631579,9.21052631578947,0.0941036913859353 -"963",0.338916125940539,21.8421052631579,9.21052631578947,0.0940999821502175 -"964",0.441187655547492,21.8421052631579,9.21052631578947,0.0940773320548805 -"965",0.574320702112717,21.8421052631579,9.21052631578947,0.0939403471249416 -"966",0.747628055154725,21.8421052631579,9.21052631578947,0.0931567077899667 -"967",0.973232737037462,21.8421052631579,9.21052631578947,0.0896867966354432 -"968",1.2669160204875,21.8421052631579,9.21052631578947,0.0815175851919085 -"969",1.64922134437622,21.8421052631579,9.21052631578947,0.0714137673221093 -"970",2.14689134777813,21.8421052631579,9.21052631578947,0.0619596814962814 -"971",2.79473854427218,21.8421052631579,9.21052631578947,0.0536629588869041 -"972",3.63808049202114,21.8421052631579,9.21052631578947,0.0464636451647949 -"973",4.73590980220715,21.8421052631579,9.21052631578947,0.0402282515795836 -"974",6.16502073107827,21.8421052631579,9.21052631578947,0.0348293715391869 -"975",8.02538101483936,21.8421052631579,9.21052631578947,0.0301550159985442 -"976",10.4471247126008,21.8421052631579,9.21052631578947,0.0261079875848821 -"977",13.5996552137305,21.8421052631579,9.21052631578947,0.0226040998442508 -"978",17.7034951740616,21.8421052631579,9.21052631578947,0.0195704600078177 -"979",23.045712295823,21.8421052631579,9.21052631578947,0.0169439573885658 -"980",30,21.8421052631579,9.21052631578947,0.0146699511318589 -"981",0.2,23.9473684210526,9.21052631578947,0.0652331863550116 -"982",0.260352117694686,23.9473684210526,9.21052631578947,0.0652327659503541 -"983",0.338916125940539,23.9473684210526,9.21052631578947,0.065230194704722 -"984",0.441187655547492,23.9473684210526,9.21052631578947,0.0652144936376746 -"985",0.574320702112717,23.9473684210526,9.21052631578947,0.0651195355574778 -"986",0.747628055154725,23.9473684210526,9.21052631578947,0.0645763160453095 -"987",0.973232737037462,23.9473684210526,9.21052631578947,0.0621709704220092 -"988",1.2669160204875,23.9473684210526,9.21052631578947,0.0565080654897305 -"989",1.64922134437622,23.9473684210526,9.21052631578947,0.0495040895925201 -"990",2.14689134777813,23.9473684210526,9.21052631578947,0.0429505085494393 -"991",2.79473854427218,23.9473684210526,9.21052631578947,0.0371992127590022 -"992",3.63808049202114,23.9473684210526,9.21052631578947,0.032208641824739 -"993",4.73590980220715,23.9473684210526,9.21052631578947,0.0278862612213654 -"994",6.16502073107827,23.9473684210526,9.21052631578947,0.0241437525813496 -"995",8.02538101483936,23.9473684210526,9.21052631578947,0.0209034849950235 -"996",10.4471247126008,23.9473684210526,9.21052631578947,0.0180980811536359 -"997",13.5996552137305,23.9473684210526,9.21052631578947,0.0156691829294045 -"998",17.7034951740616,23.9473684210526,9.21052631578947,0.0135662609875211 -"999",23.045712295823,23.9473684210526,9.21052631578947,0.0117455669413441 -"1000",30,23.9473684210526,9.21052631578947,0.0101692236998762 -"1001",0.2,26.0526315789474,9.21052631578947,0.0385563145303862 -"1002",0.260352117694686,26.0526315789474,9.21052631578947,0.0385560660486684 -"1003",0.338916125940539,26.0526315789474,9.21052631578947,0.0385545463044881 -"1004",0.441187655547492,26.0526315789474,9.21052631578947,0.0385452661311075 -"1005",0.574320702112717,26.0526315789474,9.21052631578947,0.0384891408088314 -"1006",0.747628055154725,26.0526315789474,9.21052631578947,0.0381680689198052 -"1007",0.973232737037462,26.0526315789474,9.21052631578947,0.0367463805493869 -"1008",1.2669160204875,26.0526315789474,9.21052631578947,0.0333992997777017 -"1009",1.64922134437622,26.0526315789474,9.21052631578947,0.0292595740836901 -"1010",2.14689134777813,26.0526315789474,9.21052631578947,0.0253860559234356 -"1011",2.79473854427218,26.0526315789474,9.21052631578947,0.0219867314101951 -"1012",3.63808049202114,26.0526315789474,9.21052631578947,0.0190370361188985 -"1013",4.73590980220715,26.0526315789474,9.21052631578947,0.0164822771783073 -"1014",6.16502073107827,26.0526315789474,9.21052631578947,0.0142702536927176 -"1015",8.02538101483936,26.0526315789474,9.21052631578947,0.0123550816276724 -"1016",10.4471247126008,26.0526315789474,9.21052631578947,0.0106969373772194 -"1017",13.5996552137305,26.0526315789474,9.21052631578947,0.00926132815546371 -"1018",17.7034951740616,26.0526315789474,9.21052631578947,0.00801838841336908 -"1019",23.045712295823,26.0526315789474,9.21052631578947,0.00694226050623352 -"1020",30,26.0526315789474,9.21052631578947,0.00601055704022284 -"1021",0.2,28.1578947368421,9.21052631578947,0.0209073332967495 -"1022",0.260352117694686,28.1578947368421,9.21052631578947,0.0209071985564311 -"1023",0.338916125940539,28.1578947368421,9.21052631578947,0.0209063744683799 -"1024",0.441187655547492,28.1578947368421,9.21052631578947,0.0209013422530273 -"1025",0.574320702112717,28.1578947368421,9.21052631578947,0.0208709080470223 -"1026",0.747628055154725,28.1578947368421,9.21052631578947,0.0206968053850368 -"1027",0.973232737037462,28.1578947368421,9.21052631578947,0.0199258885335047 -"1028",1.2669160204875,28.1578947368421,9.21052631578947,0.0181109190760475 -"1029",1.64922134437622,28.1578947368421,9.21052631578947,0.0158661343787547 -"1030",2.14689134777813,28.1578947368421,9.21052631578947,0.0137657019024186 -"1031",2.79473854427218,28.1578947368421,9.21052631578947,0.0119224030433921 -"1032",3.63808049202114,28.1578947368421,9.21052631578947,0.0103229176327627 -"1033",4.73590980220715,28.1578947368421,9.21052631578947,0.00893758821748116 -"1034",6.16502073107827,28.1578947368421,9.21052631578947,0.0077381086293319 -"1035",8.02538101483936,28.1578947368421,9.21052631578947,0.00669959804624783 -"1036",10.4471247126008,28.1578947368421,9.21052631578947,0.00580046194051375 -"1037",13.5996552137305,28.1578947368421,9.21052631578947,0.00502199644533582 -"1038",17.7034951740616,28.1578947368421,9.21052631578947,0.00434800683371804 -"1039",23.045712295823,28.1578947368421,9.21052631578947,0.00376447168264219 -"1040",30,28.1578947368421,9.21052631578947,0.00325925132808081 -"1041",0.2,30.2631578947368,9.21052631578947,0.0109427199361197 -"1042",0.260352117694686,30.2631578947368,9.21052631578947,0.0109426494141862 -"1043",0.338916125940539,30.2631578947368,9.21052631578947,0.0109422180935286 -"1044",0.441187655547492,30.2631578947368,9.21052631578947,0.010939584274931 -"1045",0.574320702112717,30.2631578947368,9.21052631578947,0.0109236552710708 -"1046",0.747628055154725,30.2631578947368,9.21052631578947,0.0108325314226489 -"1047",0.973232737037462,30.2631578947368,9.21052631578947,0.0104290401174395 -"1048",1.2669160204875,30.2631578947368,9.21052631578947,0.00947910058265188 -"1049",1.64922134437622,30.2631578947368,9.21052631578947,0.00830419941707946 -"1050",2.14689134777813,30.2631578947368,9.21052631578947,0.00720485097282572 -"1051",2.79473854427218,30.2631578947368,9.21052631578947,0.00624008407086828 -"1052",3.63808049202114,30.2631578947368,9.21052631578947,0.00540292704840152 -"1053",4.73590980220715,30.2631578947368,9.21052631578947,0.00467785744743759 -"1054",6.16502073107827,30.2631578947368,9.21052631578947,0.00405006006094592 -"1055",8.02538101483936,30.2631578947368,9.21052631578947,0.00350651247885653 -"1056",10.4471247126008,30.2631578947368,9.21052631578947,0.0030359123095355 -"1057",13.5996552137305,30.2631578947368,9.21052631578947,0.00262847010862176 -"1058",17.7034951740616,30.2631578947368,9.21052631578947,0.0022757096941248 -"1059",23.045712295823,30.2631578947368,9.21052631578947,0.00197029237282075 -"1060",30,30.2631578947368,9.21052631578947,0.00170586434809261 -"1061",0.2,32.3684210526316,9.21052631578947,0.00567095390899693 -"1062",0.260352117694686,32.3684210526316,9.21052631578947,0.00567091736171833 -"1063",0.338916125940539,32.3684210526316,9.21052631578947,0.0056706938341508 -"1064",0.441187655547492,32.3684210526316,9.21052631578947,0.00566932888430665 -"1065",0.574320702112717,32.3684210526316,9.21052631578947,0.00566107383919584 -"1066",0.747628055154725,32.3684210526316,9.21052631578947,0.0056138498265712 -"1067",0.973232737037462,32.3684210526316,9.21052631578947,0.00540474453941402 -"1068",1.2669160204875,32.3684210526316,9.21052631578947,0.00491244798521516 -"1069",1.64922134437622,32.3684210526316,9.21052631578947,0.00430356734160155 -"1070",2.14689134777813,32.3684210526316,9.21052631578947,0.00373384113151076 -"1071",2.79473854427218,32.3684210526316,9.21052631578947,0.00323386044427163 -"1072",3.63808049202114,32.3684210526316,9.21052631578947,0.00280001228616136 -"1073",4.73590980220715,32.3684210526316,9.21052631578947,0.00242425230035482 -"1074",6.16502073107827,32.3684210526316,9.21052631578947,0.00209890265568088 -"1075",8.02538101483936,32.3684210526316,9.21052631578947,0.00181721461985706 -"1076",10.4471247126008,32.3684210526316,9.21052631578947,0.00157333084275547 -"1077",13.5996552137305,32.3684210526316,9.21052631578947,0.00136217804386721 -"1078",17.7034951740616,32.3684210526316,9.21052631578947,0.00117936352762178 -"1079",23.045712295823,32.3684210526316,9.21052631578947,0.00102108409049504 -"1080",30,32.3684210526316,9.21052631578947,0.000884046941666011 -"1081",0.2,34.4736842105263,9.21052631578947,0.00294248493466328 -"1082",0.260352117694686,34.4736842105263,9.21052631578947,0.00294246597139565 -"1083",0.338916125940539,34.4736842105263,9.21052631578947,0.00294234998976179 -"1084",0.441187655547492,34.4736842105263,9.21052631578947,0.002941641758939 -"1085",0.574320702112717,34.4736842105263,9.21052631578947,0.00293735846793305 -"1086",0.747628055154725,34.4736842105263,9.21052631578947,0.00291285536881918 -"1087",0.973232737037462,34.4736842105263,9.21052631578947,0.00280435701614481 -"1088",1.2669160204875,34.4736842105263,9.21052631578947,0.00254891935656189 -"1089",1.64922134437622,34.4736842105263,9.21052631578947,0.00223298977053603 -"1090",2.14689134777813,34.4736842105263,9.21052631578947,0.00193737622527069 -"1091",2.79473854427218,34.4736842105263,9.21052631578947,0.00167795150353389 -"1092",3.63808049202114,34.4736842105263,9.21052631578947,0.0014528409331331 -"1093",4.73590980220715,34.4736842105263,9.21052631578947,0.00125787054278468 -"1094",6.16502073107827,34.4736842105263,9.21052631578947,0.00108905654018234 -"1095",8.02538101483936,34.4736842105263,9.21052631578947,0.000942897214081757 -"1096",10.4471247126008,34.4736842105263,9.21052631578947,0.000816353364238138 -"1097",13.5996552137305,34.4736842105263,9.21052631578947,0.000706792620206169 -"1098",17.7034951740616,34.4736842105263,9.21052631578947,0.000611935746297088 -"1099",23.045712295823,34.4736842105263,9.21052631578947,0.000529809376256673 -"1100",30,34.4736842105263,9.21052631578947,0.000458704981407175 -"1101",0.2,36.5789473684211,9.21052631578947,0.00153555162683744 -"1102",0.260352117694686,36.5789473684211,9.21052631578947,0.00153554173075399 -"1103",0.338916125940539,36.5789473684211,9.21052631578947,0.00153548120511307 -"1104",0.441187655547492,36.5789473684211,9.21052631578947,0.00153511161103995 -"1105",0.574320702112717,36.5789473684211,9.21052631578947,0.00153287635253619 -"1106",0.747628055154725,36.5789473684211,9.21052631578947,0.00152008927816118 -"1107",0.973232737037462,36.5789473684211,9.21052631578947,0.00146346882787589 -"1108",1.2669160204875,36.5789473684211,9.21052631578947,0.00133016730809327 -"1109",1.64922134437622,36.5789473684211,9.21052631578947,0.00116529775036906 -"1110",2.14689134777813,36.5789473684211,9.21052631578947,0.00101103022804465 -"1111",2.79473854427218,36.5789473684211,9.21052631578947,0.000875648038381761 -"1112",3.63808049202114,36.5789473684211,9.21052631578947,0.000758172873589866 -"1113",4.73590980220715,36.5789473684211,9.21052631578947,0.000656426524251664 -"1114",6.16502073107827,36.5789473684211,9.21052631578947,0.000568330026874485 -"1115",8.02538101483936,36.5789473684211,9.21052631578947,0.000492055994566856 -"1116",10.4471247126008,36.5789473684211,9.21052631578947,0.000426018404295938 -"1117",13.5996552137305,36.5789473684211,9.21052631578947,0.000368843539353065 -"1118",17.7034951740616,36.5789473684211,9.21052631578947,0.000319341968306119 -"1119",23.045712295823,36.5789473684211,9.21052631578947,0.000276483879336415 -"1120",30,36.5789473684211,9.21052631578947,0.000239377667542358 -"1121",0.2,38.6842105263158,9.21052631578947,0.00080736165864245 -"1122",0.260352117694686,38.6842105263158,9.21052631578947,0.000807356455484048 -"1123",0.338916125940539,38.6842105263158,9.21052631578947,0.0008073246323392 -"1124",0.441187655547492,38.6842105263158,9.21052631578947,0.000807130307330072 -"1125",0.574320702112717,38.6842105263158,9.21052631578947,0.000805955054097585 -"1126",0.747628055154725,38.6842105263158,9.21052631578947,0.00079923187175962 -"1127",0.973232737037462,38.6842105263158,9.21052631578947,0.000769461996324326 -"1128",1.2669160204875,38.6842105263158,9.21052631578947,0.000699374781912059 -"1129",1.64922134437622,38.6842105263158,9.21052631578947,0.000612689738402313 -"1130",2.14689134777813,38.6842105263158,9.21052631578947,0.000531579028399675 -"1131",2.79473854427218,38.6842105263158,9.21052631578947,0.000460397840293356 -"1132",3.63808049202114,38.6842105263158,9.21052631578947,0.000398631799843763 -"1133",4.73590980220715,38.6842105263158,9.21052631578947,0.000345135649061982 -"1134",6.16502073107827,38.6842105263158,9.21052631578947,0.00029881631143768 -"1135",8.02538101483936,38.6842105263158,9.21052631578947,0.000258712984295196 -"1136",10.4471247126008,38.6842105263158,9.21052631578947,0.00022399176914225 -"1137",13.5996552137305,38.6842105263158,9.21052631578947,0.000193930393812261 -"1138",17.7034951740616,38.6842105263158,9.21052631578947,0.000167903479570256 -"1139",23.045712295823,38.6842105263158,9.21052631578947,0.000145369572411373 -"1140",30,38.6842105263158,9.21052631578947,0.000125859884702801 -"1141",0.2,40.7894736842105,9.21052631578947,0.000427950805042532 -"1142",0.260352117694686,40.7894736842105,9.21052631578947,0.00042794804705198 -"1143",0.338916125940539,40.7894736842105,9.21052631578947,0.00042793117884885 -"1144",0.441187655547492,40.7894736842105,9.21052631578947,0.000427828174769816 -"1145",0.574320702112717,40.7894736842105,9.21052631578947,0.000427205219045342 -"1146",0.747628055154725,40.7894736842105,9.21052631578947,0.000423641523317188 -"1147",0.973232737037462,40.7894736842105,9.21052631578947,0.00040786167791312 -"1148",1.2669160204875,40.7894736842105,9.21052631578947,0.000370711189640798 -"1149",1.64922134437622,40.7894736842105,9.21052631578947,0.000324762842009924 -"1150",2.14689134777813,40.7894736842105,9.21052631578947,0.000281769230322237 -"1151",2.79473854427218,40.7894736842105,9.21052631578947,0.000244038869426472 -"1152",3.63808049202114,40.7894736842105,9.21052631578947,0.000211299109677243 -"1153",4.73590980220715,40.7894736842105,9.21052631578947,0.000182942894654306 -"1154",6.16502073107827,40.7894736842105,9.21052631578947,0.000158390827296182 -"1155",8.02538101483936,40.7894736842105,9.21052631578947,0.000137133623722299 -"1156",10.4471247126008,40.7894736842105,9.21052631578947,0.000118729266991088 -"1157",13.5996552137305,40.7894736842105,9.21052631578947,0.000102794908905783 -"1158",17.7034951740616,40.7894736842105,9.21052631578947,8.89990606840978e-05 -"1159",23.045712295823,40.7894736842105,9.21052631578947,7.70547187573181e-05 -"1160",30,40.7894736842105,9.21052631578947,6.67133971554841e-05 -"1161",0.2,42.8947368421053,9.21052631578947,0.000228722834213445 -"1162",0.260352117694686,42.8947368421053,9.21052631578947,0.000228721360176223 -"1163",0.338916125940539,42.8947368421053,9.21052631578947,0.000228712344786645 -"1164",0.441187655547492,42.8947368421053,9.21052631578947,0.000228657293167125 -"1165",0.574320702112717,42.8947368421053,9.21052631578947,0.000228324347891144 -"1166",0.747628055154725,42.8947368421053,9.21052631578947,0.000226419693015833 -"1167",0.973232737037462,42.8947368421053,9.21052631578947,0.000217985987735363 -"1168",1.2669160204875,42.8947368421053,9.21052631578947,0.000198130516335527 -"1169",1.64922134437622,42.8947368421053,9.21052631578947,0.000173572935946086 -"1170",2.14689134777813,42.8947368421053,9.21052631578947,0.00015059454543388 -"1171",2.79473854427218,42.8947368421053,9.21052631578947,0.000130429154977101 -"1172",3.63808049202114,42.8947368421053,9.21052631578947,0.000112931044088942 -"1173",4.73590980220715,42.8947368421053,9.21052631578947,9.77757650447371e-05 -"1174",6.16502073107827,42.8947368421053,9.21052631578947,8.46536529566628e-05 -"1175",8.02538101483936,42.8947368421053,9.21052631578947,7.32925156680266e-05 -"1176",10.4471247126008,42.8947368421053,9.21052631578947,6.34561125491691e-05 -"1177",13.5996552137305,42.8947368421053,9.21052631578947,5.49398263319235e-05 -"1178",17.7034951740616,42.8947368421053,9.21052631578947,4.75664893304223e-05 -"1179",23.045712295823,42.8947368421053,9.21052631578947,4.1182709451714e-05 -"1180",30,42.8947368421053,9.21052631578947,3.56556807409043e-05 -"1181",0.2,45,9.21052631578947,0.000123254185315348 -"1182",0.260352117694686,45,9.21052631578947,0.000123253390986013 -"1183",0.338916125940539,45,9.21052631578947,0.000123248532771914 -"1184",0.441187655547492,45,9.21052631578947,0.000123218866549311 -"1185",0.574320702112717,45,9.21052631578947,0.000123039448963452 -"1186",0.747628055154725,45,9.21052631578947,0.000122013068340936 -"1187",0.973232737037462,45,9.21052631578947,0.000117468312339163 -"1188",1.2669160204875,45,9.21052631578947,0.000106768593791801 -"1189",1.64922134437622,45,9.21052631578947,9.35350022502052e-05 -"1190",2.14689134777813,45,9.21052631578947,8.1152404718221e-05 -"1191",2.79473854427218,45,9.21052631578947,7.02856769563713e-05 -"1192",3.63808049202114,45,9.21052631578947,6.08562930931714e-05 -"1193",4.73590980220715,45,9.21052631578947,5.26894147041204e-05 -"1194",6.16502073107827,45,9.21052631578947,4.56181695414141e-05 -"1195",8.02538101483936,45,9.21052631578947,3.94958786665996e-05 -"1196",10.4471247126008,45,9.21052631578947,3.41952367039492e-05 -"1197",13.5996552137305,45,9.21052631578947,2.96059794781517e-05 -"1198",17.7034951740616,45,9.21052631578947,2.56326348477356e-05 -"1199",23.045712295823,45,9.21052631578947,2.21925428652778e-05 -"1200",30,45,9.21052631578947,1.92141370436288e-05 -"1201",0.2,5,11.3157894736842,0.0298790200958854 -"1202",0.260352117694686,5,11.3157894736842,0.0298788275362403 -"1203",0.338916125940539,5,11.3157894736842,0.0298776498182075 -"1204",0.441187655547492,5,11.3157894736842,0.0298704581949854 -"1205",0.574320702112717,5,11.3157894736842,0.02982696416158 -"1206",0.747628055154725,5,11.3157894736842,0.0295781511320858 -"1207",0.973232737037462,5,11.3157894736842,0.0284764209509934 -"1208",1.2669160204875,5,11.3157894736842,0.0258826177087017 -"1209",1.64922134437622,5,11.3157894736842,0.0226745583101473 -"1210",2.14689134777813,5,11.3157894736842,0.0196727950876586 -"1211",2.79473854427218,5,11.3157894736842,0.0170385058232243 -"1212",3.63808049202114,5,11.3157894736842,0.014752654440413 -"1213",4.73590980220715,5,11.3157894736842,0.0127728569764747 -"1214",6.16502073107827,5,11.3157894736842,0.0110586606124416 -"1215",8.02538101483936,5,11.3157894736842,0.00957450774888235 -"1216",10.4471247126008,5,11.3157894736842,0.00828953728465095 -"1217",13.5996552137305,5,11.3157894736842,0.00717701921052664 -"1218",17.7034951740616,5,11.3157894736842,0.00621380937098786 -"1219",23.045712295823,5,11.3157894736842,0.00537986951561848 -"1220",30,5,11.3157894736842,0.004657850647285 -"1221",0.2,7.10526315789474,11.3157894736842,0.0383612525544718 -"1222",0.260352117694686,7.10526315789474,11.3157894736842,0.038361005329859 -"1223",0.338916125940539,7.10526315789474,11.3157894736842,0.0383594932742845 -"1224",0.441187655547492,7.10526315789474,11.3157894736842,0.0383502600506442 -"1225",0.574320702112717,7.10526315789474,11.3157894736842,0.0382944186744972 -"1226",0.747628055154725,7.10526315789474,11.3157894736842,0.03797497113463 -"1227",0.973232737037462,7.10526315789474,11.3157894736842,0.0365604752914552 -"1228",1.2669160204875,7.10526315789474,11.3157894736842,0.033230327885856 -"1229",1.64922134437622,7.10526315789474,11.3157894736842,0.0291115456633212 -"1230",2.14689134777813,7.10526315789474,11.3157894736842,0.025257624192099 -"1231",2.79473854427218,7.10526315789474,11.3157894736842,0.0218754973535948 -"1232",3.63808049202114,7.10526315789474,11.3157894736842,0.0189407249977206 -"1233",4.73590980220715,7.10526315789474,11.3157894736842,0.01639889095239 -"1234",6.16502073107827,7.10526315789474,11.3157894736842,0.0141980584137859 -"1235",8.02538101483936,7.10526315789474,11.3157894736842,0.0122925754814229 -"1236",10.4471247126008,7.10526315789474,11.3157894736842,0.0106428200227355 -"1237",13.5996552137305,7.10526315789474,11.3157894736842,0.00921447375582516 -"1238",17.7034951740616,7.10526315789474,11.3157894736842,0.00797782222579095 -"1239",23.045712295823,7.10526315789474,11.3157894736842,0.00690713860549814 -"1240",30,7.10526315789474,11.3157894736842,0.00598014876217831 -"1241",0.2,9.21052631578947,11.3157894736842,0.048976328621999 -"1242",0.260352117694686,9.21052631578947,11.3157894736842,0.0489760129870007 -"1243",0.338916125940539,9.21052631578947,11.3157894736842,0.0489740825252514 -"1244",0.441187655547492,9.21052631578947,11.3157894736842,0.0489622943440755 -"1245",0.574320702112717,9.21052631578947,11.3157894736842,0.0488910009058596 -"1246",0.747628055154725,9.21052631578947,11.3157894736842,0.048483157922427 -"1247",0.973232737037462,9.21052631578947,11.3157894736842,0.0466772519981768 -"1248",1.2669160204875,9.21052631578947,11.3157894736842,0.0424256078824188 -"1249",1.64922134437622,9.21052631578947,11.3157894736842,0.0371671030573517 -"1250",2.14689134777813,9.21052631578947,11.3157894736842,0.0322467495264043 -"1251",2.79473854427218,9.21052631578947,11.3157894736842,0.0279287425674643 -"1252",3.63808049202114,9.21052631578947,11.3157894736842,0.0241818791112216 -"1253",4.73590980220715,9.21052631578947,11.3157894736842,0.0209366852967097 -"1254",6.16502073107827,9.21052631578947,11.3157894736842,0.0181268527058784 -"1255",8.02538101483936,9.21052631578947,11.3157894736842,0.015694096941543 -"1256",10.4471247126008,9.21052631578947,11.3157894736842,0.0135878318925622 -"1257",13.5996552137305,9.21052631578947,11.3157894736842,0.0117642429454893 -"1258",17.7034951740616,9.21052631578947,11.3157894736842,0.0101853932549102 -"1259",23.045712295823,9.21052631578947,11.3157894736842,0.00881843703357225 -"1260",30,9.21052631578947,11.3157894736842,0.00763493659569631 -"1261",0.2,11.3157894736842,11.3157894736842,0.0620126961672388 -"1262",0.260352117694686,11.3157894736842,11.3157894736842,0.0620122965174937 -"1263",0.338916125940539,11.3157894736842,11.3157894736842,0.0620098522114118 -"1264",0.441187655547492,11.3157894736842,11.3157894736842,0.0619949262886611 -"1265",0.574320702112717,11.3157894736842,11.3157894736842,0.0619046561837513 -"1266",0.747628055154725,11.3157894736842,11.3157894736842,0.0613882548174761 -"1267",0.973232737037462,11.3157894736842,11.3157894736842,0.0591016584445327 -"1268",1.2669160204875,11.3157894736842,11.3157894736842,0.0537183248591055 -"1269",1.64922134437622,11.3157894736842,11.3157894736842,0.0470601274975259 -"1270",2.14689134777813,11.3157894736842,11.3157894736842,0.0408300894947797 -"1271",2.79473854427218,11.3157894736842,11.3157894736842,0.0353627288100001 -"1272",3.63808049202114,11.3157894736842,11.3157894736842,0.0306185368374775 -"1273",4.73590980220715,11.3157894736842,11.3157894736842,0.0265095473789918 -"1274",6.16502073107827,11.3157894736842,11.3157894736842,0.0229518022470352 -"1275",8.02538101483936,11.3157894736842,11.3157894736842,0.019871503084001 -"1276",10.4471247126008,11.3157894736842,11.3157894736842,0.0172045989242748 -"1277",13.5996552137305,11.3157894736842,11.3157894736842,0.0148956127162321 -"1278",17.7034951740616,11.3157894736842,11.3157894736842,0.0128965097023806 -"1279",23.045712295823,11.3157894736842,11.3157894736842,0.0111657013054917 -"1280",30,11.3157894736842,11.3157894736842,0.00966718038461501 -"1281",0.2,13.4210526315789,11.3157894736842,0.0773736776002224 -"1282",0.260352117694686,13.4210526315789,11.3157894736842,0.0773731789544218 -"1283",0.338916125940539,13.4210526315789,11.3157894736842,0.0773701291765146 -"1284",0.441187655547492,13.4210526315789,11.3157894736842,0.0773515059976145 -"1285",0.574320702112717,13.4210526315789,11.3157894736842,0.0772388753521836 -"1286",0.747628055154725,13.4210526315789,11.3157894736842,0.0765945577318251 -"1287",0.973232737037462,13.4210526315789,11.3157894736842,0.0737415553388178 -"1288",1.2669160204875,13.4210526315789,11.3157894736842,0.0670247321236172 -"1289",1.64922134437622,13.4210526315789,11.3157894736842,0.0587172523993978 -"1290",2.14689134777813,13.4210526315789,11.3157894736842,0.0509439901215955 -"1291",2.79473854427218,13.4210526315789,11.3157894736842,0.0441223257029509 -"1292",3.63808049202114,13.4210526315789,11.3157894736842,0.0382029639779651 -"1293",4.73590980220715,13.4210526315789,11.3157894736842,0.0330761489018042 -"1294",6.16502073107827,13.4210526315789,11.3157894736842,0.028637125252818 -"1295",8.02538101483936,13.4210526315789,11.3157894736842,0.0247938143006527 -"1296",10.4471247126008,13.4210526315789,11.3157894736842,0.021466299204569 -"1297",13.5996552137305,13.4210526315789,11.3157894736842,0.0185853608566756 -"1298",17.7034951740616,13.4210526315789,11.3157894736842,0.0160910659518671 -"1299",23.045712295823,13.4210526315789,11.3157894736842,0.0139315241295364 -"1300",30,13.4210526315789,11.3157894736842,0.012061809026416 -"1301",0.2,15.5263157894737,11.3157894736842,0.0937748493427402 -"1302",0.260352117694686,15.5263157894737,11.3157894736842,0.0937742449972279 -"1303",0.338916125940539,15.5263157894737,11.3157894736842,0.0937705487471251 -"1304",0.441187655547492,15.5263157894737,11.3157894736842,0.0937479779472123 -"1305",0.574320702112717,15.5263157894737,11.3157894736842,0.0936114725860321 -"1306",0.747628055154725,15.5263157894737,11.3157894736842,0.0928305766838084 -"1307",0.973232737037462,15.5263157894737,11.3157894736842,0.0893728132960957 -"1308",1.2669160204875,15.5263157894737,11.3157894736842,0.0812322013386069 -"1309",1.64922134437622,15.5263157894737,11.3157894736842,0.0711637557933184 -"1310",2.14689134777813,15.5263157894737,11.3157894736842,0.0617427676535428 -"1311",2.79473854427218,15.5263157894737,11.3157894736842,0.0534750909323927 -"1312",3.63808049202114,15.5263157894737,11.3157894736842,0.0463009811940167 -"1313",4.73590980220715,15.5263157894737,11.3157894736842,0.0400874170170737 -"1314",6.16502073107827,15.5263157894737,11.3157894736842,0.0347074378455609 -"1315",8.02538101483936,15.5263157894737,11.3157894736842,0.0300494466954083 -"1316",10.4471247126008,15.5263157894737,11.3157894736842,0.0260165864708601 -"1317",13.5996552137305,15.5263157894737,11.3157894736842,0.0225249654452279 -"1318",17.7034951740616,15.5263157894737,11.3157894736842,0.0195019460390248 -"1319",23.045712295823,15.5263157894737,11.3157894736842,0.0168846385086169 -"1320",30,15.5263157894737,11.3157894736842,0.014618593290825 -"1321",0.2,17.6315789473684,11.3157894736842,0.107246338604769 -"1322",0.260352117694686,17.6315789473684,11.3157894736842,0.107245647440306 -"1323",0.338916125940539,17.6315789473684,11.3157894736842,0.107241420195017 -"1324",0.441187655547492,17.6315789473684,11.3157894736842,0.107215606923474 -"1325",0.574320702112717,17.6315789473684,11.3157894736842,0.107059491501384 -"1326",0.747628055154725,17.6315789473684,11.3157894736842,0.106166413805905 -"1327",0.973232737037462,17.6315789473684,11.3157894736842,0.102211915710808 -"1328",1.2669160204875,17.6315789473684,11.3157894736842,0.0929018412872075 -"1329",1.64922134437622,17.6315789473684,11.3157894736842,0.0813869849292188 -"1330",2.14689134777813,17.6315789473684,11.3157894736842,0.0706125982881154 -"1331",2.79473854427218,17.6315789473684,11.3157894736842,0.0611572052554859 -"1332",3.63808049202114,17.6315789473684,11.3157894736842,0.0529524786408095 -"1333",4.73590980220715,17.6315789473684,11.3157894736842,0.0458462874569952 -"1334",6.16502073107827,17.6315789473684,11.3157894736842,0.0396934322729166 -"1335",8.02538101483936,17.6315789473684,11.3157894736842,0.0343662843264404 -"1336",10.4471247126008,17.6315789473684,11.3157894736842,0.029754072243787 -"1337",13.5996552137305,17.6315789473684,11.3157894736842,0.025760852596738 -"1338",17.7034951740616,17.6315789473684,11.3157894736842,0.0223035528503903 -"1339",23.045712295823,17.6315789473684,11.3157894736842,0.0193102486584207 -"1340",30,17.6315789473684,11.3157894736842,0.0167186683527805 -"1341",0.2,19.7368421052632,11.3157894736842,0.110378812038268 -"1342",0.260352117694686,19.7368421052632,11.3157894736842,0.110378100686129 -"1343",0.338916125940539,19.7368421052632,11.3157894736842,0.110373749970577 -"1344",0.441187655547492,19.7368421052632,11.3157894736842,0.110347182739613 -"1345",0.574320702112717,19.7368421052632,11.3157894736842,0.110186507465704 -"1346",0.747628055154725,19.7368421052632,11.3157894736842,0.109267344570566 -"1347",0.973232737037462,19.7368421052632,11.3157894736842,0.105197342670054 -"1348",1.2669160204875,19.7368421052632,11.3157894736842,0.095615337650265 -"1349",1.64922134437622,19.7368421052632,11.3157894736842,0.0837641529653496 -"1350",2.14689134777813,19.7368421052632,11.3157894736842,0.0726750657912996 -"1351",2.79473854427218,19.7368421052632,11.3157894736842,0.0629434976662303 -"1352",3.63808049202114,19.7368421052632,11.3157894736842,0.0544991256847848 -"1353",4.73590980220715,19.7368421052632,11.3157894736842,0.0471853753862608 -"1354",6.16502073107827,19.7368421052632,11.3157894736842,0.0408528063242537 -"1355",8.02538101483936,19.7368421052632,11.3157894736842,0.0353700619291179 -"1356",10.4471247126008,19.7368421052632,11.3157894736842,0.0306231353936772 -"1357",13.5996552137305,19.7368421052632,11.3157894736842,0.0265132809540447 -"1358",17.7034951740616,19.7368421052632,11.3157894736842,0.0229549996753859 -"1359",23.045712295823,19.7368421052632,11.3157894736842,0.0198742664300639 -"1360",30,19.7368421052632,11.3157894736842,0.0172069907061576 -"1361",0.2,21.8421052631579,11.3157894736842,0.0971665071766236 -"1362",0.260352117694686,21.8421052631579,11.3157894736842,0.0971658809730843 -"1363",0.338916125940539,21.8421052631579,11.3157894736842,0.0971620510366498 -"1364",0.441187655547492,21.8421052631579,11.3157894736842,0.0971386638938596 -"1365",0.574320702112717,21.8421052631579,11.3157894736842,0.0969972213935545 -"1366",0.747628055154725,21.8421052631579,11.3157894736842,0.0961880819727031 -"1367",0.973232737037462,21.8421052631579,11.3157894736842,0.0926052578638712 -"1368",1.2669160204875,21.8421052631579,11.3157894736842,0.0841702154646196 -"1369",1.64922134437622,21.8421052631579,11.3157894736842,0.0737376134056385 -"1370",2.14689134777813,21.8421052631579,11.3157894736842,0.0639758860543243 -"1371",2.79473854427218,21.8421052631579,11.3157894736842,0.055409183200732 -"1372",3.63808049202114,21.8421052631579,11.3157894736842,0.0479755995664677 -"1373",4.73590980220715,21.8421052631579,11.3157894736842,0.0415373025985389 -"1374",6.16502073107827,21.8421052631579,11.3157894736842,0.0359627398192562 -"1375",8.02538101483936,21.8421052631579,11.3157894736842,0.0311362779940206 -"1376",10.4471247126008,21.8421052631579,11.3157894736842,0.0269575568902557 -"1377",13.5996552137305,21.8421052631579,11.3157894736842,0.0233396505771766 -"1378",17.7034951740616,21.8421052631579,11.3157894736842,0.020207294312286 -"1379",23.045712295823,21.8421052631579,11.3157894736842,0.0174953237496108 -"1380",30,21.8421052631579,11.3157894736842,0.015147319988897 -"1381",0.2,23.9473684210526,11.3157894736842,0.0720186540344548 -"1382",0.260352117694686,23.9473684210526,11.3157894736842,0.0720181898998742 -"1383",0.338916125940539,23.9473684210526,11.3157894736842,0.0720153511967546 -"1384",0.441187655547492,23.9473684210526,11.3157894736842,0.0719980169259816 -"1385",0.574320702112717,23.9473684210526,11.3157894736842,0.0718931814349134 -"1386",0.747628055154725,23.9473684210526,11.3157894736842,0.0712934569649372 -"1387",0.973232737037462,23.9473684210526,11.3157894736842,0.0686379105481947 -"1388",1.2669160204875,23.9473684210526,11.3157894736842,0.06238595791586 -"1389",1.64922134437622,23.9473684210526,11.3157894736842,0.0546534379334431 -"1390",2.14689134777813,23.9473684210526,11.3157894736842,0.0474181622677752 -"1391",2.79473854427218,23.9473684210526,11.3157894736842,0.0410686244799513 -"1392",3.63808049202114,23.9473684210526,11.3157894736842,0.0355589411173588 -"1393",4.73590980220715,23.9473684210526,11.3157894736842,0.0307869523387409 -"1394",6.16502073107827,23.9473684210526,11.3157894736842,0.0266551530196119 -"1395",8.02538101483936,23.9473684210526,11.3157894736842,0.023077837188239 -"1396",10.4471247126008,23.9473684210526,11.3157894736842,0.0199806190394846 -"1397",13.5996552137305,23.9473684210526,11.3157894736842,0.0172990701121665 -"1398",17.7034951740616,23.9473684210526,11.3157894736842,0.0149774050785171 -"1399",23.045712295823,23.9473684210526,11.3157894736842,0.0129673249039781 -"1400",30,23.9473684210526,11.3157894736842,0.0112270125738553 -"1401",0.2,26.0526315789474,11.3157894736842,0.0465877801991922 -"1402",0.260352117694686,26.0526315789474,11.3157894736842,0.046587479957538 -"1403",0.338916125940539,26.0526315789474,11.3157894736842,0.0465856436433391 -"1404",0.441187655547492,26.0526315789474,11.3157894736842,0.0465744303652306 -"1405",0.574320702112717,26.0526315789474,11.3157894736842,0.0465066138685127 -"1406",0.747628055154725,26.0526315789474,11.3157894736842,0.0461186611615104 -"1407",0.973232737037462,26.0526315789474,11.3157894736842,0.0444008282690383 -"1408",1.2669160204875,26.0526315789474,11.3157894736842,0.0403565344821588 -"1409",1.64922134437622,26.0526315789474,11.3157894736842,0.0353544840251431 -"1410",2.14689134777813,26.0526315789474,11.3157894736842,0.0306740934109081 -"1411",2.79473854427218,26.0526315789474,11.3157894736842,0.0265666732599555 -"1412",3.63808049202114,26.0526315789474,11.3157894736842,0.0230025422593843 -"1413",4.73590980220715,26.0526315789474,11.3157894736842,0.0199156147499518 -"1414",6.16502073107827,26.0526315789474,11.3157894736842,0.0172428161384329 -"1415",8.02538101483936,26.0526315789474,11.3157894736842,0.0149287045254144 -"1416",10.4471247126008,26.0526315789474,11.3157894736842,0.0129251608563799 -"1417",13.5996552137305,26.0526315789474,11.3157894736842,0.0111905073323151 -"1418",17.7034951740616,26.0526315789474,11.3157894736842,0.00968865726674644 -"1419",23.045712295823,26.0526315789474,11.3157894736842,0.00838836674327493 -"1420",30,26.0526315789474,11.3157894736842,0.00726258496630755 -"1421",0.2,28.1578947368421,11.3157894736842,0.0278049450604962 -"1422",0.260352117694686,28.1578947368421,11.3157894736842,0.0278047658675262 -"1423",0.338916125940539,28.1578947368421,11.3157894736842,0.0278036699016915 -"1424",0.441187655547492,28.1578947368421,11.3157894736842,0.0277969774904965 -"1425",0.574320702112717,28.1578947368421,11.3157894736842,0.0277565026286899 -"1426",0.747628055154725,28.1578947368421,11.3157894736842,0.0275249611459632 -"1427",0.973232737037462,28.1578947368421,11.3157894736842,0.0264997084081406 -"1428",1.2669160204875,28.1578947368421,11.3157894736842,0.024085956001997 -"1429",1.64922134437622,28.1578947368421,11.3157894736842,0.0211005865005421 -"1430",2.14689134777813,28.1578947368421,11.3157894736842,0.0183071929682887 -"1431",2.79473854427218,28.1578947368421,11.3157894736842,0.0158557649081985 -"1432",3.63808049202114,28.1578947368421,11.3157894736842,0.013728587647647 -"1433",4.73590980220715,28.1578947368421,11.3157894736842,0.0118862193390794 -"1434",6.16502073107827,28.1578947368421,11.3157894736842,0.0102910152269002 -"1435",8.02538101483936,28.1578947368421,11.3157894736842,0.00890988596964162 -"1436",10.4471247126008,28.1578947368421,11.3157894736842,0.00771411271310049 -"1437",13.5996552137305,28.1578947368421,11.3157894736842,0.00667882093209275 -"1438",17.7034951740616,28.1578947368421,11.3157894736842,0.00578247304035606 -"1439",23.045712295823,28.1578947368421,11.3157894736842,0.00500642175795484 -"1440",30,28.1578947368421,11.3157894736842,0.00433452238166241 -"1441",0.2,30.2631578947368,11.3157894736842,0.0159791895237446 -"1442",0.260352117694686,30.2631578947368,11.3157894736842,0.015979086543558 -"1443",0.338916125940539,30.2631578947368,11.3157894736842,0.0159784567043065 -"1444",0.441187655547492,30.2631578947368,11.3157894736842,0.0159746106507854 -"1445",0.574320702112717,30.2631578947368,11.3157894736842,0.0159513502024605 -"1446",0.747628055154725,30.2631578947368,11.3157894736842,0.0158182859138223 -"1447",0.973232737037462,30.2631578947368,11.3157894736842,0.0152290846846251 -"1448",1.2669160204875,30.2631578947368,11.3157894736842,0.0138419282965349 -"1449",1.64922134437622,30.2631578947368,11.3157894736842,0.0121262699861746 -"1450",2.14689134777813,30.2631578947368,11.3157894736842,0.0105209381083678 -"1451",2.79473854427218,30.2631578947368,11.3157894736842,0.00911212994525947 -"1452",3.63808049202114,30.2631578947368,11.3157894736842,0.00788966507352543 -"1453",4.73590980220715,30.2631578947368,11.3157894736842,0.00683087670652488 -"1454",6.16502073107827,30.2631578947368,11.3157894736842,0.00591413082617485 -"1455",8.02538101483936,30.2631578947368,11.3157894736842,0.00512041135970923 -"1456",10.4471247126008,30.2631578947368,11.3157894736842,0.00443321390428816 -"1457",13.5996552137305,30.2631578947368,11.3157894736842,0.00383824334976613 -"1458",17.7034951740616,30.2631578947368,11.3157894736842,0.0033231222873038 -"1459",23.045712295823,30.2631578947368,11.3157894736842,0.00287713433463375 -"1460",30,30.2631578947368,11.3157894736842,0.00249100131220544 -"1461",0.2,32.3684210526316,11.3157894736842,0.00905832898063802 -"1462",0.260352117694686,32.3684210526316,11.3157894736842,0.00905827060293327 -"1463",0.338916125940539,32.3684210526316,11.3157894736842,0.00905791355784431 -"1464",0.441187655547492,32.3684210526316,11.3157894736842,0.0090557332959468 -"1465",0.574320702112717,32.3684210526316,11.3157894736842,0.00904254734600545 -"1466",0.747628055154725,32.3684210526316,11.3157894736842,0.00896711547880915 -"1467",0.973232737037462,32.3684210526316,11.3157894736842,0.0086331073889787 -"1468",1.2669160204875,32.3684210526316,11.3157894736842,0.00784675218039677 -"1469",1.64922134437622,32.3684210526316,11.3157894736842,0.00687417485596386 -"1470",2.14689134777813,32.3684210526316,11.3157894736842,0.00596413969738022 -"1471",2.79473854427218,32.3684210526316,11.3157894736842,0.00516551046821433 -"1472",3.63808049202114,32.3684210526316,11.3157894736842,0.00447251606077048 -"1473",4.73590980220715,32.3684210526316,11.3157894736842,0.00387230706175262 -"1474",6.16502073107827,32.3684210526316,11.3157894736842,0.00335261951667935 -"1475",8.02538101483936,32.3684210526316,11.3157894736842,0.00290267353945077 -"1476",10.4471247126008,32.3684210526316,11.3157894736842,0.00251311306664885 -"1477",13.5996552137305,32.3684210526316,11.3157894736842,0.0021758344450614 -"1478",17.7034951740616,32.3684210526316,11.3157894736842,0.00188382113351604 -"1479",23.045712295823,32.3684210526316,11.3157894736842,0.00163099819836758 -"1480",30,32.3684210526316,11.3157894736842,0.00141210599846932 -"1481",0.2,34.4736842105263,11.3157894736842,0.00512509624012166 -"1482",0.260352117694686,34.4736842105263,11.3157894736842,0.00512506321070136 -"1483",0.338916125940539,34.4736842105263,11.3157894736842,0.00512486119877986 -"1484",0.441187655547492,34.4736842105263,11.3157894736842,0.00512362763218305 -"1485",0.574320702112717,34.4736842105263,11.3157894736842,0.00511616717643991 -"1486",0.747628055154725,34.4736842105263,11.3157894736842,0.00507348871115349 -"1487",0.973232737037462,34.4736842105263,11.3157894736842,0.00488451085342507 -"1488",1.2669160204875,34.4736842105263,11.3157894736842,0.00443960030408229 -"1489",1.64922134437622,34.4736842105263,11.3157894736842,0.00388932746685888 -"1490",2.14689134777813,34.4736842105263,11.3157894736842,0.00337444025315702 -"1491",2.79473854427218,34.4736842105263,11.3157894736842,0.00292258520700025 -"1492",3.63808049202114,34.4736842105263,11.3157894736842,0.00253049710337679 -"1493",4.73590980220715,34.4736842105263,11.3157894736842,0.00219090589502823 -"1494",6.16502073107827,34.4736842105263,11.3157894736842,0.00189687278042331 -"1495",8.02538101483936,34.4736842105263,11.3157894736842,0.00164229862650583 -"1496",10.4471247126008,34.4736842105263,11.3157894736842,0.00142188988238484 -"1497",13.5996552137305,34.4736842105263,11.3157894736842,0.00123106159616715 -"1498",17.7034951740616,34.4736842105263,11.3157894736842,0.00106584389119468 -"1499",23.045712295823,34.4736842105263,11.3157894736842,0.000922799641298758 -"1500",30,34.4736842105263,11.3157894736842,0.000798953003239084 -"1501",0.2,36.5789473684211,11.3157894736842,0.00290957300546012 -"1502",0.260352117694686,36.5789473684211,11.3157894736842,0.00290955425429815 -"1503",0.338916125940539,36.5789473684211,11.3157894736842,0.00290943956992813 -"1504",0.441187655547492,36.5789473684211,11.3157894736842,0.00290873926072371 -"1505",0.574320702112717,36.5789473684211,11.3157894736842,0.00290450387867005 -"1506",0.747628055154725,36.5789473684211,11.3157894736842,0.00288027484867844 -"1507",0.973232737037462,36.5789473684211,11.3157894736842,0.0027729900587516 -"1508",1.2669160204875,36.5789473684211,11.3157894736842,0.00252040948980964 -"1509",1.64922134437622,36.5789473684211,11.3157894736842,0.00220801360145747 -"1510",2.14689134777813,36.5789473684211,11.3157894736842,0.00191570651732593 -"1511",2.79473854427218,36.5789473684211,11.3157894736842,0.001659183481839 -"1512",3.63808049202114,36.5789473684211,11.3157894736842,0.00143659079116246 -"1513",4.73590980220715,36.5789473684211,11.3157894736842,0.00124380116021514 -"1514",6.16502073107827,36.5789473684211,11.3157894736842,0.00107687535572614 -"1515",8.02538101483936,36.5789473684211,11.3157894736842,0.000932350833371307 -"1516",10.4471247126008,36.5789473684211,11.3157894736842,0.000807222386603533 -"1517",13.5996552137305,36.5789473684211,11.3157894736842,0.000698887088251352 -"1518",17.7034951740616,36.5789473684211,11.3157894736842,0.000605091196059375 -"1519",23.045712295823,36.5789473684211,11.3157894736842,0.000523883416032673 -"1520",30,36.5789473684211,11.3157894736842,0.000453574329523331 -"1521",0.2,38.6842105263158,11.3157894736842,0.00166124956607257 -"1522",0.260352117694686,38.6842105263158,11.3157894736842,0.00166123885991066 -"1523",0.338916125940539,38.6842105263158,11.3157894736842,0.0016611733797321 -"1524",0.441187655547492,38.6842105263158,11.3157894736842,0.00166077353124582 -"1525",0.574320702112717,38.6842105263158,11.3157894736842,0.00165835529785364 -"1526",0.747628055154725,38.6842105263158,11.3157894736842,0.00164452149286425 -"1527",0.973232737037462,38.6842105263158,11.3157894736842,0.00158326617795113 -"1528",1.2669160204875,38.6842105263158,11.3157894736842,0.00143905279689289 -"1529",1.64922134437622,38.6842105263158,11.3157894736842,0.00126068726593904 -"1530",2.14689134777813,38.6842105263158,11.3157894736842,0.00109379163700579 -"1531",2.79473854427218,38.6842105263158,11.3157894736842,0.000947327265570338 -"1532",3.63808049202114,38.6842105263158,11.3157894736842,0.000820235761042565 -"1533",4.73590980220715,38.6842105263158,11.3157894736842,0.00071016060906889 -"1534",6.16502073107827,38.6842105263158,11.3157894736842,0.000614852665342003 -"1535",8.02538101483936,38.6842105263158,11.3157894736842,0.000532334955836774 -"1536",10.4471247126008,38.6842105263158,11.3157894736842,0.000460891628067988 -"1537",13.5996552137305,38.6842105263158,11.3157894736842,0.000399036514949958 -"1538",17.7034951740616,38.6842105263158,11.3157894736842,0.000345482819988222 -"1539",23.045712295823,38.6842105263158,11.3157894736842,0.000299116432522463 -"1540",30,38.6842105263158,11.3157894736842,0.000258972762219153 -"1541",0.2,40.7894736842105,11.3157894736842,0.000954846562880154 -"1542",0.260352117694686,40.7894736842105,11.3157894736842,0.000954840409234062 -"1543",0.338916125940539,40.7894736842105,11.3157894736842,0.000954802772791765 -"1544",0.441187655547492,40.7894736842105,11.3157894736842,0.000954572949434337 -"1545",0.574320702112717,40.7894736842105,11.3157894736842,0.000953183006652758 -"1546",0.747628055154725,40.7894736842105,11.3157894736842,0.000945231666038173 -"1547",0.973232737037462,40.7894736842105,11.3157894736842,0.000910023574432043 -"1548",1.2669160204875,40.7894736842105,11.3157894736842,0.000827133168296178 -"1549",1.64922134437622,40.7894736842105,11.3157894736842,0.000724612922304346 -"1550",2.14689134777813,40.7894736842105,11.3157894736842,0.00062868530197492 -"1551",2.79473854427218,40.7894736842105,11.3157894736842,0.000544501080346996 -"1552",3.63808049202114,40.7894736842105,11.3157894736842,0.000471451919794613 -"1553",4.73590980220715,40.7894736842105,11.3157894736842,0.000408183352165093 -"1554",6.16502073107827,40.7894736842105,11.3157894736842,0.000353402623043254 -"1555",8.02538101483936,40.7894736842105,11.3157894736842,0.000305973414989893 -"1556",10.4471247126008,40.7894736842105,11.3157894736842,0.000264909496988686 -"1557",13.5996552137305,40.7894736842105,11.3157894736842,0.000229356655703709 -"1558",17.7034951740616,40.7894736842105,11.3157894736842,0.000198575271251861 -"1559",23.045712295823,40.7894736842105,11.3157894736842,0.000171924979441994 -"1560",30,40.7894736842105,11.3157894736842,0.000148851356794718 -"1561",0.2,42.8947368421053,11.3157894736842,0.000552683971882075 -"1562",0.260352117694686,42.8947368421053,11.3157894736842,0.000552680410030678 -"1563",0.338916125940539,42.8947368421053,11.3157894736842,0.00055265862531759 -"1564",0.441187655547492,42.8947368421053,11.3157894736842,0.000552525599037816 -"1565",0.574320702112717,42.8947368421053,11.3157894736842,0.000551721072816456 -"1566",0.747628055154725,42.8947368421053,11.3157894736842,0.000547118680470402 -"1567",0.973232737037462,42.8947368421053,11.3157894736842,0.000526739544525702 -"1568",1.2669160204875,42.8947368421053,11.3157894736842,0.000478760947047273 -"1569",1.64922134437622,42.8947368421053,11.3157894736842,0.000419420212152462 -"1570",2.14689134777813,42.8947368421053,11.3157894736842,0.000363895418664236 -"1571",2.79473854427218,42.8947368421053,11.3157894736842,0.000315167935330391 -"1572",3.63808049202114,42.8947368421053,11.3157894736842,0.000272885644367367 -"1573",4.73590980220715,42.8947368421053,11.3157894736842,0.000236264552966777 -"1574",6.16502073107827,42.8947368421053,11.3157894736842,0.000204556389445374 -"1575",8.02538101483936,42.8947368421053,11.3157894736842,0.00017710343091863 -"1576",10.4471247126008,42.8947368421053,11.3157894736842,0.000153334827475696 -"1577",13.5996552137305,42.8947368421053,11.3157894736842,0.00013275614363585 -"1578",17.7034951740616,42.8947368421053,11.3157894736842,0.000114939272862853 -"1579",23.045712295823,42.8947368421053,11.3157894736842,9.95135597672688e-05 -"1580",30,42.8947368421053,11.3157894736842,8.6158093134034e-05 -"1581",0.2,45,11.3157894736842,0.000322180494730967 -"1582",0.260352117694686,45,11.3157894736842,0.000322178418392402 -"1583",0.338916125940539,45,11.3157894736842,0.000322165719255105 -"1584",0.441187655547492,45,11.3157894736842,0.000322088173180296 -"1585",0.574320702112717,45,11.3157894736842,0.000321619184265819 -"1586",0.747628055154725,45,11.3157894736842,0.000318936274830345 -"1587",0.973232737037462,45,11.3157894736842,0.000307056501877106 -"1588",1.2669160204875,45,11.3157894736842,0.000279087953740168 -"1589",1.64922134437622,45,11.3157894736842,0.000244495983828313 -"1590",2.14689134777813,45,11.3157894736842,0.000212128471206311 -"1591",2.79473854427218,45,11.3157894736842,0.000183723369039094 -"1592",3.63808049202114,45,11.3157894736842,0.000159075414486628 -"1593",4.73590980220715,45,11.3157894736842,0.000137727588341333 -"1594",6.16502073107827,45,11.3157894736842,0.000119243694597231 -"1595",8.02538101483936,45,11.3157894736842,0.000103240321584883 -"1596",10.4471247126008,45,11.3157894736842,8.9384699193245e-05 -"1597",13.5996552137305,45,11.3157894736842,7.73886021871096e-05 -"1598",17.7034951740616,45,11.3157894736842,6.70024709941701e-05 -"1599",23.045712295823,45,11.3157894736842,5.80102364993121e-05 -"1600",30,45,11.3157894736842,5.0224827357437e-05 -"1601",0.2,5,13.4210526315789,0.0307552335173888 -"1602",0.260352117694686,5,13.4210526315789,0.0307550353108602 -"1603",0.338916125940539,5,13.4210526315789,0.0307538230558063 -"1604",0.441187655547492,5,13.4210526315789,0.0307464205355478 -"1605",0.574320702112717,5,13.4210526315789,0.0307016510233716 -"1606",0.747628055154725,5,13.4210526315789,0.0304455414588776 -"1607",0.973232737037462,5,13.4210526315789,0.0293115026288252 -"1608",1.2669160204875,5,13.4210526315789,0.0266416351378954 -"1609",1.64922134437622,5,13.4210526315789,0.0233394981995498 -"1610",2.14689134777813,5,13.4210526315789,0.0202497071496665 -"1611",2.79473854427218,5,13.4210526315789,0.0175381663688768 -"1612",3.63808049202114,5,13.4210526315789,0.0151852815406997 -"1613",4.73590980220715,5,13.4210526315789,0.0131474257768509 -"1614",6.16502073107827,5,13.4210526315789,0.0113829599643406 -"1615",8.02538101483936,5,13.4210526315789,0.00985528376385662 -"1616",10.4471247126008,5,13.4210526315789,0.00853263106093795 -"1617",13.5996552137305,5,13.4210526315789,0.00738748797886209 -"1618",17.7034951740616,5,13.4210526315789,0.0063960316511045 -"1619",23.045712295823,5,13.4210526315789,0.00553763619807307 -"1620",30,5,13.4210526315789,0.00479444385681503 -"1621",0.2,7.10526315789474,13.4210526315789,0.039446288961373 -"1622",0.260352117694686,7.10526315789474,13.4210526315789,0.0394460347440868 -"1623",0.338916125940539,7.10526315789474,13.4210526315789,0.0394444799204785 -"1624",0.441187655547492,7.10526315789474,13.4210526315789,0.0394349855379048 -"1625",0.574320702112717,7.10526315789474,13.4210526315789,0.0393775647053507 -"1626",0.747628055154725,7.10526315789474,13.4210526315789,0.0390490816885955 -"1627",0.973232737037462,7.10526315789474,13.4210526315789,0.0375945772590203 -"1628",1.2669160204875,7.10526315789474,13.4210526315789,0.0341702376429271 -"1629",1.64922134437622,7.10526315789474,13.4210526315789,0.0299349569130195 -"1630",2.14689134777813,7.10526315789474,13.4210526315789,0.0259720284405353 -"1631",2.79473854427218,7.10526315789474,13.4210526315789,0.0224942391690247 -"1632",3.63808049202114,7.10526315789474,13.4210526315789,0.0194764576661586 -"1633",4.73590980220715,7.10526315789474,13.4210526315789,0.0168627286149084 -"1634",6.16502073107827,7.10526315789474,13.4210526315789,0.0145996461946956 -"1635",8.02538101483936,7.10526315789474,13.4210526315789,0.0126402672548598 -"1636",10.4471247126008,7.10526315789474,13.4210526315789,0.0109438489628194 -"1637",13.5996552137305,7.10526315789474,13.4210526315789,0.00947510235446929 -"1638",17.7034951740616,7.10526315789474,13.4210526315789,0.0082034725105536 -"1639",23.045712295823,7.10526315789474,13.4210526315789,0.0071025049284261 -"1640",30,7.10526315789474,13.4210526315789,0.00614929545822101 -"1641",0.2,9.21052631578947,13.4210526315789,0.0502613578884334 -"1642",0.260352117694686,9.21052631578947,13.4210526315789,0.050261033971879 -"1643",0.338916125940539,9.21052631578947,13.4210526315789,0.0502590528591333 -"1644",0.441187655547492,9.21052631578947,13.4210526315789,0.0502469553824623 -"1645",0.574320702112717,9.21052631578947,13.4210526315789,0.0501737913639642 -"1646",0.747628055154725,9.21052631578947,13.4210526315789,0.0497552474932956 -"1647",0.973232737037462,9.21052631578947,13.4210526315789,0.0479019586387527 -"1648",1.2669160204875,9.21052631578947,13.4210526315789,0.0435387608954989 -"1649",1.64922134437622,9.21052631578947,13.4210526315789,0.0381422846710226 -"1650",2.14689134777813,9.21052631578947,13.4210526315789,0.033092832073927 -"1651",2.79473854427218,9.21052631578947,13.4210526315789,0.0286615302749893 -"1652",3.63808049202114,9.21052631578947,13.4210526315789,0.0248163575061852 -"1653",4.73590980220715,9.21052631578947,13.4210526315789,0.0214860170679016 -"1654",6.16502073107827,9.21052631578947,13.4210526315789,0.0186024607575799 -"1655",8.02538101483936,9.21052631578947,13.4210526315789,0.016105874925879 -"1656",10.4471247126008,9.21052631578947,13.4210526315789,0.0139443461953 -"1657",13.5996552137305,9.21052631578947,13.4210526315789,0.0120729103549857 -"1658",17.7034951740616,9.21052631578947,13.4210526315789,0.0104526351815912 -"1659",23.045712295823,9.21052631578947,13.4210526315789,0.00904981308790677 -"1660",30,9.21052631578947,13.4210526315789,0.0078352602469149 -"1661",0.2,11.3157894736842,13.4210526315789,0.0634050579206901 -"1662",0.260352117694686,11.3157894736842,13.4210526315789,0.0634046492976694 -"1663",0.338916125940539,11.3157894736842,13.4210526315789,0.0634021501099501 -"1664",0.441187655547492,11.3157894736842,13.4210526315789,0.0633868890576976 -"1665",0.574320702112717,11.3157894736842,13.4210526315789,0.0632945921316798 -"1666",0.747628055154725,11.3157894736842,13.4210526315789,0.0627665960830852 -"1667",0.973232737037462,11.3157894736842,13.4210526315789,0.0604286591052004 -"1668",1.2669160204875,11.3157894736842,13.4210526315789,0.0549244543392943 -"1669",1.64922134437622,11.3157894736842,13.4210526315789,0.0481167614723395 -"1670",2.14689134777813,11.3157894736842,13.4210526315789,0.0417468413619976 -"1671",2.79473854427218,11.3157894736842,13.4210526315789,0.036156722848897 -"1672",3.63808049202114,11.3157894736842,13.4210526315789,0.0313060102465384 -"1673",4.73590980220715,11.3157894736842,13.4210526315789,0.0271047622648641 -"1674",6.16502073107827,11.3157894736842,13.4210526315789,0.0234671356157919 -"1675",8.02538101483936,11.3157894736842,13.4210526315789,0.0203176749582755 -"1676",10.4471247126008,11.3157894736842,13.4210526315789,0.0175908911999893 -"1677",13.5996552137305,11.3157894736842,13.4210526315789,0.0152300616714004 -"1678",17.7034951740616,11.3157894736842,13.4210526315789,0.0131860730978212 -"1679",23.045712295823,11.3157894736842,13.4210526315789,0.0114164031199443 -"1680",30,11.3157894736842,13.4210526315789,0.00988423613389179 -"1681",0.2,13.4210526315789,13.4210526315789,0.0786197138876237 -"1682",0.260352117694686,13.4210526315789,13.4210526315789,0.078619207211563 -"1683",0.338916125940539,13.4210526315789,13.4210526315789,0.0786161083196152 -"1684",0.441187655547492,13.4210526315789,13.4210526315789,0.0785971852304947 -"1685",0.574320702112717,13.4210526315789,13.4210526315789,0.078482740765744 -"1686",0.747628055154725,13.4210526315789,13.4210526315789,0.0778280469662962 -"1687",0.973232737037462,13.4210526315789,13.4210526315789,0.0749290994325125 -"1688",1.2669160204875,13.4210526315789,13.4210526315789,0.0681041075775137 -"1689",1.64922134437622,13.4210526315789,13.4210526315789,0.0596628430635017 -"1690",2.14689134777813,13.4210526315789,13.4210526315789,0.0517643991067352 -"1691",2.79473854427218,13.4210526315789,13.4210526315789,0.0448328776712117 -"1692",3.63808049202114,13.4210526315789,13.4210526315789,0.0388181897353446 -"1693",4.73590980220715,13.4210526315789,13.4210526315789,0.0336088117279411 -"1694",6.16502073107827,13.4210526315789,13.4210526315789,0.029098301434933 -"1695",8.02538101483936,13.4210526315789,13.4210526315789,0.0251930972774983 -"1696",10.4471247126008,13.4210526315789,13.4210526315789,0.021811995423163 -"1697",13.5996552137305,13.4210526315789,13.4210526315789,0.0188846620500545 -"1698",17.7034951740616,13.4210526315789,13.4210526315789,0.0163501986789244 -"1699",23.045712295823,13.4210526315789,13.4210526315789,0.0141558792997003 -"1700",30,13.4210526315789,13.4210526315789,0.012256054048816 -"1701",0.2,15.5263157894737,13.4210526315789,0.0944509136747841 -"1702",0.260352117694686,15.5263157894737,13.4210526315789,0.094450304972278 -"1703",0.338916125940539,15.5263157894737,13.4210526315789,0.0944465820742747 -"1704",0.441187655547492,15.5263157894737,13.4210526315789,0.0944238485514902 -"1705",0.574320702112717,15.5263157894737,13.4210526315789,0.0942863590628337 -"1706",0.747628055154725,15.5263157894737,13.4210526315789,0.0934998333369395 -"1707",0.973232737037462,15.5263157894737,13.4210526315789,0.0900171414048307 -"1708",1.2669160204875,15.5263157894737,13.4210526315789,0.0818178401780544 -"1709",1.64922134437622,15.5263157894737,13.4210526315789,0.0716768067591516 -"1710",2.14689134777813,15.5263157894737,13.4210526315789,0.0621878985523371 -"1711",2.79473854427218,15.5263157894737,13.4210526315789,0.053860616495863 -"1712",3.63808049202114,15.5263157894737,13.4210526315789,0.0466347854298359 -"1713",4.73590980220715,15.5263157894737,13.4210526315789,0.0403764249227005 -"1714",6.16502073107827,15.5263157894737,13.4210526315789,0.0349576591036965 -"1715",8.02538101483936,15.5263157894737,13.4210526315789,0.0302660864367761 -"1716",10.4471247126008,15.5263157894737,13.4210526315789,0.0262041515405751 -"1717",13.5996552137305,15.5263157894737,13.4210526315789,0.0226873578758718 -"1718",17.7034951740616,15.5263157894737,13.4210526315789,0.0196425441867674 -"1719",23.045712295823,15.5263157894737,13.4210526315789,0.0170063673296722 -"1720",30,15.5263157894737,13.4210526315789,0.0147239851904426 -"1721",0.2,17.6315789473684,13.4210526315789,0.107165607115603 -"1722",0.260352117694686,17.6315789473684,13.4210526315789,0.107164916471425 -"1723",0.338916125940539,17.6315789473684,13.4210526315789,0.107160692408267 -"1724",0.441187655547492,17.6315789473684,13.4210526315789,0.107134898568099 -"1725",0.574320702112717,17.6315789473684,13.4210526315789,0.106978900664525 -"1726",0.747628055154725,17.6315789473684,13.4210526315789,0.106086495248335 -"1727",0.973232737037462,17.6315789473684,13.4210526315789,0.102134973968338 -"1728",1.2669160204875,17.6315789473684,13.4210526315789,0.092831907860193 -"1729",1.64922134437622,17.6315789473684,13.4210526315789,0.0813257195044262 -"1730",2.14689134777813,17.6315789473684,13.4210526315789,0.0705594434644837 -"1731",2.79473854427218,17.6315789473684,13.4210526315789,0.0611111681383428 -"1732",3.63808049202114,17.6315789473684,13.4210526315789,0.0529126177699274 -"1733",4.73590980220715,17.6315789473684,13.4210526315789,0.0458117758913111 -"1734",6.16502073107827,17.6315789473684,13.4210526315789,0.0396635523726869 -"1735",8.02538101483936,17.6315789473684,13.4210526315789,0.0343404145266238 -"1736",10.4471247126008,17.6315789473684,13.4210526315789,0.0297316743643605 -"1737",13.5996552137305,17.6315789473684,13.4210526315789,0.0257414606807119 -"1738",17.7034951740616,17.6315789473684,13.4210526315789,0.0222867634750258 -"1739",23.045712295823,17.6315789473684,13.4210526315789,0.0192957125432429 -"1740",30,17.6315789473684,13.4210526315789,0.0167060830933623 -"1741",0.2,19.7368421052632,13.4210526315789,0.110698498916854 -"1742",0.260352117694686,19.7368421052632,13.4210526315789,0.110697785504446 -"1743",0.338916125940539,19.7368421052632,13.4210526315789,0.110693422188047 -"1744",0.441187655547492,19.7368421052632,13.4210526315789,0.1106667780112 -"1745",0.574320702112717,19.7368421052632,13.4210526315789,0.110505637378262 -"1746",0.747628055154725,19.7368421052632,13.4210526315789,0.1095838123389 -"1747",0.973232737037462,19.7368421052632,13.4210526315789,0.105502022612633 -"1748",1.2669160204875,19.7368421052632,13.4210526315789,0.0958922655159838 -"1749",1.64922134437622,19.7368421052632,13.4210526315789,0.0840067565964667 -"1750",2.14689134777813,19.7368421052632,13.4210526315789,0.0728855524282257 -"1751",2.79473854427218,19.7368421052632,13.4210526315789,0.0631257990511121 -"1752",3.63808049202114,19.7368421052632,13.4210526315789,0.0546569698856245 -"1753",4.73590980220715,19.7368421052632,13.4210526315789,0.0473220369890954 -"1754",6.16502073107827,19.7368421052632,13.4210526315789,0.0409711270951888 -"1755",8.02538101483936,19.7368421052632,13.4210526315789,0.0354725031901235 -"1756",10.4471247126008,19.7368421052632,13.4210526315789,0.0307118282721902 -"1757",13.5996552137305,19.7368421052632,13.4210526315789,0.0265900705830754 -"1758",17.7034951740616,19.7368421052632,13.4210526315789,0.0230214835599163 -"1759",23.045712295823,19.7368421052632,13.4210526315789,0.0199318276782952 -"1760",30,19.7368421052632,13.4210526315789,0.0172568268028425 -"1761",0.2,21.8421052631579,13.4210526315789,0.10052835049805 -"1762",0.260352117694686,21.8421052631579,13.4210526315789,0.100527702628627 -"1763",0.338916125940539,21.8421052631579,13.4210526315789,0.100523740181037 -"1764",0.441187655547492,21.8421052631579,13.4210526315789,0.100499543871466 -"1765",0.574320702112717,21.8421052631579,13.4210526315789,0.100353207632167 -"1766",0.747628055154725,21.8421052631579,13.4210526315789,0.09951607296854 -"1767",0.973232737037462,21.8421052631579,13.4210526315789,0.0958092874901775 -"1768",1.2669160204875,21.8421052631579,13.4210526315789,0.0870824028524854 -"1769",1.64922134437622,21.8421052631579,13.4210526315789,0.0762888454131351 -"1770",2.14689134777813,21.8421052631579,13.4210526315789,0.0661893741328151 -"1771",2.79473854427218,21.8421052631579,13.4210526315789,0.0573262737487174 -"1772",3.63808049202114,21.8421052631579,13.4210526315789,0.0496354971348836 -"1773",4.73590980220715,21.8421052631579,13.4210526315789,0.0429744428991275 -"1774",6.16502073107827,21.8421052631579,13.4210526315789,0.0372070070075558 -"1775",8.02538101483936,21.8421052631579,13.4210526315789,0.0322135554558727 -"1776",10.4471247126008,21.8421052631579,13.4210526315789,0.0278902556691543 -"1777",13.5996552137305,21.8421052631579,13.4210526315789,0.0241471741848192 -"1778",17.7034951740616,21.8421052631579,13.4210526315789,0.0209064421915482 -"1779",23.045712295823,21.8421052631579,13.4210526315789,0.0181006407360175 -"1780",30,21.8421052631579,13.4210526315789,0.0156713988924394 -"1781",0.2,23.9473684210526,13.4210526315789,0.0795134673775562 -"1782",0.260352117694686,23.9473684210526,13.4210526315789,0.0795129549415724 -"1783",0.338916125940539,23.9473684210526,13.4210526315789,0.0795098208212403 -"1784",0.441187655547492,23.9473684210526,13.4210526315789,0.0794906826133398 -"1785",0.574320702112717,23.9473684210526,13.4210526315789,0.0793749371372432 -"1786",0.747628055154725,23.9473684210526,13.4210526315789,0.0787128007405235 -"1787",0.973232737037462,23.9473684210526,13.4210526315789,0.0757808978022067 -"1788",1.2669160204875,23.9473684210526,13.4210526315789,0.0688783190419963 -"1789",1.64922134437622,23.9473684210526,13.4210526315789,0.0603410937409783 -"1790",2.14689134777813,23.9473684210526,13.4210526315789,0.0523528598129396 -"1791",2.79473854427218,23.9473684210526,13.4210526315789,0.0453425404377238 -"1792",3.63808049202114,23.9473684210526,13.4210526315789,0.0392594771788274 -"1793",4.73590980220715,23.9473684210526,13.4210526315789,0.0339908786586 -"1794",6.16502073107827,23.9473684210526,13.4210526315789,0.0294290926216797 -"1795",8.02538101483936,23.9473684210526,13.4210526315789,0.0254794938757631 -"1796",10.4471247126008,23.9473684210526,13.4210526315789,0.0220599554584756 -"1797",13.5996552137305,23.9473684210526,13.4210526315789,0.019099343988958 -"1798",17.7034951740616,23.9473684210526,13.4210526315789,0.0165360686905002 -"1799",23.045712295823,23.9473684210526,13.4210526315789,0.0143168041606742 -"1800",30,23.9473684210526,13.4210526315789,0.0123953815856038 -"1801",0.2,26.0526315789474,13.4210526315789,0.0561573431543323 -"1802",0.260352117694686,26.0526315789474,13.4210526315789,0.0561569812402524 -"1803",0.338916125940539,26.0526315789474,13.4210526315789,0.0561547677300537 -"1804",0.441187655547492,26.0526315789474,13.4210526315789,0.0561412511404259 -"1805",0.574320702112717,26.0526315789474,13.4210526315789,0.0560595045051187 -"1806",0.747628055154725,26.0526315789474,13.4210526315789,0.0555918627071703 -"1807",0.973232737037462,26.0526315789474,13.4210526315789,0.0535211709761651 -"1808",1.2669160204875,26.0526315789474,13.4210526315789,0.0486461416651385 -"1809",1.64922134437622,26.0526315789474,13.4210526315789,0.0426166235642785 -"1810",2.14689134777813,26.0526315789474,13.4210526315789,0.0369748372268288 -"1811",2.79473854427218,26.0526315789474,13.4210526315789,0.0320237148099667 -"1812",3.63808049202114,26.0526315789474,13.4210526315789,0.0277274781833172 -"1813",4.73590980220715,26.0526315789474,13.4210526315789,0.0240064670791488 -"1814",6.16502073107827,26.0526315789474,13.4210526315789,0.0207846507966874 -"1815",8.02538101483936,26.0526315789474,13.4210526315789,0.017995199155204 -"1816",10.4471247126008,26.0526315789474,13.4210526315789,0.0155801089992533 -"1817",13.5996552137305,26.0526315789474,13.4210526315789,0.0134891415226258 -"1818",17.7034951740616,26.0526315789474,13.4210526315789,0.0116787974981223 -"1819",23.045712295823,26.0526315789474,13.4210526315789,0.0101114152185909 -"1820",30,26.0526315789474,13.4210526315789,0.00875438740366299 -"1821",0.2,28.1578947368421,13.4210526315789,0.0368681294977417 -"1822",0.260352117694686,28.1578947368421,13.4210526315789,0.0368678918957753 -"1823",0.338916125940539,28.1578947368421,13.4210526315789,0.0368664386934678 -"1824",0.441187655547492,28.1578947368421,13.4210526315789,0.0368575648517087 -"1825",0.574320702112717,28.1578947368421,13.4210526315789,0.0368038969720117 -"1826",0.747628055154725,28.1578947368421,13.4210526315789,0.0364968831890067 -"1827",0.973232737037462,28.1578947368421,13.4210526315789,0.0351374433259278 -"1828",1.2669160204875,28.1578947368421,13.4210526315789,0.0319369142081191 -"1829",1.64922134437622,28.1578947368421,13.4210526315789,0.0279784460601413 -"1830",2.14689134777813,28.1578947368421,13.4210526315789,0.0242745295711427 -"1831",2.79473854427218,28.1578947368421,13.4210526315789,0.0210240441996679 -"1832",3.63808049202114,28.1578947368421,13.4210526315789,0.0182035010719606 -"1833",4.73590980220715,28.1578947368421,13.4210526315789,0.0157606020396115 -"1834",6.16502073107827,28.1578947368421,13.4210526315789,0.0136454318188038 -"1835",8.02538101483936,28.1578947368421,13.4210526315789,0.0118141154037222 -"1836",10.4471247126008,28.1578947368421,13.4210526315789,0.0102285728616969 -"1837",13.5996552137305,28.1578947368421,13.4210526315789,0.00885582167060139 -"1838",17.7034951740616,28.1578947368421,13.4210526315789,0.00766730394198601 -"1839",23.045712295823,28.1578947368421,13.4210526315789,0.00663829420597663 -"1840",30,28.1578947368421,13.4210526315789,0.00574738529892055 -"1841",0.2,30.2631578947368,13.4210526315789,0.0232830828570715 -"1842",0.260352117694686,30.2631578947368,13.4210526315789,0.0232829328058932 -"1843",0.338916125940539,30.2631578947368,13.4210526315789,0.0232820150747744 -"1844",0.441187655547492,30.2631578947368,13.4210526315789,0.0232764110369305 -"1845",0.574320702112717,30.2631578947368,13.4210526315789,0.0232425185203648 -"1846",0.747628055154725,30.2631578947368,13.4210526315789,0.0230486321625444 -"1847",0.973232737037462,30.2631578947368,13.4210526315789,0.0221901142121501 -"1848",1.2669160204875,30.2631578947368,13.4210526315789,0.0201689054974261 -"1849",1.64922134437622,30.2631578947368,13.4210526315789,0.0176690406241053 -"1850",2.14689134777813,30.2631578947368,13.4210526315789,0.0153299310548414 -"1851",2.79473854427218,30.2631578947368,13.4210526315789,0.0132771738018763 -"1852",3.63808049202114,30.2631578947368,13.4210526315789,0.0114959350941091 -"1853",4.73590980220715,30.2631578947368,13.4210526315789,0.00995318743219887 -"1854",6.16502073107827,30.2631578947368,13.4210526315789,0.00861740815131912 -"1855",8.02538101483936,30.2631578947368,13.4210526315789,0.00746088916294812 -"1856",10.4471247126008,30.2631578947368,13.4210526315789,0.00645958210228888 -"1857",13.5996552137305,30.2631578947368,13.4210526315789,0.00559265773807947 -"1858",17.7034951740616,30.2631578947368,13.4210526315789,0.00484208109832493 -"1859",23.045712295823,30.2631578947368,13.4210526315789,0.00419223747266154 -"1860",30,30.2631578947368,13.4210526315789,0.00362960773842563 -"1861",0.2,32.3684210526316,13.4210526315789,0.014454668909586 -"1862",0.260352117694686,32.3684210526316,13.4210526315789,0.014454575754392 -"1863",0.338916125940539,32.3684210526316,13.4210526315789,0.0144540060059806 -"1864",0.441187655547492,32.3684210526316,13.4210526315789,0.0144505268914626 -"1865",0.574320702112717,32.3684210526316,13.4210526315789,0.0144294856441125 -"1866",0.747628055154725,32.3684210526316,13.4210526315789,0.0143091165707564 -"1867",0.973232737037462,32.3684210526316,13.4210526315789,0.0137761290449177 -"1868",1.2669160204875,32.3684210526316,13.4210526315789,0.0125213165723661 -"1869",1.64922134437622,32.3684210526316,13.4210526315789,0.0109693434387233 -"1870",2.14689134777813,32.3684210526316,13.4210526315789,0.00951717086456242 -"1871",2.79473854427218,32.3684210526316,13.4210526315789,0.00824277233986921 -"1872",3.63808049202114,32.3684210526316,13.4210526315789,0.00713693872119553 -"1873",4.73590980220715,32.3684210526316,13.4210526315789,0.00617916578361492 -"1874",6.16502073107827,32.3684210526316,13.4210526315789,0.00534988353779165 -"1875",8.02538101483936,32.3684210526316,13.4210526315789,0.00463189017036801 -"1876",10.4471247126008,32.3684210526316,13.4210526315789,0.00401025590795056 -"1877",13.5996552137305,32.3684210526316,13.4210526315789,0.00347204948867071 -"1878",17.7034951740616,32.3684210526316,13.4210526315789,0.00300607439054807 -"1879",23.045712295823,32.3684210526316,13.4210526315789,0.00260263664522749 -"1880",30,32.3684210526316,13.4210526315789,0.002253343272997 -"1881",0.2,34.4736842105263,13.4210526315789,0.00892695208868101 -"1882",0.260352117694686,34.4736842105263,13.4210526315789,0.00892689455765354 -"1883",0.338916125940539,34.4736842105263,13.4210526315789,0.00892654269094508 -"1884",0.441187655547492,34.4736842105263,13.4210526315789,0.00892439405033582 -"1885",0.574320702112717,34.4736842105263,13.4210526315789,0.00891139934197164 -"1886",0.747628055154725,34.4736842105263,13.4210526315789,0.00883706149601126 -"1887",0.973232737037462,34.4736842105263,13.4210526315789,0.0085078976710363 -"1888",1.2669160204875,34.4736842105263,13.4210526315789,0.00773294731466261 -"1889",1.64922134437622,34.4736842105263,13.4210526315789,0.00677447570292184 -"1890",2.14689134777813,34.4736842105263,13.4210526315789,0.00587763918074917 -"1891",2.79473854427218,34.4736842105263,13.4210526315789,0.00509059281925988 -"1892",3.63808049202114,34.4736842105263,13.4210526315789,0.00440764921164767 -"1893",4.73590980220715,34.4736842105263,13.4210526315789,0.00381614530525607 -"1894",6.16502073107827,34.4736842105263,13.4210526315789,0.00330399501507898 -"1895",8.02538101483936,34.4736842105263,13.4210526315789,0.00286057480040143 -"1896",10.4471247126008,34.4736842105263,13.4210526315789,0.00247666429286964 -"1897",13.5996552137305,34.4736842105263,13.4210526315789,0.00214427737008475 -"1898",17.7034951740616,34.4736842105263,13.4210526315789,0.00185649925482812 -"1899",23.045712295823,34.4736842105263,13.4210526315789,0.0016073431208641 -"1900",30,34.4736842105263,13.4210526315789,0.00139162560991319 -"1901",0.2,36.5789473684211,13.4210526315789,0.00551733522120951 -"1902",0.260352117694686,36.5789473684211,13.4210526315789,0.00551729966394864 -"1903",0.338916125940539,36.5789473684211,13.4210526315789,0.00551708219144913 -"1904",0.441187655547492,36.5789473684211,13.4210526315789,0.00551575421630224 -"1905",0.574320702112717,36.5789473684211,13.4210526315789,0.00550772278951348 -"1906",0.747628055154725,36.5789473684211,13.4210526315789,0.00546177801332205 -"1907",0.973232737037462,36.5789473684211,13.4210526315789,0.00525833711355682 -"1908",1.2669160204875,36.5789473684211,13.4210526315789,0.00477937622596219 -"1909",1.64922134437622,36.5789473684211,13.4210526315789,0.00418698935870298 -"1910",2.14689134777813,36.5789473684211,13.4210526315789,0.003632696282825 -"1911",2.79473854427218,36.5789473684211,13.4210526315789,0.00314625941525453 -"1912",3.63808049202114,36.5789473684211,13.4210526315789,0.00272416363351998 -"1913",4.73590980220715,36.5789473684211,13.4210526315789,0.00235858249184953 -"1914",6.16502073107827,36.5789473684211,13.4210526315789,0.00204204614142713 -"1915",8.02538101483936,36.5789473684211,13.4210526315789,0.00176798866425765 -"1916",10.4471247126008,36.5789473684211,13.4210526315789,0.00153071137812958 -"1917",13.5996552137305,36.5789473684211,13.4210526315789,0.00132527843103492 -"1918",17.7034951740616,36.5789473684211,13.4210526315789,0.00114741611975268 -"1919",23.045712295823,36.5789473684211,13.4210526315789,0.000993424264543426 -"1920",30,36.5789473684211,13.4210526315789,0.000860099271961667 -"1921",0.2,38.6842105263158,13.4210526315789,0.0034225433183194 -"1922",0.260352117694686,38.6842105263158,13.4210526315789,0.00342252126124642 -"1923",0.338916125940539,38.6842105263158,13.4210526315789,0.00342238635752564 -"1924",0.441187655547492,38.6842105263158,13.4210526315789,0.00342156258077769 -"1925",0.574320702112717,38.6842105263158,13.4210526315789,0.00341658048253817 -"1926",0.747628055154725,38.6842105263158,13.4210526315789,0.00338807976970108 -"1927",0.973232737037462,38.6842105263158,13.4210526315789,0.00326188020700499 -"1928",1.2669160204875,38.6842105263158,13.4210526315789,0.00296476859064502 -"1929",1.64922134437622,38.6842105263158,13.4210526315789,0.00259729595519517 -"1930",2.14689134777813,38.6842105263158,13.4210526315789,0.00225345386709 -"1931",2.79473854427218,38.6842105263158,13.4210526315789,0.00195170471027104 -"1932",3.63808049202114,38.6842105263158,13.4210526315789,0.00168986796489566 -"1933",4.73590980220715,38.6842105263158,13.4210526315789,0.00146308868766091 -"1934",6.16502073107827,38.6842105263158,13.4210526315789,0.00126673314142206 -"1935",8.02538101483936,38.6842105263158,13.4210526315789,0.0010967283203055 -"1936",10.4471247126008,38.6842105263158,13.4210526315789,0.000949539186843968 -"1937",13.5996552137305,38.6842105263158,13.4210526315789,0.000822103906540781 -"1938",17.7034951740616,38.6842105263158,13.4210526315789,0.000711771392627217 -"1939",23.045712295823,38.6842105263158,13.4210526315789,0.000616246329532268 -"1940",30,38.6842105263158,13.4210526315789,0.000533541446788955 -"1941",0.2,40.7894736842105,13.4210526315789,0.0021337968636229 -"1942",0.260352117694686,40.7894736842105,13.4210526315789,0.00213378311206192 -"1943",0.338916125940539,40.7894736842105,13.4210526315789,0.00213369900585507 -"1944",0.441187655547492,40.7894736842105,13.4210526315789,0.00213318541929747 -"1945",0.574320702112717,40.7894736842105,13.4210526315789,0.00213007931234453 -"1946",0.747628055154725,40.7894736842105,13.4210526315789,0.00211231044106764 -"1947",0.973232737037462,40.7894736842105,13.4210526315789,0.00203363087268055 -"1948",1.2669160204875,40.7894736842105,13.4210526315789,0.00184839557361467 -"1949",1.64922134437622,40.7894736842105,13.4210526315789,0.00161929344573417 -"1950",2.14689134777813,40.7894736842105,13.4210526315789,0.00140492386704886 -"1951",2.79473854427218,40.7894736842105,13.4210526315789,0.00121679727680973 -"1952",3.63808049202114,40.7894736842105,13.4210526315789,0.00105355422212794 -"1953",4.73590980220715,40.7894736842105,13.4210526315789,0.000912167871250195 -"1954",6.16502073107827,40.7894736842105,13.4210526315789,0.000789749304193128 -"1955",8.02538101483936,40.7894736842105,13.4210526315789,0.000683759190888314 -"1956",10.4471247126008,40.7894736842105,13.4210526315789,0.000591993599592949 -"1957",13.5996552137305,40.7894736842105,13.4210526315789,0.000512543618647385 -"1958",17.7034951740616,40.7894736842105,13.4210526315789,0.000443756418530953 -"1959",23.045712295823,40.7894736842105,13.4210526315789,0.000384200976547688 -"1960",30,40.7894736842105,13.4210526315789,0.000332638321822652 -"1961",0.2,42.8947368421053,13.4210526315789,0.00133783937098357 -"1962",0.260352117694686,42.8947368421053,13.4210526315789,0.00133783074908521 -"1963",0.338916125940539,42.8947368421053,13.4210526315789,0.00133777801651408 -"1964",0.441187655547492,42.8947368421053,13.4210526315789,0.00133745601008091 -"1965",0.574320702112717,42.8947368421053,13.4210526315789,0.00133550855564279 -"1966",0.747628055154725,42.8947368421053,13.4210526315789,0.00132436790023297 -"1967",0.973232737037462,42.8947368421053,13.4210526315789,0.00127503770105856 -"1968",1.2669160204875,42.8947368421053,13.4210526315789,0.00115889961865202 -"1969",1.64922134437622,42.8947368421053,13.4210526315789,0.00101525808843896 -"1970",2.14689134777813,42.8947368421053,13.4210526315789,0.000880853512635317 -"1971",2.79473854427218,42.8947368421053,13.4210526315789,0.000762902660123762 -"1972",3.63808049202114,42.8947368421053,13.4210526315789,0.000660553186602596 -"1973",4.73590980220715,42.8947368421053,13.4210526315789,0.000571907341279348 -"1974",6.16502073107827,42.8947368421053,13.4210526315789,0.000495153840728097 -"1975",8.02538101483936,42.8947368421053,13.4210526315789,0.000428700586001012 -"1976",10.4471247126008,42.8947368421053,13.4210526315789,0.000371165764842786 -"1977",13.5996552137305,42.8947368421053,13.4210526315789,0.000321352535502668 -"1978",17.7034951740616,42.8947368421053,13.4210526315789,0.00027822461357891 -"1979",23.045712295823,42.8947368421053,13.4210526315789,0.000240884782220146 -"1980",30,42.8947368421053,13.4210526315789,0.000208556236452925 -"1981",0.2,45,13.4210526315789,0.000843730768444278 -"1982",0.260352117694686,45,13.4210526315789,0.000843725330899915 -"1983",0.338916125940539,45,13.4210526315789,0.00084369207422223 -"1984",0.441187655547492,45,13.4210526315789,0.000843488995481092 -"1985",0.574320702112717,45,13.4210526315789,0.000842260800777581 -"1986",0.747628055154725,45,13.4210526315789,0.0008352347601678 -"1987",0.973232737037462,45,13.4210526315789,0.000804123845240596 -"1988",1.2669160204875,45,13.4210526315789,0.000730879421702309 -"1989",1.64922134437622,45,13.4210526315789,0.000640289488937749 -"1990",2.14689134777813,45,13.4210526315789,0.000555524995916543 -"1991",2.79473854427218,45,13.4210526315789,0.00048113731860139 -"1992",3.63808049202114,45,13.4210526315789,0.000416588911806939 -"1993",4.73590980220715,45,13.4210526315789,0.000360682927264872 -"1994",6.16502073107827,45,13.4210526315789,0.000312277048797351 -"1995",8.02538101483936,45,13.4210526315789,0.000270367192582485 -"1996",10.4471247126008,45,13.4210526315789,0.000234081895617092 -"1997",13.5996552137305,45,13.4210526315789,0.000202666349639454 -"1998",17.7034951740616,45,13.4210526315789,0.000175467004564578 -"1999",23.045712295823,45,13.4210526315789,0.000151918015583376 -"2000",30,45,13.4210526315789,0.000131529477650897 -"2001",0.2,5,15.5263157894737,0.0316615838339548 -"2002",0.260352117694686,5,15.5263157894737,0.0316613797863212 -"2003",0.338916125940539,5,15.5263157894737,0.0316601318063637 -"2004",0.441187655547492,5,15.5263157894737,0.0316525111353773 -"2005",0.574320702112717,5,15.5263157894737,0.0316064222750156 -"2006",0.747628055154725,5,15.5263157894737,0.0313427652150775 -"2007",0.973232737037462,5,15.5263157894737,0.0301753064972511 -"2008",1.2669160204875,5,15.5263157894737,0.0274267585682676 -"2009",1.64922134437622,5,15.5263157894737,0.024027308343137 -"2010",2.14689134777813,5,15.5263157894737,0.0208464617955089 -"2011",2.79473854427218,5,15.5263157894737,0.0180550124735059 -"2012",3.63808049202114,5,15.5263157894737,0.0156327886202274 -"2013",4.73590980220715,5,15.5263157894737,0.0135348776720914 -"2014",6.16502073107827,5,15.5263157894737,0.0117184134201339 -"2015",8.02538101483936,5,15.5263157894737,0.0101457169206775 -"2016",10.4471247126008,5,15.5263157894737,0.00878408591849413 -"2017",13.5996552137305,5,15.5263157894737,0.0076051957086533 -"2018",17.7034951740616,5,15.5263157894737,0.0065845213697232 -"2019",23.045712295823,5,15.5263157894737,0.00570082918174245 -"2020",30,5,15.5263157894737,0.00493573511720899 -"2021",0.2,7.10526315789474,15.5263157894737,0.0405372676602684 -"2022",0.260352117694686,7.10526315789474,15.5263157894737,0.040537006412013 -"2023",0.338916125940539,7.10526315789474,15.5263157894737,0.0405354085861481 -"2024",0.441187655547492,7.10526315789474,15.5263157894737,0.0405256516143823 -"2025",0.574320702112717,7.10526315789474,15.5263157894737,0.040466642675397 -"2026",0.747628055154725,7.10526315789474,15.5263157894737,0.0401290746982142 -"2027",0.973232737037462,7.10526315789474,15.5263157894737,0.0386343425718924 -"2028",1.2669160204875,7.10526315789474,15.5263157894737,0.0351152948938419 -"2029",1.64922134437622,7.10526315789474,15.5263157894737,0.0307628776428107 -"2030",2.14689134777813,7.10526315789474,15.5263157894737,0.0266903451831692 -"2031",2.79473854427218,7.10526315789474,15.5263157894737,0.0231163695753931 -"2032",3.63808049202114,7.10526315789474,15.5263157894737,0.0200151243190476 -"2033",4.73590980220715,7.10526315789474,15.5263157894737,0.0173291065229071 -"2034",6.16502073107827,7.10526315789474,15.5263157894737,0.0150034333044391 -"2035",8.02538101483936,7.10526315789474,15.5263157894737,0.0129898631911696 -"2036",10.4471247126008,7.10526315789474,15.5263157894737,0.0112465265128941 -"2037",13.5996552137305,7.10526315789474,15.5263157894737,0.00973715830727899 -"2038",17.7034951740616,7.10526315789474,15.5263157894737,0.00843035858784091 -"2039",23.045712295823,7.10526315789474,15.5263157894737,0.00729894119124666 -"2040",30,7.10526315789474,15.5263157894737,0.00631936850019214 -"2041",0.2,9.21052631578947,15.5263157894737,0.0514910310663412 -"2042",0.260352117694686,9.21052631578947,15.5263157894737,0.0514906992249811 -"2043",0.338916125940539,9.21052631578947,15.5263157894737,0.0514886696431667 -"2044",0.441187655547492,9.21052631578947,15.5263157894737,0.0514762761947352 -"2045",0.574320702112717,9.21052631578947,15.5263157894737,0.0514013221762269 -"2046",0.747628055154725,9.21052631578947,15.5263157894737,0.0509725383877932 -"2047",0.973232737037462,9.21052631578947,15.5263157894737,0.0490739077499978 -"2048",1.2669160204875,9.21052631578947,15.5263157894737,0.0446039618514973 -"2049",1.64922134437622,9.21052631578947,15.5263157894737,0.0390754577163707 -"2050",2.14689134777813,9.21052631578947,15.5263157894737,0.0339024673422905 -"2051",2.79473854427218,9.21052631578947,15.5263157894737,0.0293627511830113 -"2052",3.63808049202114,9.21052631578947,15.5263157894737,0.0254235040394417 -"2053",4.73590980220715,9.21052631578947,15.5263157894737,0.0220116848969944 -"2054",6.16502073107827,9.21052631578947,15.5263157894737,0.019057580714495 -"2055",8.02538101483936,9.21052631578947,15.5263157894737,0.0164999144670918 -"2056",10.4471247126008,9.21052631578947,15.5263157894737,0.0142855026864932 -"2057",13.5996552137305,9.21052631578947,15.5263157894737,0.0123682810864284 -"2058",17.7034951740616,9.21052631578947,15.5263157894737,0.010708364944201 -"2059",23.045712295823,9.21052631578947,15.5263157894737,0.00927122199699315 -"2060",30,9.21052631578947,15.5263157894737,0.00802695441858741 -"2061",0.2,11.3157894736842,15.5263157894737,0.0646230734042617 -"2062",0.260352117694686,11.3157894736842,15.5263157894737,0.0646226569315648 -"2063",0.338916125940539,11.3157894736842,15.5263157894737,0.0646201097342791 -"2064",0.441187655547492,11.3157894736842,15.5263157894737,0.0646045555161728 -"2065",0.574320702112717,11.3157894736842,15.5263157894737,0.0645104855599164 -"2066",0.747628055154725,11.3157894736842,15.5263157894737,0.0639723466712465 -"2067",0.973232737037462,11.3157894736842,15.5263157894737,0.0615894977646914 -"2068",1.2669160204875,11.3157894736842,15.5263157894737,0.0559795568501327 -"2069",1.64922134437622,11.3157894736842,15.5263157894737,0.0490410877392745 -"2070",2.14689134777813,11.3157894736842,15.5263157894737,0.0425488010295168 -"2071",2.79473854427218,11.3157894736842,15.5263157894737,0.0368512959588254 -"2072",3.63808049202114,11.3157894736842,15.5263157894737,0.03190740083681 -"2073",4.73590980220715,11.3157894736842,15.5263157894737,0.027625446595102 -"2074",6.16502073107827,11.3157894736842,15.5263157894737,0.0239179408902049 -"2075",8.02538101483936,11.3157894736842,15.5263157894737,0.0207079788788288 -"2076",10.4471247126008,11.3157894736842,15.5263157894737,0.0179288134187216 -"2077",13.5996552137305,11.3157894736842,15.5263157894737,0.0155226321940032 -"2078",17.7034951740616,11.3157894736842,15.5263157894737,0.0134393784606322 -"2079",23.045712295823,11.3157894736842,15.5263157894737,0.0116357130018812 -"2080",30,11.3157894736842,15.5263157894737,0.0100741129836128 -"2081",0.2,13.4210526315789,15.5263157894737,0.0795195333359126 -"2082",0.260352117694686,13.4210526315789,15.5263157894737,0.0795190208608359 -"2083",0.338916125940539,13.4210526315789,15.5263157894737,0.0795158865014066 -"2084",0.441187655547492,13.4210526315789,15.5263157894737,0.0794967468334821 -"2085",0.574320702112717,13.4210526315789,15.5263157894737,0.0793809925273437 -"2086",0.747628055154725,13.4210526315789,15.5263157894737,0.0787188056172715 -"2087",0.973232737037462,13.4210526315789,15.5263157894737,0.0757866790086544 -"2088",1.2669160204875,13.4210526315789,15.5263157894737,0.0688835736614808 -"2089",1.64922134437622,13.4210526315789,15.5263157894737,0.0603456970688658 -"2090",2.14689134777813,13.4210526315789,15.5263157894737,0.0523568537309253 -"2091",2.79473854427218,13.4210526315789,15.5263157894737,0.045345999549383 -"2092",3.63808049202114,13.4210526315789,15.5263157894737,0.0392624722230824 -"2093",4.73590980220715,13.4210526315789,15.5263157894737,0.0339934717696948 -"2094",6.16502073107827,13.4210526315789,15.5263157894737,0.0294313377212358 -"2095",8.02538101483936,13.4210526315789,15.5263157894737,0.0254814376665937 -"2096",10.4471247126008,13.4210526315789,15.5263157894737,0.022061638378056 -"2097",13.5996552137305,13.4210526315789,15.5263157894737,0.019100801048109 -"2098",17.7034951740616,13.4210526315789,15.5263157894737,0.0165373302013783 -"2099",23.045712295823,13.4210526315789,15.5263157894737,0.0143178963673242 -"2100",30,13.4210526315789,15.5263157894737,0.0123963272099237 -"2101",0.2,15.5263157894737,15.5263157894737,0.0946495841111515 -"2102",0.260352117694686,15.5263157894737,15.5263157894737,0.0946489741282851 -"2103",0.338916125940539,15.5263157894737,15.5263157894737,0.0946452433994442 -"2104",0.441187655547492,15.5263157894737,15.5263157894737,0.094622462058394 -"2105",0.574320702112717,15.5263157894737,15.5263157894737,0.0944846833708759 -"2106",0.747628055154725,15.5263157894737,15.5263157894737,0.0936965032469129 -"2107",0.973232737037462,15.5263157894737,15.5263157894737,0.0902064857326687 -"2108",1.2669160204875,15.5263157894737,15.5263157894737,0.0819899378886893 -"2109",1.64922134437622,15.5263157894737,15.5263157894737,0.0718275735640688 -"2110",2.14689134777813,15.5263157894737,15.5263157894737,0.0623187061481716 -"2111",2.79473854427218,15.5263157894737,15.5263157894737,0.0539739082763861 -"2112",3.63808049202114,15.5263157894737,15.5263157894737,0.0467328782148686 -"2113",4.73590980220715,15.5263157894737,15.5263157894737,0.0404613537142416 -"2114",6.16502073107827,15.5263157894737,15.5263157894737,0.0350311899264096 -"2115",8.02538101483936,15.5263157894737,15.5263157894737,0.0303297488870964 -"2116",10.4471247126008,15.5263157894737,15.5263157894737,0.0262592700144856 -"2117",13.5996552137305,15.5263157894737,15.5263157894737,0.0227350790372017 -"2118",17.7034951740616,15.5263157894737,15.5263157894737,0.019683860810113 -"2119",23.045712295823,15.5263157894737,15.5263157894737,0.0170421389520627 -"2120",30,15.5263157894737,15.5263157894737,0.0147549559926195 -"2121",0.2,17.6315789473684,15.5263157894737,0.106708402843287 -"2122",0.260352117694686,17.6315789473684,15.5263157894737,0.106707715145628 -"2123",0.338916125940539,17.6315789473684,15.5263157894737,0.106703509103734 -"2124",0.441187655547492,17.6315789473684,15.5263157894737,0.106677825308702 -"2125",0.574320702112717,17.6315789473684,15.5263157894737,0.106522492944287 -"2126",0.747628055154725,17.6315789473684,15.5263157894737,0.105633894827658 -"2127",0.973232737037462,17.6315789473684,15.5263157894737,0.101699232057215 -"2128",1.2669160204875,17.6315789473684,15.5263157894737,0.0924358559362286 -"2129",1.64922134437622,17.6315789473684,15.5263157894737,0.0809787568229522 -"2130",2.14689134777813,17.6315789473684,15.5263157894737,0.0702584133124367 -"2131",2.79473854427218,17.6315789473684,15.5263157894737,0.0608504474844772 -"2132",3.63808049202114,17.6315789473684,15.5263157894737,0.0526868748701764 -"2133",4.73590980220715,17.6315789473684,15.5263157894737,0.0456163275546325 -"2134",6.16502073107827,17.6315789473684,15.5263157894737,0.0394943344109908 -"2135",8.02538101483936,17.6315789473684,15.5263157894737,0.0341939068488597 -"2136",10.4471247126008,17.6315789473684,15.5263157894737,0.029604829111407 -"2137",13.5996552137305,17.6315789473684,15.5263157894737,0.0256316390120288 -"2138",17.7034951740616,17.6315789473684,15.5263157894737,0.0221916806984602 -"2139",23.045712295823,17.6315789473684,15.5263157894737,0.0192133905889368 -"2140",30,17.6315789473684,15.5263157894737,0.0166348093632026 -"2141",0.2,19.7368421052632,15.5263157894737,0.110978961161913 -"2142",0.260352117694686,19.7368421052632,15.5263157894737,0.110978245942027 -"2143",0.338916125940539,19.7368421052632,15.5263157894737,0.110973871570865 -"2144",0.441187655547492,19.7368421052632,15.5263157894737,0.110947159889167 -"2145",0.574320702112717,19.7368421052632,15.5263157894737,0.110785610995376 -"2146",0.747628055154725,19.7368421052632,15.5263157894737,0.109861450449005 -"2147",0.973232737037462,19.7368421052632,15.5263157894737,0.105769319228303 -"2148",1.2669160204875,19.7368421052632,15.5263157894737,0.0961352151524614 -"2149",1.64922134437622,19.7368421052632,15.5263157894737,0.0842195934803066 -"2150",2.14689134777813,19.7368421052632,15.5263157894737,0.0730702129779752 -"2151",2.79473854427218,19.7368421052632,15.5263157894737,0.0632857325957969 -"2152",3.63808049202114,19.7368421052632,15.5263157894737,0.0547954470703404 -"2153",4.73590980220715,19.7368421052632,15.5263157894737,0.0474419306178674 -"2154",6.16502073107827,19.7368421052632,15.5263157894737,0.0410749302578348 -"2155",8.02538101483936,19.7368421052632,15.5263157894737,0.035562375211695 -"2156",10.4471247126008,19.7368421052632,15.5263157894737,0.0307896387970969 -"2157",13.5996552137305,19.7368421052632,15.5263157894737,0.0266574383519701 -"2158",17.7034951740616,19.7368421052632,15.5263157894737,0.0230798100686494 -"2159",23.045712295823,19.7368421052632,15.5263157894737,0.0199823263317864 -"2160",30,19.7368421052632,15.5263157894737,0.0173005481580107 -"2161",0.2,21.8421052631579,15.5263157894737,0.104127180038011 -"2162",0.260352117694686,21.8421052631579,15.5263157894737,0.104126508975414 -"2163",0.338916125940539,21.8421052631579,15.5263157894737,0.104122404675566 -"2164",0.441187655547492,21.8421052631579,15.5263157894737,0.104097342158669 -"2165",0.574320702112717,21.8421052631579,15.5263157894737,0.10394576720633 -"2166",0.747628055154725,21.8421052631579,15.5263157894737,0.103078663832966 -"2167",0.973232737037462,21.8421052631579,15.5263157894737,0.0992391785837252 -"2168",1.2669160204875,21.8421052631579,15.5263157894737,0.0901998788902765 -"2169",1.64922134437622,21.8421052631579,15.5263157894737,0.0790199212646946 -"2170",2.14689134777813,21.8421052631579,15.5263157894737,0.0685588974929477 -"2171",2.79473854427218,21.8421052631579,15.5263157894737,0.0593785056450997 -"2172",3.63808049202114,21.8421052631579,15.5263157894737,0.0514124057624966 -"2173",4.73590980220715,21.8421052631579,15.5263157894737,0.0445128914442647 -"2174",6.16502073107827,21.8421052631579,15.5263157894737,0.0385389862477298 -"2175",8.02538101483936,21.8421052631579,15.5263157894737,0.0333667733728823 -"2176",10.4471247126008,21.8421052631579,15.5263157894737,0.0288887031268311 -"2177",13.5996552137305,21.8421052631579,15.5263157894737,0.025011622505441 -"2178",17.7034951740616,21.8421052631579,15.5263157894737,0.021654875060104 -"2179",23.045712295823,21.8421052631579,15.5263157894737,0.0187486282962458 -"2180",30,21.8421052631579,15.5263157894737,0.0162324216585269 -"2181",0.2,23.9473684210526,15.5263157894737,0.0877120925204013 -"2182",0.260352117694686,23.9473684210526,15.5263157894737,0.0877115272471978 -"2183",0.338916125940539,23.9473684210526,15.5263157894737,0.0877080699680525 -"2184",0.441187655547492,23.9473684210526,15.5263157894737,0.0876869584215761 -"2185",0.574320702112717,23.9473684210526,15.5263157894737,0.087559278441781 -"2186",0.747628055154725,23.9473684210526,15.5263157894737,0.0868288692317986 -"2187",0.973232737037462,23.9473684210526,15.5263157894737,0.0835946580941383 -"2188",1.2669160204875,23.9473684210526,15.5263157894737,0.0759803551739788 -"2189",1.64922134437622,23.9473684210526,15.5263157894737,0.06656285748249 -"2190",2.14689134777813,23.9473684210526,15.5263157894737,0.05775095760591 -"2191",2.79473854427218,23.9473684210526,15.5263157894737,0.0500178049474203 -"2192",3.63808049202114,23.9473684210526,15.5263157894737,0.043307517684531 -"2193",4.73590980220715,23.9473684210526,15.5263157894737,0.0374956745326692 -"2194",6.16502073107827,23.9473684210526,15.5263157894737,0.0324635232239015 -"2195",8.02538101483936,23.9473684210526,15.5263157894737,0.0281066817724359 -"2196",10.4471247126008,23.9473684210526,15.5263157894737,0.0243345551135643 -"2197",13.5996552137305,23.9473684210526,15.5263157894737,0.0210686753111123 -"2198",17.7034951740616,23.9473684210526,15.5263157894737,0.0182411009699504 -"2199",23.045712295823,23.9473684210526,15.5263157894737,0.0157930083110924 -"2200",30,23.9473684210526,15.5263157894737,0.0136734680591862 -"2201",0.2,26.0526315789474,15.5263157894737,0.0674340448162541 -"2202",0.260352117694686,26.0526315789474,15.5263157894737,0.0674336102278474 -"2203",0.338916125940539,26.0526315789474,15.5263157894737,0.0674309522326938 -"2204",0.441187655547492,26.0526315789474,15.5263157894737,0.0674147214379388 -"2205",0.574320702112717,26.0526315789474,15.5263157894737,0.0673165596311431 -"2206",0.747628055154725,26.0526315789474,15.5263157894737,0.0667550128023669 -"2207",0.973232737037462,26.0526315789474,15.5263157894737,0.064268514845982 -"2208",1.2669160204875,26.0526315789474,15.5263157894737,0.0584145529849862 -"2209",1.64922134437622,26.0526315789474,15.5263157894737,0.0511742746706008 -"2210",2.14689134777813,26.0526315789474,15.5263157894737,0.0443995867784447 -"2211",2.79473854427218,26.0526315789474,15.5263157894737,0.0384542518997649 -"2212",3.63808049202114,26.0526315789474,15.5263157894737,0.0332953074599163 -"2213",4.73590980220715,26.0526315789474,15.5263157894737,0.0288270969736993 -"2214",6.16502073107827,26.0526315789474,15.5263157894737,0.0249583223597692 -"2215",8.02538101483936,26.0526315789474,15.5263157894737,0.0216087335715744 -"2216",10.4471247126008,26.0526315789474,15.5263157894737,0.0187086801028036 -"2217",13.5996552137305,26.0526315789474,15.5263157894737,0.0161978349201759 -"2218",17.7034951740616,26.0526315789474,15.5263157894737,0.0140239639137482 -"2219",23.045712295823,26.0526315789474,15.5263157894737,0.0121418426995795 -"2220",30,26.0526315789474,15.5263157894737,0.0105123162770552 -"2221",0.2,28.1578947368421,15.5263157894737,0.0486368841609512 -"2222",0.260352117694686,28.1578947368421,15.5263157894737,0.0486365707135516 -"2223",0.338916125940539,28.1578947368421,15.5263157894737,0.0486346536314199 -"2224",0.441187655547492,28.1578947368421,15.5263157894737,0.048622947151607 -"2225",0.574320702112717,28.1578947368421,15.5263157894737,0.0485521478329667 -"2226",0.747628055154725,28.1578947368421,15.5263157894737,0.048147131522043 -"2227",0.973232737037462,28.1578947368421,15.5263157894737,0.046353741945596 -"2228",1.2669160204875,28.1578947368421,15.5263157894737,0.0421315650660734 -"2229",1.64922134437622,28.1578947368421,15.5263157894737,0.0369095058135202 -"2230",2.14689134777813,28.1578947368421,15.5263157894737,0.0320232542007743 -"2231",2.79473854427218,28.1578947368421,15.5263157894737,0.0277351744247453 -"2232",3.63808049202114,28.1578947368421,15.5263157894737,0.0240142796779242 -"2233",4.73590980220715,28.1578947368421,15.5263157894737,0.0207915776078194 -"2234",6.16502073107827,28.1578947368421,15.5263157894737,0.0180012193658474 -"2235",8.02538101483936,28.1578947368421,15.5263157894737,0.0155853245115173 -"2236",10.4471247126008,28.1578947368421,15.5263157894737,0.0134936575352073 -"2237",13.5996552137305,28.1578947368421,15.5263157894737,0.0116827074931877 -"2238",17.7034951740616,28.1578947368421,15.5263157894737,0.0101148004722078 -"2239",23.045712295823,28.1578947368421,15.5263157894737,0.00875731833214308 -"2240",30,28.1578947368421,15.5263157894737,0.0075820204827336 -"2241",0.2,30.2631578947368,15.5263157894737,0.0337681539683947 -"2242",0.260352117694686,30.2631578947368,15.5263157894737,0.0337679363446667 -"2243",0.338916125940539,30.2631578947368,15.5263157894737,0.0337666053316771 -"2244",0.441187655547492,30.2631578947368,15.5263157894737,0.0337584776273727 -"2245",0.574320702112717,30.2631578947368,15.5263157894737,0.0337093222932276 -"2246",0.747628055154725,30.2631578947368,15.5263157894737,0.0334281230884899 -"2247",0.973232737037462,30.2631578947368,15.5263157894737,0.0321829887344394 -"2248",1.2669160204875,30.2631578947368,15.5263157894737,0.0292515690637692 -"2249",1.64922134437622,30.2631578947368,15.5263157894737,0.0256259399982076 -"2250",2.14689134777813,30.2631578947368,15.5263157894737,0.0222334591755979 -"2251",2.79473854427218,30.2631578947368,15.5263157894737,0.0192562837129073 -"2252",3.63808049202114,30.2631578947368,15.5263157894737,0.016672899746635 -"2253",4.73590980220715,30.2631578947368,15.5263157894737,0.0144354065030827 -"2254",6.16502073107827,30.2631578947368,15.5263157894737,0.0124980857152198 -"2255",8.02538101483936,30.2631578947368,15.5263157894737,0.0108207515105347 -"2256",10.4471247126008,30.2631578947368,15.5263157894737,0.00936852582368957 -"2257",13.5996552137305,30.2631578947368,15.5263157894737,0.00811119939534312 -"2258",17.7034951740616,30.2631578947368,15.5263157894737,0.00702261556424561 -"2259",23.045712295823,30.2631578947368,15.5263157894737,0.0060801278472414 -"2260",30,30.2631578947368,15.5263157894737,0.00526412905492061 -"2261",0.2,32.3684210526316,15.5263157894737,0.0229867728695842 -"2262",0.260352117694686,32.3684210526316,15.5263157894737,0.0229866247280182 -"2263",0.338916125940539,32.3684210526316,15.5263157894737,0.0229857186763191 -"2264",0.441187655547492,32.3684210526316,15.5263157894737,0.0229801859577414 -"2265",0.574320702112717,32.3684210526316,15.5263157894737,0.0229467247711341 -"2266",0.747628055154725,32.3684210526316,15.5263157894737,0.0227553058900053 -"2267",0.973232737037462,32.3684210526316,15.5263157894737,0.0219077137884216 -"2268",1.2669160204875,32.3684210526316,15.5263157894737,0.0199122277983318 -"2269",1.64922134437622,32.3684210526316,15.5263157894737,0.0174441772227087 -"2270",2.14689134777813,32.3684210526316,15.5263157894737,0.0151348361137236 -"2271",2.79473854427218,32.3684210526316,15.5263157894737,0.0131082030849291 -"2272",3.63808049202114,32.3684210526316,15.5263157894737,0.0113496331458318 -"2273",4.73590980220715,32.3684210526316,15.5263157894737,0.00982651911848809 -"2274",6.16502073107827,32.3684210526316,15.5263157894737,0.00850773950833206 -"2275",8.02538101483936,32.3684210526316,15.5263157894737,0.00736593885125235 -"2276",10.4471247126008,32.3684210526316,15.5263157894737,0.00637737483172887 -"2277",13.5996552137305,32.3684210526316,15.5263157894737,0.00552148329977317 -"2278",17.7034951740616,32.3684210526316,15.5263157894737,0.00478045880378324 -"2279",23.045712295823,32.3684210526316,15.5263157894737,0.00413888535255384 -"2280",30,32.3684210526316,15.5263157894737,0.00358341587327793 -"2281",0.2,34.4736842105263,15.5263157894737,0.0155157062020491 -"2282",0.260352117694686,34.4736842105263,15.5263157894737,0.0155156062088475 -"2283",0.338916125940539,34.4736842105263,15.5263157894737,0.0155149946383566 -"2284",0.441187655547492,34.4736842105263,15.5263157894737,0.0155112601412857 -"2285",0.574320702112717,34.4736842105263,15.5263157894737,0.0154886743723517 -"2286",0.747628055154725,34.4736842105263,15.5263157894737,0.0153594696711103 -"2287",0.973232737037462,34.4736842105263,15.5263157894737,0.0147873584790799 -"2288",1.2669160204875,34.4736842105263,15.5263157894737,0.0134404371635826 -"2289",1.64922134437622,34.4736842105263,15.5263157894737,0.0117745422665291 -"2290",2.14689134777813,34.4736842105263,15.5263157894737,0.0102157737360088 -"2291",2.79473854427218,34.4736842105263,15.5263157894737,0.00884782866461728 -"2292",3.63808049202114,34.4736842105263,15.5263157894737,0.00766082191662384 -"2293",4.73590980220715,34.4736842105263,15.5263157894737,0.00663274416536389 -"2294",6.16502073107827,34.4736842105263,15.5263157894737,0.00574258889683081 -"2295",8.02538101483936,34.4736842105263,15.5263157894737,0.0049718916076956 -"2296",10.4471247126008,34.4736842105263,15.5263157894737,0.00430462661248009 -"2297",13.5996552137305,34.4736842105263,15.5263157894737,0.0037269134369078 -"2298",17.7034951740616,34.4736842105263,15.5263157894737,0.00322673368425036 -"2299",23.045712295823,34.4736842105263,15.5263157894737,0.00279368180555531 -"2300",30,34.4736842105263,15.5263157894737,0.00241874873889356 -"2301",0.2,36.5789473684211,15.5263157894737,0.0104509452069421 -"2302",0.260352117694686,36.5789473684211,15.5263157894737,0.0104508778543216 -"2303",0.338916125940539,36.5789473684211,15.5263157894737,0.0104504659175649 -"2304",0.441187655547492,36.5789473684211,15.5263157894737,0.0104479504649162 -"2305",0.574320702112717,36.5789473684211,15.5263157894737,0.010432737323438 -"2306",0.747628055154725,36.5789473684211,15.5263157894737,0.010345708654838 -"2307",0.973232737037462,36.5789473684211,15.5263157894737,0.00996035057687959 -"2308",1.2669160204875,36.5789473684211,15.5263157894737,0.00905310209698342 -"2309",1.64922134437622,36.5789473684211,15.5263157894737,0.00793100194485947 -"2310",2.14689134777813,36.5789473684211,15.5263157894737,0.00688105911334194 -"2311",2.79473854427218,36.5789473684211,15.5263157894737,0.00595964962020967 -"2312",3.63808049202114,36.5789473684211,15.5263157894737,0.00516011511485073 -"2313",4.73590980220715,36.5789473684211,15.5263157894737,0.00446763073115732 -"2314",6.16502073107827,36.5789473684211,15.5263157894737,0.003868047069546 -"2315",8.02538101483936,36.5789473684211,15.5263157894737,0.00334892695764113 -"2316",10.4471247126008,36.5789473684211,15.5263157894737,0.00289947594247645 -"2317",13.5996552137305,36.5789473684211,15.5263157894737,0.00251034452527824 -"2318",17.7034951740616,36.5789473684211,15.5263157894737,0.00217343745056485 -"2319",23.045712295823,36.5789473684211,15.5263157894737,0.00188174583195147 -"2320",30,36.5789473684211,15.5263157894737,0.00162920141760602 -"2321",0.2,38.6842105263158,15.5263157894737,0.00704897149791719 -"2322",0.260352117694686,38.6842105263158,15.5263157894737,0.00704892606980591 -"2323",0.338916125940539,38.6842105263158,15.5263157894737,0.00704864822599378 -"2324",0.441187655547492,38.6842105263158,15.5263157894737,0.00704695159916487 -"2325",0.574320702112717,38.6842105263158,15.5263157894737,0.00703669061333535 -"2326",0.747628055154725,38.6842105263158,15.5263157894737,0.00697799136725608 -"2327",0.973232737037462,38.6842105263158,15.5263157894737,0.00671807438805152 -"2328",1.2669160204875,38.6842105263158,15.5263157894737,0.00610615187294076 -"2329",1.64922134437622,38.6842105263158,15.5263157894737,0.00534931583241915 -"2330",2.14689134777813,38.6842105263158,15.5263157894737,0.00464114858560463 -"2331",2.79473854427218,38.6842105263158,15.5263157894737,0.00401967472593064 -"2332",3.63808049202114,38.6842105263158,15.5263157894737,0.00348040331762464 -"2333",4.73590980220715,38.6842105263158,15.5263157894737,0.00301333525949673 -"2334",6.16502073107827,38.6842105263158,15.5263157894737,0.00260892704018011 -"2335",8.02538101483936,38.6842105263158,15.5263157894737,0.00225879001425997 -"2336",10.4471247126008,38.6842105263158,15.5263157894737,0.0019556435205341 -"2337",13.5996552137305,38.6842105263158,15.5263157894737,0.00169318149298923 -"2338",17.7034951740616,38.6842105263158,15.5263157894737,0.00146594382978496 -"2339",23.045712295823,38.6842105263158,15.5263157894737,0.00126920316517778 -"2340",30,38.6842105263158,15.5263157894737,0.00109886657423509 -"2341",0.2,40.7894736842105,15.5263157894737,0.00476943338010024 -"2342",0.260352117694686,40.7894736842105,15.5263157894737,0.00476940264280042 -"2343",0.338916125940539,40.7894736842105,15.5263157894737,0.0047692146497645 -"2344",0.441187655547492,40.7894736842105,15.5263157894737,0.00476806668815992 -"2345",0.574320702112717,40.7894736842105,15.5263157894737,0.00476112396065102 -"2346",0.747628055154725,40.7894736842105,15.5263157894737,0.00472140722414274 -"2347",0.973232737037462,40.7894736842105,15.5263157894737,0.00454554373582542 -"2348",1.2669160204875,40.7894736842105,15.5263157894737,0.00413150834492243 -"2349",1.64922134437622,40.7894736842105,15.5263157894737,0.00361942242203379 -"2350",2.14689134777813,40.7894736842105,15.5263157894737,0.00314026649032818 -"2351",2.79473854427218,40.7894736842105,15.5263157894737,0.00271976852519032 -"2352",3.63808049202114,40.7894736842105,15.5263157894737,0.00235488989623456 -"2353",4.73590980220715,40.7894736842105,15.5263157894737,0.00203886507078704 -"2354",6.16502073107827,40.7894736842105,15.5263157894737,0.0017652367746639 -"2355",8.02538101483936,40.7894736842105,15.5263157894737,0.00152832913224742 -"2356",10.4471247126008,40.7894736842105,15.5263157894737,0.00132321594564087 -"2357",13.5996552137305,40.7894736842105,15.5263157894737,0.00114563044177678 -"2358",17.7034951740616,40.7894736842105,15.5263157894737,0.000991878238859993 -"2359",23.045712295823,40.7894736842105,15.5263157894737,0.000858760734657022 -"2360",30,40.7894736842105,15.5263157894737,0.000743508598521335 -"2361",0.2,42.8947368421053,15.5263157894737,0.00324024858026102 -"2362",0.260352117694686,42.8947368421053,15.5263157894737,0.00324022769801272 -"2363",0.338916125940539,42.8947368421053,15.5263157894737,0.00324009997966146 -"2364",0.441187655547492,42.8947368421053,15.5263157894737,0.0032393200796895 -"2365",0.574320702112717,42.8947368421053,15.5263157894737,0.00323460334267673 -"2366",0.747628055154725,42.8947368421053,15.5263157894737,0.00320762066175272 -"2367",0.973232737037462,42.8947368421053,15.5263157894737,0.00308814285948013 -"2368",1.2669160204875,42.8947368421053,15.5263157894737,0.00280685628293442 -"2369",1.64922134437622,42.8947368421053,15.5263157894737,0.0024589563224203 -"2370",2.14689134777813,42.8947368421053,15.5263157894737,0.00213342827669674 -"2371",2.79473854427218,42.8947368421053,15.5263157894737,0.00184775116875652 -"2372",3.63808049202114,42.8947368421053,15.5263157894737,0.00159986061966646 -"2373",4.73590980220715,42.8947368421053,15.5263157894737,0.00138516027470388 -"2374",6.16502073107827,42.8947368421053,15.5263157894737,0.00119926320321284 -"2375",8.02538101483936,42.8947368421053,15.5263157894737,0.00103831333960937 -"2376",10.4471247126008,42.8947368421053,15.5263157894737,0.000898963932933996 -"2377",13.5996552137305,42.8947368421053,15.5263157894737,0.000778316231013797 -"2378",17.7034951740616,42.8947368421053,15.5263157894737,0.000673860351769994 -"2379",23.045712295823,42.8947368421053,15.5263157894737,0.000583423234899625 -"2380",30,42.8947368421053,15.5263157894737,0.000505123457814183 -"2381",0.2,45,15.5263157894737,0.00221133413715916 -"2382",0.260352117694686,45,15.5263157894737,0.00221131988589807 -"2383",0.338916125940539,45,15.5263157894737,0.00221123272346498 -"2384",0.441187655547492,45,15.5263157894737,0.00221070047435234 -"2385",0.574320702112717,45,15.5263157894737,0.00220748149861206 -"2386",0.747628055154725,45,15.5263157894737,0.00218906694739435 -"2387",0.973232737037462,45,15.5263157894737,0.00210752834433542 -"2388",1.2669160204875,45,15.5263157894737,0.00191556202026097 -"2389",1.64922134437622,45,15.5263157894737,0.00167813484763979 -"2390",2.14689134777813,45,15.5263157894737,0.00145597557118908 -"2391",2.79473854427218,45,15.5263157894737,0.00126101289306572 -"2392",3.63808049202114,45,15.5263157894737,0.00109183796098757 -"2393",4.73590980220715,45,15.5263157894737,0.000945313955092513 -"2394",6.16502073107827,45,15.5263157894737,0.000818446978685127 -"2395",8.02538101483936,45,15.5263157894737,0.000708605428278891 -"2396",10.4471247126008,45,15.5263157894737,0.000613505286317159 -"2397",13.5996552137305,45,15.5263157894737,0.000531168275678164 -"2398",17.7034951740616,45,15.5263157894737,0.000459881506815452 -"2399",23.045712295823,45,15.5263157894737,0.000398161956957463 -"2400",30,45,15.5263157894737,0.00034472563387541 -"2401",0.2,5,17.6315789473684,0.0324817254372966 -"2402",0.260352117694686,5,17.6315789473684,0.0324815161041424 -"2403",0.338916125940539,5,17.6315789473684,0.0324802357973029 -"2404",0.441187655547492,5,17.6315789473684,0.0324724177252846 -"2405",0.574320702112717,5,17.6315789473684,0.0324251350082912 -"2406",0.747628055154725,5,17.6315789473684,0.0321546483429548 -"2407",0.973232737037462,5,17.6315789473684,0.0309569485143331 -"2408",1.2669160204875,5,17.6315789473684,0.0281372039415822 -"2409",1.64922134437622,5,17.6315789473684,0.0246496965120888 -"2410",2.14689134777813,5,17.6315789473684,0.0213864553312283 -"2411",2.79473854427218,5,17.6315789473684,0.0185226980749601 -"2412",3.63808049202114,5,17.6315789473684,0.0160377304699761 -"2413",4.73590980220715,5,17.6315789473684,0.0138854765661088 -"2414",6.16502073107827,5,17.6315789473684,0.0120219597752819 -"2415",8.02538101483936,5,17.6315789473684,0.0104085251423387 -"2416",10.4471247126008,5,17.6315789473684,0.00901162331355521 -"2417",13.5996552137305,5,17.6315789473684,0.00780219587879432 -"2418",17.7034951740616,5,17.6315789473684,0.00675508263860109 -"2419",23.045712295823,5,17.6315789473684,0.00584849984818832 -"2420",30,5,17.6315789473684,0.00506358727185569 -"2421",0.2,7.10526315789474,17.6315789473684,0.0414634647218411 -"2422",0.260352117694686,7.10526315789474,17.6315789473684,0.0414631975045754 -"2423",0.338916125940539,7.10526315789474,17.6315789473684,0.0414615631715233 -"2424",0.441187655547492,7.10526315789474,17.6315789473684,0.0414515832720887 -"2425",0.574320702112717,7.10526315789474,17.6315789473684,0.04139122609458 -"2426",0.747628055154725,7.10526315789474,17.6315789473684,0.04104594535118 -"2427",0.973232737037462,7.10526315789474,17.6315789473684,0.0395170615273427 -"2428",1.2669160204875,7.10526315789474,17.6315789473684,0.0359176105116459 -"2429",1.64922134437622,7.10526315789474,17.6315789473684,0.0314657490626873 -"2430",2.14689134777813,7.10526315789474,17.6315789473684,0.0273001672236725 -"2431",2.79473854427218,7.10526315789474,17.6315789473684,0.0236445332827843 -"2432",3.63808049202114,7.10526315789474,17.6315789473684,0.0204724306547059 -"2433",4.73590980220715,7.10526315789474,17.6315789473684,0.0177250426199255 -"2434",6.16502073107827,7.10526315789474,17.6315789473684,0.0153462323296851 -"2435",8.02538101483936,7.10526315789474,17.6315789473684,0.0132866560884788 -"2436",10.4471247126008,7.10526315789474,17.6315789473684,0.011503487586256 -"2437",13.5996552137305,7.10526315789474,17.6315789473684,0.00995963327741885 -"2438",17.7034951740616,7.10526315789474,17.6315789473684,0.00862297574737669 -"2439",23.045712295823,7.10526315789474,17.6315789473684,0.00746570768228351 -"2440",30,7.10526315789474,17.6315789473684,0.00646375367644342 -"2441",0.2,9.21052631578947,17.6315789473684,0.0524208105821597 -"2442",0.260352117694686,9.21052631578947,17.6315789473684,0.0524204727487017 -"2443",0.338916125940539,9.21052631578947,17.6315789473684,0.0524184065184933 -"2444",0.441187655547492,9.21052631578947,17.6315789473684,0.052405789280127 -"2445",0.574320702112717,9.21052631578947,17.6315789473684,0.0523294818082192 -"2446",0.747628055154725,9.21052631578947,17.6315789473684,0.0518929554212214 -"2447",0.973232737037462,9.21052631578947,17.6315789473684,0.0499600409899465 -"2448",1.2669160204875,9.21052631578947,17.6315789473684,0.0454093807602863 -"2449",1.64922134437622,9.21052631578947,17.6315789473684,0.0397810477852335 -"2450",2.14689134777813,9.21052631578947,17.6315789473684,0.0345146481244145 -"2451",2.79473854427218,9.21052631578947,17.6315789473684,0.0298929577842904 -"2452",3.63808049202114,9.21052631578947,17.6315789473684,0.0258825791984873 -"2453",4.73590980220715,9.21052631578947,17.6315789473684,0.0224091524423521 -"2454",6.16502073107827,9.21052631578947,17.6315789473684,0.0194017056582462 -"2455",8.02538101483936,9.21052631578947,17.6315789473684,0.0167978553349779 -"2456",10.4471247126008,9.21052631578947,17.6315789473684,0.0145434576642049 -"2457",13.5996552137305,9.21052631578947,17.6315789473684,0.0125916165715002 -"2458",17.7034951740616,9.21052631578947,17.6315789473684,0.0109017271311069 -"2459",23.045712295823,9.21052631578947,17.6315789473684,0.00943863352713524 -"2460",30,9.21052631578947,17.6315789473684,0.00817189806485457 -"2461",0.2,11.3157894736842,17.6315789473684,0.0653396150124188 -"2462",0.260352117694686,11.3157894736842,17.6315789473684,0.0653391939218665 -"2463",0.338916125940539,11.3157894736842,17.6315789473684,0.065336618481219 -"2464",0.441187655547492,11.3157894736842,17.6315789473684,0.0653208917977088 -"2465",0.574320702112717,11.3157894736842,17.6315789473684,0.0652257787923651 -"2466",0.747628055154725,11.3157894736842,17.6315789473684,0.064681673011618 -"2467",0.973232737037462,11.3157894736842,17.6315789473684,0.0622724030406109 -"2468",1.2669160204875,11.3157894736842,17.6315789473684,0.056600259016964 -"2469",1.64922134437622,11.3157894736842,17.6315789473684,0.0495848560564304 -"2470",2.14689134777813,11.3157894736842,17.6315789473684,0.0430205827741597 -"2471",2.79473854427218,11.3157894736842,17.6315789473684,0.0372599036817021 -"2472",3.63808049202114,11.3157894736842,17.6315789473684,0.0322611905763462 -"2473",4.73590980220715,11.3157894736842,17.6315789473684,0.0279317579617169 -"2474",6.16502073107827,11.3157894736842,17.6315789473684,0.0241831433778994 -"2475",8.02538101483936,11.3157894736842,17.6315789473684,0.0209375892595468 -"2476",10.4471247126008,11.3157894736842,17.6315789473684,0.0181276083710915 -"2477",13.5996552137305,11.3157894736842,17.6315789473684,0.0156947473728271 -"2478",17.7034951740616,11.3157894736842,17.6315789473684,0.0135883944907824 -"2479",23.045712295823,11.3157894736842,17.6315789473684,0.0117647299623446 -"2480",30,11.3157894736842,17.6315789473684,0.0101858148996278 -"2481",0.2,13.4210526315789,17.6315789473684,0.0796890479043038 -"2482",0.260352117694686,13.4210526315789,17.6315789473684,0.079688534336766 -"2483",0.338916125940539,13.4210526315789,17.6315789473684,0.0796853932957133 -"2484",0.441187655547492,13.4210526315789,17.6315789473684,0.0796662128270897 -"2485",0.574320702112717,13.4210526315789,17.6315789473684,0.0795502117634514 -"2486",0.747628055154725,13.4210526315789,17.6315789473684,0.0788866132463998 -"2487",0.973232737037462,13.4210526315789,17.6315789473684,0.0759482361210143 -"2488",1.2669160204875,13.4210526315789,17.6315789473684,0.0690304151829111 -"2489",1.64922134437622,13.4210526315789,17.6315789473684,0.0604743381003679 -"2490",2.14689134777813,13.4210526315789,17.6315789473684,0.0524684646658767 -"2491",2.79473854427218,13.4210526315789,17.6315789473684,0.0454426652014488 -"2492",3.63808049202114,13.4210526315789,17.6315789473684,0.0393461694073296 -"2493",4.73590980220715,13.4210526315789,17.6315789473684,0.0340659368415259 -"2494",6.16502073107827,13.4210526315789,17.6315789473684,0.0294940775324708 -"2495",8.02538101483936,13.4210526315789,17.6315789473684,0.0255357573378346 -"2496",10.4471247126008,13.4210526315789,17.6315789473684,0.0221086679436328 -"2497",13.5996552137305,13.4210526315789,17.6315789473684,0.0191415188932694 -"2498",17.7034951740616,13.4210526315789,17.6315789473684,0.0165725834061423 -"2499",23.045712295823,13.4210526315789,17.6315789473684,0.0143484183274157 -"2500",30,13.4210526315789,17.6315789473684,0.0124227528938843 -"2501",0.2,15.5263157894737,17.6315789473684,0.0939993969741149 -"2502",0.260352117694686,15.5263157894737,17.6315789473684,0.093998791181473 -"2503",0.338916125940539,15.5263157894737,17.6315789473684,0.0939950860805514 -"2504",0.441187655547492,15.5263157894737,17.6315789473684,0.0939724612339545 -"2505",0.574320702112717,15.5263157894737,17.6315789473684,0.0938356290052214 -"2506",0.747628055154725,15.5263157894737,17.6315789473684,0.0930528632164938 -"2507",0.973232737037462,15.5263157894737,17.6315789473684,0.0895868200759049 -"2508",1.2669160204875,15.5263157894737,17.6315789473684,0.0814267150971443 -"2509",1.64922134437622,15.5263157894737,17.6315789473684,0.0713341602558701 -"2510",2.14689134777813,15.5263157894737,17.6315789473684,0.0618906131827896 -"2511",2.79473854427218,15.5263157894737,17.6315789473684,0.0536031391787037 -"2512",3.63808049202114,15.5263157894737,17.6315789473684,0.0464118507473171 -"2513",4.73590980220715,15.5263157894737,17.6315789473684,0.0401834079421693 -"2514",6.16502073107827,15.5263157894737,17.6315789473684,0.0347905461951229 -"2515",8.02538101483936,15.5263157894737,17.6315789473684,0.0301214012986613 -"2516",10.4471247126008,15.5263157894737,17.6315789473684,0.026078884228835 -"2517",13.5996552137305,15.5263157894737,17.6315789473684,0.0225789023768569 -"2518",17.7034951740616,15.5263157894737,17.6315789473684,0.0195486442296479 -"2519",23.045712295823,15.5263157894737,17.6315789473684,0.0169250694515648 -"2520",30,15.5263157894737,17.6315789473684,0.0146535980977694 -"2521",0.2,17.6315789473684,17.6315789473684,0.105566668518954 -"2522",0.260352117694686,17.6315789473684,17.6315789473684,0.105565988179366 -"2523",0.338916125940539,17.6315789473684,17.6315789473684,0.105561827140323 -"2524",0.441187655547492,17.6315789473684,17.6315789473684,0.105536418150926 -"2525",0.574320702112717,17.6315789473684,17.6315789473684,0.105382747776452 -"2526",0.747628055154725,17.6315789473684,17.6315789473684,0.104503657280059 -"2527",0.973232737037462,17.6315789473684,17.6315789473684,0.100611093720362 -"2528",1.2669160204875,17.6315789473684,17.6315789473684,0.0914468317665341 -"2529",1.64922134437622,17.6315789473684,17.6315789473684,0.080112318719269 -"2530",2.14689134777813,17.6315789473684,17.6315789473684,0.0695066783045592 -"2531",2.79473854427218,17.6315789473684,17.6315789473684,0.0601993736918529 -"2532",3.63808049202114,17.6315789473684,17.6315789473684,0.052123147817027 -"2533",4.73590980220715,17.6315789473684,17.6315789473684,0.0451282523372043 -"2534",6.16502073107827,17.6315789473684,17.6315789473684,0.0390717619048692 -"2535",8.02538101483936,17.6315789473684,17.6315789473684,0.0338280466532973 -"2536",10.4471247126008,17.6315789473684,17.6315789473684,0.0292880700871701 -"2537",13.5996552137305,17.6315789473684,17.6315789473684,0.0253573914244987 -"2538",17.7034951740616,17.6315789473684,17.6315789473684,0.0219542391953268 -"2539",23.045712295823,17.6315789473684,17.6315789473684,0.0190078155176425 -"2540",30,17.6315789473684,17.6315789473684,0.0164568240094475 -"2541",0.2,19.7368421052632,17.6315789473684,0.110944463417388 -"2542",0.260352117694686,19.7368421052632,17.6315789473684,0.110943748419826 -"2543",0.338916125940539,19.7368421052632,17.6315789473684,0.110939375408436 -"2544",0.441187655547492,19.7368421052632,17.6315789473684,0.110912672030049 -"2545",0.574320702112717,19.7368421052632,17.6315789473684,0.110751173353635 -"2546",0.747628055154725,19.7368421052632,17.6315789473684,0.109827300082025 -"2547",0.973232737037462,19.7368421052632,17.6315789473684,0.105736440897896 -"2548",1.2669160204875,19.7368421052632,17.6315789473684,0.096105331577615 -"2549",1.64922134437622,19.7368421052632,17.6315789473684,0.0841934138694189 -"2550",2.14689134777813,19.7368421052632,17.6315789473684,0.0730474991454311 -"2551",2.79473854427218,19.7368421052632,17.6315789473684,0.0632660602632002 -"2552",3.63808049202114,19.7368421052632,17.6315789473684,0.0547784139379843 -"2553",4.73590980220715,19.7368421052632,17.6315789473684,0.0474271833217572 -"2554",6.16502073107827,19.7368421052632,17.6315789473684,0.0410621621400257 -"2555",8.02538101483936,19.7368421052632,17.6315789473684,0.0355513206683659 -"2556",10.4471247126008,19.7368421052632,17.6315789473684,0.0307800678560632 -"2557",13.5996552137305,19.7368421052632,17.6315789473684,0.0266491519030041 -"2558",17.7034951740616,19.7368421052632,17.6315789473684,0.0230726357233221 -"2559",23.045712295823,19.7368421052632,17.6315789473684,0.019976114837449 -"2560",30,19.7368421052632,17.6315789473684,0.0172951702928346 -"2561",0.2,21.8421052631579,17.6315789473684,0.107716984371885 -"2562",0.260352117694686,21.8421052631579,17.6315789473684,0.107716290174277 -"2563",0.338916125940539,21.8421052631579,17.6315789473684,0.107712044377911 -"2564",0.441187655547492,21.8421052631579,17.6315789473684,0.107686117825979 -"2565",0.574320702112717,21.8421052631579,17.6315789473684,0.107529317298332 -"2566",0.747628055154725,21.8421052631579,17.6315789473684,0.106632320371273 -"2567",0.973232737037462,21.8421052631579,17.6315789473684,0.102660468137902 -"2568",1.2669160204875,21.8421052631579,17.6315789473684,0.0933095368685012 -"2569",1.64922134437622,21.8421052631579,17.6315789473684,0.0817441480776636 -"2570",2.14689134777813,21.8421052631579,17.6315789473684,0.070922478521993 -"2571",2.79473854427218,21.8421052631579,17.6315789473684,0.0614255909193378 -"2572",3.63808049202114,21.8421052631579,17.6315789473684,0.0531848582283536 -"2573",4.73590980220715,21.8421052631579,17.6315789473684,0.0460474818419069 -"2574",6.16502073107827,21.8421052631579,17.6315789473684,0.0398676251276526 -"2575",8.02538101483936,21.8421052631579,17.6315789473684,0.0345170992303352 -"2576",10.4471247126008,21.8421052631579,17.6315789473684,0.0298846466609482 -"2577",13.5996552137305,21.8421052631579,17.6315789473684,0.0258739029478239 -"2578",17.7034951740616,21.8421052631579,17.6315789473684,0.0224014309959498 -"2579",23.045712295823,21.8421052631579,17.6315789473684,0.0193949908222212 -"2580",30,21.8421052631579,17.6315789473684,0.0167920374821551 -"2581",0.2,23.9473684210526,17.6315789473684,0.096429445142314 -"2582",0.260352117694686,23.9473684210526,17.6315789473684,0.096428823688877 -"2583",0.338916125940539,23.9473684210526,17.6315789473684,0.0964250228046419 -"2584",0.441187655547492,23.9473684210526,17.6315789473684,0.0964018130663456 -"2585",0.574320702112717,23.9473684210526,17.6315789473684,0.0962614434861243 -"2586",0.747628055154725,23.9473684210526,17.6315789473684,0.0954584418381012 -"2587",0.973232737037462,23.9473684210526,17.6315789473684,0.0919027954441318 -"2588",1.2669160204875,23.9473684210526,17.6315789473684,0.0835317375359454 -"2589",1.64922134437622,23.9473684210526,17.6315789473684,0.0731782725697771 -"2590",2.14689134777813,23.9473684210526,17.6315789473684,0.0634905933532472 -"2591",2.79473854427218,23.9473684210526,17.6315789473684,0.0549888737085411 -"2592",3.63808049202114,23.9473684210526,17.6315789473684,0.0476116779432544 -"2593",4.73590980220715,23.9473684210526,17.6315789473684,0.0412222190410188 -"2594",6.16502073107827,23.9473684210526,17.6315789473684,0.0356899424229028 -"2595",8.02538101483936,23.9473684210526,17.6315789473684,0.030900091996747 -"2596",10.4471247126008,23.9473684210526,17.6315789473684,0.0267530688181937 -"2597",13.5996552137305,23.9473684210526,17.6315789473684,0.023162606338021 -"2598",17.7034951740616,23.9473684210526,17.6315789473684,0.0200540107386917 -"2599",23.045712295823,23.9473684210526,17.6315789473684,0.0173626119820636 -"2600",30,23.9473684210526,17.6315789473684,0.0150324191366407 -"2601",0.2,26.0526315789474,17.6315789473684,0.0804195972720802 -"2602",0.260352117694686,26.0526315789474,17.6315789473684,0.0804190789964119 -"2603",0.338916125940539,26.0526315789474,17.6315789473684,0.0804159091598644 -"2604",0.441187655547492,26.0526315789474,17.6315789473684,0.0803965528542897 -"2605",0.574320702112717,26.0526315789474,17.6315789473684,0.0802794883508697 -"2606",0.747628055154725,26.0526315789474,17.6315789473684,0.0796098062942372 -"2607",0.973232737037462,26.0526315789474,17.6315789473684,0.0766444915957762 -"2608",1.2669160204875,26.0526315789474,17.6315789473684,0.0696632515323901 -"2609",1.64922134437622,26.0526315789474,17.6315789473684,0.0610287366109257 -"2610",2.14689134777813,26.0526315789474,17.6315789473684,0.0529494693296026 -"2611",2.79473854427218,26.0526315789474,17.6315789473684,0.0458592608467231 -"2612",3.63808049202114,26.0526315789474,17.6315789473684,0.0397068754257961 -"2613",4.73590980220715,26.0526315789474,17.6315789473684,0.0343782363265463 -"2614",6.16502073107827,26.0526315789474,17.6315789473684,0.0297644644960642 -"2615",8.02538101483936,26.0526315789474,17.6315789473684,0.0257698563999949 -"2616",10.4471247126008,26.0526315789474,17.6315789473684,0.0223113491628637 -"2617",13.5996552137305,26.0526315789474,17.6315789473684,0.019316998772795 -"2618",17.7034951740616,26.0526315789474,17.6315789473684,0.016724512568909 -"2619",23.045712295823,26.0526315789474,17.6315789473684,0.0144799574562339 -"2620",30,26.0526315789474,17.6315789473684,0.0125366384843304 -"2621",0.2,28.1578947368421,17.6315789473684,0.0635838834417348 -"2622",0.260352117694686,28.1578947368421,17.6315789473684,0.0635834736662472 -"2623",0.338916125940539,28.1578947368421,17.6315789473684,0.0635809674299019 -"2624",0.441187655547492,28.1578947368421,17.6315789473684,0.063565663335884 -"2625",0.574320702112717,28.1578947368421,17.6315789473684,0.0634731060986793 -"2626",0.747628055154725,28.1578947368421,17.6315789473684,0.0629436209075526 -"2627",0.973232737037462,28.1578947368421,17.6315789473684,0.0605990900898079 -"2628",1.2669160204875,28.1578947368421,17.6315789473684,0.055079361447456 -"2629",1.64922134437622,28.1578947368421,17.6315789473684,0.048252468389476 -"2630",2.14689134777813,28.1578947368421,17.6315789473684,0.0418645827678625 -"2631",2.79473854427218,28.1578947368421,17.6315789473684,0.0362586980700349 -"2632",3.63808049202114,28.1578947368421,17.6315789473684,0.0313943046788401 -"2633",4.73590980220715,28.1578947368421,17.6315789473684,0.0271812076367912 -"2634",6.16502073107827,28.1578947368421,17.6315789473684,0.0235333215462451 -"2635",8.02538101483936,28.1578947368421,17.6315789473684,0.0203749782544159 -"2636",10.4471247126008,28.1578947368421,17.6315789473684,0.0176405039657155 -"2637",13.5996552137305,28.1578947368421,17.6315789473684,0.0152730160318765 -"2638",17.7034951740616,28.1578947368421,17.6315789473684,0.0132232626607611 -"2639",23.045712295823,28.1578947368421,17.6315789473684,0.0114486015644112 -"2640",30,28.1578947368421,17.6315789473684,0.00991211330544146 -"2641",0.2,30.2631578947368,17.6315789473684,0.0485225184196286 -"2642",0.260352117694686,30.2631578947368,17.6315789473684,0.0485222057092754 -"2643",0.338916125940539,30.2631578947368,17.6315789473684,0.048520293135009 -"2644",0.441187655547492,30.2631578947368,17.6315789473684,0.0485086141820467 -"2645",0.574320702112717,30.2631578947368,17.6315789473684,0.0484379813423389 -"2646",0.747628055154725,30.2631578947368,17.6315789473684,0.0480339173948622 -"2647",0.973232737037462,30.2631578947368,17.6315789473684,0.0462447448305024 -"2648",1.2669160204875,30.2631578947368,17.6315789473684,0.0420324960620657 -"2649",1.64922134437622,30.2631578947368,17.6315789473684,0.0368227160639909 -"2650",2.14689134777813,30.2631578947368,17.6315789473684,0.0319479540809288 -"2651",2.79473854427218,30.2631578947368,17.6315789473684,0.0276699573813735 -"2652",3.63808049202114,30.2631578947368,17.6315789473684,0.0239578120208143 -"2653",4.73590980220715,30.2631578947368,17.6315789473684,0.0207426878767561 -"2654",6.16502073107827,30.2631578947368,17.6315789473684,0.0179588909389138 -"2655",8.02538101483936,30.2631578947368,17.6315789473684,0.0155486768680207 -"2656",10.4471247126008,30.2631578947368,17.6315789473684,0.0134619282792364 -"2657",13.5996552137305,30.2631578947368,17.6315789473684,0.0116552365413337 -"2658",17.7034951740616,30.2631578947368,17.6315789473684,0.0100910163282543 -"2659",23.045712295823,30.2631578947368,17.6315789473684,0.00873672619882016 -"2660",30,30.2631578947368,17.6315789473684,0.00756419196825965 -"2661",0.2,32.3684210526316,17.6315789473684,0.0362541968695133 -"2662",0.260352117694686,32.3684210526316,17.6315789473684,0.036253963224124 -"2663",0.338916125940539,32.3684210526316,17.6315789473684,0.0362525342207202 -"2664",0.441187655547492,32.3684210526316,17.6315789473684,0.0362438081472658 -"2665",0.574320702112717,32.3684210526316,17.6315789473684,0.0361910339517042 -"2666",0.747628055154725,32.3684210526316,17.6315789473684,0.0358891325999853 -"2667",0.973232737037462,32.3684210526316,17.6315789473684,0.0345523302967562 -"2668",1.2669160204875,32.3684210526316,17.6315789473684,0.0314050967835737 -"2669",1.64922134437622,32.3684210526316,17.6315789473684,0.0275125455342006 -"2670",2.14689134777813,32.3684210526316,17.6315789473684,0.0238703071182642 -"2671",2.79473854427218,32.3684210526316,17.6315789473684,0.0206739492290977 -"2672",3.63808049202114,32.3684210526316,17.6315789473684,0.0179003741325602 -"2673",4.73590980220715,32.3684210526316,17.6315789473684,0.0154981545554441 -"2674",6.16502073107827,32.3684210526316,17.6315789473684,0.0134182064093796 -"2675",8.02538101483936,32.3684210526316,17.6315789473684,0.0116173853005461 -"2676",10.4471247126008,32.3684210526316,17.6315789473684,0.0100582454079976 -"2677",13.5996552137305,32.3684210526316,17.6315789473684,0.00870835343862375 -"2678",17.7034951740616,32.3684210526316,17.6315789473684,0.00753962705344688 -"2679",23.045712295823,32.3684210526316,17.6315789473684,0.00652775251415909 -"2680",30,32.3684210526316,17.6315789473684,0.00565167913183053 -"2681",0.2,34.4736842105263,17.6315789473684,0.0267843774652269 -"2682",0.260352117694686,34.4736842105263,17.6315789473684,0.0267842048494516 -"2683",0.338916125940539,34.4736842105263,17.6315789473684,0.0267831491105338 -"2684",0.441187655547492,34.4736842105263,17.6315789473684,0.0267767023411837 -"2685",0.574320702112717,34.4736842105263,17.6315789473684,0.0267377130903824 -"2686",0.747628055154725,34.4736842105263,17.6315789473684,0.0265146702302466 -"2687",0.973232737037462,34.4736842105263,17.6315789473684,0.0255270489180178 -"2688",1.2669160204875,34.4736842105263,17.6315789473684,0.0232018921729464 -"2689",1.64922134437622,34.4736842105263,17.6315789473684,0.0203260992725768 -"2690",2.14689134777813,34.4736842105263,17.6315789473684,0.0176352359526165 -"2691",2.79473854427218,34.4736842105263,17.6315789473684,0.0152737864209794 -"2692",3.63808049202114,34.4736842105263,17.6315789473684,0.0132246862138726 -"2693",4.73590980220715,34.4736842105263,17.6315789473684,0.011449941178438 -"2694",6.16502073107827,34.4736842105263,17.6315789473684,0.0099132882923514 -"2695",8.02538101483936,34.4736842105263,17.6315789473684,0.0085828527430563 -"2696",10.4471247126008,34.4736842105263,17.6315789473684,0.00743096978855535 -"2697",13.5996552137305,34.4736842105263,17.6315789473684,0.00643367791155916 -"2698",17.7034951740616,34.4736842105263,17.6315789473684,0.00557023005290666 -"2699",23.045712295823,34.4736842105263,17.6315789473684,0.00482266337241214 -"2700",30,34.4736842105263,17.6315789473684,0.00417542575068293 -"2701",0.2,36.5789473684211,17.6315789473684,0.0196895552458642 -"2702",0.260352117694686,36.5789473684211,17.6315789473684,0.0196894283536918 -"2703",0.338916125940539,36.5789473684211,17.6315789473684,0.0196886522658483 -"2704",0.441187655547492,36.5789473684211,17.6315789473684,0.0196839131592015 -"2705",0.574320702112717,36.5789473684211,17.6315789473684,0.0196552516378111 -"2706",0.747628055154725,36.5789473684211,17.6315789473684,0.0194912898387161 -"2707",0.973232737037462,36.5789473684211,17.6315789473684,0.0187652761609904 -"2708",1.2669160204875,36.5789473684211,17.6315789473684,0.0170560222406104 -"2709",1.64922134437622,36.5789473684211,17.6315789473684,0.0149419882944788 -"2710",2.14689134777813,36.5789473684211,17.6315789473684,0.0129638985641421 -"2711",2.79473854427218,36.5789473684211,17.6315789473684,0.0112279653294103 -"2712",3.63808049202114,36.5789473684211,17.6315789473684,0.009721644273992 -"2713",4.73590980220715,36.5789473684211,17.6315789473684,0.00841700538634645 -"2714",6.16502073107827,36.5789473684211,17.6315789473684,0.00728739123221503 -"2715",8.02538101483936,36.5789473684211,17.6315789473684,0.00630937020921696 -"2716",10.4471247126008,36.5789473684211,17.6315789473684,0.00546260559432679 -"2717",13.5996552137305,36.5789473684211,17.6315789473684,0.00472948295468877 -"2718",17.7034951740616,36.5789473684211,17.6315789473684,0.0040947508487463 -"2719",23.045712295823,36.5789473684211,17.6315789473684,0.00354520455166795 -"2720",30,36.5789473684211,17.6315789473684,0.00306941149182238 -"2721",0.2,38.6842105263158,17.6315789473684,0.014456566992138 -"2722",0.260352117694686,38.6842105263158,17.6315789473684,0.0144564738247115 -"2723",0.338916125940539,38.6842105263158,17.6315789473684,0.0144559040014849 -"2724",0.441187655547492,38.6842105263158,17.6315789473684,0.0144524244301148 -"2725",0.574320702112717,38.6842105263158,17.6315789473684,0.0144313804197803 -"2726",0.747628055154725,38.6842105263158,17.6315789473684,0.0143109955404282 -"2727",0.973232737037462,38.6842105263158,17.6315789473684,0.0137779380265235 -"2728",1.2669160204875,38.6842105263158,17.6315789473684,0.0125229607810757 -"2729",1.64922134437622,38.6842105263158,17.6315789473684,0.0109707838535483 -"2730",2.14689134777813,38.6842105263158,17.6315789473684,0.00951842059059045 -"2731",2.79473854427218,38.6842105263158,17.6315789473684,0.00824385472110233 -"2732",3.63808049202114,38.6842105263158,17.6315789473684,0.00713787589235776 -"2733",4.73590980220715,38.6842105263158,17.6315789473684,0.00617997718696379 -"2734",6.16502073107827,38.6842105263158,17.6315789473684,0.00535058604579526 -"2735",8.02538101483936,38.6842105263158,17.6315789473684,0.00463249839667678 -"2736",10.4471247126008,38.6842105263158,17.6315789473684,0.00401078250574507 -"2737",13.5996552137305,38.6842105263158,17.6315789473684,0.00347250541309178 -"2738",17.7034951740616,38.6842105263158,17.6315789473684,0.00300646912649025 -"2739",23.045712295823,38.6842105263158,17.6315789473684,0.00260297840464353 -"2740",30,38.6842105263158,17.6315789473684,0.00225363916573429 -"2741",0.2,40.7894736842105,17.6315789473684,0.010625068885736 -"2742",0.260352117694686,40.7894736842105,17.6315789473684,0.0106250004109505 -"2743",0.338916125940539,40.7894736842105,17.6315789473684,0.0106245816108966 -"2744",0.441187655547492,40.7894736842105,17.6315789473684,0.0106220242481755 -"2745",0.574320702112717,40.7894736842105,17.6315789473684,0.0106065576398474 -"2746",0.747628055154725,40.7894736842105,17.6315789473684,0.0105180789825969 -"2747",0.973232737037462,40.7894736842105,17.6315789473684,0.0101263004359767 -"2748",1.2669160204875,40.7894736842105,17.6315789473684,0.00920393624742726 -"2749",1.64922134437622,40.7894736842105,17.6315789473684,0.00806314073305671 -"2750",2.14689134777813,40.7894736842105,17.6315789473684,0.00699570475573016 -"2751",2.79473854427218,40.7894736842105,17.6315789473684,0.0060589436166517 -"2752",3.63808049202114,40.7894736842105,17.6315789473684,0.00524608803012363 -"2753",4.73590980220715,40.7894736842105,17.6315789473684,0.00454206613226203 -"2754",6.16502073107827,40.7894736842105,17.6315789473684,0.00393249277968619 -"2755",8.02538101483936,40.7894736842105,17.6315789473684,0.00340472358371945 -"2756",10.4471247126008,40.7894736842105,17.6315789473684,0.00294778424451819 -"2757",13.5996552137305,40.7894736842105,17.6315789473684,0.00255216949087957 -"2758",17.7034951740616,40.7894736842105,17.6315789473684,0.00220964919189803 -"2759",23.045712295823,40.7894736842105,17.6315789473684,0.0019130976858103 -"2760",30,40.7894736842105,17.6315789473684,0.00165634561736141 -"2761",0.2,42.8947368421053,17.6315789473684,0.00782684290863783 -"2762",0.260352117694686,42.8947368421053,17.6315789473684,0.00782679246742229 -"2763",0.338916125940539,42.8947368421053,17.6315789473684,0.00782648396285942 -"2764",0.441187655547492,42.8947368421053,17.6315789473684,0.00782460010907049 -"2765",0.574320702112717,42.8947368421053,17.6315789473684,0.00781320679811737 -"2766",0.747628055154725,42.8947368421053,17.6315789473684,0.00774802994528804 -"2767",0.973232737037462,42.8947368421053,17.6315789473684,0.00745943048561894 -"2768",1.2669160204875,42.8947368421053,17.6315789473684,0.0067799808099541 -"2769",1.64922134437622,42.8947368421053,17.6315789473684,0.00593962604351642 -"2770",2.14689134777813,42.8947368421053,17.6315789473684,0.00515331079234857 -"2771",2.79473854427218,42.8947368421053,17.6315789473684,0.00446325575766295 -"2772",3.63808049202114,42.8947368421053,17.6315789473684,0.00386447441783513 -"2773",4.73590980220715,42.8947368421053,17.6315789473684,0.00334586424616827 -"2774",6.16502073107827,42.8947368421053,17.6315789473684,0.00289682858125057 -"2775",8.02538101483936,42.8947368421053,17.6315789473684,0.00250805306993175 -"2776",10.4471247126008,42.8947368421053,17.6315789473684,0.00217145361206788 -"2777",13.5996552137305,42.8947368421053,17.6315789473684,0.00188002825168967 -"2778",17.7034951740616,42.8947368421053,17.6315789473684,0.00162771435123607 -"2779",23.045712295823,42.8947368421053,17.6315789473684,0.00140926286848055 -"2780",30,42.8947368421053,17.6315789473684,0.0012201292141176 -"2781",0.2,45,17.6315789473684,0.00578279721279066 -"2782",0.260352117694686,45,17.6315789473684,0.00578275994472179 -"2783",0.338916125940539,45,17.6315789473684,0.00578253200871398 -"2784",0.441187655547492,45,17.6315789473684,0.0057811401391483 -"2785",0.574320702112717,45,17.6315789473684,0.00577272228694489 -"2786",0.747628055154725,45,17.6315789473684,0.00572456691609109 -"2787",0.973232737037462,45,17.6315789473684,0.0055113376267763 -"2788",1.2669160204875,45,17.6315789473684,0.0050093319347584 -"2789",1.64922134437622,45,17.6315789473684,0.00438844286647928 -"2790",2.14689134777813,45,17.6315789473684,0.00380748044064472 -"2791",2.79473854427218,45,17.6315789473684,0.0032976390680974 -"2792",3.63808049202114,45,17.6315789473684,0.00285523449917396 -"2793",4.73590980220715,45,17.6315789473684,0.00247206372517897 -"2794",6.16502073107827,45,17.6315789473684,0.00214029749173842 -"2795",8.02538101483936,45,17.6315789473684,0.00185305396717826 -"2796",10.4471247126008,45,17.6315789473684,0.00160436028193592 -"2797",13.5996552137305,45,17.6315789473684,0.00138904309959261 -"2798",17.7034951740616,45,17.6315789473684,0.00120262309125423 -"2799",23.045712295823,45,17.6315789473684,0.00104122204611323 -"2800",30,45,17.6315789473684,0.000901482232492093 -"2801",0.2,5,19.7368421052632,0.0329017287667389 -"2802",0.260352117694686,5,19.7368421052632,0.0329015167268128 -"2803",0.338916125940539,5,19.7368421052632,0.0329002198650296 -"2804",0.441187655547492,5,19.7368421052632,0.0328923007018213 -"2805",0.574320702112717,5,19.7368421052632,0.0328444065980159 -"2806",0.747628055154725,5,19.7368421052632,0.0325704224183547 -"2807",0.973232737037462,5,19.7368421052632,0.0313572357918823 -"2808",1.2669160204875,5,19.7368421052632,0.0285010306526809 -"2809",1.64922134437622,5,19.7368421052632,0.0249684281824493 -"2810",2.14689134777813,5,19.7368421052632,0.0216629918243843 -"2811",2.79473854427218,5,19.7368421052632,0.0187622048978583 -"2812",3.63808049202114,5,19.7368421052632,0.0162451055432952 -"2813",4.73590980220715,5,19.7368421052632,0.0140650220277536 -"2814",6.16502073107827,5,19.7368421052632,0.0121774091260803 -"2815",8.02538101483936,5,19.7368421052632,0.0105431120571504 -"2816",10.4471247126008,5,19.7368421052632,0.00912814765899614 -"2817",13.5996552137305,5,19.7368421052632,0.00790308178315862 -"2818",17.7034951740616,5,19.7368421052632,0.00684242889747971 -"2819",23.045712295823,5,19.7368421052632,0.00592412358354757 -"2820",30,5,19.7368421052632,0.00512906173432557 -"2821",0.2,7.10526315789474,19.7368421052632,0.0417972395974459 -"2822",0.260352117694686,7.10526315789474,19.7368421052632,0.04179697022912 -"2823",0.338916125940539,7.10526315789474,19.7368421052632,0.0417953227399239 -"2824",0.441187655547492,7.10526315789474,19.7368421052632,0.0417852625037468 -"2825",0.574320702112717,7.10526315789474,19.7368421052632,0.0417244194597155 -"2826",0.747628055154725,7.10526315789474,19.7368421052632,0.0413763592564236 -"2827",0.973232737037462,7.10526315789474,19.7368421052632,0.0398351681396106 -"2828",1.2669160204875,7.10526315789474,19.7368421052632,0.036206742065436 -"2829",1.64922134437622,7.10526315789474,19.7368421052632,0.0317190437776772 -"2830",2.14689134777813,7.10526315789474,19.7368421052632,0.0275199296091895 -"2831",2.79473854427218,7.10526315789474,19.7368421052632,0.0238348683454266 -"2832",3.63808049202114,7.10526315789474,19.7368421052632,0.020637230751392 -"2833",4.73590980220715,7.10526315789474,19.7368421052632,0.0178677266415153 -"2834",6.16502073107827,7.10526315789474,19.7368421052632,0.0154697672735496 -"2835",8.02538101483936,7.10526315789474,19.7368421052632,0.0133936117423994 -"2836",10.4471247126008,7.10526315789474,19.7368421052632,0.0115960889924308 -"2837",13.5996552137305,7.10526315789474,19.7368421052632,0.0100398068803857 -"2838",17.7034951740616,7.10526315789474,19.7368421052632,0.00869238945114535 -"2839",23.045712295823,7.10526315789474,19.7368421052632,0.00752580554602146 -"2840",30,7.10526315789474,19.7368421052632,0.0065157859557951 -"2841",0.2,9.21052631578947,19.7368421052632,0.0524886952377724 -"2842",0.260352117694686,9.21052631578947,19.7368421052632,0.052488356966822 -"2843",0.338916125940539,9.21052631578947,19.7368421052632,0.0524862880608571 -"2844",0.441187655547492,9.21052631578947,19.7368421052632,0.0524736544832379 -"2845",0.574320702112717,9.21052631578947,19.7368421052632,0.0523972481935821 -"2846",0.747628055154725,9.21052631578947,19.7368421052632,0.0519601565073621 -"2847",0.973232737037462,9.21052631578947,19.7368421052632,0.0500247389627427 -"2848",1.2669160204875,9.21052631578947,19.7368421052632,0.0454681856536152 -"2849",1.64922134437622,9.21052631578947,19.7368421052632,0.0398325640189357 -"2850",2.14689134777813,9.21052631578947,19.7368421052632,0.0345593444001016 -"2851",2.79473854427218,9.21052631578947,19.7368421052632,0.0299316689969156 -"2852",3.63808049202114,9.21052631578947,19.7368421052632,0.0259160969933429 -"2853",4.73590980220715,9.21052631578947,19.7368421052632,0.0224381721690451 -"2854",6.16502073107827,9.21052631578947,19.7368421052632,0.0194268307582262 -"2855",8.02538101483936,9.21052631578947,19.7368421052632,0.0168196084633974 -"2856",10.4471247126008,9.21052631578947,19.7368421052632,0.0145622913602884 -"2857",13.5996552137305,9.21052631578947,19.7368421052632,0.0126079226443188 -"2858",17.7034951740616,9.21052631578947,19.7368421052632,0.0109158448065809 -"2859",23.045712295823,9.21052631578947,19.7368421052632,0.00945085650460028 -"2860",30,9.21052631578947,19.7368421052632,0.00818248062700259 -"2861",0.2,11.3157894736842,19.7368421052632,0.0648642077719785 -"2862",0.260352117694686,11.3157894736842,19.7368421052632,0.0648637897452566 -"2863",0.338916125940539,11.3157894736842,19.7368421052632,0.0648612330433656 -"2864",0.441187655547492,11.3157894736842,19.7368421052632,0.0648456207862903 -"2865",0.574320702112717,11.3157894736842,19.7368421052632,0.0647511998176443 -"2866",0.747628055154725,11.3157894736842,19.7368421052632,0.0642110529189274 -"2867",0.973232737037462,11.3157894736842,19.7368421052632,0.0618193126561711 -"2868",1.2669160204875,11.3157894736842,19.7368421052632,0.0561884388227013 -"2869",1.64922134437622,11.3157894736842,19.7368421052632,0.0492240795262819 -"2870",2.14689134777813,11.3157894736842,19.7368421052632,0.042707567514812 -"2871",2.79473854427218,11.3157894736842,19.7368421052632,0.0369888027885453 -"2872",3.63808049202114,11.3157894736842,19.7368421052632,0.0320264600291536 -"2873",4.73590980220715,11.3157894736842,19.7368421052632,0.0277285281145453 -"2874",6.16502073107827,11.3157894736842,19.7368421052632,0.0240071882325213 -"2875",8.02538101483936,11.3157894736842,19.7368421052632,0.0207852485772599 -"2876",10.4471247126008,11.3157894736842,19.7368421052632,0.0179957129463964 -"2877",13.5996552137305,11.3157894736842,19.7368421052632,0.0155805533033257 -"2878",17.7034951740616,11.3157894736842,19.7368421052632,0.0134895261224021 -"2879",23.045712295823,11.3157894736842,19.7368421052632,0.011679130471058 -"2880",30,11.3157894736842,19.7368421052632,0.0101117035025504 -"2881",0.2,13.4210526315789,19.7368421052632,0.0783621516222006 -"2882",0.260352117694686,13.4210526315789,19.7368421052632,0.0783616466060369 -"2883",0.338916125940539,13.4210526315789,19.7368421052632,0.07835855786622 -"2884",0.441187655547492,13.4210526315789,19.7368421052632,0.0783396967701223 -"2885",0.574320702112717,13.4210526315789,19.7368421052632,0.0782256272313811 -"2886",0.747628055154725,13.4210526315789,19.7368421052632,0.0775730782428186 -"2887",0.973232737037462,13.4210526315789,19.7368421052632,0.0746836278116982 -"2888",1.2669160204875,13.4210526315789,19.7368421052632,0.0678809949844387 -"2889",1.64922134437622,13.4210526315789,19.7368421052632,0.05946738449133 -"2890",2.14689134777813,13.4210526315789,19.7368421052632,0.0515948162471326 -"2891",2.79473854427218,13.4210526315789,19.7368421052632,0.0446860028357863 -"2892",3.63808049202114,13.4210526315789,19.7368421052632,0.0386910193299403 -"2893",4.73590980220715,13.4210526315789,19.7368421052632,0.0334987075154124 -"2894",6.16502073107827,13.4210526315789,19.7368421052632,0.0290029738883553 -"2895",8.02538101483936,13.4210526315789,19.7368421052632,0.0251105633825379 -"2896",10.4471247126008,13.4210526315789,19.7368421052632,0.0217405381934582 -"2897",13.5996552137305,13.4210526315789,19.7368421052632,0.0188227949164967 -"2898",17.7034951740616,13.4210526315789,19.7368421052632,0.0162966345789853 -"2899",23.045712295823,13.4210526315789,19.7368421052632,0.0141095039039987 -"2900",30,13.4210526315789,19.7368421052632,0.0122159025792943 -"2901",0.2,15.5263157894737,19.7368421052632,0.0917389665783843 -"2902",0.260352117694686,15.5263157894737,19.7368421052632,0.0917383753534115 -"2903",0.338916125940539,15.5263157894737,19.7368421052632,0.0917347593501119 -"2904",0.441187655547492,15.5263157894737,19.7368421052632,0.0917126785696749 -"2905",0.574320702112717,15.5263157894737,19.7368421052632,0.0915791367846989 -"2906",0.747628055154725,15.5263157894737,19.7368421052632,0.090815194388871 -"2907",0.973232737037462,15.5263157894737,19.7368421052632,0.0874325001794466 -"2908",1.2669160204875,15.5263157894737,19.7368421052632,0.0794686235800172 -"2909",1.64922134437622,15.5263157894737,19.7368421052632,0.0696187672928633 -"2910",2.14689134777813,15.5263157894737,19.7368421052632,0.0604023118983962 -"2911",2.79473854427218,15.5263157894737,19.7368421052632,0.0523141291530385 -"2912",3.63808049202114,15.5263157894737,19.7368421052632,0.0452957716922543 -"2913",4.73590980220715,15.5263157894737,19.7368421052632,0.0392171060334291 -"2914",6.16502073107827,15.5263157894737,19.7368421052632,0.0339539279759105 -"2915",8.02538101483936,15.5263157894737,19.7368421052632,0.0293970633427887 -"2916",10.4471247126008,15.5263157894737,19.7368421052632,0.0254517578376537 -"2917",13.5996552137305,15.5263157894737,19.7368421052632,0.022035941050744 -"2918",17.7034951740616,15.5263157894737,19.7368421052632,0.0190785523882695 -"2919",23.045712295823,15.5263157894737,19.7368421052632,0.0165180674635765 -"2920",30,15.5263157894737,19.7368421052632,0.0143012188313775 -"2921",0.2,17.6315789473684,19.7368421052632,0.103007774009361 -"2922",0.260352117694686,17.6315789473684,19.7368421052632,0.103007110160937 -"2923",0.338916125940539,17.6315789473684,19.7368421052632,0.103003049983843 -"2924",0.441187655547492,17.6315789473684,19.7368421052632,0.102978256898353 -"2925",0.574320702112717,17.6315789473684,19.7368421052632,0.102828311433294 -"2926",0.747628055154725,17.6315789473684,19.7368421052632,0.101970529744655 -"2927",0.973232737037462,17.6315789473684,19.7368421052632,0.0981723203941118 -"2928",1.2669160204875,17.6315789473684,19.7368421052632,0.0892301965443567 -"2929",1.64922134437622,17.6315789473684,19.7368421052632,0.0781704276337824 -"2930",2.14689134777813,17.6315789473684,19.7368421052632,0.0678218637699257 -"2931",2.79473854427218,17.6315789473684,19.7368421052632,0.0587401645590635 -"2932",3.63808049202114,17.6315789473684,19.7368421052632,0.0508597032218446 -"2933",4.73590980220715,17.6315789473684,19.7368421052632,0.0440343612563045 -"2934",6.16502073107827,17.6315789473684,19.7368421052632,0.0381246777691172 -"2935",8.02538101483936,17.6315789473684,19.7368421052632,0.0330080681120987 -"2936",10.4471247126008,17.6315789473684,19.7368421052632,0.0285781387916763 -"2937",13.5996552137305,17.6315789473684,19.7368421052632,0.0247427382332588 -"2938",17.7034951740616,17.6315789473684,19.7368421052632,0.0214220770751485 -"2939",23.045712295823,17.6315789473684,19.7368421052632,0.018547073548138 -"2940",30,17.6315789473684,19.7368421052632,0.0160579170704116 -"2941",0.2,19.7368421052632,19.7368421052632,0.109843838742165 -"2942",0.260352117694686,19.7368421052632,19.7368421052632,0.109843130837738 -"2943",0.338916125940539,19.7368421052632,19.7368421052632,0.109838801208812 -"2944",0.441187655547492,19.7368421052632,19.7368421052632,0.10981236274132 -"2945",0.574320702112717,19.7368421052632,19.7368421052632,0.109652466212709 -"2946",0.747628055154725,19.7368421052632,19.7368421052632,0.108737758226938 -"2947",0.973232737037462,19.7368421052632,19.7368421052632,0.104687482415987 -"2948",1.2669160204875,19.7368421052632,19.7368421052632,0.0951519185266472 -"2949",1.64922134437622,19.7368421052632,19.7368421052632,0.0833581730115918 -"2950",2.14689134777813,19.7368421052632,19.7368421052632,0.0723228313472708 -"2951",2.79473854427218,19.7368421052632,19.7368421052632,0.0626384292405702 -"2952",3.63808049202114,19.7368421052632,19.7368421052632,0.0542349846203547 -"2953",4.73590980220715,19.7368421052632,19.7368421052632,0.0469566818957974 -"2954",6.16502073107827,19.7368421052632,19.7368421052632,0.0406548049139218 -"2955",8.02538101483936,19.7368421052632,19.7368421052632,0.0351986337513348 -"2956",10.4471247126008,19.7368421052632,19.7368421052632,0.0304747141579705 -"2957",13.5996552137305,19.7368421052632,19.7368421052632,0.0263847789613111 -"2958",17.7034951740616,19.7368421052632,19.7368421052632,0.022843743614448 -"2959",23.045712295823,19.7368421052632,19.7368421052632,0.0197779417675369 -"2960",30,19.7368421052632,19.7368421052632,0.0171235935363195 -"2961",0.2,21.8421052631579,19.7368421052632,0.110536034659287 -"2962",0.260352117694686,21.8421052631579,19.7368421052632,0.110535322293904 -"2963",0.338916125940539,21.8421052631579,19.7368421052632,0.110530965381231 -"2964",0.441187655547492,21.8421052631579,19.7368421052632,0.110504360308134 -"2965",0.574320702112717,21.8421052631579,19.7368421052632,0.11034345616976 -"2966",0.747628055154725,21.8421052631579,19.7368421052632,0.109422984026979 -"2967",0.973232737037462,21.8421052631579,19.7368421052632,0.105347184851116 -"2968",1.2669160204875,21.8421052631579,19.7368421052632,0.0957515313066144 -"2969",1.64922134437622,21.8421052631579,19.7368421052632,0.0838834658971838 -"2970",2.14689134777813,21.8421052631579,19.7368421052632,0.0727785835236927 -"2971",2.79473854427218,21.8421052631579,19.7368421052632,0.0630331538375231 -"2972",3.63808049202114,21.8421052631579,19.7368421052632,0.0545767537659824 -"2973",4.73590980220715,21.8421052631579,19.7368421052632,0.047252585825067 -"2974",6.16502073107827,21.8421052631579,19.7368421052632,0.0409109967066983 -"2975",8.02538101483936,21.8421052631579,19.7368421052632,0.035420442738074 -"2976",10.4471247126008,21.8421052631579,19.7368421052632,0.0306667547217123 -"2977",13.5996552137305,21.8421052631579,19.7368421052632,0.0265510462411178 -"2978",17.7034951740616,21.8421052631579,19.7368421052632,0.022987696577516 -"2979",23.045712295823,21.8421052631579,19.7368421052632,0.0199025751625214 -"2980",30,21.8421052631579,19.7368421052632,0.0172315001942443 -"2981",0.2,23.9473684210526,19.7368421052632,0.104934085844921 -"2982",0.260352117694686,23.9473684210526,19.7368421052632,0.104933409582103 -"2983",0.338916125940539,23.9473684210526,19.7368421052632,0.104929273477078 -"2984",0.441187655547492,23.9473684210526,19.7368421052632,0.104904016744892 -"2985",0.574320702112717,23.9473684210526,19.7368421052632,0.10475126720289 -"2986",0.747628055154725,23.9473684210526,19.7368421052632,0.103877444443224 -"2987",0.973232737037462,23.9473684210526,19.7368421052632,0.100008206127186 -"2988",1.2669160204875,23.9473684210526,19.7368421052632,0.090898858791898 -"2989",1.64922134437622,23.9473684210526,19.7368421052632,0.079632265066829 -"2990",2.14689134777813,23.9473684210526,19.7368421052632,0.0690901763817275 -"2991",2.79473854427218,23.9473684210526,19.7368421052632,0.0598386435360245 -"2992",3.63808049202114,23.9473684210526,19.7368421052632,0.0518108124872519 -"2993",4.73590980220715,23.9473684210526,19.7368421052632,0.0448578322231813 -"2994",6.16502073107827,23.9473684210526,19.7368421052632,0.0388376338418003 -"2995",8.02538101483936,23.9473684210526,19.7368421052632,0.0336253402829108 -"2996",10.4471247126008,23.9473684210526,19.7368421052632,0.0291125684259645 -"2997",13.5996552137305,23.9473684210526,19.7368421052632,0.0252054434024681 -"2998",17.7034951740616,23.9473684210526,19.7368421052632,0.0218226837381793 -"2999",23.045712295823,23.9473684210526,19.7368421052632,0.0188939157902344 -"3000",30,23.9473684210526,19.7368421052632,0.0163582104803474 -"3001",0.2,26.0526315789474,19.7368421052632,0.0945448816519 -"3002",0.260352117694686,26.0526315789474,19.7368421052632,0.0945442723438036 -"3003",0.338916125940539,26.0526315789474,19.7368421052632,0.0945405457419379 -"3004",0.441187655547492,26.0526315789474,19.7368421052632,0.0945177896018693 -"3005",0.574320702112717,26.0526315789474,19.7368421052632,0.094380163326721 -"3006",0.747628055154725,26.0526315789474,19.7368421052632,0.0935928550966822 -"3007",0.973232737037462,26.0526315789474,19.7368421052632,0.0901066982799784 -"3008",1.2669160204875,26.0526315789474,19.7368421052632,0.081899239675787 -"3009",1.64922134437622,26.0526315789474,19.7368421052632,0.0717481170755395 -"3010",2.14689134777813,26.0526315789474,19.7368421052632,0.0622497684782138 -"3011",2.79473854427218,26.0526315789474,19.7368421052632,0.0539142017178731 -"3012",3.63808049202114,26.0526315789474,19.7368421052632,0.0466811817671457 -"3013",4.73590980220715,26.0526315789474,19.7368421052632,0.0404165948990993 -"3014",6.16502073107827,26.0526315789474,19.7368421052632,0.0349924380209443 -"3015",8.02538101483936,26.0526315789474,19.7368421052632,0.030296197769817 -"3016",10.4471247126008,26.0526315789474,19.7368421052632,0.0262302217077816 -"3017",13.5996552137305,26.0526315789474,19.7368421052632,0.0227099292311161 -"3018",17.7034951740616,26.0526315789474,19.7368421052632,0.0196620862967462 -"3019",23.045712295823,26.0526315789474,19.7368421052632,0.0170232867418185 -"3020",30,26.0526315789474,19.7368421052632,0.0147386338904879 -"3021",0.2,28.1578947368421,19.7368421052632,0.0816762812329656 -"3022",0.260352117694686,28.1578947368421,19.7368421052632,0.0816757548584166 -"3023",0.338916125940539,28.1578947368421,19.7368421052632,0.0816725354881375 -"3024",0.441187655547492,28.1578947368421,19.7368421052632,0.081652876709539 -"3025",0.574320702112717,28.1578947368421,19.7368421052632,0.081533982887286 -"3026",0.747628055154725,28.1578947368421,19.7368421052632,0.0808538359846706 -"3027",0.973232737037462,28.1578947368421,19.7368421052632,0.0778421835333864 -"3028",1.2669160204875,28.1578947368421,19.7368421052632,0.0707518505037042 -"3029",1.64922134437622,28.1578947368421,19.7368421052632,0.0619824075699157 -"3030",2.14689134777813,28.1578947368421,19.7368421052632,0.0537768889027047 -"3031",2.79473854427218,28.1578947368421,19.7368421052632,0.0465758846488688 -"3032",3.63808049202114,28.1578947368421,19.7368421052632,0.0403273584321416 -"3033",4.73590980220715,28.1578947368421,19.7368421052632,0.0349154508819604 -"3034",6.16502073107827,28.1578947368421,19.7368421052632,0.03022958153725 -"3035",8.02538101483936,28.1578947368421,19.7368421052632,0.0261725513438981 -"3036",10.4471247126008,28.1578947368421,19.7368421052632,0.0226599994370478 -"3037",13.5996552137305,28.1578947368421,19.7368421052632,0.0196188575653488 -"3038",17.7034951740616,28.1578947368421,19.7368421052632,0.0169858596461378 -"3039",23.045712295823,28.1578947368421,19.7368421052632,0.0147062297941566 -"3040",30,28.1578947368421,19.7368421052632,0.0127325433761862 -"3041",0.2,30.2631578947368,19.7368421052632,0.0684178816261654 -"3042",0.260352117694686,30.2631578947368,19.7368421052632,0.0684174406972808 -"3043",0.338916125940539,30.2631578947368,19.7368421052632,0.068414743922999 -"3044",0.441187655547492,30.2631578947368,19.7368421052632,0.0683982763271833 -"3045",0.574320702112717,30.2631578947368,19.7368421052632,0.0682986823773341 -"3046",0.747628055154725,30.2631578947368,19.7368421052632,0.0677289427960373 -"3047",0.973232737037462,30.2631578947368,19.7368421052632,0.0652061677896264 -"3048",1.2669160204875,30.2631578947368,19.7368421052632,0.059266798873806 -"3049",1.64922134437622,30.2631578947368,19.7368421052632,0.0519208876800775 -"3050",2.14689134777813,30.2631578947368,19.7368421052632,0.0450473596939877 -"3051",2.79473854427218,30.2631578947368,19.7368421052632,0.0390152846632551 -"3052",3.63808049202114,30.2631578947368,19.7368421052632,0.0337810732057741 -"3053",4.73590980220715,30.2631578947368,19.7368421052632,0.0292476732449713 -"3054",6.16502073107827,30.2631578947368,19.7368421052632,0.0253224546955661 -"3055",8.02538101483936,30.2631578947368,19.7368421052632,0.0219239966936547 -"3056",10.4471247126008,30.2631578947368,19.7368421052632,0.0189816325587945 -"3057",13.5996552137305,30.2631578947368,19.7368421052632,0.0164341551094625 -"3058",17.7034951740616,30.2631578947368,19.7368421052632,0.0142285681601168 -"3059",23.045712295823,30.2631578947368,19.7368421052632,0.012318987520427 -"3060",30,30.2631578947368,19.7368421052632,0.0106656869333606 -"3061",0.2,32.3684210526316,19.7368421052632,0.0561293064940038 -"3062",0.260352117694686,32.3684210526316,19.7368421052632,0.0561289447606102 -"3063",0.338916125940539,32.3684210526316,19.7368421052632,0.0561267323555106 -"3064",0.441187655547492,32.3684210526316,19.7368421052632,0.0561132225140659 -"3065",0.574320702112717,32.3684210526316,19.7368421052632,0.0560315166909218 -"3066",0.747628055154725,32.3684210526316,19.7368421052632,0.05556410836403 -"3067",0.973232737037462,32.3684210526316,19.7368421052632,0.053494450429808 -"3068",1.2669160204875,32.3684210526316,19.7368421052632,0.0486218549864327 -"3069",1.64922134437622,32.3684210526316,19.7368421052632,0.0425953471339471 -"3070",2.14689134777813,32.3684210526316,19.7368421052632,0.0369563774690517 -"3071",2.79473854427218,32.3684210526316,19.7368421052632,0.0320077269094686 -"3072",3.63808049202114,32.3684210526316,19.7368421052632,0.0277136351871224 -"3073",4.73590980220715,32.3684210526316,19.7368421052632,0.0239944818048217 -"3074",6.16502073107827,32.3684210526316,19.7368421052632,0.0207742740202641 -"3075",8.02538101483936,32.3684210526316,19.7368421052632,0.0179862150178157 -"3076",10.4471247126008,32.3684210526316,19.7368421052632,0.0155723306002167 -"3077",13.5996552137305,32.3684210526316,19.7368421052632,0.0134824070430769 -"3078",17.7034951740616,32.3684210526316,19.7368421052632,0.0116729668362692 -"3079",23.045712295823,32.3684210526316,19.7368421052632,0.0101063670753206 -"3080",30,32.3684210526316,19.7368421052632,0.00875001675910906 -"3081",0.2,34.4736842105263,19.7368421052632,0.0454487569742761 -"3082",0.260352117694686,34.4736842105263,19.7368421052632,0.045448464073221 -"3083",0.338916125940539,34.4736842105263,19.7368421052632,0.0454466726550122 -"3084",0.441187655547492,34.4736842105263,19.7368421052632,0.0454357335300001 -"3085",0.574320702112717,34.4736842105263,19.7368421052632,0.0453695750767533 -"3086",0.747628055154725,34.4736842105263,19.7368421052632,0.0449911074137165 -"3087",0.973232737037462,34.4736842105263,19.7368421052632,0.0433152737655245 -"3088",1.2669160204875,34.4736842105263,19.7368421052632,0.0393698587947625 -"3089",1.64922134437622,34.4736842105263,19.7368421052632,0.0344901033176403 -"3090",2.14689134777813,34.4736842105263,19.7368421052632,0.0299241434315597 -"3091",2.79473854427218,34.4736842105263,19.7368421052632,0.025917145471285 -"3092",3.63808049202114,34.4736842105263,19.7368421052632,0.022440153801434 -"3093",4.73590980220715,34.4736842105263,19.7368421052632,0.0194286984890421 -"3094",6.16502073107827,34.4736842105263,19.7368421052632,0.0168212470497006 -"3095",8.02538101483936,34.4736842105263,19.7368421052632,0.0145637130813136 -"3096",10.4471247126008,34.4736842105263,19.7368421052632,0.0126091539906686 -"3097",13.5996552137305,34.4736842105263,19.7368421052632,0.0109169109579954 -"3098",17.7034951740616,34.4736842105263,19.7368421052632,0.00945177957912338 -"3099",23.045712295823,34.4736842105263,19.7368421052632,0.00818327981921776 -"3100",30,34.4736842105263,19.7368421052632,0.00708502224676647 -"3101",0.2,36.5789473684211,19.7368421052632,0.0365233760195092 -"3102",0.260352117694686,36.5789473684211,19.7368421052632,0.0365231406393561 -"3103",0.338916125940539,36.5789473684211,19.7368421052632,0.0365217010259277 -"3104",0.441187655547492,36.5789473684211,19.7368421052632,0.0365129101633664 -"3105",0.574320702112717,36.5789473684211,19.7368421052632,0.0364597441314291 -"3106",0.747628055154725,36.5789473684211,19.7368421052632,0.0361556012309723 -"3107",0.973232737037462,36.5789473684211,19.7368421052632,0.0348088734752779 -"3108",1.2669160204875,36.5789473684211,19.7368421052632,0.031638272470465 -"3109",1.64922134437622,36.5789473684211,19.7368421052632,0.0277168199151163 -"3110",2.14689134777813,36.5789473684211,19.7368421052632,0.0240475387089503 -"3111",2.79473854427218,36.5789473684211,19.7368421052632,0.0208274485908564 -"3112",3.63808049202114,36.5789473684211,19.7368421052632,0.0180332803312812 -"3113",4.73590980220715,36.5789473684211,19.7368421052632,0.015613224821233 -"3114",6.16502073107827,36.5789473684211,19.7368421052632,0.0135178335341714 -"3115",8.02538101483936,36.5789473684211,19.7368421052632,0.0117036417389836 -"3116",10.4471247126008,36.5789473684211,19.7368421052632,0.0101329255880363 -"3117",13.5996552137305,36.5789473684211,19.7368421052632,0.00877301097840899 -"3118",17.7034951740616,36.5789473684211,19.7368421052632,0.0075956070661565 -"3119",23.045712295823,36.5789473684211,19.7368421052632,0.00657621958900476 -"3120",30,36.5789473684211,19.7368421052632,0.00569364156145573 -"3121",0.2,38.6842105263158,19.7368421052632,0.0292391022711075 -"3122",0.260352117694686,38.6842105263158,19.7368421052632,0.0292389138355049 -"3123",0.338916125940539,38.6842105263158,19.7368421052632,0.0292377613406139 -"3124",0.441187655547492,38.6842105263158,19.7368421052632,0.0292307237401099 -"3125",0.574320702112717,38.6842105263158,19.7368421052632,0.029188161216746 -"3126",0.747628055154725,38.6842105263158,19.7368421052632,0.0289446770063395 -"3127",0.973232737037462,38.6842105263158,19.7368421052632,0.0278665425381826 -"3128",1.2669160204875,38.6842105263158,19.7368421052632,0.0253282906802196 -"3129",1.64922134437622,38.6842105263158,19.7368421052632,0.0221889381664791 -"3130",2.14689134777813,38.6842105263158,19.7368421052632,0.019251463591532 -"3131",2.79473854427218,38.6842105263158,19.7368421052632,0.0166735927990062 -"3132",3.63808049202114,38.6842105263158,19.7368421052632,0.0144366974073874 -"3133",4.73590980220715,38.6842105263158,19.7368421052632,0.0124993011896264 -"3134",6.16502073107827,38.6842105263158,19.7368421052632,0.0108218177032243 -"3135",8.02538101483936,38.6842105263158,19.7368421052632,0.0093694508844898 -"3136",10.4471247126008,38.6842105263158,19.7368421052632,0.00811200058329373 -"3137",13.5996552137305,38.6842105263158,19.7368421052632,0.00702330926599529 -"3138",17.7034951740616,38.6842105263158,19.7368421052632,0.006080728454562 -"3139",23.045712295823,38.6842105263158,19.7368421052632,0.00526464905701657 -"3140",30,38.6842105263158,19.7368421052632,0.00455809363903018 -"3141",0.2,40.7894736842105,19.7368421052632,0.0233757819365125 -"3142",0.260352117694686,40.7894736842105,19.7368421052632,0.0233756312879217 -"3143",0.338916125940539,40.7894736842105,19.7368421052632,0.0233747099029556 -"3144",0.441187655547492,40.7894736842105,19.7368421052632,0.0233690835532403 -"3145",0.574320702112717,40.7894736842105,19.7368421052632,0.0233350560972809 -"3146",0.747628055154725,40.7894736842105,19.7368421052632,0.0231403978018697 -"3147",0.973232737037462,40.7894736842105,19.7368421052632,0.02227846175499 -"3148",1.2669160204875,40.7894736842105,19.7368421052632,0.0202492058160919 -"3149",1.64922134437622,40.7894736842105,19.7368421052632,0.0177393880008044 -"3150",2.14689134777813,40.7894736842105,19.7368421052632,0.0153909655194526 -"3151",2.79473854427218,40.7894736842105,19.7368421052632,0.0133300354352162 -"3152",3.63808049202114,40.7894736842105,19.7368421052632,0.011541704917937 -"3153",4.73590980220715,40.7894736842105,19.7368421052632,0.00999281497285288 -"3154",6.16502073107827,40.7894736842105,19.7368421052632,0.00865171743105236 -"3155",8.02538101483936,40.7894736842105,19.7368421052632,0.00749059388725215 -"3156",10.4471247126008,40.7894736842105,19.7368421052632,0.00648530023068846 -"3157",13.5996552137305,40.7894736842105,19.7368421052632,0.00561492430076498 -"3158",17.7034951740616,40.7894736842105,19.7368421052632,0.00486135932119383 -"3159",23.045712295823,40.7894736842105,19.7368421052632,0.00420892841332863 -"3160",30,40.7894736842105,19.7368421052632,0.00364405862957908 -"3161",0.2,42.8947368421053,19.7368421052632,0.0186921039115616 -"3162",0.260352117694686,42.8947368421053,19.7368421052632,0.0186919834476079 -"3163",0.338916125940539,42.8947368421053,19.7368421052632,0.0186912466755257 -"3164",0.441187655547492,42.8947368421053,19.7368421052632,0.0186867476468384 -"3165",0.574320702112717,42.8947368421053,19.7368421052632,0.0186595380867746 -"3166",0.747628055154725,42.8947368421053,19.7368421052632,0.0185038824130968 -"3167",0.973232737037462,42.8947368421053,19.7368421052632,0.0178146477942441 -"3168",1.2669160204875,42.8947368421053,19.7368421052632,0.0161919828080607 -"3169",1.64922134437622,42.8947368421053,19.7368421052632,0.0141850435095227 -"3170",2.14689134777813,42.8947368421053,19.7368421052632,0.0123071616414895 -"3171",2.79473854427218,42.8947368421053,19.7368421052632,0.0106591688858402 -"3172",3.63808049202114,42.8947368421053,19.7368421052632,0.00922915640762714 -"3173",4.73590980220715,42.8947368421053,19.7368421052632,0.00799060909914706 -"3174",6.16502073107827,42.8947368421053,19.7368421052632,0.00691821996260573 -"3175",8.02538101483936,42.8947368421053,19.7368421052632,0.00598974441497183 -"3176",10.4471247126008,42.8947368421053,19.7368421052632,0.00518587596936613 -"3177",13.5996552137305,42.8947368421053,19.7368421052632,0.00448989252083645 -"3178",17.7034951740616,42.8947368421053,19.7368421052632,0.00388731524917496 -"3179",23.045712295823,42.8947368421053,19.7368421052632,0.0033656083664682 -"3180",30,42.8947368421053,19.7368421052632,0.00291391846265987 -"3181",0.2,45,19.7368421052632,0.0149647094668531 -"3182",0.260352117694686,45,19.7368421052632,0.0149646130246292 -"3183",0.338916125940539,45,19.7368421052632,0.014964023172347 -"3184",0.441187655547492,45,19.7368421052632,0.0149604212954525 -"3185",0.574320702112717,45,19.7368421052632,0.0149386375966777 -"3186",0.747628055154725,45,19.7368421052632,0.0148140212375736 -"3187",0.973232737037462,45,19.7368421052632,0.0142622269679489 -"3188",1.2669160204875,45,19.7368421052632,0.0129631377806023 -"3189",1.64922134437622,45,19.7368421052632,0.01135640246272 -"3190",2.14689134777813,45,19.7368421052632,0.00985298921929126 -"3191",2.79473854427218,45,19.7368421052632,0.00853362287570295 -"3192",3.63808049202114,45,19.7368421052632,0.00738876933906083 -"3193",4.73590980220715,45,19.7368421052632,0.00639720088213111 -"3194",6.16502073107827,45,19.7368421052632,0.00553865697826246 -"3195",8.02538101483936,45,19.7368421052632,0.00479532883911037 -"3196",10.4471247126008,45,19.7368421052632,0.00415175988641375 -"3197",13.5996552137305,45,19.7368421052632,0.00359456257196147 -"3198",17.7034951740616,45,19.7368421052632,0.0031121452986354 -"3199",23.045712295823,45,19.7368421052632,0.00269447204133367 -"3200",30,45,19.7368421052632,0.00233285366966276 -"3201",0.2,5,21.8421052631579,0.0320836763908571 -"3202",0.260352117694686,5,21.8421052631579,0.0320834696229872 -"3203",0.338916125940539,5,21.8421052631579,0.0320822050057366 -"3204",0.441187655547492,5,21.8421052631579,0.0320744827407011 -"3205",0.574320702112717,5,21.8421052631579,0.0320277794522989 -"3206",0.747628055154725,5,21.8421052631579,0.0317606074803097 -"3207",0.973232737037462,5,21.8421052631579,0.0305775849284732 -"3208",1.2669160204875,5,21.8421052631579,0.0277923950668184 -"3209",1.64922134437622,5,21.8421052631579,0.0243476254841626 -"3210",2.14689134777813,5,21.8421052631579,0.0211243738673679 -"3211",2.79473854427218,5,21.8421052631579,0.0182957106779865 -"3212",3.63808049202114,5,21.8421052631579,0.0158411952417921 -"3213",4.73590980220715,5,21.8421052631579,0.01371531624882 -"3214",6.16502073107827,5,21.8421052631579,0.0118746360244509 -"3215",8.02538101483936,5,21.8421052631579,0.0102809733127492 -"3216",10.4471247126008,5,21.8421052631579,0.00890118989234556 -"3217",13.5996552137305,5,21.8421052631579,0.00770658345094827 -"3218",17.7034951740616,5,21.8421052631579,0.00667230211611603 -"3219",23.045712295823,5,21.8421052631579,0.00577682909313046 -"3220",30,5,21.8421052631579,0.00500153527006113 -"3221",0.2,7.10526315789474,21.8421052631579,0.0404630098878639 -"3222",0.260352117694686,7.10526315789474,21.8421052631579,0.0404627491181734 -"3223",0.338916125940539,7.10526315789474,21.8421052631579,0.0404611542192692 -"3224",0.441187655547492,7.10526315789474,21.8421052631579,0.0404514151207108 -"3225",0.574320702112717,7.10526315789474,21.8421052631579,0.040392514276637 -"3226",0.747628055154725,7.10526315789474,21.8421052631579,0.0400555646698444 -"3227",0.973232737037462,7.10526315789474,21.8421052631579,0.0385635706530314 -"3228",1.2669160204875,7.10526315789474,21.8421052631579,0.0350509693058917 -"3229",1.64922134437622,7.10526315789474,21.8421052631579,0.0307065249851612 -"3230",2.14689134777813,7.10526315789474,21.8421052631579,0.0266414527517745 -"3231",2.79473854427218,7.10526315789474,21.8421052631579,0.0230740240940663 -"3232",3.63808049202114,7.10526315789474,21.8421052631579,0.0199784598216082 -"3233",4.73590980220715,7.10526315789474,21.8421052631579,0.0172973623792481 -"3234",6.16502073107827,7.10526315789474,21.8421052631579,0.0149759494210915 -"3235",8.02538101483936,7.10526315789474,21.8421052631579,0.0129660678453041 -"3236",10.4471247126008,7.10526315789474,21.8421052631579,0.0112259246802019 -"3237",13.5996552137305,7.10526315789474,21.8421052631579,0.00971932139504534 -"3238",17.7034951740616,7.10526315789474,21.8421052631579,0.00841491552308996 -"3239",23.045712295823,7.10526315789474,21.8421052631579,0.00728557070169331 -"3240",30,7.10526315789474,21.8421052631579,0.00630779243069086 -"3241",0.2,9.21052631578947,21.8421052631579,0.0503673723081886 -"3242",0.260352117694686,9.21052631578947,21.8421052631579,0.050367047708409 -"3243",0.338916125940539,9.21052631578947,21.8421052631579,0.0503650624169756 -"3244",0.441187655547492,9.21052631578947,21.8421052631579,0.0503529394235454 -"3245",0.574320702112717,9.21052631578947,21.8421052631579,0.0502796210828942 -"3246",0.747628055154725,9.21052631578947,21.8421052631579,0.0498601943931483 -"3247",0.973232737037462,9.21052631578947,21.8421052631579,0.0480029964650982 -"3248",1.2669160204875,9.21052631578947,21.8421052631579,0.0436305955905233 -"3249",1.64922134437622,9.21052631578947,21.8421052631579,0.0382227367787136 -"3250",2.14689134777813,9.21052631578947,21.8421052631579,0.0331626335583628 -"3251",2.79473854427218,9.21052631578947,21.8421052631579,0.0287219849787429 -"3252",3.63808049202114,9.21052631578947,21.8421052631579,0.0248687017295008 -"3253",4.73590980220715,9.21052631578947,21.8421052631579,0.0215313367275367 -"3254",6.16502073107827,9.21052631578947,21.8421052631579,0.0186416982387401 -"3255",8.02538101483936,9.21052631578947,21.8421052631579,0.0161398464510555 -"3256",10.4471247126008,9.21052631578947,21.8421052631579,0.0139737584880209 -"3257",13.5996552137305,9.21052631578947,21.8421052631579,0.0120983752974348 -"3258",17.7034951740616,9.21052631578947,21.8421052631579,0.0104746825376564 -"3259",23.045712295823,9.21052631578947,21.8421052631579,0.0090689015233115 -"3260",30,9.21052631578947,21.8421052631579,0.00785178687101749 -"3261",0.2,11.3157894736842,21.8421052631579,0.0616469324407538 -"3262",0.260352117694686,11.3157894736842,21.8421052631579,0.0616465351482257 -"3263",0.338916125940539,11.3157894736842,21.8421052631579,0.0616441052591673 -"3264",0.441187655547492,11.3157894736842,21.8421052631579,0.0616292673726006 -"3265",0.574320702112717,11.3157894736842,21.8421052631579,0.0615395296994669 -"3266",0.747628055154725,11.3157894736842,21.8421052631579,0.0610261741754106 -"3267",0.973232737037462,11.3157894736842,21.8421052631579,0.0587530646214901 -"3268",1.2669160204875,11.3157894736842,21.8421052631579,0.0534014830525824 -"3269",1.64922134437622,11.3157894736842,21.8421052631579,0.0467825571181324 -"3270",2.14689134777813,11.3157894736842,21.8421052631579,0.0405892651699342 -"3271",2.79473854427218,11.3157894736842,21.8421052631579,0.0351541521109102 -"3272",3.63808049202114,11.3157894736842,21.8421052631579,0.0304379423652909 -"3273",4.73590980220715,11.3157894736842,21.8421052631579,0.0263531885777131 -"3274",6.16502073107827,11.3157894736842,21.8421052631579,0.0228164277634491 -"3275",8.02538101483936,11.3157894736842,21.8421052631579,0.0197542968428909 -"3276",10.4471247126008,11.3157894736842,21.8421052631579,0.0171031226362862 -"3277",13.5996552137305,11.3157894736842,21.8421052631579,0.0148077553071513 -"3278",17.7034951740616,11.3157894736842,21.8421052631579,0.0128204434169433 -"3279",23.045712295823,11.3157894736842,21.8421052631579,0.011099843686476 -"3280",30,11.3157894736842,21.8421052631579,0.00961016135237452 -"3281",0.2,13.4210526315789,21.8421052631579,0.0738372434292826 -"3282",0.260352117694686,13.4210526315789,21.8421052631579,0.0738367675745409 -"3283",0.338916125940539,13.4210526315789,21.8421052631579,0.0738338571895014 -"3284",0.441187655547492,13.4210526315789,21.8421052631579,0.0738160851998982 -"3285",0.574320702112717,13.4210526315789,21.8421052631579,0.0737086024403576 -"3286",0.747628055154725,13.4210526315789,21.8421052631579,0.0730937339417191 -"3287",0.973232737037462,13.4210526315789,21.8421052631579,0.0703711306129069 -"3288",1.2669160204875,13.4210526315789,21.8421052631579,0.0639613058999765 -"3289",1.64922134437622,13.4210526315789,21.8421052631579,0.0560335270776958 -"3290",2.14689134777813,13.4210526315789,21.8421052631579,0.0486155488085059 -"3291",2.79473854427218,13.4210526315789,21.8421052631579,0.0421056747545047 -"3292",3.63808049202114,13.4210526315789,21.8421052631579,0.0364568628304804 -"3293",4.73590980220715,13.4210526315789,21.8421052631579,0.0315643734912594 -"3294",6.16502073107827,13.4210526315789,21.8421052631579,0.0273282394476891 -"3295",8.02538101483936,13.4210526315789,21.8421052631579,0.0236605905113713 -"3296",10.4471247126008,13.4210526315789,21.8421052631579,0.0204851625133173 -"3297",13.5996552137305,13.4210526315789,21.8421052631579,0.017735900067796 -"3298",17.7034951740616,13.4210526315789,21.8421052631579,0.0153556091758166 -"3299",23.045712295823,13.4210526315789,21.8421052631579,0.013294771172807 -"3300",30,13.4210526315789,21.8421052631579,0.0115105130957151 -"3301",0.2,15.5263157894737,21.8421052631579,0.0860717259536223 -"3302",0.260352117694686,15.5263157894737,21.8421052631579,0.0860711712519973 -"3303",0.338916125940539,15.5263157894737,21.8421052631579,0.0860677786299016 -"3304",0.441187655547492,15.5263157894737,21.8421052631579,0.0860470619055532 -"3305",0.574320702112717,15.5263157894737,21.8421052631579,0.0859217697603666 -"3306",0.747628055154725,15.5263157894737,21.8421052631579,0.0852050204553493 -"3307",0.973232737037462,15.5263157894737,21.8421052631579,0.0820312946130191 -"3308",1.2669160204875,15.5263157894737,21.8421052631579,0.0745593922168997 -"3309",1.64922134437622,15.5263157894737,21.8421052631579,0.0653180178843679 -"3310",2.14689134777813,15.5263157894737,21.8421052631579,0.0566709156489339 -"3311",2.79473854427218,15.5263157894737,21.8421052631579,0.0490823862084324 -"3312",3.63808049202114,15.5263157894737,21.8421052631579,0.0424975928262982 -"3313",4.73590980220715,15.5263157894737,21.8421052631579,0.0367944411093769 -"3314",6.16502073107827,15.5263157894737,21.8421052631579,0.0318563996608198 -"3315",8.02538101483936,15.5263157894737,21.8421052631579,0.0275810386169967 -"3316",10.4471247126008,15.5263157894737,21.8421052631579,0.0238794571962909 -"3317",13.5996552137305,15.5263157894737,21.8421052631579,0.0206746549475162 -"3318",17.7034951740616,15.5263157894737,21.8421052631579,0.0178999610961595 -"3319",23.045712295823,15.5263157894737,21.8421052631579,0.0154976519687916 -"3320",30,15.5263157894737,21.8421052631579,0.0134177507548591 -"3321",0.2,17.6315789473684,21.8421052631579,0.0971087000861452 -"3322",0.260352117694686,17.6315789473684,21.8421052631579,0.097108074255152 -"3323",0.338916125940539,17.6315789473684,21.8421052631579,0.0971042465972545 -"3324",0.441187655547492,17.6315789473684,21.8421052631579,0.0970808733681338 -"3325",0.574320702112717,17.6315789473684,21.8421052631579,0.096939515015954 -"3326",0.747628055154725,17.6315789473684,21.8421052631579,0.0961308569749223 -"3327",0.973232737037462,17.6315789473684,21.8421052631579,0.0925501643890138 -"3328",1.2669160204875,17.6315789473684,21.8421052631579,0.0841201402339425 -"3329",1.64922134437622,17.6315789473684,21.8421052631579,0.0736937448236171 -"3330",2.14689134777813,17.6315789473684,21.8421052631579,0.0639378249987091 -"3331",2.79473854427218,17.6315789473684,21.8421052631579,0.0553762187178079 -"3332",3.63808049202114,17.6315789473684,21.8421052631579,0.0479470575317123 -"3333",4.73590980220715,17.6315789473684,21.8421052631579,0.0415125908878959 -"3334",6.16502073107827,17.6315789473684,21.8421052631579,0.0359413445729414 -"3335",8.02538101483936,17.6315789473684,21.8421052631579,0.0311177541457166 -"3336",10.4471247126008,17.6315789473684,21.8421052631579,0.0269415190807727 -"3337",13.5996552137305,17.6315789473684,21.8421052631579,0.0233257651620078 -"3338",17.7034951740616,17.6315789473684,21.8421052631579,0.0201952724240389 -"3339",23.045712295823,17.6315789473684,21.8421052631579,0.0174849152889968 -"3340",30,17.6315789473684,21.8421052631579,0.0151383084218195 -"3341",0.2,19.7368421052632,21.8421052631579,0.10555600402663 -"3342",0.260352117694686,19.7368421052632,21.8421052631579,0.105555323755771 -"3343",0.338916125940539,19.7368421052632,21.8421052631579,0.105551163137082 -"3344",0.441187655547492,19.7368421052632,21.8421052631579,0.105525756714537 -"3345",0.574320702112717,19.7368421052632,21.8421052631579,0.105372101864059 -"3346",0.747628055154725,19.7368421052632,21.8421052631579,0.104493100174616 -"3347",0.973232737037462,19.7368421052632,21.8421052631579,0.100600929847127 -"3348",1.2669160204875,19.7368421052632,21.8421052631579,0.0914375936798437 -"3349",1.64922134437622,19.7368421052632,21.8421052631579,0.0801042256609202 -"3350",2.14689134777813,19.7368421052632,21.8421052631579,0.0694996566428205 -"3351",2.79473854427218,19.7368421052632,21.8421052631579,0.0601932922670279 -"3352",3.63808049202114,19.7368421052632,21.8421052631579,0.0521178822638218 -"3353",4.73590980220715,19.7368421052632,21.8421052631579,0.0451236934181119 -"3354",6.16502073107827,19.7368421052632,21.8421052631579,0.0390678148209008 -"3355",8.02538101483936,19.7368421052632,21.8421052631579,0.0338246292967688 -"3356",10.4471247126008,19.7368421052632,21.8421052631579,0.0292851113654163 -"3357",13.5996552137305,19.7368421052632,21.8421052631579,0.0253548297853944 -"3358",17.7034951740616,19.7368421052632,21.8421052631579,0.0219520213474146 -"3359",23.045712295823,19.7368421052632,21.8421052631579,0.0190058953215662 -"3360",30,19.7368421052632,21.8421052631579,0.0164551615180969 -"3361",0.2,21.8421052631579,21.8421052631579,0.110273049710927 -"3362",0.260352117694686,21.8421052631579,21.8421052631579,0.110272339040388 -"3363",0.338916125940539,21.8421052631579,21.8421052631579,0.110267992493588 -"3364",0.441187655547492,21.8421052631579,21.8421052631579,0.110241450718707 -"3365",0.574320702112717,21.8421052631579,21.8421052631579,0.110080929399987 -"3366",0.747628055154725,21.8421052631579,21.8421052631579,0.109162647224665 -"3367",0.973232737037462,21.8421052631579,21.8421052631579,0.105096545102248 -"3368",1.2669160204875,21.8421052631579,21.8421052631579,0.0955237213295905 -"3369",1.64922134437622,21.8421052631579,21.8421052631579,0.0836838921652762 -"3370",2.14689134777813,21.8421052631579,21.8421052631579,0.0726054302882914 -"3371",2.79473854427218,21.8421052631579,21.8421052631579,0.0628831867181306 -"3372",3.63808049202114,21.8421052631579,21.8421052631579,0.0544469059311561 -"3373",4.73590980220715,21.8421052631579,21.8421052631579,0.0471401634925545 -"3374",6.16502073107827,21.8421052631579,21.8421052631579,0.0408136621461685 -"3375",8.02538101483936,21.8421052631579,21.8421052631579,0.0353361711850636 -"3376",10.4471247126008,21.8421052631579,21.8421052631579,0.0305937930406486 -"3377",13.5996552137305,21.8421052631579,21.8421052631579,0.0264878765648566 -"3378",17.7034951740616,21.8421052631579,21.8421052631579,0.0229330047458795 -"3379",23.045712295823,21.8421052631579,21.8421052631579,0.0198552233851804 -"3380",30,21.8421052631579,21.8421052631579,0.0171905033808276 -"3381",0.2,23.9473684210526,21.8421052631579,0.11076433532131 -"3382",0.260352117694686,23.9473684210526,21.8421052631579,0.11076362148461 -"3383",0.338916125940539,23.9473684210526,21.8421052631579,0.110759255573188 -"3384",0.441187655547492,23.9473684210526,21.8421052631579,0.110732595550085 -"3385",0.574320702112717,23.9473684210526,21.8421052631579,0.110571359080979 -"3386",0.747628055154725,23.9473684210526,21.8421052631579,0.109648985798898 -"3387",0.973232737037462,23.9473684210526,21.8421052631579,0.105564768484525 -"3388",1.2669160204875,23.9473684210526,21.8421052631579,0.0959492961174687 -"3389",1.64922134437622,23.9473684210526,21.8421052631579,0.0840567184555562 -"3390",2.14689134777813,23.9473684210526,21.8421052631579,0.0729289001046225 -"3391",2.79473854427218,23.9473684210526,21.8421052631579,0.0631633422488844 -"3392",3.63808049202114,23.9473684210526,21.8421052631579,0.0546894763641308 -"3393",4.73590980220715,23.9473684210526,21.8421052631579,0.0473501811174926 -"3394",6.16502073107827,23.9473684210526,21.8421052631579,0.0409954941075769 -"3395",8.02538101483936,23.9473684210526,21.8421052631579,0.0354935999718319 -"3396",10.4471247126008,23.9473684210526,21.8421052631579,0.0307300937081942 -"3397",13.5996552137305,23.9473684210526,21.8421052631579,0.0266058846605792 -"3398",17.7034951740616,23.9473684210526,21.8421052631579,0.0230351752695389 -"3399",23.045712295823,23.9473684210526,21.8421052631579,0.0199436818577232 -"3400",30,23.9473684210526,21.8421052631579,0.0172670900624181 -"3401",0.2,26.0526315789474,21.8421052631579,0.107322137517437 -"3402",0.260352117694686,26.0526315789474,21.8421052631579,0.107321445864476 -"3403",0.338916125940539,26.0526315789474,21.8421052631579,0.107317215631481 -"3404",0.441187655547492,26.0526315789474,21.8421052631579,0.107291384115791 -"3405",0.574320702112717,26.0526315789474,21.8421052631579,0.107135158355396 -"3406",0.747628055154725,26.0526315789474,21.8421052631579,0.106241449455914 -"3407",0.973232737037462,26.0526315789474,21.8421052631579,0.102284156424788 -"3408",1.2669160204875,26.0526315789474,21.8421052631579,0.0929675018836063 -"3409",1.64922134437622,26.0526315789474,21.8421052631579,0.0814445071257168 -"3410",2.14689134777813,26.0526315789474,21.8421052631579,0.07066250542938 -"3411",2.79473854427218,26.0526315789474,21.8421052631579,0.0612004295717698 -"3412",3.63808049202114,26.0526315789474,21.8421052631579,0.0529899040704907 -"3413",4.73590980220715,26.0526315789474,21.8421052631579,0.0458786904162411 -"3414",6.16502073107827,26.0526315789474,21.8421052631579,0.0397214865547267 -"3415",8.02538101483936,26.0526315789474,21.8421052631579,0.0343905735191369 -"3416",10.4471247126008,26.0526315789474,21.8421052631579,0.0297751016453763 -"3417",13.5996552137305,26.0526315789474,21.8421052631579,0.0257790596949161 -"3418",17.7034951740616,26.0526315789474,21.8421052631579,0.0223193164193538 -"3419",23.045712295823,26.0526315789474,21.8421052631579,0.0193238966381158 -"3420",30,26.0526315789474,21.8421052631579,0.0167304846711637 -"3421",0.2,28.1578947368421,21.8421052631579,0.100839914858442 -"3422",0.260352117694686,28.1578947368421,21.8421052631579,0.100839264981098 -"3423",0.338916125940539,28.1578947368421,21.8421052631579,0.100835290252818 -"3424",0.441187655547492,28.1578947368421,21.8421052631579,0.100811018952384 -"3425",0.574320702112717,28.1578947368421,21.8421052631579,0.100664229177774 -"3426",0.747628055154725,28.1578947368421,21.8421052631579,0.0998245000089676 -"3427",0.973232737037462,28.1578947368421,21.8421052631579,0.0961062262067545 -"3428",1.2669160204875,28.1578947368421,21.8421052631579,0.0873522946095044 -"3429",1.64922134437622,28.1578947368421,21.8421052631579,0.0765252850364696 -"3430",2.14689134777813,28.1578947368421,21.8421052631579,0.0663945127819054 -"3431",2.79473854427218,28.1578947368421,21.8421052631579,0.0575039432690636 -"3432",3.63808049202114,28.1578947368421,21.8421052631579,0.0497893308727392 -"3433",4.73590980220715,28.1578947368421,21.8421052631579,0.0431076322407285 -"3434",6.16502073107827,28.1578947368421,21.8421052631579,0.0373223215161793 -"3435",8.02538101483936,28.1578947368421,21.8421052631579,0.0323133939168823 -"3436",10.4471247126008,28.1578947368421,21.8421052631579,0.0279766950628744 -"3437",13.5996552137305,28.1578947368421,21.8421052631579,0.0242220127636171 -"3438",17.7034951740616,28.1578947368421,21.8421052631579,0.0209712368714291 -"3439",23.045712295823,28.1578947368421,21.8421052631579,0.0181567394835416 -"3440",30,28.1578947368421,21.8421052631579,0.0157199687669891 -"3441",0.2,30.2631578947368,21.8421052631579,0.092448642616583 -"3442",0.260352117694686,30.2631578947368,21.8421052631579,0.0924480468180008 -"3443",0.338916125940539,30.2631578947368,21.8421052631579,0.0924444028419543 -"3444",0.441187655547492,30.2631578947368,21.8421052631579,0.092422151248597 -"3445",0.574320702112717,30.2631578947368,21.8421052631579,0.0922875764085472 -"3446",0.747628055154725,30.2631578947368,21.8421052631579,0.0915177242926395 -"3447",0.973232737037462,30.2631578947368,21.8421052631579,0.0881088621731708 -"3448",1.2669160204875,30.2631578947368,21.8421052631579,0.0800833784660468 -"3449",1.64922134437622,30.2631578947368,21.8421052631579,0.0701573254737478 -"3450",2.14689134777813,30.2631578947368,21.8421052631579,0.0608695732487785 -"3451",2.79473854427218,30.2631578947368,21.8421052631579,0.0527188217858841 -"3452",3.63808049202114,30.2631578947368,21.8421052631579,0.0456461715822971 -"3453",4.73590980220715,30.2631578947368,21.8421052631579,0.0395204824663393 -"3454",6.16502073107827,30.2631578947368,21.8421052631579,0.0342165894161464 -"3455",8.02538101483936,30.2631578947368,21.8421052631579,0.0296244737031393 -"3456",10.4471247126008,30.2631578947368,21.8421052631579,0.0256486480288244 -"3457",13.5996552137305,30.2631578947368,21.8421052631579,0.022206407101607 -"3458",17.7034951740616,30.2631578947368,21.8421052631579,0.0192261406158075 -"3459",23.045712295823,30.2631578947368,21.8421052631579,0.0166458482432546 -"3460",30,30.2631578947368,21.8421052631579,0.0144118504713469 -"3461",0.2,32.3684210526316,21.8421052631579,0.0831948044211494 -"3462",0.260352117694686,32.3684210526316,21.8421052631579,0.0831942682602593 -"3463",0.338916125940539,32.3684210526316,21.8421052631579,0.083190989035536 -"3464",0.441187655547492,32.3684210526316,21.8421052631579,0.0831709647614631 -"3465",0.574320702112717,32.3684210526316,21.8421052631579,0.0830498604685165 -"3466",0.747628055154725,32.3684210526316,21.8421052631579,0.0823570682932785 -"3467",0.973232737037462,32.3684210526316,21.8421052631579,0.079289423281939 -"3468",1.2669160204875,32.3684210526316,21.8421052631579,0.0720672669743727 -"3469",1.64922134437622,32.3684210526316,21.8421052631579,0.0631347827972588 -"3470",2.14689134777813,32.3684210526316,21.8421052631579,0.0547767073512727 -"3471",2.79473854427218,32.3684210526316,21.8421052631579,0.0474418222231781 -"3472",3.63808049202114,32.3684210526316,21.8421052631579,0.0410771235778237 -"3473",4.73590980220715,32.3684210526316,21.8421052631579,0.035564597990396 -"3474",6.16502073107827,32.3684210526316,21.8421052631579,0.03079160909091 -"3475",8.02538101483936,32.3684210526316,21.8421052631579,0.0266591507030961 -"3476",10.4471247126008,32.3684210526316,21.8421052631579,0.0230812935272041 -"3477",13.5996552137305,32.3684210526316,21.8421052631579,0.0199836108289515 -"3478",17.7034951740616,32.3684210526316,21.8421052631579,0.0173016602843957 -"3479",23.045712295823,32.3684210526316,21.8421052631579,0.0149796476165167 -"3480",30,32.3684210526316,21.8421052631579,0.0129692664746112 -"3481",0.2,34.4736842105263,21.8421052631579,0.0738721080076276 -"3482",0.260352117694686,34.4736842105263,21.8421052631579,0.0738716319281961 -"3483",0.338916125940539,34.4736842105263,21.8421052631579,0.0738687201689267 -"3484",0.441187655547492,34.4736842105263,21.8421052631579,0.0738509397877193 -"3485",0.574320702112717,34.4736842105263,21.8421052631579,0.073743406276811 -"3486",0.747628055154725,34.4736842105263,21.8421052631579,0.0731282474486592 -"3487",0.973232737037462,34.4736842105263,21.8421052631579,0.0704043585569976 -"3488",1.2669160204875,34.4736842105263,21.8421052631579,0.0639915072435942 -"3489",1.64922134437622,34.4736842105263,21.8421052631579,0.0560599850710337 -"3490",2.14689134777813,34.4736842105263,21.8421052631579,0.04863850416994 -"3491",2.79473854427218,34.4736842105263,21.8421052631579,0.0421255562740207 -"3492",3.63808049202114,34.4736842105263,21.8421052631579,0.0364740770856629 -"3493",4.73590980220715,34.4736842105263,21.8421052631579,0.0315792776036204 -"3494",6.16502073107827,34.4736842105263,21.8421052631579,0.0273411433360387 -"3495",8.02538101483936,34.4736842105263,21.8421052631579,0.0236717626038447 -"3496",10.4471247126008,34.4736842105263,21.8421052631579,0.020494835227522 -"3497",13.5996552137305,34.4736842105263,21.8421052631579,0.0177442746312103 -"3498",17.7034951740616,34.4736842105263,21.8421052631579,0.015362859809972 -"3499",23.045712295823,34.4736842105263,21.8421052631579,0.013301048717439 -"3500",30,34.4736842105263,21.8421052631579,0.0115159481467406 -"3501",0.2,36.5789473684211,21.8421052631579,0.064993499465389 -"3502",0.260352117694686,36.5789473684211,21.8421052631579,0.0649930806054281 -"3503",0.338916125940539,36.5789473684211,21.8421052631579,0.0649905188073472 -"3504",0.441187655547492,36.5789473684211,21.8421052631579,0.0649748754308731 -"3505",0.574320702112717,36.5789473684211,21.8421052631579,0.0648802662560137 -"3506",0.747628055154725,36.5789473684211,21.8421052631579,0.064339042700237 -"3507",0.973232737037462,36.5789473684211,21.8421052631579,0.0619425350602261 -"3508",1.2669160204875,36.5789473684211,21.8421052631579,0.0563004373910183 -"3509",1.64922134437622,36.5789473684211,21.8421052631579,0.0493221962661163 -"3510",2.14689134777813,36.5789473684211,21.8421052631579,0.042792695105437 -"3511",2.79473854427218,36.5789473684211,21.8421052631579,0.0370625313534045 -"3512",3.63808049202114,36.5789473684211,21.8421052631579,0.0320902973192916 -"3513",4.73590980220715,36.5789473684211,21.8421052631579,0.0277837984782613 -"3514",6.16502073107827,36.5789473684211,21.8421052631579,0.0240550409717626 -"3515",8.02538101483936,36.5789473684211,21.8421052631579,0.0208266791300844 -"3516",10.4471247126008,36.5789473684211,21.8421052631579,0.0180315832095336 -"3517",13.5996552137305,36.5789473684211,21.8421052631579,0.0156116095081272 -"3518",17.7034951740616,36.5789473684211,21.8421052631579,0.0135164143514513 -"3519",23.045712295823,36.5789473684211,21.8421052631579,0.0117024100979591 -"3520",30,36.5789473684211,21.8421052631579,0.010131858828793 -"3521",0.2,38.6842105263158,21.8421052631579,0.0568391314778902 -"3522",0.260352117694686,38.6842105263158,21.8421052631579,0.0568387651699274 -"3523",0.338916125940539,38.6842105263158,21.8421052631579,0.05683652478621 -"3524",0.441187655547492,38.6842105263158,21.8421052631579,0.0568228440959951 -"3525",0.574320702112717,38.6842105263158,21.8421052631579,0.0567401050009612 -"3526",0.747628055154725,38.6842105263158,21.8421052631579,0.0562667857136669 -"3527",0.973232737037462,38.6842105263158,21.8421052631579,0.0541709543773209 -"3528",1.2669160204875,38.6842105263158,21.8421052631579,0.0492367388962484 -"3529",1.64922134437622,38.6842105263158,21.8421052631579,0.0431340183465733 -"3530",2.14689134777813,38.6842105263158,21.8421052631579,0.0374237368875094 -"3531",2.79473854427218,38.6842105263158,21.8421052631579,0.0324125044785659 -"3532",3.63808049202114,38.6842105263158,21.8421052631579,0.0280641086185416 -"3533",4.73590980220715,38.6842105263158,21.8421052631579,0.0242979219098992 -"3534",6.16502073107827,38.6842105263158,21.8421052631579,0.0210369905874689 -"3535",8.02538101483936,38.6842105263158,21.8421052631579,0.0182136731066942 -"3536",10.4471247126008,38.6842105263158,21.8421052631579,0.0157692621143902 -"3537",13.5996552137305,38.6842105263158,21.8421052631579,0.0136529088710859 -"3538",17.7034951740616,38.6842105263158,21.8421052631579,0.0118205860393916 -"3539",23.045712295823,38.6842105263158,21.8421052631579,0.0102341746734272 -"3540",30,38.6842105263158,21.8421052631579,0.00886067161827259 -"3541",0.2,40.7894736842105,21.8421052631579,0.0495253595713581 -"3542",0.260352117694686,40.7894736842105,21.8421052631579,0.0495250403980508 -"3543",0.338916125940539,40.7894736842105,21.8421052631579,0.0495230882955768 -"3544",0.441187655547492,40.7894736842105,21.8421052631579,0.0495111679673722 -"3545",0.574320702112717,40.7894736842105,21.8421052631579,0.0494390753205351 -"3546",0.747628055154725,40.7894736842105,21.8421052631579,0.0490266603647502 -"3547",0.973232737037462,40.7894736842105,21.8421052631579,0.0472005100025859 -"3548",1.2669160204875,40.7894736842105,21.8421052631579,0.0429012044089081 -"3549",1.64922134437622,40.7894736842105,21.8421052631579,0.0375837510677405 -"3550",2.14689134777813,40.7894736842105,21.8421052631579,0.0326082397402353 -"3551",2.79473854427218,40.7894736842105,21.8421052631579,0.0282418273673595 -"3552",3.63808049202114,40.7894736842105,21.8421052631579,0.0244529610893786 -"3553",4.73590980220715,40.7894736842105,21.8421052631579,0.0211713882344003 -"3554",6.16502073107827,40.7894736842105,21.8421052631579,0.0183300570584712 -"3555",8.02538101483936,40.7894736842105,21.8421052631579,0.01587002978881 -"3556",10.4471247126008,40.7894736842105,21.8421052631579,0.0137401532374568 -"3557",13.5996552137305,40.7894736842105,21.8421052631579,0.0118961216235075 -"3558",17.7034951740616,40.7894736842105,21.8421052631579,0.0102995728246264 -"3559",23.045712295823,40.7894736842105,21.8421052631579,0.0089172928480571 -"3560",30,40.7894736842105,21.8421052631579,0.00772052521790162 -"3561",0.2,42.8947368421053,21.8421052631579,0.0430661663154471 -"3562",0.260352117694686,42.8947368421053,21.8421052631579,0.0430658887693404 -"3563",0.338916125940539,42.8947368421053,21.8421052631579,0.0430641912638495 -"3564",0.441187655547492,42.8947368421053,21.8421052631579,0.0430538256079222 -"3565",0.574320702112717,42.8947368421053,21.8421052631579,0.0429911354236271 -"3566",0.747628055154725,42.8947368421053,21.8421052631579,0.0426325084246404 -"3567",0.973232737037462,42.8947368421053,21.8421052631579,0.0410445281273815 -"3568",1.2669160204875,42.8947368421053,21.8421052631579,0.0373059462909088 -"3569",1.64922134437622,42.8947368421053,21.8421052631579,0.0326820055068868 -"3570",2.14689134777813,42.8947368421053,21.8421052631579,0.0283554099972472 -"3571",2.79473854427218,42.8947368421053,21.8421052631579,0.0245584735776104 -"3572",3.63808049202114,42.8947368421053,21.8421052631579,0.0212637585732819 -"3573",4.73590980220715,42.8947368421053,21.8421052631579,0.0184101748018179 -"3574",6.16502073107827,42.8947368421053,21.8421052631579,0.0159394155374954 -"3575",8.02538101483936,42.8947368421053,21.8421052631579,0.0138002297859389 -"3576",10.4471247126008,42.8947368421053,21.8421052631579,0.0119481358569734 -"3577",13.5996552137305,42.8947368421053,21.8421052631579,0.0103446064153979 -"3578",17.7034951740616,42.8947368421053,21.8421052631579,0.00895628260112514 -"3579",23.045712295823,42.8947368421053,21.8421052631579,0.00775428225462237 -"3580",30,42.8947368421053,21.8421052631579,0.00671359937523897 -"3581",0.2,45,21.8421052631579,0.0374182130685388 -"3582",0.260352117694686,45,21.8421052631579,0.0374179719214796 -"3583",0.338916125940539,45,21.8421052631579,0.037416497036957 -"3584",0.441187655547492,45,21.8421052631579,0.0374074907948123 -"3585",0.574320702112717,45,21.8421052631579,0.0373530221742233 -"3586",0.747628055154725,45,21.8421052631579,0.0370414276533198 -"3587",0.973232737037462,45,21.8421052631579,0.0356617045389787 -"3588",1.2669160204875,45,21.8421052631579,0.0324134225649892 -"3589",1.64922134437622,45,21.8421052631579,0.0283958928827434 -"3590",2.14689134777813,45,21.8421052631579,0.0246367128467203 -"3591",2.79473854427218,45,21.8421052631579,0.0213377292567484 -"3592",3.63808049202114,45,21.8421052631579,0.0184751027780164 -"3593",4.73590980220715,45,21.8421052631579,0.0159957549580255 -"3594",6.16502073107827,45,21.8421052631579,0.0138490257619252 -"3595",8.02538101483936,45,21.8421052631579,0.0119903855556291 -"3596",10.4471247126008,45,21.8421052631579,0.010381186242429 -"3597",13.5996552137305,45,21.8421052631579,0.00898795319105742 -"3598",17.7034951740616,45,21.8421052631579,0.0077817024207874 -"3599",23.045712295823,45,21.8421052631579,0.00673733955030441 -"3600",30,45,21.8421052631579,0.00583313801464133 -"3601",0.2,5,23.9473684210526,0.027710754164123 -"3602",0.260352117694686,5,23.9473684210526,0.0277105755781798 -"3603",0.338916125940539,5,23.9473684210526,0.0277094833249941 -"3604",0.441187655547492,5,23.9473684210526,0.027702813584738 -"3605",0.574320702112717,5,23.9473684210526,0.0276624758339204 -"3606",0.747628055154725,5,23.9473684210526,0.0274317187116647 -"3607",0.973232737037462,5,23.9473684210526,0.0264099390781469 -"3608",1.2669160204875,5,23.9473684210526,0.0240043634010802 -"3609",1.64922134437622,5,23.9473684210526,0.0210291070154302 -"3610",2.14689134777813,5,23.9473684210526,0.0182451762690285 -"3611",2.79473854427218,5,23.9473684210526,0.0158020525665219 -"3612",3.63808049202114,5,23.9473684210526,0.0136820812447875 -"3613",4.73590980220715,5,23.9473684210526,0.0118459540678623 -"3614",6.16502073107827,5,23.9473684210526,0.0102561538039877 -"3615",8.02538101483936,5,23.9473684210526,0.0088797032037977 -"3616",10.4471247126008,5,23.9473684210526,0.00768798069990678 -"3617",13.5996552137305,5,23.9473684210526,0.00665619603105656 -"3618",17.7034951740616,5,23.9473684210526,0.00576288457083237 -"3619",23.045712295823,5,23.9473684210526,0.0049894622080626 -"3620",30,5,23.9473684210526,0.00431983893065791 -"3621",0.2,7.10526315789474,23.9473684210526,0.0346171770039191 -"3622",0.260352117694686,7.10526315789474,23.9473684210526,0.03461695390854 -"3623",0.338916125940539,7.10526315789474,23.9473684210526,0.0346155894302715 -"3624",0.441187655547492,7.10526315789474,23.9473684210526,0.0346072573734228 -"3625",0.574320702112717,7.10526315789474,23.9473684210526,0.0345568661407727 -"3626",0.747628055154725,7.10526315789474,23.9473684210526,0.03426859682487 -"3627",0.973232737037462,7.10526315789474,23.9473684210526,0.0329921564139381 -"3628",1.2669160204875,7.10526315789474,23.9473684210526,0.0299870328970489 -"3629",1.64922134437622,7.10526315789474,23.9473684210526,0.0262702456770377 -"3630",2.14689134777813,7.10526315789474,23.9473684210526,0.0227924686795566 -"3631",2.79473854427218,7.10526315789474,23.9473684210526,0.0197404389458571 -"3632",3.63808049202114,7.10526315789474,23.9473684210526,0.0170921016955224 -"3633",4.73590980220715,7.10526315789474,23.9473684210526,0.0147983517994038 -"3634",6.16502073107827,7.10526315789474,23.9473684210526,0.0128123215091608 -"3635",8.02538101483936,7.10526315789474,23.9473684210526,0.0110928145703847 -"3636",10.4471247126008,7.10526315789474,23.9473684210526,0.00960407598851831 -"3637",13.5996552137305,7.10526315789474,23.9473684210526,0.00831513696145417 -"3638",17.7034951740616,7.10526315789474,23.9473684210526,0.00719918317849118 -"3639",23.045712295823,7.10526315789474,23.9473684210526,0.00623299876242595 -"3640",30,7.10526315789474,23.9473684210526,0.00539648354589408 -"3641",0.2,9.21052631578947,23.9473684210526,0.0426729857524171 -"3642",0.260352117694686,9.21052631578947,23.9473684210526,0.0426727107402191 -"3643",0.338916125940539,9.21052631578947,23.9473684210526,0.0426710287324198 -"3644",0.441187655547492,9.21052631578947,23.9473684210526,0.0426607577116733 -"3645",0.574320702112717,9.21052631578947,23.9473684210526,0.0425986398690577 -"3646",0.747628055154725,9.21052631578947,23.9473684210526,0.0422432870218575 -"3647",0.973232737037462,9.21052631578947,23.9473684210526,0.0406698044856201 -"3648",1.2669160204875,9.21052631578947,23.9473684210526,0.0369653547263013 -"3649",1.64922134437622,9.21052631578947,23.9473684210526,0.0323836290683614 -"3650",2.14689134777813,9.21052631578947,23.9473684210526,0.0280965340159025 -"3651",2.79473854427218,9.21052631578947,23.9473684210526,0.0243342624324234 -"3652",3.63808049202114,9.21052631578947,23.9473684210526,0.0210696271405758 -"3653",4.73590980220715,9.21052631578947,23.9473684210526,0.0182420956920815 -"3654",6.16502073107827,9.21052631578947,23.9473684210526,0.015793893683298 -"3655",8.02538101483936,9.21052631578947,23.9473684210526,0.0136742380253202 -"3656",10.4471247126008,9.21052631578947,23.9473684210526,0.0118390531318245 -"3657",13.5996552137305,9.21052631578947,23.9473684210526,0.0102501634100712 -"3658",17.7034951740616,9.21052631578947,23.9473684210526,0.00887451455588117 -"3659",23.045712295823,9.21052631578947,23.9473684210526,0.00768348809476069 -"3660",30,9.21052631578947,23.9473684210526,0.00665230632298585 -"3661",0.2,11.3157894736842,23.9473684210526,0.0517856933290574 -"3662",0.260352117694686,11.3157894736842,23.9473684210526,0.0517853595887039 -"3663",0.338916125940539,11.3157894736842,23.9473684210526,0.051783318392417 -"3664",0.441187655547492,11.3157894736842,23.9473684210526,0.0517708540213124 -"3665",0.574320702112717,11.3157894736842,23.9473684210526,0.0516954710713915 -"3666",0.747628055154725,11.3157894736842,23.9473684210526,0.0512642335274454 -"3667",0.973232737037462,11.3157894736842,23.9473684210526,0.0493547377974542 -"3668",1.2669160204875,11.3157894736842,23.9473684210526,0.0448592122136106 -"3669",1.64922134437622,11.3157894736842,23.9473684210526,0.0392990706941832 -"3670",2.14689134777813,11.3157894736842,23.9473684210526,0.0340964773966992 -"3671",2.79473854427218,11.3157894736842,23.9473684210526,0.0295307822852049 -"3672",3.63808049202114,11.3157894736842,23.9473684210526,0.0255689924297749 -"3673",4.73590980220715,11.3157894736842,23.9473684210526,0.022137648831754 -"3674",6.16502073107827,11.3157894736842,23.9473684210526,0.0191666395105404 -"3675",8.02538101483936,11.3157894736842,23.9473684210526,0.0165943367777508 -"3676",10.4471247126008,11.3157894736842,23.9473684210526,0.0143672528176999 -"3677",13.5996552137305,11.3157894736842,23.9473684210526,0.0124390597369111 -"3678",17.7034951740616,11.3157894736842,23.9473684210526,0.0107696445686153 -"3679",23.045712295823,11.3157894736842,23.9473684210526,0.00932427743587645 -"3680",30,11.3157894736842,23.9473684210526,0.0080728894193578 -"3681",0.2,13.4210526315789,23.9473684210526,0.0617110252838339 -"3682",0.260352117694686,13.4210526315789,23.9473684210526,0.0617106275782502 -"3683",0.338916125940539,13.4210526315789,23.9473684210526,0.0617081951628943 -"3684",0.441187655547492,13.4210526315789,23.9473684210526,0.0616933418497313 -"3685",0.574320702112717,13.4210526315789,23.9473684210526,0.0616035108784824 -"3686",0.747628055154725,13.4210526315789,23.9473684210526,0.0610896216309504 -"3687",0.973232737037462,13.4210526315789,23.9473684210526,0.0588141487793252 -"3688",1.2669160204875,13.4210526315789,23.9473684210526,0.0534570032988951 -"3689",1.64922134437622,13.4210526315789,23.9473684210526,0.0468311958252593 -"3690",2.14689134777813,13.4210526315789,23.9473684210526,0.0406314648593636 -"3691",2.79473854427218,13.4210526315789,23.9473684210526,0.0351907010431223 -"3692",3.63808049202114,13.4210526315789,23.9473684210526,0.0304695879668879 -"3693",4.73590980220715,13.4210526315789,23.9473684210526,0.0263805873583709 -"3694",6.16502073107827,13.4210526315789,23.9473684210526,0.022840149458372 -"3695",8.02538101483936,13.4210526315789,23.9473684210526,0.0197748349134417 -"3696",10.4471247126008,13.4210526315789,23.9473684210526,0.0171209043443437 -"3697",13.5996552137305,13.4210526315789,23.9473684210526,0.0148231505766269 -"3698",17.7034951740616,13.4210526315789,23.9473684210526,0.0128337725257182 -"3699",23.045712295823,13.4210526315789,23.9473684210526,0.0111113839288116 -"3700",30,13.4210526315789,23.9473684210526,0.00962015280757181 -"3701",0.2,15.5263157894737,23.9473684210526,0.0720333119279288 -"3702",0.260352117694686,15.5263157894737,23.9473684210526,0.0720328476988833 -"3703",0.338916125940539,15.5263157894737,23.9473684210526,0.0720300084180049 -"3704",0.441187655547492,15.5263157894737,23.9473684210526,0.0720126706192029 -"3705",0.574320702112717,15.5263157894737,23.9473684210526,0.0719078137910593 -"3706",0.747628055154725,15.5263157894737,23.9473684210526,0.0713079672596879 -"3707",0.973232737037462,15.5263157894737,23.9473684210526,0.0686518803619128 -"3708",1.2669160204875,15.5263157894737,23.9473684210526,0.0623986552751437 -"3709",1.64922134437622,15.5263157894737,23.9473684210526,0.0546645614997185 -"3710",2.14689134777813,15.5263157894737,23.9473684210526,0.0474278132447418 -"3711",2.79473854427218,15.5263157894737,23.9473684210526,0.0410769831410623 -"3712",3.63808049202114,15.5263157894737,23.9473684210526,0.0355661783974487 -"3713",4.73590980220715,15.5263157894737,23.9473684210526,0.0307932183801411 -"3714",6.16502073107827,15.5263157894737,23.9473684210526,0.0266605781195215 -"3715",8.02538101483936,15.5263157894737,23.9473684210526,0.0230825342001958 -"3716",10.4471247126008,15.5263157894737,23.9473684210526,0.0199846856773488 -"3717",13.5996552137305,15.5263157894737,23.9473684210526,0.01730259097673 -"3718",17.7034951740616,15.5263157894737,23.9473684210526,0.0149804534166331 -"3719",23.045712295823,15.5263157894737,23.9473684210526,0.0129699641322396 -"3720",30,15.5263157894737,23.9473684210526,0.011229297597875 -"3721",0.2,17.6315789473684,23.9473684210526,0.0821855427376248 -"3722",0.260352117694686,17.6315789473684,23.9473684210526,0.0821850130810668 -"3723",0.338916125940539,17.6315789473684,23.9473684210526,0.0821817736376241 -"3724",0.441187655547492,17.6315789473684,23.9473684210526,0.0821619922841603 -"3725",0.574320702112717,17.6315789473684,23.9473684210526,0.0820423571445273 -"3726",0.747628055154725,17.6315789473684,23.9473684210526,0.0813579694436068 -"3727",0.973232737037462,17.6315789473684,23.9473684210526,0.0783275389745713 -"3728",1.2669160204875,17.6315789473684,23.9473684210526,0.0711929968597946 -"3729",1.64922134437622,17.6315789473684,23.9473684210526,0.0623688753873157 -"3730",2.14689134777813,17.6315789473684,23.9473684210526,0.0541121943175089 -"3731",2.79473854427218,17.6315789473684,23.9473684210526,0.0468662909300933 -"3732",3.63808049202114,17.6315789473684,23.9473684210526,0.040578804395695 -"3733",4.73590980220715,17.6315789473684,23.9473684210526,0.0351331529465449 -"3734",6.16502073107827,17.6315789473684,23.9473684210526,0.0304180666390015 -"3735",8.02538101483936,17.6315789473684,23.9473684210526,0.026335740371079 -"3736",10.4471247126008,17.6315789473684,23.9473684210526,0.022801287277712 -"3737",13.5996552137305,17.6315789473684,23.9473684210526,0.0197411835181542 -"3738",17.7034951740616,17.6315789473684,23.9473684210526,0.0170917685380553 -"3739",23.045712295823,17.6315789473684,23.9473684210526,0.0147979249178789 -"3740",30,17.6315789473684,23.9473684210526,0.0128119323260749 -"3741",0.2,19.7368421052632,23.9473684210526,0.0915204472588765 -"3742",0.260352117694686,19.7368421052632,23.9473684210526,0.0915198574421829 -"3743",0.338916125940539,19.7368421052632,23.9473684210526,0.0915162500520889 -"3744",0.441187655547492,19.7368421052632,23.9473684210526,0.0914942218673731 -"3745",0.574320702112717,19.7368421052632,23.9473684210526,0.0913609981747091 -"3746",0.747628055154725,19.7368421052632,23.9473684210526,0.0905988754655281 -"3747",0.973232737037462,19.7368421052632,23.9473684210526,0.0872242387268199 -"3748",1.2669160204875,19.7368421052632,23.9473684210526,0.079279331829798 -"3749",1.64922134437622,19.7368421052632,23.9473684210526,0.069452937589072 -"3750",2.14689134777813,19.7368421052632,23.9473684210526,0.0602584355001216 -"3751",2.79473854427218,19.7368421052632,23.9473684210526,0.0521895185504828 -"3752",3.63808049202114,19.7368421052632,23.9473684210526,0.0451878785953954 -"3753",4.73590980220715,19.7368421052632,23.9473684210526,0.0391236921260883 -"3754",6.16502073107827,19.7368421052632,23.9473684210526,0.0338730507923903 -"3755",8.02538101483936,19.7368421052632,23.9473684210526,0.0293270404668311 -"3756",10.4471247126008,19.7368421052632,23.9473684210526,0.0253911325547407 -"3757",13.5996552137305,19.7368421052632,23.9473684210526,0.0219834521354802 -"3758",17.7034951740616,19.7368421052632,23.9473684210526,0.0190331078793484 -"3759",23.045712295823,19.7368421052632,23.9473684210526,0.0164787219488367 -"3760",30,19.7368421052632,23.9473684210526,0.0142671537800289 -"3761",0.2,21.8421052631579,23.9473684210526,0.0994222254111273 -"3762",0.260352117694686,21.8421052631579,23.9473684210526,0.0994215846702872 -"3763",0.338916125940539,21.8421052631579,23.9473684210526,0.0994176658219663 -"3764",0.441187655547492,21.8421052631579,23.9473684210526,0.0993937357471928 -"3765",0.574320702112717,21.8421052631579,23.9473684210526,0.0992490096624887 -"3766",0.747628055154725,21.8421052631579,23.9473684210526,0.0984210860885489 -"3767",0.973232737037462,21.8421052631579,23.9473684210526,0.0947550868002427 -"3768",1.2669160204875,21.8421052631579,23.9473684210526,0.0861242250852446 -"3769",1.64922134437622,21.8421052631579,23.9473684210526,0.0754494304088527 -"3770",2.14689134777813,21.8421052631579,23.9473684210526,0.0654610847810723 -"3771",2.79473854427218,21.8421052631579,23.9473684210526,0.0566955061173071 -"3772",3.63808049202114,21.8421052631579,23.9473684210526,0.0490893520095458 -"3773",4.73590980220715,21.8421052631579,23.9473684210526,0.042501590125241 -"3774",6.16502073107827,21.8421052631579,23.9473684210526,0.0367976139989521 -"3775",8.02538101483936,21.8421052631579,23.9473684210526,0.0318591059731927 -"3776",10.4471247126008,21.8421052631579,23.9473684210526,0.0275833759548897 -"3777",13.5996552137305,21.8421052631579,23.9473684210526,0.0238814800297696 -"3778",17.7034951740616,21.8421052631579,23.9473684210526,0.0206764061860652 -"3779",23.045712295823,21.8421052631579,23.9473684210526,0.0179014772890069 -"3780",30,21.8421052631579,23.9473684210526,0.0154989646748658 -"3781",0.2,23.9473684210526,23.9473684210526,0.105424081592245 -"3782",0.260352117694686,23.9473684210526,23.9473684210526,0.105423402171578 -"3783",0.338916125940539,23.9473684210526,23.9473684210526,0.105419246752773 -"3784",0.441187655547492,23.9473684210526,23.9473684210526,0.105393872082824 -"3785",0.574320702112717,23.9473684210526,23.9473684210526,0.105240409268053 -"3786",0.747628055154725,23.9473684210526,23.9473684210526,0.104362506142769 -"3787",0.973232737037462,23.9473684210526,23.9473684210526,0.100475200195941 -"3788",1.2669160204875,23.9473684210526,23.9473684210526,0.0913233162395042 -"3789",1.64922134437622,23.9473684210526,23.9473684210526,0.0800041125072325 -"3790",2.14689134777813,23.9473684210526,23.9473684210526,0.0694127969328699 -"3791",2.79473854427218,23.9473684210526,23.9473684210526,0.0601180635226018 -"3792",3.63808049202114,23.9473684210526,23.9473684210526,0.0520527460551648 -"3793",4.73590980220715,23.9473684210526,23.9473684210526,0.0450672984499707 -"3794",6.16502073107827,23.9473684210526,23.9473684210526,0.0390189884061001 -"3795",8.02538101483936,23.9473684210526,23.9473684210526,0.0337823557427424 -"3796",10.4471247126008,23.9473684210526,23.9473684210526,0.029248511238136 -"3797",13.5996552137305,23.9473684210526,23.9473684210526,0.0253231416696915 -"3798",17.7034951740616,23.9473684210526,23.9473684210526,0.0219245860146494 -"3799",23.045712295823,23.9473684210526,23.9473684210526,0.0189821420163741 -"3800",30,23.9473684210526,23.9473684210526,0.0164345960847452 -"3801",0.2,26.0526315789474,23.9473684210526,0.109288062991127 -"3802",0.260352117694686,26.0526315789474,23.9473684210526,0.109287358668477 -"3803",0.338916125940539,26.0526315789474,23.9473684210526,0.10928305094613 -"3804",0.441187655547492,26.0526315789474,23.9473684210526,0.109256746249083 -"3805",0.574320702112717,26.0526315789474,23.9473684210526,0.109097658747308 -"3806",0.747628055154725,26.0526315789474,23.9473684210526,0.108187578900207 -"3807",0.973232737037462,26.0526315789474,23.9473684210526,0.104157796228484 -"3808",1.2669160204875,26.0526315789474,23.9473684210526,0.0946704793345412 -"3809",1.64922134437622,26.0526315789474,23.9473684210526,0.0829364065134324 -"3810",2.14689134777813,26.0526315789474,23.9473684210526,0.0719569002548262 -"3811",2.79473854427218,26.0526315789474,23.9473684210526,0.0623214982187335 -"3812",3.63808049202114,26.0526315789474,23.9473684210526,0.0539605724215907 -"3813",4.73590980220715,26.0526315789474,23.9473684210526,0.0467190956511273 -"3814",6.16502073107827,26.0526315789474,23.9473684210526,0.04044910421197 -"3815",8.02538101483936,26.0526315789474,23.9473684210526,0.0350205395829894 -"3816",10.4471247126008,26.0526315789474,23.9473684210526,0.0303205215574317 -"3817",13.5996552137305,26.0526315789474,23.9473684210526,0.0262512801641905 -"3818",17.7034951740616,26.0526315789474,23.9473684210526,0.0227281613577714 -"3819",23.045712295823,26.0526315789474,23.9473684210526,0.0196778715172096 -"3820",30,26.0526315789474,23.9473684210526,0.0170369534646769 -"3821",0.2,28.1578947368421,23.9473684210526,0.111020487470355 -"3822",0.260352117694686,28.1578947368421,23.9473684210526,0.111019771982846 -"3823",0.338916125940539,28.1578947368421,23.9473684210526,0.111015395974875 -"3824",0.441187655547492,28.1578947368421,23.9473684210526,0.110988674298152 -"3825",0.574320702112717,28.1578947368421,23.9473684210526,0.110827064955702 -"3826",0.747628055154725,28.1578947368421,23.9473684210526,0.109902558605267 -"3827",0.973232737037462,28.1578947368421,23.9473684210526,0.105808896183503 -"3828",1.2669160204875,28.1578947368421,23.9473684210526,0.09617118720117 -"3829",1.64922134437622,28.1578947368421,23.9473684210526,0.0842511069201433 -"3830",2.14689134777813,28.1578947368421,23.9473684210526,0.073097554522447 -"3831",2.79473854427218,28.1578947368421,23.9473684210526,0.0633094129656997 -"3832",3.63808049202114,28.1578947368421,23.9473684210526,0.0548159505298468 -"3833",4.73590980220715,28.1578947368421,23.9473684210526,0.0474596825252856 -"3834",6.16502073107827,28.1578947368421,23.9473684210526,0.0410902997495408 -"3835",8.02538101483936,28.1578947368421,23.9473684210526,0.035575682005582 -"3836",10.4471247126008,28.1578947368421,23.9473684210526,0.0308011597198386 -"3837",13.5996552137305,28.1578947368421,23.9473684210526,0.0266674130804744 -"3838",17.7034951740616,28.1578947368421,23.9473684210526,0.0230884461137309 -"3839",23.045712295823,28.1578947368421,23.9473684210526,0.0199898033548 -"3840",30,28.1578947368421,23.9473684210526,0.0173070217084161 -"3841",0.2,30.2631578947368,23.9473684210526,0.110827288905264 -"3842",0.260352117694686,30.2631578947368,23.9473684210526,0.110826574662851 -"3843",0.338916125940539,30.2631578947368,23.9473684210526,0.110822206270037 -"3844",0.441187655547492,30.2631578947368,23.9473684210526,0.110795531094547 -"3845",0.574320702112717,30.2631578947368,23.9473684210526,0.110634202985713 -"3846",0.747628055154725,30.2631578947368,23.9473684210526,0.109711305467164 -"3847",0.973232737037462,30.2631578947368,23.9473684210526,0.105624766863029 -"3848",1.2669160204875,30.2631578947368,23.9473684210526,0.0960038294837456 -"3849",1.64922134437622,30.2631578947368,23.9473684210526,0.0841044926029555 -"3850",2.14689134777813,30.2631578947368,23.9473684210526,0.0729703496887519 -"3851",2.79473854427218,30.2631578947368,23.9473684210526,0.0631992415187854 -"3852",3.63808049202114,30.2631578947368,23.9473684210526,0.0547205594607948 -"3853",4.73590980220715,30.2631578947368,23.9473684210526,0.0473770928810452 -"3854",6.16502073107827,30.2631578947368,23.9473684210526,0.0410187941461007 -"3855",8.02538101483936,30.2631578947368,23.9473684210526,0.0355137729753459 -"3856",10.4471247126008,30.2631578947368,23.9473684210526,0.0307475593439385 -"3857",13.5996552137305,30.2631578947368,23.9473684210526,0.0266210062770165 -"3858",17.7034951740616,30.2631578947368,23.9473684210526,0.0230482674515669 -"3859",23.045712295823,30.2631578947368,23.9473684210526,0.0199550169706596 -"3860",30,30.2631578947368,23.9473684210526,0.0172769039181212 -"3861",0.2,32.3684210526316,23.9473684210526,0.10903699961002 -"3862",0.260352117694686,32.3684210526316,23.9473684210526,0.109036296905384 -"3863",0.338916125940539,32.3684210526316,23.9473684210526,0.109031999079007 -"3864",0.441187655547492,32.3684210526316,23.9473684210526,0.109005754810756 -"3865",0.574320702112717,32.3684210526316,23.9473684210526,0.108847032774751 -"3866",0.747628055154725,32.3684210526316,23.9473684210526,0.107939043620058 -"3867",0.973232737037462,32.3684210526316,23.9473684210526,0.103918518417404 -"3868",1.2669160204875,32.3684210526316,23.9473684210526,0.0944529963818541 -"3869",1.64922134437622,32.3684210526316,23.9473684210526,0.0827458798075302 -"3870",2.14689134777813,32.3684210526316,23.9473684210526,0.0717915963581561 -"3871",2.79473854427218,32.3684210526316,23.9473684210526,0.0621783293709178 -"3872",3.63808049202114,32.3684210526316,23.9473684210526,0.053836610816015 -"3873",4.73590980220715,32.3684210526316,23.9473684210526,0.046611769619396 -"3874",6.16502073107827,32.3684210526316,23.9473684210526,0.0403561819971529 -"3875",8.02538101483936,32.3684210526316,23.9473684210526,0.0349400882067342 -"3876",10.4471247126008,32.3684210526316,23.9473684210526,0.030250867356865 -"3877",13.5996552137305,32.3684210526316,23.9473684210526,0.0261909740797378 -"3878",17.7034951740616,32.3684210526316,23.9473684210526,0.0226759488024323 -"3879",23.045712295823,32.3684210526316,23.9473684210526,0.0196326662786787 -"3880",30,32.3684210526316,23.9473684210526,0.0169978151084508 -"3881",0.2,34.4736842105263,23.9473684210526,0.106022760163323 -"3882",0.260352117694686,34.4736842105263,23.9473684210526,0.106022076884386 -"3883",0.338916125940539,34.4736842105263,23.9473684210526,0.106017897867935 -"3884",0.441187655547492,34.4736842105263,23.9473684210526,0.105992379101201 -"3885",0.574320702112717,34.4736842105263,23.9473684210526,0.105838044807189 -"3886",0.747628055154725,34.4736842105263,23.9473684210526,0.104955156276477 -"3887",0.973232737037462,34.4736842105263,23.9473684210526,0.101045775233196 -"3888",1.2669160204875,34.4736842105263,23.9473684210526,0.0918419198796464 -"3889",1.64922134437622,34.4736842105263,23.9473684210526,0.0804584370508549 -"3890",2.14689134777813,34.4736842105263,23.9473684210526,0.0698069758856734 -"3891",2.79473854427218,34.4736842105263,23.9473684210526,0.060459459869832 -"3892",3.63808049202114,34.4736842105263,23.9473684210526,0.0523483413608895 -"3893",4.73590980220715,34.4736842105263,23.9473684210526,0.0453232250412284 -"3894",6.16502073107827,34.4736842105263,23.9473684210526,0.0392405680667532 -"3895",8.02538101483936,34.4736842105263,23.9473684210526,0.0339741977977858 -"3896",10.4471247126008,34.4736842105263,23.9473684210526,0.0294146066562771 -"3897",13.5996552137305,34.4736842105263,23.9473684210526,0.0254669458370227 -"3898",17.7034951740616,34.4736842105263,23.9473684210526,0.0220490905835153 -"3899",23.045712295823,34.4736842105263,23.9473684210526,0.0190899371376284 -"3900",30,34.4736842105263,23.9473684210526,0.0165279242916564 -"3901",0.2,36.5789473684211,23.9473684210526,0.102143455876788 -"3902",0.260352117694686,36.5789473684211,23.9473684210526,0.102142797598587 -"3903",0.338916125940539,36.5789473684211,23.9473684210526,0.102138771489647 -"3904",0.441187655547492,36.5789473684211,23.9473684210526,0.102114186438099 -"3905",0.574320702112717,36.5789473684211,23.9473684210526,0.10196549913618 -"3906",0.747628055154725,36.5789473684211,23.9473684210526,0.101114914926317 -"3907",0.973232737037462,36.5789473684211,23.9473684210526,0.0973485756093185 -"3908",1.2669160204875,36.5789473684211,23.9473684210526,0.0884814833759766 -"3909",1.64922134437622,36.5789473684211,23.9473684210526,0.0775145148283206 -"3910",2.14689134777813,36.5789473684211,23.9473684210526,0.0672527837446073 -"3911",2.79473854427218,36.5789473684211,23.9473684210526,0.0582472872997792 -"3912",3.63808049202114,36.5789473684211,23.9473684210526,0.0504329493759852 -"3913",4.73590980220715,36.5789473684211,23.9473684210526,0.0436648775230997 -"3914",6.16502073107827,36.5789473684211,23.9473684210526,0.037804781036941 -"3915",8.02538101483936,36.5789473684211,23.9473684210526,0.0327311038531885 -"3916",10.4471247126008,36.5789473684211,23.9473684210526,0.0283383452053147 -"3917",13.5996552137305,36.5789473684211,23.9473684210526,0.0245351267446097 -"3918",17.7034951740616,36.5789473684211,23.9473684210526,0.0212423286063413 -"3919",23.045712295823,36.5789473684211,23.9473684210526,0.0183914486729479 -"3920",30,36.5789473684211,23.9473684210526,0.0159231782215355 -"3921",0.2,38.6842105263158,23.9473684210526,0.0977096893140521 -"3922",0.260352117694686,38.6842105263158,23.9473684210526,0.0977090596098974 -"3923",0.338916125940539,38.6842105263158,23.9473684210526,0.0977052082632762 -"3924",0.441187655547492,38.6842105263158,23.9473684210526,0.097681690381216 -"3925",0.574320702112717,38.6842105263158,23.9473684210526,0.0975394571862378 -"3926",0.747628055154725,38.6842105263158,23.9473684210526,0.0967257944981323 -"3927",0.973232737037462,38.6842105263158,23.9473684210526,0.0931229416148388 -"3928",1.2669160204875,38.6842105263158,23.9473684210526,0.0846407454741092 -"3929",1.64922134437622,38.6842105263158,23.9473684210526,0.0741498228759835 -"3930",2.14689134777813,38.6842105263158,23.9473684210526,0.0643335253226341 -"3931",2.79473854427218,38.6842105263158,23.9473684210526,0.0557189327166782 -"3932",3.63808049202114,38.6842105263158,23.9473684210526,0.0482437937156055 -"3933",4.73590980220715,38.6842105263158,23.9473684210526,0.0417695052521495 -"3934",6.16502073107827,38.6842105263158,23.9473684210526,0.0361637794413484 -"3935",8.02538101483936,38.6842105263158,23.9473684210526,0.0313103366333994 -"3936",10.4471247126008,38.6842105263158,23.9473684210526,0.0271082555599618 -"3937",13.5996552137305,38.6842105263158,23.9473684210526,0.0234701243551863 -"3938",17.7034951740616,38.6842105263158,23.9473684210526,0.0203202575301182 -"3939",23.045712295823,38.6842105263158,23.9473684210526,0.0175931264557639 -"3940",30,38.6842105263158,23.9473684210526,0.0152319968378129 -"3941",0.2,40.7894736842105,23.9473684210526,0.0929707382775433 -"3942",0.260352117694686,40.7894736842105,23.9473684210526,0.0929701391142404 -"3943",0.338916125940539,40.7894736842105,23.9473684210526,0.0929664745591564 -"3944",0.441187655547492,40.7894736842105,23.9473684210526,0.0929440973018628 -"3945",0.574320702112717,40.7894736842105,23.9473684210526,0.0928087624621193 -"3946",0.747628055154725,40.7894736842105,23.9473684210526,0.0920345626734074 -"3947",0.973232737037462,40.7894736842105,23.9473684210526,0.0886064493018812 -"3948",1.2669160204875,40.7894736842105,23.9473684210526,0.0805356423741884 -"3949",1.64922134437622,40.7894736842105,23.9473684210526,0.0705535328617387 -"3950",2.14689134777813,40.7894736842105,23.9473684210526,0.0612133288646343 -"3951",2.79473854427218,40.7894736842105,23.9473684210526,0.0530165467424257 -"3952",3.63808049202114,40.7894736842105,23.9473684210526,0.0459039543625311 -"3953",4.73590980220715,40.7894736842105,23.9473684210526,0.0397436709505695 -"3954",6.16502073107827,40.7894736842105,23.9473684210526,0.0344098246261117 -"3955",8.02538101483936,40.7894736842105,23.9473684210526,0.0297917753393871 -"3956",10.4471247126008,40.7894736842105,23.9473684210526,0.0257934965356963 -"3957",13.5996552137305,40.7894736842105,23.9473684210526,0.0223318158525105 -"3958",17.7034951740616,40.7894736842105,23.9473684210526,0.0193347185711827 -"3959",23.045712295823,40.7894736842105,23.9473684210526,0.016739854222086 -"3960",30,40.7894736842105,23.9473684210526,0.0144932401422446 -"3961",0.2,42.8947368421053,23.9473684210526,0.0881152544735355 -"3962",0.260352117694686,42.8947368421053,23.9473684210526,0.0881146866020969 -"3963",0.338916125940539,42.8947368421053,23.9473684210526,0.0881112134318312 -"3964",0.441187655547492,42.8947368421053,23.9473684210526,0.0880900048477393 -"3965",0.574320702112717,42.8947368421053,23.9473684210526,0.0879617379966412 -"3966",0.747628055154725,42.8947368421053,23.9473684210526,0.087227971516353 -"3967",0.973232737037462,42.8947368421053,23.9473684210526,0.0839788945735152 -"3968",1.2669160204875,42.8947368421053,23.9473684210526,0.076329593089887 -"3969",1.64922134437622,42.8947368421053,23.9473684210526,0.0668688085874941 -"3970",2.14689134777813,42.8947368421053,23.9473684210526,0.058016405484244 -"3971",2.79473854427218,42.8947368421053,23.9473684210526,0.0502477079785149 -"3972",3.63808049202114,42.8947368421053,23.9473684210526,0.0435065773912759 -"3973",4.73590980220715,42.8947368421053,23.9473684210526,0.0376680205449954 -"3974",6.16502073107827,42.8947368421053,23.9473684210526,0.0326127393359846 -"3975",8.02538101483936,42.8947368421053,23.9473684210526,0.0282358719946035 -"3976",10.4471247126008,42.8947368421053,23.9473684210526,0.0244464070428289 -"3977",13.5996552137305,42.8947368421053,23.9473684210526,0.0211655158725937 -"3978",17.7034951740616,42.8947368421053,23.9473684210526,0.0183249448013201 -"3979",23.045712295823,42.8947368421053,23.9473684210526,0.0158655996710019 -"3980",30,42.8947368421053,23.9473684210526,0.0137363171137516 -"3981",0.2,45,23.9473684210526,0.0832790299143118 -"3982",0.260352117694686,45,23.9473684210526,0.0832784932106183 -"3983",0.338916125940539,45,23.9473684210526,0.0832752106660444 -"3984",0.441187655547492,45,23.9473684210526,0.0832551661196196 -"3985",0.574320702112717,45,23.9473684210526,0.083133939222036 -"3986",0.747628055154725,45,23.9473684210526,0.0824404456717178 -"3987",0.973232737037462,45,23.9473684210526,0.079369695010744 -"3988",1.2669160204875,45,23.9473684210526,0.0721402270725905 -"3989",1.64922134437622,45,23.9473684210526,0.0631986997480082 -"3990",2.14689134777813,45,23.9473684210526,0.0548321626795539 -"3991",2.79473854427218,45,23.9473684210526,0.0474898517954702 -"3992",3.63808049202114,45,23.9473684210526,0.0411187096001132 -"3993",4.73590980220715,45,23.9473684210526,0.0356006031931932 -"3994",6.16502073107827,45,23.9473684210526,0.030822782172919 -"3995",8.02538101483936,45,23.9473684210526,0.0266861401302711 -"3996",10.4471247126008,45,23.9473684210526,0.0231046607716334 -"3997",13.5996552137305,45,23.9473684210526,0.0200038420139269 -"3998",17.7034951740616,45,23.9473684210526,0.017319176292518 -"3999",23.045712295823,45,23.9473684210526,0.0149948128448825 -"4000",30,45,23.9473684210526,0.0129823964155056 -"4001",0.2,5,26.0526315789474,0.00930244581560227 -"4002",0.260352117694686,5,26.0526315789474,0.00930238586465144 -"4003",0.338916125940539,5,26.0526315789474,0.00930201919739958 -"4004",0.441187655547492,5,26.0526315789474,0.00929978017867893 -"4005",0.574320702112717,5,26.0526315789474,0.00928623887485581 -"4006",0.747628055154725,5,26.0526315789474,0.00920877416156673 -"4007",0.973232737037462,5,26.0526315789474,0.00886576474291326 -"4008",1.2669160204875,5,26.0526315789474,0.00805821770688865 -"4009",1.64922134437622,5,26.0526315789474,0.00705942997447585 -"4010",2.14689134777813,5,26.0526315789474,0.00612486988385514 -"4011",2.79473854427218,5,26.0526315789474,0.00530471804934442 -"4012",3.63808049202114,5,26.0526315789474,0.00459304783516461 -"4013",4.73590980220715,5,26.0526315789474,0.00397666354360984 -"4014",6.16502073107827,5,26.0526315789474,0.00344297071357235 -"4015",8.02538101483936,5,26.0526315789474,0.00298089894712803 -"4016",10.4471247126008,5,26.0526315789474,0.00258084004024949 -"4017",13.5996552137305,5,26.0526315789474,0.00223447195086075 -"4018",17.7034951740616,5,26.0526315789474,0.00193458904597933 -"4019",23.045712295823,5,26.0526315789474,0.00167495267593943 -"4020",30,5,26.0526315789474,0.00145016145524476 -"4021",0.2,7.10526315789474,26.0526315789474,0.0114728854560623 -"4022",0.260352117694686,7.10526315789474,26.0526315789474,0.0114728115174008 -"4023",0.338916125940539,7.10526315789474,26.0526315789474,0.0114723592996223 -"4024",0.441187655547492,7.10526315789474,26.0526315789474,0.0114695978747428 -"4025",0.574320702112717,7.10526315789474,26.0526315789474,0.0114528971241264 -"4026",0.747628055154725,7.10526315789474,26.0526315789474,0.0113573584023677 -"4027",0.973232737037462,7.10526315789474,26.0526315789474,0.0109343182849008 -"4028",1.2669160204875,7.10526315789474,26.0526315789474,0.00993835498359853 -"4029",1.64922134437622,7.10526315789474,26.0526315789474,0.00870653085088787 -"4030",2.14689134777813,7.10526315789474,26.0526315789474,0.00755391990490254 -"4031",2.79473854427218,7.10526315789474,26.0526315789474,0.0065424108630397 -"4032",3.63808049202114,7.10526315789474,26.0526315789474,0.00566469429133101 -"4033",4.73590980220715,7.10526315789474,26.0526315789474,0.00490449568183596 -"4034",6.16502073107827,7.10526315789474,26.0526315789474,0.00424628204328165 -"4035",8.02538101483936,7.10526315789474,26.0526315789474,0.00367640004085122 -"4036",10.4471247126008,7.10526315789474,26.0526315789474,0.00318299969160148 -"4037",13.5996552137305,7.10526315789474,26.0526315789474,0.00275581726087696 -"4038",17.7034951740616,7.10526315789474,26.0526315789474,0.00238596590284322 -"4039",23.045712295823,7.10526315789474,26.0526315789474,0.00206575137080053 -"4040",30,7.10526315789474,26.0526315789474,0.0017885120320631 -"4041",0.2,9.21052631578947,26.0526315789474,0.013993273137112 -"4042",0.260352117694686,9.21052631578947,26.0526315789474,0.0139931829554494 -"4043",0.338916125940539,9.21052631578947,26.0526315789474,0.0139926313935153 -"4044",0.441187655547492,9.21052631578947,26.0526315789474,0.0139892633329925 -"4045",0.574320702112717,9.21052631578947,26.0526315789474,0.0139688937262476 -"4046",0.747628055154725,9.21052631578947,26.0526315789474,0.0138523668565372 -"4047",0.973232737037462,9.21052631578947,26.0526315789474,0.013336392393588 -"4048",1.2669160204875,9.21052631578947,26.0526315789474,0.0121216337730965 -"4049",1.64922134437622,9.21052631578947,26.0526315789474,0.0106191999161632 -"4050",2.14689134777813,9.21052631578947,26.0526315789474,0.00921338096592904 -"4051",2.79473854427218,9.21052631578947,26.0526315789474,0.00797966148379423 -"4052",3.63808049202114,9.21052631578947,26.0526315789474,0.00690912628391569 -"4053",4.73590980220715,9.21052631578947,26.0526315789474,0.00598192564011461 -"4054",6.16502073107827,9.21052631578947,26.0526315789474,0.0051791142408257 -"4055",8.02538101483936,9.21052631578947,26.0526315789474,0.00448403935783542 -"4056",10.4471247126008,9.21052631578947,26.0526315789474,0.00388224777894801 -"4057",13.5996552137305,9.21052631578947,26.0526315789474,0.00336122101062575 -"4058",17.7034951740616,9.21052631578947,26.0526315789474,0.00291011992599292 -"4059",23.045712295823,9.21052631578947,26.0526315789474,0.00251955999000244 -"4060",30,9.21052631578947,26.0526315789474,0.00218141612844621 -"4061",0.2,11.3157894736842,26.0526315789474,0.0168651416065501 -"4062",0.260352117694686,11.3157894736842,26.0526315789474,0.0168650329167178 -"4063",0.338916125940539,11.3157894736842,26.0526315789474,0.016864368156584 -"4064",0.441187655547492,11.3157894736842,26.0526315789474,0.0168603088620144 -"4065",0.574320702112717,11.3157894736842,26.0526315789474,0.0168357587586286 -"4066",0.747628055154725,11.3157894736842,26.0526315789474,0.0166953168377587 -"4067",0.973232737037462,11.3157894736842,26.0526315789474,0.0160734478655935 -"4068",1.2669160204875,11.3157894736842,26.0526315789474,0.0146093818138824 -"4069",1.64922134437622,11.3157894736842,26.0526315789474,0.012798600340286 -"4070",2.14689134777813,11.3157894736842,26.0526315789474,0.0111042622510802 -"4071",2.79473854427218,11.3157894736842,26.0526315789474,0.00961734396076388 -"4072",3.63808049202114,11.3157894736842,26.0526315789474,0.00832710060141256 -"4073",4.73590980220715,11.3157894736842,26.0526315789474,0.00720960864637331 -"4074",6.16502073107827,11.3157894736842,26.0526315789474,0.00624203459849371 -"4075",8.02538101483936,11.3157894736842,26.0526315789474,0.00540430805560951 -"4076",10.4471247126008,11.3157894736842,26.0526315789474,0.0046790095428085 -"4077",13.5996552137305,11.3157894736842,26.0526315789474,0.00405105137015958 -"4078",17.7034951740616,11.3157894736842,26.0526315789474,0.00350736987429683 -"4079",23.045712295823,11.3157894736842,26.0526315789474,0.00303665451258096 -"4080",30,11.3157894736842,26.0526315789474,0.0026291126849719 -"4081",0.2,13.4210526315789,26.0526315789474,0.0200713242621131 -"4082",0.260352117694686,13.4210526315789,26.0526315789474,0.0200711949095753 -"4083",0.338916125940539,13.4210526315789,26.0526315789474,0.0200704037738403 -"4084",0.441187655547492,13.4210526315789,26.0526315789474,0.0200655727786738 -"4085",0.574320702112717,13.4210526315789,26.0526315789474,0.0200363555270657 -"4086",0.747628055154725,13.4210526315789,26.0526315789474,0.0198692146041173 -"4087",0.973232737037462,13.4210526315789,26.0526315789474,0.0191291239437444 -"4088",1.2669160204875,13.4210526315789,26.0526315789474,0.0173867285846902 -"4089",1.64922134437622,13.4210526315789,26.0526315789474,0.0152317047507803 -"4090",2.14689134777813,13.4210526315789,26.0526315789474,0.0132152610118857 -"4091",2.79473854427218,13.4210526315789,26.0526315789474,0.0114456690421026 -"4092",3.63808049202114,13.4210526315789,26.0526315789474,0.00991014129814816 -"4093",4.73590980220715,13.4210526315789,26.0526315789474,0.00858020622181387 -"4094",6.16502073107827,13.4210526315789,26.0526315789474,0.00742868950670642 -"4095",8.02538101483936,13.4210526315789,26.0526315789474,0.0064317052253128 -"4096",10.4471247126008,13.4210526315789,26.0526315789474,0.00556852233738475 -"4097",13.5996552137305,13.4210526315789,26.0526315789474,0.00482118487646563 -"4098",17.7034951740616,13.4210526315789,26.0526315789474,0.00417414568442388 -"4099",23.045712295823,13.4210526315789,26.0526315789474,0.0036139440044992 -"4100",30,13.4210526315789,26.0526315789474,0.00312892559415042 -"4101",0.2,15.5263157894737,26.0526315789474,0.0235739961063685 -"4102",0.260352117694686,15.5263157894737,26.0526315789474,0.023573844180358 -"4103",0.338916125940539,15.5263157894737,26.0526315789474,0.0235729149825385 -"4104",0.441187655547492,15.5263157894737,26.0526315789474,0.0235672409243769 -"4105",0.574320702112717,15.5263157894737,26.0526315789474,0.02353292493373 -"4106",0.747628055154725,15.5263157894737,26.0526315789474,0.0233366160397406 -"4107",0.973232737037462,15.5263157894737,26.0526315789474,0.0224673712346569 -"4108",1.2669160204875,15.5263157894737,26.0526315789474,0.0204209082871357 -"4109",1.64922134437622,15.5263157894737,26.0526315789474,0.0178898085546871 -"4110",2.14689134777813,15.5263157894737,26.0526315789474,0.0155214727025708 -"4111",2.79473854427218,15.5263157894737,26.0526315789474,0.0134430670298435 -"4112",3.63808049202114,15.5263157894737,26.0526315789474,0.0116395724230859 -"4113",4.73590980220715,15.5263157894737,26.0526315789474,0.0100775487169367 -"4114",6.16502073107827,15.5263157894737,26.0526315789474,0.00872507938288277 -"4115",8.02538101483936,15.5263157894737,26.0526315789474,0.00755411013039313 -"4116",10.4471247126008,15.5263157894737,26.0526315789474,0.00654029211951529 -"4117",13.5996552137305,15.5263157894737,26.0526315789474,0.00566253586567875 -"4118",17.7034951740616,15.5263157894737,26.0526315789474,0.00490258105678493 -"4119",23.045712295823,15.5263157894737,26.0526315789474,0.00424461788261342 -"4120",30,15.5263157894737,26.0526315789474,0.00367495830421372 -"4121",0.2,17.6315789473684,26.0526315789474,0.0273152957521607 -"4122",0.260352117694686,17.6315789473684,26.0526315789474,0.0273151197148061 -"4123",0.338916125940539,17.6315789473684,26.0526315789474,0.0273140430490963 -"4124",0.441187655547492,17.6315789473684,26.0526315789474,0.0273074684922796 -"4125",0.574320702112717,17.6315789473684,26.0526315789474,0.0272677063989409 -"4126",0.747628055154725,17.6315789473684,26.0526315789474,0.0270402423969148 -"4127",0.973232737037462,17.6315789473684,26.0526315789474,0.0260330445156241 -"4128",1.2669160204875,17.6315789473684,26.0526315789474,0.0236617986561969 -"4129",1.64922134437622,17.6315789473684,26.0526315789474,0.0207290019653817 -"4130",2.14689134777813,17.6315789473684,26.0526315789474,0.0179848005177737 -"4131",2.79473854427218,17.6315789473684,26.0526315789474,0.0155765424783919 -"4132",3.63808049202114,17.6315789473684,26.0526315789474,0.0134868251326891 -"4133",4.73590980220715,17.6315789473684,26.0526315789474,0.0116769012100401 -"4134",6.16502073107827,17.6315789473684,26.0526315789474,0.0101097888847168 -"4135",8.02538101483936,17.6315789473684,26.0526315789474,0.00875298152358387 -"4136",10.4471247126008,17.6315789473684,26.0526315789474,0.00757826601582511 -"4137",13.5996552137305,17.6315789473684,26.0526315789474,0.00656120588042548 -"4138",17.7034951740616,17.6315789473684,26.0526315789474,0.00568064281129001 -"4139",23.045712295823,17.6315789473684,26.0526315789474,0.00491825790991684 -"4140",30,17.6315789473684,26.0526315789474,0.00425819078375679 -"4141",0.2,19.7368421052632,26.0526315789474,0.0312209080038604 -"4142",0.260352117694686,19.7368421052632,26.0526315789474,0.0312207067962256 -"4143",0.338916125940539,19.7368421052632,26.0526315789474,0.0312194761860436 -"4144",0.441187655547492,19.7368421052632,26.0526315789474,0.0312119615819403 -"4145",0.574320702112717,19.7368421052632,26.0526315789474,0.0311665142007575 -"4146",0.747628055154725,19.7368421052632,26.0526315789474,0.0309065268022728 -"4147",0.973232737037462,19.7368421052632,26.0526315789474,0.0297553171401562 -"4148",1.2669160204875,19.7368421052632,26.0526315789474,0.0270450243612154 -"4149",1.64922134437622,19.7368421052632,26.0526315789474,0.0236928887479401 -"4150",2.14689134777813,19.7368421052632,26.0526315789474,0.0205563142177868 -"4151",2.79473854427218,19.7368421052632,26.0526315789474,0.0178037171608376 -"4152",3.63808049202114,19.7368421052632,26.0526315789474,0.0154152065770157 -"4153",4.73590980220715,19.7368421052632,26.0526315789474,0.0133464950098514 -"4154",6.16502073107827,19.7368421052632,26.0526315789474,0.011555312875689 -"4155",8.02538101483936,19.7368421052632,26.0526315789474,0.0100045056581782 -"4156",10.4471247126008,19.7368421052632,26.0526315789474,0.008661826262311 -"4157",13.5996552137305,19.7368421052632,26.0526315789474,0.00749934421526254 -"4158",17.7034951740616,19.7368421052632,26.0526315789474,0.00649287594113079 -"4159",23.045712295823,19.7368421052632,26.0526315789474,0.00562148325751245 -"4160",30,19.7368421052632,26.0526315789474,0.00486703801155221 -"4161",0.2,21.8421052631579,26.0526315789474,0.0352062709070171 -"4162",0.260352117694686,21.8421052631579,26.0526315789474,0.0352060440151375 -"4163",0.338916125940539,21.8421052631579,26.0526315789474,0.0352046563170141 -"4164",0.441187655547492,21.8421052631579,26.0526315789474,0.0351961824703282 -"4165",0.574320702112717,21.8421052631579,26.0526315789474,0.0351449337105631 -"4166",0.747628055154725,21.8421052631579,26.0526315789474,0.0348517588041084 -"4167",0.973232737037462,21.8421052631579,26.0526315789474,0.0335535967125304 -"4168",1.2669160204875,21.8421052631579,26.0526315789474,0.0304973338453223 -"4169",1.64922134437622,21.8421052631579,26.0526315789474,0.0267172966182359 -"4170",2.14689134777813,21.8421052631579,26.0526315789474,0.0231803369431691 -"4171",2.79473854427218,21.8421052631579,26.0526315789474,0.0200763696378995 -"4172",3.63808049202114,21.8421052631579,26.0526315789474,0.0173829646072735 -"4173",4.73590980220715,21.8421052631579,26.0526315789474,0.0150501810811486 -"4174",6.16502073107827,21.8421052631579,26.0526315789474,0.0130303537445659 -"4175",8.02538101483936,21.8421052631579,26.0526315789474,0.0112815852905064 -"4176",10.4471247126008,21.8421052631579,26.0526315789474,0.009767512267828 -"4177",13.5996552137305,21.8421052631579,26.0526315789474,0.00845663886632823 -"4178",17.7034951740616,21.8421052631579,26.0526315789474,0.00732169446579963 -"4179",23.045712295823,21.8421052631579,26.0526315789474,0.00633906811546841 -"4180",30,21.8421052631579,26.0526315789474,0.00548831759564039 -"4181",0.2,23.9473684210526,26.0526315789474,0.0391843539680811 -"4182",0.260352117694686,23.9473684210526,26.0526315789474,0.0391841014388727 -"4183",0.338916125940539,23.9473684210526,26.0526315789474,0.0391825569397517 -"4184",0.441187655547492,23.9473684210526,26.0526315789474,0.0391731256026787 -"4185",0.574320702112717,23.9473684210526,26.0526315789474,0.0391160860613889 -"4186",0.747628055154725,23.9473684210526,26.0526315789474,0.0387897842687502 -"4187",0.973232737037462,23.9473684210526,26.0526315789474,0.0373449381775899 -"4188",1.2669160204875,23.9473684210526,26.0526315789474,0.0339433371865484 -"4189",1.64922134437622,23.9473684210526,26.0526315789474,0.0297361799698733 -"4190",2.14689134777813,23.9473684210526,26.0526315789474,0.0257995665113027 -"4191",2.79473854427218,23.9473684210526,26.0526315789474,0.0223448707863205 -"4192",3.63808049202114,23.9473684210526,26.0526315789474,0.0193471282427208 -"4193",4.73590980220715,23.9473684210526,26.0526315789474,0.0167507551232841 -"4194",6.16502073107827,23.9473684210526,26.0526315789474,0.0145027002378322 -"4195",8.02538101483936,23.9473684210526,26.0526315789474,0.012556332152071 -"4196",10.4471247126008,23.9473684210526,26.0526315789474,0.0108711785778443 -"4197",13.5996552137305,23.9473684210526,26.0526315789474,0.00941218488017689 -"4198",17.7034951740616,23.9473684210526,26.0526315789474,0.00814899903348898 -"4199",23.045712295823,23.9473684210526,26.0526315789474,0.00705534220083455 -"4200",30,23.9473684210526,26.0526315789474,0.00610846232265847 -"4201",0.2,26.0526315789474,26.0526315789474,0.0430735264295427 -"4202",0.260352117694686,26.0526315789474,26.0526315789474,0.0430732488360027 -"4203",0.338916125940539,26.0526315789474,26.0526315789474,0.0430715510404039 -"4204",0.441187655547492,26.0526315789474,26.0526315789474,0.0430611836129604 -"4205",0.574320702112717,26.0526315789474,26.0526315789474,0.0429984827147582 -"4206",0.747628055154725,26.0526315789474,26.0526315789474,0.0426397944255324 -"4207",0.973232737037462,26.0526315789474,26.0526315789474,0.041051542738522 -"4208",1.2669160204875,26.0526315789474,26.0526315789474,0.037312321969188 -"4209",1.64922134437622,26.0526315789474,26.0526315789474,0.0326875909422757 -"4210",2.14689134777813,26.0526315789474,26.0526315789474,0.028360256006787 -"4211",2.79473854427218,26.0526315789474,26.0526315789474,0.0245626706813466 -"4212",3.63808049202114,26.0526315789474,26.0526315789474,0.0212673926020936 -"4213",4.73590980220715,26.0526315789474,26.0526315789474,0.0184133211461214 -"4214",6.16502073107827,26.0526315789474,26.0526315789474,0.0159421396229437 -"4215",8.02538101483936,26.0526315789474,26.0526315789474,0.0138025882792635 -"4216",10.4471247126008,26.0526315789474,26.0526315789474,0.0119501778228752 -"4217",13.5996552137305,26.0526315789474,26.0526315789474,0.0103463743341612 -"4218",17.7034951740616,26.0526315789474,26.0526315789474,0.00895781325192266 -"4219",23.045712295823,26.0526315789474,26.0526315789474,0.00775560748059455 -"4220",30,26.0526315789474,26.0526315789474,0.00671474674593902 -"4221",0.2,28.1578947368421,26.0526315789474,0.0468040736826896 -"4222",0.260352117694686,28.1578947368421,26.0526315789474,0.0468037720471009 -"4223",0.338916125940539,28.1578947368421,26.0526315789474,0.0468019272074304 -"4224",0.441187655547492,28.1578947368421,26.0526315789474,0.0467906618693402 -"4225",0.574320702112717,28.1578947368421,26.0526315789474,0.046722530520396 -"4226",0.747628055154725,28.1578947368421,26.0526315789474,0.0463327766620603 -"4227",0.973232737037462,28.1578947368421,26.0526315789474,0.0446069683722031 -"4228",1.2669160204875,28.1578947368421,26.0526315789474,0.0405438981081506 -"4229",1.64922134437622,28.1578947368421,26.0526315789474,0.0355186245889209 -"4230",2.14689134777813,28.1578947368421,26.0526315789474,0.0308165042853606 -"4231",2.79473854427218,28.1578947368421,26.0526315789474,0.0266900145799274 -"4232",3.63808049202114,28.1578947368421,26.0526315789474,0.0231093363580365 -"4233",4.73590980220715,28.1578947368421,26.0526315789474,0.0200080771439925 -"4234",6.16502073107827,28.1578947368421,26.0526315789474,0.0173228695076198 -"4235",8.02538101483936,28.1578947368421,26.0526315789474,0.0149980141489273 -"4236",10.4471247126008,28.1578947368421,26.0526315789474,0.0129851686106545 -"4237",13.5996552137305,28.1578947368421,26.0526315789474,0.0112424615959151 -"4238",17.7034951740616,28.1578947368421,26.0526315789474,0.00973363887826939 -"4239",23.045712295823,28.1578947368421,26.0526315789474,0.00842731148492175 -"4240",30,28.1578947368421,26.0526315789474,0.00729630303132035 -"4241",0.2,30.2631578947368,26.0526315789474,0.0503223882307774 -"4242",0.260352117694686,30.2631578947368,26.0526315789474,0.0503220639209043 -"4243",0.338916125940539,30.2631578947368,26.0526315789474,0.0503200804025732 -"4244",0.441187655547492,30.2631578947368,26.0526315789474,0.0503079682364235 -"4245",0.574320702112717,30.2631578947368,26.0526315789474,0.0502347153778049 -"4246",0.747628055154725,30.2631578947368,26.0526315789474,0.0498156632861731 -"4247",0.973232737037462,30.2631578947368,26.0526315789474,0.047960124057625 -"4248",1.2669160204875,30.2631578947368,26.0526315789474,0.0435916282591023 -"4249",1.64922134437622,30.2631578947368,26.0526315789474,0.038188599310918 -"4250",2.14689134777813,30.2631578947368,26.0526315789474,0.0331330153669269 -"4251",2.79473854427218,30.2631578947368,26.0526315789474,0.0286963328167087 -"4252",3.63808049202114,30.2631578947368,26.0526315789474,0.024846491009496 -"4253",4.73590980220715,30.2631578947368,26.0526315789474,0.0215121066729651 -"4254",6.16502073107827,30.2631578947368,26.0526315789474,0.0186250489763661 -"4255",8.02538101483936,30.2631578947368,26.0526315789474,0.0161254316410528 -"4256",10.4471247126008,30.2631578947368,26.0526315789474,0.0139612782532033 -"4257",13.5996552137305,30.2631578947368,26.0526315789474,0.01208757000373 -"4258",17.7034951740616,30.2631578947368,26.0526315789474,0.0104653273954575 -"4259",23.045712295823,30.2631578947368,26.0526315789474,0.00906080191141072 -"4260",30,30.2631578947368,26.0526315789474,0.00784477428782652 -"4261",0.2,32.3684210526316,26.0526315789474,0.0535925377292278 -"4262",0.260352117694686,32.3684210526316,26.0526315789474,0.0535921923444056 -"4263",0.338916125940539,32.3684210526316,26.0526315789474,0.0535900799291421 -"4264",0.441187655547492,32.3684210526316,26.0526315789474,0.0535771806661266 -"4265",0.574320702112717,32.3684210526316,26.0526315789474,0.0534991675445853 -"4266",0.747628055154725,32.3684210526316,26.0526315789474,0.053052883776647 -"4267",0.973232737037462,32.3684210526316,26.0526315789474,0.051076764208196 -"4268",1.2669160204875,32.3684210526316,26.0526315789474,0.0464243861289078 -"4269",1.64922134437622,32.3684210526316,26.0526315789474,0.0406702468096499 -"4270",2.14689134777813,32.3684210526316,26.0526315789474,0.0352861308567446 -"4271",2.79473854427218,32.3684210526316,26.0526315789474,0.0305611349786723 -"4272",3.63808049202114,32.3684210526316,26.0526315789474,0.0264611150957046 -"4273",4.73590980220715,32.3684210526316,26.0526315789474,0.0229100491657696 -"4274",6.16502073107827,32.3684210526316,26.0526315789474,0.0198353789449948 -"4275",8.02538101483936,32.3684210526316,26.0526315789474,0.0171733265054908 -"4276",10.4471247126008,32.3684210526316,26.0526315789474,0.0148685377987572 -"4277",13.5996552137305,32.3684210526316,26.0526315789474,0.0128730685139339 -"4278",17.7034951740616,32.3684210526316,26.0526315789474,0.0111454061106494 -"4279",23.045712295823,32.3684210526316,26.0526315789474,0.00964960895868906 -"4280",30,32.3684210526316,26.0526315789474,0.00835455900998926 -"4281",0.2,34.4736842105263,26.0526315789474,0.0565955277206869 -"4282",0.260352117694686,34.4736842105263,26.0526315789474,0.0565951629826635 -"4283",0.338916125940539,34.4736842105263,26.0526315789474,0.0565929322008854 -"4284",0.441187655547492,34.4736842105263,26.0526315789474,0.0565793101440002 -"4285",0.574320702112717,34.4736842105263,26.0526315789474,0.0564969256559755 -"4286",0.747628055154725,34.4736842105263,26.0526315789474,0.0560256349421964 -"4287",0.973232737037462,34.4736842105263,26.0526315789474,0.0539387860159387 -"4288",1.2669160204875,34.4736842105263,26.0526315789474,0.0490257178219339 -"4289",1.64922134437622,34.4736842105263,26.0526315789474,0.0429491525919551 -"4290",2.14689134777813,34.4736842105263,26.0526315789474,0.0372633445191297 -"4291",2.79473854427218,34.4736842105263,26.0526315789474,0.0322735894799364 -"4292",3.63808049202114,34.4736842105263,26.0526315789474,0.0279438301743733 -"4293",4.73590980220715,34.4736842105263,26.0526315789474,0.024193784761502 -"4294",6.16502073107827,34.4736842105263,26.0526315789474,0.0209468292881297 -"4295",8.02538101483936,34.4736842105263,26.0526315789474,0.0181356121109347 -"4296",10.4471247126008,34.4736842105263,26.0526315789474,0.0157016774873998 -"4297",13.5996552137305,34.4736842105263,26.0526315789474,0.0135943946079141 -"4298",17.7034951740616,34.4736842105263,26.0526315789474,0.0117699248294704 -"4299",23.045712295823,34.4736842105263,26.0526315789474,0.0101903125781154 -"4300",30,34.4736842105263,26.0526315789474,0.00882269614536453 -"4301",0.2,36.5789473684211,26.0526315789474,0.0593269504654957 -"4302",0.260352117694686,36.5789473684211,26.0526315789474,0.0593265681244253 -"4303",0.338916125940539,36.5789473684211,26.0526315789474,0.0593242296802871 -"4304",0.441187655547492,36.5789473684211,26.0526315789474,0.0593099501934334 -"4305",0.574320702112717,36.5789473684211,26.0526315789474,0.0592235896515848 -"4306",0.747628055154725,36.5789473684211,26.0526315789474,0.0587295534272172 -"4307",0.973232737037462,36.5789473684211,26.0526315789474,0.0565419886519919 -"4308",1.2669160204875,36.5789473684211,26.0526315789474,0.0513918051460117 -"4309",1.64922134437622,36.5789473684211,26.0526315789474,0.0450219717171498 -"4310",2.14689134777813,36.5789473684211,26.0526315789474,0.0390617542321642 -"4311",2.79473854427218,36.5789473684211,26.0526315789474,0.0338311828077551 -"4312",3.63808049202114,36.5789473684211,26.0526315789474,0.0292924599405281 -"4313",4.73590980220715,36.5789473684211,26.0526315789474,0.0253614292140233 -"4314",6.16502073107827,36.5789473684211,26.0526315789474,0.0219577686371113 -"4315",8.02538101483936,36.5789473684211,26.0526315789474,0.0190108760302909 -"4316",10.4471247126008,36.5789473684211,26.0526315789474,0.0164594744503047 -"4317",13.5996552137305,36.5789473684211,26.0526315789474,0.0142504895350119 -"4318",17.7034951740616,36.5789473684211,26.0526315789474,0.012337966893546 -"4319",23.045712295823,36.5789473684211,26.0526315789474,0.010682119133749 -"4320",30,36.5789473684211,26.0526315789474,0.00924849856991154 -"4321",0.2,38.6842105263158,26.0526315789474,0.0617938056734254 -"4322",0.260352117694686,38.6842105263158,26.0526315789474,0.0617934074343517 -"4323",0.338916125940539,38.6842105263158,26.0526315789474,0.0617909717561056 -"4324",0.441187655547492,38.6842105263158,26.0526315789474,0.0617760985184147 -"4325",0.574320702112717,38.6842105263158,26.0526315789474,0.0616861470461247 -"4326",0.747628055154725,38.6842105263158,26.0526315789474,0.0611715684573944 -"4327",0.973232737037462,38.6842105263158,26.0526315789474,0.0588930432414907 -"4328",1.2669160204875,38.6842105263158,26.0526315789474,0.0535287115801808 -"4329",1.64922134437622,38.6842105263158,26.0526315789474,0.0468940161173809 -"4330",2.14689134777813,38.6842105263158,26.0526315789474,0.0406859687097738 -"4331",2.79473854427218,38.6842105263158,26.0526315789474,0.0352379065453636 -"4332",3.63808049202114,38.6842105263158,26.0526315789474,0.0305104604746933 -"4333",4.73590980220715,38.6842105263158,26.0526315789474,0.026415974799904 -"4334",6.16502073107827,38.6842105263158,26.0526315789474,0.0228707876864973 -"4335",8.02538101483936,38.6842105263158,26.0526315789474,0.0198013612680229 -"4336",10.4471247126008,38.6842105263158,26.0526315789474,0.0171438706639806 -"4337",13.5996552137305,38.6842105263158,26.0526315789474,0.0148430346439239 -"4338",17.7034951740616,38.6842105263158,26.0526315789474,0.0128509880019596 -"4339",23.045712295823,38.6842105263158,26.0526315789474,0.0111262889589306 -"4340",30,38.6842105263158,26.0526315789474,0.00963305747077711 -"4341",0.2,40.7894736842105,26.0526315789474,0.0640111649053613 -"4342",0.260352117694686,40.7894736842105,26.0526315789474,0.0640107523761968 -"4343",0.338916125940539,40.7894736842105,26.0526315789474,0.0640082292980312 -"4344",0.441187655547492,40.7894736842105,26.0526315789474,0.0639928223610391 -"4345",0.574320702112717,40.7894736842105,26.0526315789474,0.063899643142451 -"4346",0.747628055154725,40.7894736842105,26.0526315789474,0.0633665998294357 -"4347",0.973232737037462,40.7894736842105,26.0526315789474,0.061006313846937 -"4348",1.2669160204875,40.7894736842105,26.0526315789474,0.0554494928219645 -"4349",1.64922134437622,40.7894736842105,26.0526315789474,0.0485767232823992 -"4350",2.14689134777813,40.7894736842105,26.0526315789474,0.0421459112937546 -"4351",2.79473854427218,40.7894736842105,26.0526315789474,0.0365023552476395 -"4352",3.63808049202114,40.7894736842105,26.0526315789474,0.0316052733036961 -"4353",4.73590980220715,40.7894736842105,26.0526315789474,0.027363864397491 -"4354",6.16502073107827,40.7894736842105,26.0526315789474,0.0236914646405323 -"4355",8.02538101483936,40.7894736842105,26.0526315789474,0.0205118973927048 -"4356",10.4471247126008,40.7894736842105,26.0526315789474,0.0177590475328206 -"4357",13.5996552137305,40.7894736842105,26.0526315789474,0.0153756501632137 -"4358",17.7034951740616,40.7894736842105,26.0526315789474,0.0133121225214329 -"4359",23.045712295823,40.7894736842105,26.0526315789474,0.0115255357648427 -"4360",30,40.7894736842105,26.0526315789474,0.00997872235873499 -"4361",0.2,42.8947368421053,26.0526315789474,0.0659991389447994 -"4362",0.260352117694686,42.8947368421053,26.0526315789474,0.0659987136038502 -"4363",0.338916125940539,42.8947368421053,26.0526315789474,0.0659961121672623 -"4364",0.441187655547492,42.8947368421053,26.0526315789474,0.0659802267420125 -"4365",0.574320702112717,42.8947368421053,26.0526315789474,0.0658841536865782 -"4366",0.747628055154725,42.8947368421053,26.0526315789474,0.065334555819842 -"4367",0.973232737037462,42.8947368421053,26.0526315789474,0.0629009671991895 -"4368",1.2669160204875,42.8947368421053,26.0526315789474,0.0571715697813989 -"4369",1.64922134437622,42.8947368421053,26.0526315789474,0.0500853548617363 -"4370",2.14689134777813,42.8947368421053,26.0526315789474,0.0434548232256703 -"4371",2.79473854427218,42.8947368421053,26.0526315789474,0.0376359970852462 -"4372",3.63808049202114,42.8947368421053,26.0526315789474,0.0325868280516841 -"4373",4.73590980220715,42.8947368421053,26.0526315789474,0.0282136950812685 -"4374",6.16502073107827,42.8947368421053,26.0526315789474,0.0244272427931605 -"4375",8.02538101483936,42.8947368421053,26.0526315789474,0.0211489287539776 -"4376",10.4471247126008,42.8947368421053,26.0526315789474,0.0183105845266028 -"4377",13.5996552137305,42.8947368421053,26.0526315789474,0.0158531667559698 -"4378",17.7034951740616,42.8947368421053,26.0526315789474,0.013725552803815 -"4379",23.045712295823,42.8947368421053,26.0526315789474,0.0118834806003257 -"4380",30,42.8947368421053,26.0526315789474,0.0102886283106928 -"4381",0.2,45,26.0526315789474,0.0677803892725847 -"4382",0.260352117694686,45,26.0526315789474,0.0677799524521114 -"4383",0.338916125940539,45,26.0526315789474,0.0677772808053685 -"4384",0.441187655547492,45,26.0526315789474,0.0677609666484809 -"4385",0.574320702112717,45,26.0526315789474,0.0676623006779841 -"4386",0.747628055154725,45,26.0526315789474,0.0670978697180299 -"4387",0.973232737037462,45,26.0526315789474,0.0645986009900679 -"4388",1.2669160204875,45,26.0526315789474,0.0587145729029743 -"4389",1.64922134437622,45,26.0526315789474,0.0514371081753565 -"4390",2.14689134777813,45,26.0526315789474,0.0446276251644852 -"4391",2.79473854427218,45,26.0526315789474,0.03865175476355 -"4392",3.63808049202114,45,26.0526315789474,0.0334663137400821 -"4393",4.73590980220715,45,26.0526315789474,0.0289751543126318 -"4394",6.16502073107827,45,26.0526315789474,0.025086509488573 -"4395",8.02538101483936,45,26.0526315789474,0.0217197170533043 -"4396",10.4471247126008,45,26.0526315789474,0.0188047687722068 -"4397",13.5996552137305,45,26.0526315789474,0.0162810277694918 -"4398",17.7034951740616,45,26.0526315789474,0.0140959916583473 -"4399",23.045712295823,45,26.0526315789474,0.0122042037802487 -"4400",30,45,26.0526315789474,0.0105663080326391 -"4401",0.2,5,28.1578947368421,0.0105823374613747 -"4402",0.260352117694686,5,28.1578947368421,0.0105822692619779 -"4403",0.338916125940539,5,28.1578947368421,0.0105818521462352 -"4404",0.441187655547492,5,28.1578947368421,0.0105793050686006 -"4405",0.574320702112717,5,28.1578947368421,0.0105639006631825 -"4406",0.747628055154725,5,28.1578947368421,0.0104757778454179 -"4407",0.973232737037462,5,28.1578947368421,0.0100855749361429 -"4408",1.2669160204875,5,28.1578947368421,0.00916692027041917 -"4409",1.64922134437622,5,28.1578947368421,0.00803071275616028 -"4410",2.14689134777813,5,28.1578947368421,0.0069675697448574 -"4411",2.79473854427218,5,28.1578947368421,0.00603457602961306 -"4412",3.63808049202114,5,28.1578947368421,0.00522498954913841 -"4413",4.73590980220715,5,28.1578947368421,0.00452379905489413 -"4414",6.16502073107827,5,28.1578947368421,0.00391667725702239 -"4415",8.02538101483936,5,28.1578947368421,0.00339103061948047 -"4416",10.4471247126008,5,28.1578947368421,0.00293592897837047 -"4417",13.5996552137305,5,28.1578947368421,0.00254190529036193 -"4418",17.7034951740616,5,28.1578947368421,0.00220076252411976 -"4419",23.045712295823,5,28.1578947368421,0.00190540367554681 -"4420",30,5,28.1578947368421,0.00164968420102372 -"4421",0.2,7.10526315789474,28.1578947368421,0.0117899000427748 -"4422",0.260352117694686,7.10526315789474,28.1578947368421,0.0117898240610672 -"4423",0.338916125940539,7.10526315789474,28.1578947368421,0.011789359347772 -"4424",0.441187655547492,7.10526315789474,28.1578947368421,0.0117865216202072 -"4425",0.574320702112717,7.10526315789474,28.1578947368421,0.0117693594005407 -"4426",0.747628055154725,7.10526315789474,28.1578947368421,0.0116711807876657 -"4427",0.973232737037462,7.10526315789474,28.1578947368421,0.0112364513799575 -"4428",1.2669160204875,7.10526315789474,28.1578947368421,0.0102129679839456 -"4429",1.64922134437622,7.10526315789474,28.1578947368421,0.0089471065360513 -"4430",2.14689134777813,7.10526315789474,28.1578947368421,0.00776264706476856 -"4431",2.79473854427218,7.10526315789474,28.1578947368421,0.00672318837396255 -"4432",3.63808049202114,7.10526315789474,28.1578947368421,0.00582121905805132 -"4433",4.73590980220715,7.10526315789474,28.1578947368421,0.00504001491782633 -"4434",6.16502073107827,7.10526315789474,28.1578947368421,0.00436361376006475 -"4435",8.02538101483936,7.10526315789474,28.1578947368421,0.00377798498598152 -"4436",10.4471247126008,7.10526315789474,28.1578947368421,0.00327095117822648 -"4437",13.5996552137305,7.10526315789474,28.1578947368421,0.0028319649983714 -"4438",17.7034951740616,7.10526315789474,28.1578947368421,0.00245189404249882 -"4439",23.045712295823,7.10526315789474,28.1578947368421,0.00212283145929031 -"4440",30,7.10526315789474,28.1578947368421,0.00183793154425523 -"4441",0.2,9.21052631578947,28.1578947368421,0.01306446921825 -"4442",0.260352117694686,9.21052631578947,28.1578947368421,0.013064385022398 -"4443",0.338916125940539,9.21052631578947,28.1578947368421,0.0130638700704036 -"4444",0.441187655547492,9.21052631578947,28.1578947368421,0.0130607255649977 -"4445",0.574320702112717,9.21052631578947,28.1578947368421,0.0130417079915037 -"4446",0.747628055154725,9.21052631578947,28.1578947368421,0.0129329155962211 -"4447",0.973232737037462,9.21052631578947,28.1578947368421,0.0124511889535298 -"4448",1.2669160204875,9.21052631578947,28.1578947368421,0.0113170599724464 -"4449",1.64922134437622,9.21052631578947,28.1578947368421,0.00991435020725892 -"4450",2.14689134777813,9.21052631578947,28.1578947368421,0.00860184253147745 -"4451",2.79473854427218,9.21052631578947,28.1578947368421,0.00745001121650376 -"4452",3.63808049202114,9.21052631578947,28.1578947368421,0.00645053282221918 -"4453",4.73590980220715,9.21052631578947,28.1578947368421,0.00558487514860781 -"4454",6.16502073107827,9.21052631578947,28.1578947368421,0.00483535037972054 -"4455",8.02538101483936,9.21052631578947,28.1578947368421,0.00418641111267217 -"4456",10.4471247126008,9.21052631578947,28.1578947368421,0.00362456346765441 -"4457",13.5996552137305,9.21052631578947,28.1578947368421,0.00313811986650882 -"4458",17.7034951740616,9.21052631578947,28.1578947368421,0.00271696062972706 -"4459",23.045712295823,9.21052631578947,28.1578947368421,0.00235232412105369 -"4460",30,9.21052631578947,28.1578947368421,0.00203662456832179 -"4461",0.2,11.3157894736842,28.1578947368421,0.014398776980109 -"4462",0.260352117694686,11.3157894736842,28.1578947368421,0.0143986841851185 -"4463",0.338916125940539,11.3157894736842,28.1578947368421,0.0143981166397557 -"4464",0.441187655547492,11.3157894736842,28.1578947368421,0.0143946509779446 -"4465",0.574320702112717,11.3157894736842,28.1578947368421,0.0143736910908747 -"4466",0.747628055154725,11.3157894736842,28.1578947368421,0.0142537874491242 -"4467",0.973232737037462,11.3157894736842,28.1578947368421,0.0137228608284085 -"4468",1.2669160204875,11.3157894736842,28.1578947368421,0.0124729003445577 -"4469",1.64922134437622,11.3157894736842,28.1578947368421,0.0109269282320021 -"4470",2.14689134777813,11.3157894736842,28.1578947368421,0.00948037077968256 -"4471",2.79473854427218,11.3157894736842,28.1578947368421,0.00821089997716087 -"4472",3.63808049202114,11.3157894736842,28.1578947368421,0.00710934229002287 -"4473",4.73590980220715,11.3157894736842,28.1578947368421,0.00615527277711543 -"4474",6.16502073107827,11.3157894736842,28.1578947368421,0.00532919712046345 -"4475",8.02538101483936,11.3157894736842,28.1578947368421,0.00461398002103378 -"4476",10.4471247126008,11.3157894736842,28.1578947368421,0.00399474943445096 -"4477",13.5996552137305,11.3157894736842,28.1578947368421,0.00345862410021143 -"4478",17.7034951740616,11.3157894736842,28.1578947368421,0.00299445078997374 -"4479",23.045712295823,11.3157894736842,28.1578947368421,0.00259257301909124 -"4480",30,11.3157894736842,28.1578947368421,0.00224463026102214 -"4481",0.2,13.4210526315789,28.1578947368421,0.0157842474347364 -"4482",0.260352117694686,13.4210526315789,28.1578947368421,0.0157841457108822 -"4483",0.338916125940539,13.4210526315789,28.1578947368421,0.015783523555511 -"4484",0.441187655547492,13.4210526315789,28.1578947368421,0.0157797244228745 -"4485",0.574320702112717,13.4210526315789,28.1578947368421,0.0157567477461628 -"4486",0.747628055154725,13.4210526315789,28.1578947368421,0.0156253068083435 -"4487",0.973232737037462,13.4210526315789,28.1578947368421,0.0150432936857956 -"4488",1.2669160204875,13.4210526315789,28.1578947368421,0.013673060256387 -"4489",1.64922134437622,13.4210526315789,28.1578947368421,0.0119783325454508 -"4490",2.14689134777813,13.4210526315789,28.1578947368421,0.0103925853123688 -"4491",2.79473854427218,13.4210526315789,28.1578947368421,0.00900096425414584 -"4492",3.63808049202114,13.4210526315789,28.1578947368421,0.00779341314605925 -"4493",4.73590980220715,13.4210526315789,28.1578947368421,0.00674754173055827 -"4494",6.16502073107827,13.4210526315789,28.1578947368421,0.00584197991913361 -"4495",8.02538101483936,13.4210526315789,28.1578947368421,0.0050579436303191 -"4496",10.4471247126008,13.4210526315789,28.1578947368421,0.00437912981083412 -"4497",13.5996552137305,13.4210526315789,28.1578947368421,0.00379141774727777 -"4498",17.7034951740616,13.4210526315789,28.1578947368421,0.0032825810320822 -"4499",23.045712295823,13.4210526315789,28.1578947368421,0.00284203402014551 -"4500",30,13.4210526315789,28.1578947368421,0.00246061172337168 -"4501",0.2,15.5263157894737,28.1578947368421,0.0172112541174461 -"4502",0.260352117694686,15.5263157894737,28.1578947368421,0.0172111431970419 -"4503",0.338916125940539,15.5263157894737,28.1578947368421,0.0172104647944612 -"4504",0.441187655547492,15.5263157894737,28.1578947368421,0.0172063221935863 -"4505",0.574320702112717,15.5263157894737,28.1578947368421,0.0171812682641357 -"4506",0.747628055154725,15.5263157894737,28.1578947368421,0.0170379441435784 -"4507",0.973232737037462,15.5263157894737,28.1578947368421,0.0164033129523684 -"4508",1.2669160204875,15.5263157894737,28.1578947368421,0.0149092008097856 -"4509",1.64922134437622,15.5263157894737,28.1578947368421,0.0130612578265422 -"4510",2.14689134777813,15.5263157894737,28.1578947368421,0.0113321479207668 -"4511",2.79473854427218,15.5263157894737,28.1578947368421,0.00981471455770671 -"4512",3.63808049202114,15.5263157894737,28.1578947368421,0.00849799235938742 -"4513",4.73590980220715,15.5263157894737,28.1578947368421,0.00735756683192476 -"4514",6.16502073107827,15.5263157894737,28.1578947368421,0.00637013588091313 -"4515",8.02538101483936,15.5263157894737,28.1578947368421,0.00551521721216565 -"4516",10.4471247126008,15.5263157894737,28.1578947368421,0.00477503386203146 -"4517",13.5996552137305,15.5263157894737,28.1578947368421,0.00413418850557206 -"4518",17.7034951740616,15.5263157894737,28.1578947368421,0.00357934938221643 -"4519",23.045712295823,15.5263157894737,28.1578947368421,0.00309897383029513 -"4520",30,15.5263157894737,28.1578947368421,0.00268306828250276 -"4521",0.2,17.6315789473684,28.1578947368421,0.0186694321437014 -"4522",0.260352117694686,17.6315789473684,28.1578947368421,0.0186693118258591 -"4523",0.338916125940539,17.6315789473684,28.1578947368421,0.0186685759474124 -"4524",0.441187655547492,17.6315789473684,28.1578947368421,0.0186640823756247 -"4525",0.574320702112717,17.6315789473684,28.1578947368421,0.0186369058182037 -"4526",0.747628055154725,17.6315789473684,28.1578947368421,0.0184814389402504 -"4527",0.973232737037462,17.6315789473684,28.1578947368421,0.0177930402983082 -"4528",1.2669160204875,17.6315789473684,28.1578947368421,0.016172343452472 -"4529",1.64922134437622,17.6315789473684,28.1578947368421,0.0141678383829593 -"4530",2.14689134777813,17.6315789473684,28.1578947368421,0.0122922342093998 -"4531",2.79473854427218,17.6315789473684,28.1578947368421,0.0106462403143051 -"4532",3.63808049202114,17.6315789473684,28.1578947368421,0.00921796230702673 -"4533",4.73590980220715,17.6315789473684,28.1578947368421,0.00798091724019878 -"4534",6.16502073107827,17.6315789473684,28.1578947368421,0.00690982881104033 -"4535",8.02538101483936,17.6315789473684,28.1578947368421,0.00598247941711173 -"4536",10.4471247126008,17.6315789473684,28.1578947368421,0.00517958598849048 -"4537",13.5996552137305,17.6315789473684,28.1578947368421,0.00448444670256841 -"4538",17.7034951740616,17.6315789473684,28.1578947368421,0.0038826003005878 -"4539",23.045712295823,17.6315789473684,28.1578947368421,0.00336152619936951 -"4540",30,17.6315789473684,28.1578947368421,0.00291038415302508 -"4541",0.2,19.7368421052632,28.1578947368421,0.0201480237771937 -"4542",0.260352117694686,19.7368421052632,28.1578947368421,0.0201478939303548 -"4543",0.338916125940539,19.7368421052632,28.1578947368421,0.0201470997714148 -"4544",0.441187655547492,19.7368421052632,28.1578947368421,0.0201422503153346 -"4545",0.574320702112717,19.7368421052632,28.1578947368421,0.02011292141444 -"4546",0.747628055154725,19.7368421052632,28.1578947368421,0.019945141787858 -"4547",0.973232737037462,19.7368421052632,28.1578947368421,0.0192022229835108 -"4548",1.2669160204875,19.7368421052632,28.1578947368421,0.017453169325414 -"4549",1.64922134437622,19.7368421052632,28.1578947368421,0.0152899103954592 -"4550",2.14689134777813,19.7368421052632,28.1578947368421,0.0132657611232903 -"4551",2.79473854427218,19.7368421052632,28.1578947368421,0.0114894069267503 -"4552",3.63808049202114,19.7368421052632,28.1578947368421,0.00994801139690304 -"4553",4.73590980220715,19.7368421052632,28.1578947368421,0.00861299417580784 -"4554",6.16502073107827,19.7368421052632,28.1578947368421,0.00745707711458956 -"4555",8.02538101483936,19.7368421052632,28.1578947368421,0.00645628300929359 -"4556",10.4471247126008,19.7368421052632,28.1578947368421,0.00558980159915219 -"4557",13.5996552137305,19.7368421052632,28.1578947368421,0.00483960830171199 -"4558",17.7034951740616,19.7368421052632,28.1578947368421,0.00419009654773962 -"4559",23.045712295823,19.7368421052632,28.1578947368421,0.00362775414223866 -"4560",30,19.7368421052632,28.1578947368421,0.0031408823077514 -"4561",0.2,21.8421052631579,28.1578947368421,0.0216362332519967 -"4562",0.260352117694686,21.8421052631579,28.1578947368421,0.0216360938141777 -"4563",0.338916125940539,21.8421052631579,28.1578947368421,0.0216352409956454 -"4564",0.441187655547492,21.8421052631579,28.1578947368421,0.021630033340341 -"4565",0.574320702112717,21.8421052631579,28.1578947368421,0.0215985380955569 -"4566",0.747628055154725,21.8421052631579,28.1578947368421,0.0214183656292244 -"4567",0.973232737037462,21.8421052631579,28.1578947368421,0.0206205720234642 -"4568",1.2669160204875,21.8421052631579,28.1578947368421,0.0187423266265297 -"4569",1.64922134437622,21.8421052631579,28.1578947368421,0.0164192811849243 -"4570",2.14689134777813,21.8421052631579,28.1578947368421,0.0142456205681903 -"4571",2.79473854427218,21.8421052631579,28.1578947368421,0.012338058111469 -"4572",3.63808049202114,21.8421052631579,28.1578947368421,0.0106828092599608 -"4573",4.73590980220715,21.8421052631579,28.1578947368421,0.00924918260205784 -"4574",6.16502073107827,21.8421052631579,28.1578947368421,0.00800788512131976 -"4575",8.02538101483936,21.8421052631579,28.1578947368421,0.00693316856654195 -"4576",10.4471247126008,21.8421052631579,28.1578947368421,0.00600268555214532 -"4577",13.5996552137305,21.8421052631579,28.1578947368421,0.00519708013163388 -"4578",17.7034951740616,21.8421052631579,28.1578947368421,0.00449959297536167 -"4579",23.045712295823,21.8421052631579,28.1578947368421,0.00389571382634657 -"4580",30,21.8421052631579,28.1578947368421,0.00337287979104442 -"4581",0.2,23.9473684210526,28.1578947368421,0.0231235667845707 -"4582",0.260352117694686,23.9473684210526,28.1578947368421,0.0231234177614167 -"4583",0.338916125940539,23.9473684210526,28.1578947368421,0.0231225063178185 -"4584",0.441187655547492,23.9473684210526,28.1578947368421,0.0231169406741217 -"4585",0.574320702112717,23.9473684210526,28.1578947368421,0.023083280360532 -"4586",0.747628055154725,23.9473684210526,28.1578947368421,0.0228907223487257 -"4587",0.973232737037462,23.9473684210526,28.1578947368421,0.0220380862402018 -"4588",1.2669160204875,23.9473684210526,28.1578947368421,0.020030725145136 -"4589",1.64922134437622,23.9473684210526,28.1578947368421,0.0175479872403023 -"4590",2.14689134777813,23.9473684210526,28.1578947368421,0.0152249032795856 -"4591",2.79473854427218,23.9473684210526,28.1578947368421,0.0131862097902896 -"4592",3.63808049202114,23.9473684210526,28.1578947368421,0.0114171746298186 -"4593",4.73590980220715,23.9473684210526,28.1578947368421,0.0098849965754384 -"4594",6.16502073107827,23.9473684210526,28.1578947368421,0.00855836892907037 -"4595",8.02538101483936,23.9473684210526,28.1578947368421,0.00740977343467695 -"4596",10.4471247126008,23.9473684210526,28.1578947368421,0.00641532648660092 -"4597",13.5996552137305,23.9473684210526,28.1578947368421,0.00555434155792858 -"4598",17.7034951740616,23.9473684210526,28.1578947368421,0.00480890723710232 -"4599",23.045712295823,23.9473684210526,28.1578947368421,0.00416351579260161 -"4600",30,23.9473684210526,28.1578947368421,0.0036047407234042 -"4601",0.2,26.0526315789474,28.1578947368421,0.0246001365043004 -"4602",0.260352117694686,26.0526315789474,28.1578947368421,0.0245999779651803 -"4603",0.338916125940539,26.0526315789474,28.1578947368421,0.024599008320785 -"4604",0.441187655547492,26.0526315789474,28.1578947368421,0.024593087279453 -"4605",0.574320702112717,26.0526315789474,28.1578947368421,0.0245572775656316 -"4606",0.747628055154725,26.0526315789474,28.1578947368421,0.0243524236423783 -"4607",0.973232737037462,26.0526315789474,28.1578947368421,0.0234453419255481 -"4608",1.2669160204875,26.0526315789474,28.1578947368421,0.0213097995409282 -"4609",1.64922134437622,26.0526315789474,28.1578947368421,0.0186685248650827 -"4610",2.14689134777813,26.0526315789474,28.1578947368421,0.0161970989351213 -"4611",2.79473854427218,26.0526315789474,28.1578947368421,0.0140282234067762 -"4612",3.63808049202114,26.0526315789474,28.1578947368421,0.0121462254073356 -"4613",4.73590980220715,26.0526315789474,28.1578947368421,0.0105162091716138 -"4614",6.16502073107827,26.0526315789474,28.1578947368421,0.009104868892881 -"4615",8.02538101483936,26.0526315789474,28.1578947368421,0.00788292911976797 -"4616",10.4471247126008,26.0526315789474,28.1578947368421,0.00682498114414343 -"4617",13.5996552137305,26.0526315789474,28.1578947368421,0.00590901748806865 -"4618",17.7034951740616,26.0526315789474,28.1578947368421,0.0051159829956757 -"4619",23.045712295823,26.0526315789474,28.1578947368421,0.00442937967961553 -"4620",30,26.0526315789474,28.1578947368421,0.00383492368130352 -"4621",0.2,28.1578947368421,28.1578947368421,0.0260569119291081 -"4622",0.260352117694686,28.1578947368421,28.1578947368421,0.0260567440015891 -"4623",0.338916125940539,28.1578947368421,28.1578947368421,0.0260557169366131 -"4624",0.441187655547492,28.1578947368421,28.1578947368421,0.0260494452619624 -"4625",0.574320702112717,28.1578947368421,28.1578947368421,0.0260115149618973 -"4626",0.747628055154725,28.1578947368421,28.1578947368421,0.0257945299611998 -"4627",0.973232737037462,28.1578947368421,28.1578947368421,0.024833732511811 -"4628",1.2669160204875,28.1578947368421,28.1578947368421,0.022571727184028 -"4629",1.64922134437622,28.1578947368421,28.1578947368421,0.019774041016837 -"4630",2.14689134777813,28.1578947368421,28.1578947368421,0.0171562617299187 -"4631",2.79473854427218,28.1578947368421,28.1578947368421,0.0148589493301519 -"4632",3.63808049202114,28.1578947368421,28.1578947368421,0.0128655028257551 -"4633",4.73590980220715,28.1578947368421,28.1578947368421,0.011138959987678 -"4634",6.16502073107827,28.1578947368421,28.1578947368421,0.00964404269977946 -"4635",8.02538101483936,28.1578947368421,28.1578947368421,0.00834974187160663 -"4636",10.4471247126008,28.1578947368421,28.1578947368421,0.0072291441374596 -"4637",13.5996552137305,28.1578947368421,28.1578947368421,0.00625893877650835 -"4638",17.7034951740616,28.1578947368421,28.1578947368421,0.00541894222114714 -"4639",23.045712295823,28.1578947368421,28.1578947368421,0.00469167950316646 -"4640",30,28.1578947368421,28.1578947368421,0.00406202089980715 -"4641",0.2,30.2631578947368,28.1578947368421,0.0274859087394832 -"4642",0.260352117694686,30.2631578947368,28.1578947368421,0.0274857316025887 -"4643",0.338916125940539,30.2631578947368,28.1578947368421,0.0274846482119598 -"4644",0.441187655547492,30.2631578947368,28.1578947368421,0.0274780325900641 -"4645",0.574320702112717,30.2631578947368,28.1578947368421,0.0274380221402884 -"4646",0.747628055154725,30.2631578947368,28.1578947368421,0.0272091373843651 -"4647",0.973232737037462,30.2631578947368,28.1578947368421,0.0261956484842653 -"4648",1.2669160204875,30.2631578947368,28.1578947368421,0.0238095916799586 -"4649",1.64922134437622,30.2631578947368,28.1578947368421,0.0208584765638491 -"4650",2.14689134777813,30.2631578947368,28.1578947368421,0.0180971346682284 -"4651",2.79473854427218,30.2631578947368,28.1578947368421,0.0156738345036552 -"4652",3.63808049202114,30.2631578947368,28.1578947368421,0.0135710646571761 -"4653",4.73590980220715,30.2631578947368,28.1578947368421,0.0117498358403729 -"4654",6.16502073107827,30.2631578947368,28.1578947368421,0.0101729352368 -"4655",8.02538101483936,30.2631578947368,28.1578947368421,0.00880765317492775 -"4656",10.4471247126008,30.2631578947368,28.1578947368421,0.00762560032314566 -"4657",13.5996552137305,30.2631578947368,28.1578947368421,0.00660218756870205 -"4658",17.7034951740616,30.2631578947368,28.1578947368421,0.00571612444944396 -"4659",23.045712295823,30.2631578947368,28.1578947368421,0.00494897764592288 -"4660",30,30.2631578947368,28.1578947368421,0.00428478770061969 -"4661",0.2,32.3684210526316,28.1578947368421,0.0288803110000826 -"4662",0.260352117694686,32.3684210526316,28.1578947368421,0.028880124876762 -"4663",0.338916125940539,32.3684210526316,28.1578947368421,0.0288789865240667 -"4664",0.441187655547492,32.3684210526316,28.1578947368421,0.0288720352815366 -"4665",0.574320702112717,32.3684210526316,28.1578947368421,0.0288299950403451 -"4666",0.747628055154725,32.3684210526316,28.1578947368421,0.0285894986100871 -"4667",0.973232737037462,32.3684210526316,28.1578947368421,0.0275245938653527 -"4668",1.2669160204875,32.3684210526316,28.1578947368421,0.0250174887437653 -"4669",1.64922134437622,32.3684210526316,28.1578947368421,0.0219166590365104 -"4670",2.14689134777813,32.3684210526316,28.1578947368421,0.0190152300359649 -"4671",2.79473854427218,32.3684210526316,28.1578947368421,0.0164689921413855 -"4672",3.63808049202114,32.3684210526316,28.1578947368421,0.0142595455590108 -"4673",4.73590980220715,32.3684210526316,28.1578947368421,0.0123459230140871 -"4674",6.16502073107827,32.3684210526316,28.1578947368421,0.0106890238269781 -"4675",8.02538101483936,32.3684210526316,28.1578947368421,0.00925447891440393 -"4676",10.4471247126008,32.3684210526316,28.1578947368421,0.00801245871046712 -"4677",13.5996552137305,32.3684210526316,28.1578947368421,0.00693712665905399 -"4678",17.7034951740616,32.3684210526316,28.1578947368421,0.00600611220024815 -"4679",23.045712295823,32.3684210526316,28.1578947368421,0.00520004686406438 -"4680",30,32.3684210526316,28.1578947368421,0.00450216154525266 -"4681",0.2,34.4736842105263,28.1578947368421,0.0302345287902769 -"4682",0.260352117694686,34.4736842105263,28.1578947368421,0.0302343339395048 -"4683",0.338916125940539,34.4736842105263,28.1578947368421,0.030233142208663 -"4684",0.441187655547492,34.4736842105263,28.1578947368421,0.0302258650175551 -"4685",0.574320702112717,34.4736842105263,28.1578947368421,0.03018185348033 -"4686",0.747628055154725,34.4736842105263,28.1578947368421,0.0299300800058486 -"4687",0.973232737037462,34.4736842105263,28.1578947368421,0.0288152411398999 -"4688",1.2669160204875,34.4736842105263,28.1578947368421,0.0261905761223152 -"4689",1.64922134437622,34.4736842105263,28.1578947368421,0.0229443463619266 -"4690",2.14689134777813,34.4736842105263,28.1578947368421,0.0199068673455239 -"4691",2.79473854427218,34.4736842105263,28.1578947368421,0.0172412345921115 -"4692",3.63808049202114,34.4736842105263,28.1578947368421,0.014928185528852 -"4693",4.73590980220715,34.4736842105263,28.1578947368421,0.0129248318970974 -"4694",6.16502073107827,34.4736842105263,28.1578947368421,0.0111902395592555 -"4695",8.02538101483936,34.4736842105263,28.1578947368421,0.00968842784192164 -"4696",10.4471247126008,34.4736842105263,28.1578947368421,0.00838816845018845 -"4697",13.5996552137305,34.4736842105263,28.1578947368421,0.00726241333392723 -"4698",17.7034951740616,34.4736842105263,28.1578947368421,0.0062877429621695 -"4699",23.045712295823,34.4736842105263,28.1578947368421,0.00544388066395455 -"4700",30,34.4736842105263,28.1578947368421,0.00471327101907004 -"4701",0.2,36.5789473684211,28.1578947368421,0.0315441978227556 -"4702",0.260352117694686,36.5789473684211,28.1578947368421,0.031543994531633 -"4703",0.338916125940539,36.5789473684211,28.1578947368421,0.0315427511785883 -"4704",0.441187655547492,36.5789473684211,28.1578947368421,0.0315351587614055 -"4705",0.574320702112717,36.5789473684211,28.1578947368421,0.0314892407764968 -"4706",0.747628055154725,36.5789473684211,28.1578947368421,0.031226561230847 -"4707",0.973232737037462,36.5789473684211,28.1578947368421,0.0300634308916274 -"4708",1.2669160204875,36.5789473684211,28.1578947368421,0.0273250732639146 -"4709",1.64922134437622,36.5789473684211,28.1578947368421,0.0239382265744849 -"4710",2.14689134777813,36.5789473684211,28.1578947368421,0.0207691730846653 -"4711",2.79473854427218,36.5789473684211,28.1578947368421,0.0179880731217813 -"4712",3.63808049202114,36.5789473684211,28.1578947368421,0.0155748297161601 -"4713",4.73590980220715,36.5789473684211,28.1578947368421,0.0134846968185267 -"4714",6.16502073107827,36.5789473684211,28.1578947368421,0.0116749671473199 -"4715",8.02538101483936,36.5789473684211,28.1578947368421,0.010108101454366 -"4716",10.4471247126008,36.5789473684211,28.1578947368421,0.00875151872876 -"4717",13.5996552137305,36.5789473684211,28.1578947368421,0.00757699928003146 -"4718",17.7034951740616,36.5789473684211,28.1578947368421,0.00656010911342858 -"4719",23.045712295823,36.5789473684211,28.1578947368421,0.0056796932334689 -"4720",30,36.5789473684211,28.1578947368421,0.00491743577183247 -"4721",0.2,38.6842105263158,28.1578947368421,0.0328061307400901 -"4722",0.260352117694686,38.6842105263158,28.1578947368421,0.0328059193162592 -"4723",0.338916125940539,38.6842105263158,28.1578947368421,0.0328046262225889 -"4724",0.441187655547492,38.6842105263158,28.1578947368421,0.0327967300690036 -"4725",0.574320702112717,38.6842105263158,28.1578947368421,0.0327489751245063 -"4726",0.747628055154725,38.6842105263158,28.1578947368421,0.0324757870229812 -"4727",0.973232737037462,38.6842105263158,28.1578947368421,0.0312661253859787 -"4728",1.2669160204875,38.6842105263158,28.1578947368421,0.0284182191290928 -"4729",1.64922134437622,38.6842105263158,28.1578947368421,0.0248958808558426 -"4730",2.14689134777813,38.6842105263158,28.1578947368421,0.0216000486494404 -"4731",2.79473854427218,38.6842105263158,28.1578947368421,0.0187076901403958 -"4732",3.63808049202114,38.6842105263158,28.1578947368421,0.016197904375124 -"4733",4.73590980220715,38.6842105263158,28.1578947368421,0.014024155228317 -"4734",6.16502073107827,38.6842105263158,28.1578947368421,0.0121420269037539 -"4735",8.02538101483936,38.6842105263158,28.1578947368421,0.0105124783869701 -"4736",10.4471247126008,38.6842105263158,28.1578947368421,0.00910162525619639 -"4737",13.5996552137305,38.6842105263158,28.1578947368421,0.00788011888572941 -"4738",17.7034951740616,38.6842105263158,28.1578947368421,0.0068225477932155 -"4739",23.045712295823,38.6842105263158,28.1578947368421,0.00590691067269337 -"4740",30,38.6842105263158,28.1578947368421,0.00511415892530182 -"4741",0.2,40.7894736842105,28.1578947368421,0.0340182313529281 -"4742",0.260352117694686,40.7894736842105,28.1578947368421,0.0340180121175404 -"4743",0.338916125940539,40.7894736842105,28.1578947368421,0.0340166712474455 -"4744",0.441187655547492,40.7894736842105,28.1578947368421,0.034008483351665 -"4745",0.574320702112717,40.7894736842105,28.1578947368421,0.0339589639870369 -"4746",0.747628055154725,40.7894736842105,28.1578947368421,0.0336756823006296 -"4747",0.973232737037462,40.7894736842105,28.1578947368421,0.0324213268341977 -"4748",1.2669160204875,40.7894736842105,28.1578947368421,0.0294681978996781 -"4749",1.64922134437622,40.7894736842105,28.1578947368421,0.0258157184521012 -"4750",2.14689134777813,40.7894736842105,28.1578947368421,0.0223981138773316 -"4751",2.79473854427218,40.7894736842105,28.1578947368421,0.0193988902963547 -"4752",3.63808049202114,40.7894736842105,28.1578947368421,0.0167963745200895 -"4753",4.73590980220715,40.7894736842105,28.1578947368421,0.0145423110352744 -"4754",6.16502073107827,40.7894736842105,28.1578947368421,0.0125906429983411 -"4755",8.02538101483936,40.7894736842105,28.1578947368421,0.0109008869315877 -"4756",10.4471247126008,40.7894736842105,28.1578947368421,0.00943790647260257 -"4757",13.5996552137305,40.7894736842105,28.1578947368421,0.00817126864082554 -"4758",17.7034951740616,40.7894736842105,28.1578947368421,0.00707462306618171 -"4759",23.045712295823,40.7894736842105,28.1578947368421,0.00612515555207506 -"4760",30,40.7894736842105,28.1578947368421,0.00530311370380407 -"4761",0.2,42.8947368421053,28.1578947368421,0.035179383306261 -"4762",0.260352117694686,42.8947368421053,28.1578947368421,0.0351791565876625 -"4763",0.338916125940539,42.8947368421053,28.1578947368421,0.0351777699493466 -"4764",0.441187655547492,42.8947368421053,28.1578947368421,0.0351693025742751 -"4765",0.574320702112717,42.8947368421053,28.1578947368421,0.03511809295402 -"4766",0.747628055154725,42.8947368421053,28.1578947368421,0.0348251419500017 -"4767",0.973232737037462,42.8947368421053,28.1578947368421,0.0335279712858921 -"4768",1.2669160204875,42.8947368421053,28.1578947368421,0.030474042536262 -"4769",1.64922134437622,42.8947368421053,28.1578947368421,0.0266968921849846 -"4770",2.14689134777813,42.8947368421053,28.1578947368421,0.0231626337434532 -"4771",2.79473854427218,42.8947368421053,28.1578947368421,0.0200610369884156 -"4772",3.63808049202114,42.8947368421053,28.1578947368421,0.0173696889549458 -"4773",4.73590980220715,42.8947368421053,28.1578947368421,0.0150386870134785 -"4774",6.16502073107827,42.8947368421053,28.1578947368421,0.0130204022518298 -"4775",8.02538101483936,42.8947368421053,28.1578947368421,0.0112729693606345 -"4776",10.4471247126008,42.8947368421053,28.1578947368421,0.00976005266010838 -"4777",13.5996552137305,42.8947368421053,28.1578947368421,0.00845018039391074 -"4778",17.7034951740616,42.8947368421053,28.1578947368421,0.00731610276884956 -"4779",23.045712295823,42.8947368421053,28.1578947368421,0.00633422686621756 -"4780",30,42.8947368421053,28.1578947368421,0.00548412607837565 -"4781",0.2,45,28.1578947368421,0.0362893238461481 -"4782",0.260352117694686,45,28.1578947368421,0.0362890899743779 -"4783",0.338916125940539,45,28.1578947368421,0.0362876595864015 -"4784",0.441187655547492,45,28.1578947368421,0.0362789250581858 -"4785",0.574320702112717,45,28.1578947368421,0.0362260997292908 -"4786",0.747628055154725,45,28.1578947368421,0.0359239058629765 -"4787",0.973232737037462,45,28.1578947368421,0.0345858083214765 -"4788",1.2669160204875,45,28.1578947368421,0.0314355254289771 -"4789",1.64922134437622,45,28.1578947368421,0.0275392026560676 -"4790",2.14689134777813,45,28.1578947368421,0.0238934352466689 -"4791",2.79473854427218,45,28.1578947368421,0.0206939803811911 -"4792",3.63808049202114,45,28.1578947368421,0.0179177179459171 -"4793",4.73590980220715,45,28.1578947368421,0.0155131708393493 -"4794",6.16502073107827,45,28.1578947368421,0.0134312074151588 -"4795",8.02538101483936,45,28.1578947368421,0.0116286414765822 -"4796",10.4471247126008,45,28.1578947368421,0.0100679909211227 -"4797",13.5996552137305,45,28.1578947368421,0.00871679103079733 -"4798",17.7034951740616,45,28.1578947368421,0.00754693225742904 -"4799",23.045712295823,45,28.1578947368421,0.00653407730493759 -"4800",30,45,28.1578947368421,0.00565715508821498 -"4801",0.2,5,30.2631578947368,-0.0449193698458747 -"4802",0.260352117694686,5,30.2631578947368,-0.0449190803565311 -"4803",0.338916125940539,5,30.2631578947368,-0.044917309804762 -"4804",0.441187655547492,5,30.2631578947368,-0.0449064980986797 -"4805",0.574320702112717,5,30.2631578947368,-0.0448411102591067 -"4806",0.747628055154725,5,30.2631578947368,-0.0444670509874687 -"4807",0.973232737037462,5,30.2631578947368,-0.042810737449875 -"4808",1.2669160204875,5,30.2631578947368,-0.0389112786733145 -"4809",1.64922134437622,5,30.2631578947368,-0.034088362588759 -"4810",2.14689134777813,5,30.2631578947368,-0.0295755870041514 -"4811",2.79473854427218,5,30.2631578947368,-0.0256152625567496 -"4812",3.63808049202114,5,30.2631578947368,-0.0221787708864172 -"4813",4.73590980220715,5,30.2631578947368,-0.0192023930059788 -"4814",6.16502073107827,5,30.2631578947368,-0.0166253131614138 -"4815",8.02538101483936,5,30.2631578947368,-0.0143940749490464 -"4816",10.4471247126008,5,30.2631578947368,-0.0124622825629975 -"4817",13.5996552137305,5,30.2631578947368,-0.0107897507774356 -"4818",17.7034951740616,5,30.2631578947368,-0.00934168524909567 -"4819",23.045712295823,5,30.2631578947368,-0.00808796097459341 -"4820",30,5,30.2631578947368,-0.00700249590651918 -"4821",0.2,7.10526315789474,30.2631578947368,-0.0462231254707567 -"4822",0.260352117694686,7.10526315789474,30.2631578947368,-0.0462228275791724 -"4823",0.338916125940539,7.10526315789474,30.2631578947368,-0.0462210056382845 -"4824",0.441187655547492,7.10526315789474,30.2631578947368,-0.0462098801294337 -"4825",0.574320702112717,7.10526315789474,30.2631578947368,-0.0461425944501552 -"4826",0.747628055154725,7.10526315789474,30.2631578947368,-0.0457576783503579 -"4827",0.973232737037462,7.10526315789474,30.2631578947368,-0.0440532913847839 -"4828",1.2669160204875,7.10526315789474,30.2631578947368,-0.0400406533420988 -"4829",1.64922134437622,7.10526315789474,30.2631578947368,-0.0350777552409846 -"4830",2.14689134777813,7.10526315789474,30.2631578947368,-0.030433999267016 -"4831",2.79473854427218,7.10526315789474,30.2631578947368,-0.0263587289668034 -"4832",3.63808049202114,7.10526315789474,30.2631578947368,-0.0228224953508376 -"4833",4.73590980220715,7.10526315789474,30.2631578947368,-0.0197597300295977 -"4834",6.16502073107827,7.10526315789474,30.2631578947368,-0.0171078521111807 -"4835",8.02538101483936,7.10526315789474,30.2631578947368,-0.0148118536544064 -"4836",10.4471247126008,7.10526315789474,30.2631578947368,-0.0128239922451708 -"4837",13.5996552137305,7.10526315789474,30.2631578947368,-0.0111029163074825 -"4838",17.7034951740616,7.10526315789474,30.2631578947368,-0.00961282161479213 -"4839",23.045712295823,7.10526315789474,30.2631578947368,-0.00832270880499782 -"4840",30,7.10526315789474,30.2631578947368,-0.00720573881615176 -"4841",0.2,9.21052631578947,30.2631578947368,-0.0475311716935409 -"4842",0.260352117694686,9.21052631578947,30.2631578947368,-0.0475308653720644 -"4843",0.338916125940539,9.21052631578947,30.2631578947368,-0.0475289918729387 -"4844",0.441187655547492,9.21052631578947,30.2631578947368,-0.0475175515286093 -"4845",0.574320702112717,9.21052631578947,30.2631578947368,-0.0474483617639248 -"4846",0.747628055154725,9.21052631578947,30.2631578947368,-0.047052553106662 -"4847",0.973232737037462,9.21052631578947,30.2631578947368,-0.0452999345057371 -"4848",1.2669160204875,9.21052631578947,30.2631578947368,-0.0411737447293326 -"4849",1.64922134437622,9.21052631578947,30.2631578947368,-0.0360704039374849 -"4850",2.14689134777813,9.21052631578947,30.2631578947368,-0.0312952365239085 -"4851",2.79473854427218,9.21052631578947,30.2631578947368,-0.0271046420895374 -"4852",3.63808049202114,9.21052631578947,30.2631578947368,-0.0234683382819275 -"4853",4.73590980220715,9.21052631578947,30.2631578947368,-0.0203189012229174 -"4854",6.16502073107827,9.21052631578947,30.2631578947368,-0.0175919790737362 -"4855",8.02538101483936,9.21052631578947,30.2631578947368,-0.0152310072496632 -"4856",10.4471247126008,9.21052631578947,30.2631578947368,-0.0131868922967461 -"4857",13.5996552137305,9.21052631578947,30.2631578947368,-0.01141711245043 -"4858",17.7034951740616,9.21052631578947,30.2631578947368,-0.00988485027740348 -"4859",23.045712295823,9.21052631578947,30.2631578947368,-0.008558229179374 -"4860",30,9.21052631578947,30.2631578947368,-0.00740965058855667 -"4861",0.2,11.3157894736842,30.2631578947368,-0.0488427985178875 -"4862",0.260352117694686,11.3157894736842,30.2631578947368,-0.0488424837434432 -"4863",0.338916125940539,11.3157894736842,30.2631578947368,-0.0488405585449459 -"4864",0.441187655547492,11.3157894736842,30.2631578947368,-0.0488288025033179 -"4865",0.574320702112717,11.3157894736842,30.2631578947368,-0.0487577034410483 -"4866",0.747628055154725,11.3157894736842,30.2631578947368,-0.0483509724094009 -"4867",0.973232737037462,11.3157894736842,30.2631578947368,-0.0465499901454752 -"4868",1.2669160204875,11.3157894736842,30.2631578947368,-0.0423099378026696 -"4869",1.64922134437622,11.3157894736842,30.2631578947368,-0.0370657698770091 -"4870",2.14689134777813,11.3157894736842,30.2631578947368,-0.0321588313025874 -"4871",2.79473854427218,11.3157894736842,30.2631578947368,-0.027852597049667 -"4872",3.63808049202114,11.3157894736842,30.2631578947368,-0.0241159491216494 -"4873",4.73590980220715,11.3157894736842,30.2631578947368,-0.0208796030725807 -"4874",6.16502073107827,11.3157894736842,30.2631578947368,-0.0180774312690919 -"4875",8.02538101483936,11.3157894736842,30.2631578947368,-0.0156513082218186 -"4876",10.4471247126008,11.3157894736842,30.2631578947368,-0.0135507857386688 -"4877",13.5996552137305,11.3157894736842,30.2631578947368,-0.0117321686632901 -"4878",17.7034951740616,11.3157894736842,30.2631578947368,-0.0101576235820905 -"4879",23.045712295823,11.3157894736842,30.2631578947368,-0.00879439425927037 -"4880",30,11.3157894736842,30.2631578947368,-0.00761412054216203 -"4881",0.2,13.4210526315789,30.2631578947368,-0.050157325627289 -"4882",0.260352117694686,13.4210526315789,30.2631578947368,-0.0501570023811856 -"4883",0.338916125940539,13.4210526315789,30.2631578947368,-0.0501550253689984 -"4884",0.441187655547492,13.4210526315789,30.2631578947368,-0.0501429529319981 -"4885",0.574320702112717,13.4210526315789,30.2631578947368,-0.0500699403502817 -"4886",0.747628055154725,13.4210526315789,30.2631578947368,-0.0496522627925637 -"4887",0.973232737037462,13.4210526315789,30.2631578947368,-0.0478028099233222 -"4888",1.2669160204875,13.4210526315789,30.2631578947368,-0.0434486432398352 -"4889",1.64922134437622,13.4210526315789,30.2631578947368,-0.0380633367817048 -"4890",2.14689134777813,13.4210526315789,30.2631578947368,-0.0330243356724576 -"4891",2.79473854427218,13.4210526315789,30.2631578947368,-0.0286022058968262 -"4892",3.63808049202114,13.4210526315789,30.2631578947368,-0.0247649919662715 -"4893",4.73590980220715,13.4210526315789,30.2631578947368,-0.0214415447529371 -"4894",6.16502073107827,13.4210526315789,30.2631578947368,-0.0185639569021975 -"4895",8.02538101483936,13.4210526315789,30.2631578947368,-0.0160725385685532 -"4896",10.4471247126008,13.4210526315789,30.2631578947368,-0.0139154838261596 -"4897",13.5996552137305,13.4210526315789,30.2631578947368,-0.0120479215322482 -"4898",17.7034951740616,13.4210526315789,30.2631578947368,-0.010431000046399 -"4899",23.045712295823,13.4210526315789,30.2631578947368,-0.00903108155024004 -"4900",30,13.4210526315789,30.2631578947368,-0.00781904262219513 -"4901",0.2,15.5263157894737,30.2631578947368,-0.0514741027570687 -"4902",0.260352117694686,15.5263157894737,30.2631578947368,-0.0514737710248055 -"4903",0.338916125940539,15.5263157894737,30.2631578947368,-0.0514717421102411 -"4904",0.441187655547492,15.5263157894737,30.2631578947368,-0.051459352736308 -"4905",0.574320702112717,15.5263157894737,30.2631578947368,-0.0513844233598544 -"4906",0.747628055154725,15.5263157894737,30.2631578947368,-0.0509557805393608 -"4907",0.973232737037462,15.5263157894737,30.2631578947368,-0.0490577740997213 -"4908",1.2669160204875,15.5263157894737,30.2631578947368,-0.0445892977508692 -"4909",1.64922134437622,15.5263157894737,30.2631578947368,-0.0390626111794207 -"4910",2.14689134777813,15.5263157894737,30.2631578947368,-0.0338913214895004 -"4911",2.79473854427218,15.5263157894737,30.2631578947368,-0.0293530978177004 -"4912",3.63808049202114,15.5263157894737,30.2631578947368,-0.0254151457500414 -"4913",4.73590980220715,15.5263157894737,30.2631578947368,-0.0220044482850674 -"4914",6.16502073107827,15.5263157894737,30.2631578947368,-0.0190513153006231 -"4915",8.02538101483936,15.5263157894737,30.2631578947368,-0.0164944899174317 -"4916",10.4471247126008,15.5263157894737,30.2631578947368,-0.0142808061519204 -"4917",13.5996552137305,15.5263157894737,30.2631578947368,-0.0123642148620188 -"4918",17.7034951740616,15.5263157894737,30.2631578947368,-0.010704844437623 -"4919",23.045712295823,15.5263157894737,30.2631578947368,-0.00926817396882108 -"4920",30,15.5263157894737,30.2631578947368,-0.00802431545867341 -"4921",0.2,17.6315789473684,30.2631578947368,-0.0527925098869645 -"4922",0.260352117694686,17.6315789473684,30.2631578947368,-0.0527921696580369 -"4923",0.338916125940539,17.6315789473684,30.2631578947368,-0.0527900887768468 -"4924",0.441187655547492,17.6315789473684,30.2631578947368,-0.0527773820736539 -"4925",0.574320702112717,17.6315789473684,30.2631578947368,-0.0527005335297188 -"4926",0.747628055154725,17.6315789473684,30.2631578947368,-0.0522609118728696 -"4927",0.973232737037462,17.6315789473684,30.2631578947368,-0.0503142917597792 -"4928",1.2669160204875,17.6315789473684,30.2631578947368,-0.0457313642449514 -"4929",1.64922134437622,17.6315789473684,30.2631578947368,-0.040063122549854 -"4930",2.14689134777813,17.6315789473684,30.2631578947368,-0.0347593805230737 -"4931",2.79473854427218,17.6315789473684,30.2631578947368,-0.0301049192458471 -"4932",3.63808049202114,17.6315789473684,30.2631578947368,-0.0260661043402734 -"4933",4.73590980220715,17.6315789473684,30.2631578947368,-0.0225680486191106 -"4934",6.16502073107827,17.6315789473684,30.2631578947368,-0.0195392769858375 -"4935",8.02538101483936,17.6315789473684,30.2631578947368,-0.0169169635876143 -"4936",10.4471247126008,17.6315789473684,30.2631578947368,-0.0146465806995645 -"4937",13.5996552137305,17.6315789473684,30.2631578947368,-0.0126808997221043 -"4938",17.7034951740616,17.6315789473684,30.2631578947368,-0.0109790278128553 -"4939",23.045712295823,17.6315789473684,30.2631578947368,-0.00950555987721228 -"4940",30,17.6315789473684,30.2631578947368,-0.00822984239642651 -"4941",0.2,19.7368421052632,30.2631578947368,-0.0541119572691577 -"4942",0.260352117694686,19.7368421052632,30.2631578947368,-0.0541116085368615 -"4943",0.338916125940539,19.7368421052632,30.2631578947368,-0.054109475648043 -"4944",0.441187655547492,19.7368421052632,30.2631578947368,-0.0540964513652105 -"4945",0.574320702112717,19.7368421052632,30.2631578947368,-0.0540176821395283 -"4946",0.747628055154725,19.7368421052632,30.2631578947368,-0.0535670729837797 -"4947",0.973232737037462,19.7368421052632,30.2631578947368,-0.051571800839978 -"4948",1.2669160204875,19.7368421052632,30.2631578947368,-0.0468743318546809 -"4949",1.64922134437622,19.7368421052632,30.2631578947368,-0.0410644233458205 -"4950",2.14689134777813,19.7368421052632,30.2631578947368,-0.0356281244743657 -"4951",2.79473854427218,19.7368421052632,30.2631578947368,-0.0308573338776787 -"4952",3.63808049202114,19.7368421052632,30.2631578947368,-0.0267175765511872 -"4953",4.73590980220715,19.7368421052632,30.2631578947368,-0.0231320936462452 -"4954",6.16502073107827,19.7368421052632,30.2631578947368,-0.0200276236835814 -"4955",8.02538101483936,19.7368421052632,30.2631578947368,-0.0173397705988386 -"4956",10.4471247126008,19.7368421052632,30.2631578947368,-0.0150126438513923 -"4957",13.5996552137305,19.7368421052632,30.2631578947368,-0.0129978344535276 -"4958",17.7034951740616,19.7368421052632,30.2631578947368,-0.0112534275248167 -"4959",23.045712295823,19.7368421052632,30.2631578947368,-0.00974313308831974 -"4960",30,19.7368421052632,30.2631578947368,-0.00843553149946551 -"4961",0.2,21.8421052631579,30.2631578947368,-0.0554318853065748 -"4962",0.260352117694686,21.8421052631579,30.2631578947368,-0.0554315280678124 -"4963",0.338916125940539,21.8421052631579,30.2631578947368,-0.0554293431524199 -"4964",0.441187655547492,21.8421052631579,30.2631578947368,-0.0554160011742582 -"4965",0.574320702112717,21.8421052631579,30.2631578947368,-0.0553353105671529 -"4966",0.747628055154725,21.8421052631579,30.2631578947368,-0.0548737099099209 -"4967",0.973232737037462,21.8421052631579,30.2631578947368,-0.0528297680121907 -"4968",1.2669160204875,21.8421052631579,30.2631578947368,-0.0480177158306557 -"4969",1.64922134437622,21.8421052631579,30.2631578947368,-0.0420660889009012 -"4970",2.14689134777813,21.8421052631579,30.2631578947368,-0.0364971848962682 -"4971",2.79473854427218,21.8421052631579,30.2631578947368,-0.0316100226030652 -"4972",3.63808049202114,21.8421052631579,30.2631578947368,-0.0273692860838204 -"4973",4.73590980220715,21.8421052631579,30.2631578947368,-0.0236963441466653 -"4974",6.16502073107827,21.8421052631579,30.2631578947368,-0.0205161482788258 -"4975",8.02538101483936,21.8421052631579,30.2631578947368,-0.0177627316324221 -"4976",10.4471247126008,21.8421052631579,30.2631578947368,-0.0153788403546281 -"4977",13.5996552137305,21.8421052631579,30.2631578947368,-0.0133148846395997 -"4978",17.7034951740616,21.8421052631579,30.2631578947368,-0.0115279271965466 -"4979",23.045712295823,21.8421052631579,30.2631578947368,-0.00998079284384459 -"4980",30,21.8421052631579,30.2631578947368,-0.00864129553201153 -"4981",0.2,23.9473684210526,30.2631578947368,-0.0567517642961101 -"4982",0.260352117694686,23.9473684210526,30.2631578947368,-0.0567513985511976 -"4983",0.338916125940539,23.9473684210526,30.2631578947368,-0.0567491616111643 -"4984",0.441187655547492,23.9473684210526,30.2631578947368,-0.0567355019494788 -"4985",0.574320702112717,23.9473684210526,30.2631578947368,-0.056652890032348 -"4986",0.747628055154725,23.9473684210526,30.2631578947368,-0.0561802982820716 -"4987",0.973232737037462,23.9473684210526,30.2631578947368,-0.0540876884389572 -"4988",1.2669160204875,23.9473684210526,30.2631578947368,-0.0491610573190399 -"4989",1.64922134437622,23.9473684210526,30.2631578947368,-0.0430677172345786 -"4990",2.14689134777813,23.9473684210526,30.2631578947368,-0.0373662130243094 -"4991",2.79473854427218,23.9473684210526,30.2631578947368,-0.0323626833589059 -"4992",3.63808049202114,23.9473684210526,30.2631578947368,-0.0280209713992453 -"4993",4.73590980220715,23.9473684210526,30.2631578947368,-0.0242605736798122 -"4994",6.16502073107827,23.9473684210526,30.2631578947368,-0.0210046547207346 -"4995",8.02538101483936,23.9473684210526,30.2631578947368,-0.0181856769489799 -"4996",10.4471247126008,23.9473684210526,30.2631578947368,-0.0157450232501805 -"4997",13.5996552137305,23.9473684210526,30.2631578947368,-0.0136319230442417 -"4998",17.7034951740616,23.9473684210526,30.2631578947368,-0.0118024166680026 -"4999",23.045712295823,23.9473684210526,30.2631578947368,-0.0102184437680489 -"5000",30,23.9473684210526,30.2631578947368,-0.0088470519184665 -"5001",0.2,26.0526315789474,30.2631578947368,-0.0580710940510687 -"5002",0.260352117694686,26.0526315789474,30.2631578947368,-0.0580707198035457 -"5003",0.338916125940539,26.0526315789474,30.2631578947368,-0.0580684308605204 -"5004",0.441187655547492,26.0526315789474,30.2631578947368,-0.0580544536475072 -"5005",0.574320702112717,26.0526315789474,30.2631578947368,-0.0579699212198559 -"5006",0.747628055154725,26.0526315789474,30.2631578947368,-0.057486342950203 -"5007",0.973232737037462,26.0526315789474,30.2631578947368,-0.0553450854136506 -"5008",1.2669160204875,26.0526315789474,30.2631578947368,-0.0503039230345059 -"5009",1.64922134437622,26.0526315789474,30.2631578947368,-0.0440689287657172 -"5010",2.14689134777813,26.0526315789474,30.2631578947368,-0.0382348795280655 -"5011",2.79473854427218,26.0526315789474,30.2631578947368,-0.0331150309138282 -"5012",3.63808049202114,26.0526315789474,30.2631578947368,-0.0286723855321519 -"5013",4.73590980220715,26.0526315789474,30.2631578947368,-0.0248245684229737 -"5014",6.16502073107827,26.0526315789474,30.2631578947368,-0.0214929578829254 -"5015",8.02538101483936,26.0526315789474,30.2631578947368,-0.0186084462674396 -"5016",10.4471247126008,26.0526315789474,30.2631578947368,-0.0161110537678944 -"5017",13.5996552137305,26.0526315789474,30.2631578947368,-0.0139488295212939 -"5018",17.7034951740616,26.0526315789474,30.2631578947368,-0.0120767919175415 -"5019",23.045712295823,26.0526315789474,30.2631578947368,-0.0104559957997746 -"5020",30,26.0526315789474,30.2631578947368,-0.00905272268455573 -"5021",0.2,28.1578947368421,30.2631578947368,-0.0593894034166722 -"5022",0.260352117694686,28.1578947368421,30.2631578947368,-0.0593890206731148 -"5023",0.338916125940539,28.1578947368421,30.2631578947368,-0.0593866797673173 -"5024",0.441187655547492,28.1578947368421,30.2631578947368,-0.0593723852485753 -"5025",0.574320702112717,28.1578947368421,30.2631578947368,-0.0592859337957551 -"5026",0.747628055154725,28.1578947368421,30.2631578947368,-0.058791377503864 -"5027",0.973232737037462,28.1578947368421,30.2631578947368,-0.0566015098987271 -"5028",1.2669160204875,28.1578947368421,30.2631578947368,-0.0514459048405429 -"5029",1.64922134437622,28.1578947368421,30.2631578947368,-0.0450693659448905 -"5030",2.14689134777813,28.1578947368421,30.2631578947368,-0.0391028741921619 -"5031",2.79473854427218,28.1578947368421,30.2631578947368,-0.0338667965919048 -"5032",3.63808049202114,28.1578947368421,30.2631578947368,-0.0293232958516301 -"5033",4.73590980220715,28.1578947368421,30.2631578947368,-0.0253881269641695 -"5034",6.16502073107827,28.1578947368421,30.2631578947368,-0.0219808833841509 -"5035",8.02538101483936,28.1578947368421,30.2631578947368,-0.0190308886097885 -"5036",10.4471247126008,28.1578947368421,30.2631578947368,-0.016476801192134 -"5037",13.5996552137305,28.1578947368421,30.2631578947368,-0.0142654908981392 -"5038",17.7034951740616,28.1578947368421,30.2631578947368,-0.0123509549611607 -"5039",23.045712295823,28.1578947368421,30.2631578947368,-0.0106933641052078 -"5040",30,28.1578947368421,30.2631578947368,-0.0092582343817999 -"5041",0.2,30.2631578947368,30.2631578947368,-0.060706249691905 -"5042",0.260352117694686,30.2631578947368,30.2631578947368,-0.0607058584617422 -"5043",0.338916125940539,30.2631578947368,30.2631578947368,-0.0607034656508421 -"5044",0.441187655547492,30.2631578947368,30.2631578947368,-0.0606888541785246 -"5045",0.574320702112717,30.2631578947368,30.2631578947368,-0.0606004858303142 -"5046",0.747628055154725,30.2631578947368,30.2631578947368,-0.0600949636998492 -"5047",0.973232737037462,30.2631578947368,30.2631578947368,-0.0578565399747114 -"5048",1.2669160204875,30.2631578947368,30.2631578947368,-0.0525866192486326 -"5049",1.64922134437622,30.2631578947368,30.2631578947368,-0.0460686928156328 -"5050",2.14689134777813,30.2631578947368,30.2631578947368,-0.0399699055356085 -"5051",2.79473854427218,30.2631578947368,30.2631578947368,-0.0346177279429612 -"5052",3.63808049202114,30.2631578947368,30.2631578947368,-0.029973483775709 -"5053",4.73590980220715,30.2631578947368,30.2631578947368,-0.0259510600549997 -"5054",6.16502073107827,30.2631578947368,30.2631578947368,-0.022468267374316 -"5055",8.02538101483936,30.2631578947368,30.2631578947368,-0.0194528621158085 -"5056",10.4471247126008,30.2631578947368,30.2631578947368,-0.0168421427013825 -"5057",13.5996552137305,30.2631578947368,30.2631578947368,-0.0145818008368296 -"5058",17.7034951740616,30.2631578947368,30.2631578947368,-0.0126248137322627 -"5059",23.045712295823,30.2631578947368,30.2631578947368,-0.0109304689737793 -"5060",30,30.2631578947368,30.2631578947368,-0.0094635179973865 -"5061",0.2,32.3684210526316,30.2631578947368,-0.0620212179703493 -"5062",0.260352117694686,32.3684210526316,30.2631578947368,-0.0620208182656842 -"5063",0.338916125940539,32.3684210526316,30.2631578947368,-0.062018373623705 -"5064",0.441187655547492,32.3684210526316,30.2631578947368,-0.0620034456498296 -"5065",0.574320702112717,32.3684210526316,30.2631578947368,-0.0619131631399752 -"5066",0.747628055154725,32.3684210526316,30.2631578947368,-0.061396690809671 -"5067",0.973232737037462,32.3684210526316,30.2631578947368,-0.0591097802119754 -"5068",1.2669160204875,32.3684210526316,30.2631578947368,-0.0537257068472494 -"5069",1.64922134437622,32.3684210526316,30.2631578947368,-0.0470665945142124 -"5070",2.14689134777813,32.3684210526316,30.2631578947368,-0.040835700377795 -"5071",2.79473854427218,32.3684210526316,30.2631578947368,-0.0353675883666876 -"5072",3.63808049202114,32.3684210526316,30.2631578947368,-0.0306227444458962 -"5073",4.73590980220715,32.3684210526316,30.2631578947368,-0.0265131903288597 -"5074",6.16502073107827,32.3684210526316,30.2631578947368,-0.0229549562905113 -"5075",8.02538101483936,32.3684210526316,30.2631578947368,-0.019874233831852 -"5076",10.4471247126008,32.3684210526316,30.2631578947368,-0.0172069631853648 -"5077",13.5996552137305,32.3684210526316,30.2631578947368,-0.014897659675752 -"5078",17.7034951740616,32.3684210526316,30.2631578947368,-0.0128982819445711 -"5079",23.045712295823,32.3684210526316,30.2631578947368,-0.0111672356994786 -"5080",30,32.3684210526316,30.2631578947368,-0.00966850885141235 -"5081",0.2,34.4736842105263,30.2631578947368,-0.0633339204119477 -"5082",0.260352117694686,34.4736842105263,30.2631578947368,-0.0633335122473828 -"5083",0.338916125940539,34.4736842105263,30.2631578947368,-0.0633310158636353 -"5084",0.441187655547492,34.4736842105263,30.2631578947368,-0.0633157719335694 -"5085",0.574320702112717,34.4736842105263,30.2631578947368,-0.0632235785603848 -"5086",0.747628055154725,34.4736842105263,30.2631578947368,-0.0626961748986557 -"5087",0.973232737037462,34.4736842105263,30.2631578947368,-0.0603608609766857 -"5088",1.2669160204875,34.4736842105263,30.2631578947368,-0.0548628316710267 -"5089",1.64922134437622,34.4736842105263,30.2631578947368,-0.048062776716988 -"5090",2.14689134777813,34.4736842105263,30.2631578947368,-0.0417000033590093 -"5091",2.79473854427218,34.4736842105263,30.2631578947368,-0.036116156697361 -"5092",3.63808049202114,34.4736842105263,30.2631578947368,-0.0312708863676139 -"5093",4.73590980220715,34.4736842105263,30.2631578947368,-0.0270743519896303 -"5094",6.16502073107827,34.4736842105263,30.2631578947368,-0.0234408065874813 -"5095",8.02538101483936,34.4736842105263,30.2631578947368,-0.0202948794774831 -"5096",10.4471247126008,34.4736842105263,30.2631578947368,-0.0175711550430081 -"5097",13.5996552137305,34.4736842105263,30.2631578947368,-0.0152129742547049 -"5098",17.7034951740616,34.4736842105263,30.2631578947368,-0.0131712789406823 -"5099",23.045712295823,34.4736842105263,30.2631578947368,-0.0114035944497312 -"5100",30,34.4736842105263,30.2631578947368,-0.00987314648335844 -"5101",0.2,36.5789473684211,30.2631578947368,-0.0646439954568998 -"5102",0.260352117694686,36.5789473684211,30.2631578947368,-0.0646435788493678 -"5103",0.338916125940539,36.5789473684211,30.2631578947368,-0.0646410308274139 -"5104",0.441187655547492,36.5789473684211,30.2631578947368,-0.0646254715735494 -"5105",0.574320702112717,36.5789473684211,30.2631578947368,-0.0645313711616605 -"5106",0.747628055154725,36.5789473684211,30.2631578947368,-0.0639930580477555 -"5107",0.973232737037462,36.5789473684211,30.2631578947368,-0.061609437681602 -"5108",1.2669160204875,36.5789473684211,30.2631578947368,-0.0559976805197972 -"5109",1.64922134437622,36.5789473684211,30.2631578947368,-0.0490569650438511 -"5110",2.14689134777813,36.5789473684211,30.2631578947368,-0.0425625764228545 -"5111",2.79473854427218,36.5789473684211,30.2631578947368,-0.0368632267555706 -"5112",3.63808049202114,36.5789473684211,30.2631578947368,-0.0319177310220626 -"5113",4.73590980220715,36.5789473684211,30.2631578947368,-0.027634390475629 -"5114",6.16502073107827,36.5789473684211,30.2631578947368,-0.0239256844466769 -"5115",8.02538101483936,36.5789473684211,30.2631578947368,-0.0207146831935775 -"5116",10.4471247126008,36.5789473684211,30.2631578947368,-0.0179346179643479 -"5117",13.5996552137305,36.5789473684211,30.2631578947368,-0.0155276577260731 -"5118",17.7034951740616,36.5789473684211,30.2631578947368,-0.013443729528583 -"5119",23.045712295823,36.5789473684211,30.2631578947368,-0.0116394801238561 -"5120",30,36.5789473684211,30.2631578947368,-0.010077374529544 -"5121",0.2,38.6842105263158,30.2631578947368,-0.0659511069921298 -"5122",0.260352117694686,38.6842105263158,30.2631578947368,-0.0659506819607294 -"5123",0.338916125940539,38.6842105263158,30.2631578947368,-0.0659480824173795 -"5124",0.441187655547492,38.6842105263158,30.2631578947368,-0.0659322085530077 -"5125",0.574320702112717,38.6842105263158,30.2631578947368,-0.0658362054163107 -"5126",0.747628055154725,38.6842105263158,30.2631578947368,-0.0652870075284097 -"5127",0.973232737037462,38.6842105263158,30.2631578947368,-0.0628551899916731 -"5128",1.2669160204875,38.6842105263158,30.2631578947368,-0.0571299622365477 -"5129",1.64922134437622,38.6842105263158,30.2631578947368,-0.0500489044256757 -"5130",2.14689134777813,38.6842105263158,30.2631578947368,-0.0434231982674389 -"5131",2.79473854427218,38.6842105263158,30.2631578947368,-0.0376086068728953 -"5132",3.63808049202114,38.6842105263158,30.2631578947368,-0.0325631124546679 -"5133",4.73590980220715,38.6842105263158,30.2631578947368,-0.0281931621032866 -"5134",6.16502073107827,38.6842105263158,30.2631578947368,-0.0244094654677522 -"5135",8.02538101483936,38.6842105263158,30.2631578947368,-0.0211335372752225 -"5136",10.4471247126008,38.6842105263158,30.2631578947368,-0.0182972586992754 -"5137",13.5996552137305,38.6842105263158,30.2631578947368,-0.0158416293546118 -"5138",17.7034951740616,38.6842105263158,30.2631578947368,-0.0137155638083042 -"5139",23.045712295823,38.6842105263158,30.2631578947368,-0.0118748322029849 -"5140",30,38.6842105263158,30.2631578947368,-0.0102811405931869 -"5141",0.2,40.7894736842105,30.2631578947368,-0.0672549434799829 -"5142",0.260352117694686,40.7894736842105,30.2631578947368,-0.0672545100458206 -"5143",0.338916125940539,40.7894736842105,30.2631578947368,-0.0672518591101647 -"5144",0.441187655547492,40.7894736842105,30.2631578947368,-0.0672356714235613 -"5145",0.574320702112717,40.7894736842105,30.2631578947368,-0.0671377703294488 -"5146",0.747628055154725,40.7894736842105,30.2631578947368,-0.0665777149400144 -"5147",0.973232737037462,40.7894736842105,30.2631578947368,-0.0640978209936343 -"5148",1.2669160204875,40.7894736842105,30.2631578947368,-0.0582594069526548 -"5149",1.64922134437622,40.7894736842105,30.2631578947368,-0.051038358443105 -"5150",2.14689134777813,40.7894736842105,30.2631578947368,-0.0442816637716967 -"5151",2.79473854427218,40.7894736842105,30.2631578947368,-0.0383521193950438 -"5152",3.63808049202114,40.7894736842105,30.2631578947368,-0.0332068768448778 -"5153",4.73590980220715,40.7894736842105,30.2631578947368,-0.0287505336946779 -"5154",6.16502073107827,40.7894736842105,30.2631578947368,-0.0248920343460827 -"5155",8.02538101483936,40.7894736842105,30.2631578947368,-0.0215513418925146 -"5156",10.4471247126008,40.7894736842105,30.2631578947368,-0.0186589908158061 -"5157",13.5996552137305,40.7894736842105,30.2631578947368,-0.016154814308157 -"5158",17.7034951740616,40.7894736842105,30.2631578947368,-0.0139867169907197 -"5159",23.045712295823,40.7894736842105,30.2631578947368,-0.0121095945931785 -"5160",30,40.7894736842105,30.2631578947368,-0.0104843961085756 -"5161",0.2,42.8947368421053,30.2631578947368,-0.0685552170580289 -"5162",0.260352117694686,42.8947368421053,30.2631578947368,-0.0685547752440664 -"5163",0.338916125940539,42.8947368421053,30.2631578947368,-0.0685520730565409 -"5164",0.441187655547492,42.8947368421053,30.2631578947368,-0.0685355724052677 -"5165",0.574320702112717,42.8947368421053,30.2631578947368,-0.0684357785401655 -"5166",0.747628055154725,42.8947368421053,30.2631578947368,-0.0678648953187912 -"5167",0.973232737037462,42.8947368421053,30.2631578947368,-0.0653370563380688 -"5168",1.2669160204875,42.8947368421053,30.2631578947368,-0.0593857653080925 -"5169",1.64922134437622,42.8947368421053,30.2631578947368,-0.0520251086434105 -"5170",2.14689134777813,42.8947368421053,30.2631578947368,-0.0451377834026855 -"5171",2.79473854427218,42.8947368421053,30.2631578947368,-0.0390936001685171 -"5172",3.63808049202114,42.8947368421053,30.2631578947368,-0.0338488820616939 -"5173",4.73590980220715,42.8947368421053,30.2631578947368,-0.0293063821927 -"5174",6.16502073107827,42.8947368421053,30.2631578947368,-0.0253732845395894 -"5175",8.02538101483936,42.8947368421053,30.2631578947368,-0.0219680048020985 -"5176",10.4471247126008,42.8947368421053,30.2631578947368,-0.0190197344503318 -"5177",13.5996552137305,42.8947368421053,30.2631578947368,-0.0164671434413959 -"5178",17.7034951740616,42.8947368421053,30.2631578947368,-0.0142571292103368 -"5179",23.045712295823,42.8947368421053,30.2631578947368,-0.0123437154633424 -"5180",30,42.8947368421053,30.2631578947368,-0.0106870962007377 -"5181",0.2,45,30.2631578947368,-0.0698516626180748 -"5182",0.260352117694686,45,30.2631578947368,-0.0698512124489822 -"5183",0.338916125940539,45,30.2631578947368,-0.0698484591604732 -"5184",0.441187655547492,45,30.2631578947368,-0.0698316464659012 -"5185",0.574320702112717,45,30.2631578947368,-0.0697299654021453 -"5186",0.747628055154725,45,30.2631578947368,-0.0691482862260733 -"5187",0.973232737037462,45,30.2631578947368,-0.0665726433616539 -"5188",1.2669160204875,45,30.2631578947368,-0.0605088076536288 -"5189",1.64922134437622,45,30.2631578947368,-0.0530089538415748 -"5190",2.14689134777813,45,30.2631578947368,-0.0459913826091936 -"5191",2.79473854427218,45,30.2631578947368,-0.0398328980154159 -"5192",3.63808049202114,45,30.2631578947368,-0.0344889972089373 -"5193",4.73590980220715,45,30.2631578947368,-0.0298605942673635 -"5194",6.16502073107827,45,30.2631578947368,-0.025853117927868 -"5195",8.02538101483936,45,30.2631578947368,-0.0223834410520434 -"5196",10.4471247126008,45,30.2631578947368,-0.0193794160521057 -"5197",13.5996552137305,45,30.2631578947368,-0.0167785530746433 -"5198",17.7034951740616,45,30.2631578947368,-0.0145267453337617 -"5199",23.045712295823,45,30.2631578947368,-0.0125771470793983 -"5200",30,45,30.2631578947368,-0.0108891995418664 -"5201",0.2,5,32.3684210526316,NA -"5202",0.260352117694686,5,32.3684210526316,NA -"5203",0.338916125940539,5,32.3684210526316,NA -"5204",0.441187655547492,5,32.3684210526316,NA -"5205",0.574320702112717,5,32.3684210526316,NA -"5206",0.747628055154725,5,32.3684210526316,NA -"5207",0.973232737037462,5,32.3684210526316,NA -"5208",1.2669160204875,5,32.3684210526316,NA -"5209",1.64922134437622,5,32.3684210526316,NA -"5210",2.14689134777813,5,32.3684210526316,NA -"5211",2.79473854427218,5,32.3684210526316,NA -"5212",3.63808049202114,5,32.3684210526316,NA -"5213",4.73590980220715,5,32.3684210526316,NA -"5214",6.16502073107827,5,32.3684210526316,NA -"5215",8.02538101483936,5,32.3684210526316,NA -"5216",10.4471247126008,5,32.3684210526316,NA -"5217",13.5996552137305,5,32.3684210526316,NA -"5218",17.7034951740616,5,32.3684210526316,NA -"5219",23.045712295823,5,32.3684210526316,NA -"5220",30,5,32.3684210526316,NA -"5221",0.2,7.10526315789474,32.3684210526316,NA -"5222",0.260352117694686,7.10526315789474,32.3684210526316,NA -"5223",0.338916125940539,7.10526315789474,32.3684210526316,NA -"5224",0.441187655547492,7.10526315789474,32.3684210526316,NA -"5225",0.574320702112717,7.10526315789474,32.3684210526316,NA -"5226",0.747628055154725,7.10526315789474,32.3684210526316,NA -"5227",0.973232737037462,7.10526315789474,32.3684210526316,NA -"5228",1.2669160204875,7.10526315789474,32.3684210526316,NA -"5229",1.64922134437622,7.10526315789474,32.3684210526316,NA -"5230",2.14689134777813,7.10526315789474,32.3684210526316,NA -"5231",2.79473854427218,7.10526315789474,32.3684210526316,NA -"5232",3.63808049202114,7.10526315789474,32.3684210526316,NA -"5233",4.73590980220715,7.10526315789474,32.3684210526316,NA -"5234",6.16502073107827,7.10526315789474,32.3684210526316,NA -"5235",8.02538101483936,7.10526315789474,32.3684210526316,NA -"5236",10.4471247126008,7.10526315789474,32.3684210526316,NA -"5237",13.5996552137305,7.10526315789474,32.3684210526316,NA -"5238",17.7034951740616,7.10526315789474,32.3684210526316,NA -"5239",23.045712295823,7.10526315789474,32.3684210526316,NA -"5240",30,7.10526315789474,32.3684210526316,NA -"5241",0.2,9.21052631578947,32.3684210526316,NA -"5242",0.260352117694686,9.21052631578947,32.3684210526316,NA -"5243",0.338916125940539,9.21052631578947,32.3684210526316,NA -"5244",0.441187655547492,9.21052631578947,32.3684210526316,NA -"5245",0.574320702112717,9.21052631578947,32.3684210526316,NA -"5246",0.747628055154725,9.21052631578947,32.3684210526316,NA -"5247",0.973232737037462,9.21052631578947,32.3684210526316,NA -"5248",1.2669160204875,9.21052631578947,32.3684210526316,NA -"5249",1.64922134437622,9.21052631578947,32.3684210526316,NA -"5250",2.14689134777813,9.21052631578947,32.3684210526316,NA -"5251",2.79473854427218,9.21052631578947,32.3684210526316,NA -"5252",3.63808049202114,9.21052631578947,32.3684210526316,NA -"5253",4.73590980220715,9.21052631578947,32.3684210526316,NA -"5254",6.16502073107827,9.21052631578947,32.3684210526316,NA -"5255",8.02538101483936,9.21052631578947,32.3684210526316,NA -"5256",10.4471247126008,9.21052631578947,32.3684210526316,NA -"5257",13.5996552137305,9.21052631578947,32.3684210526316,NA -"5258",17.7034951740616,9.21052631578947,32.3684210526316,NA -"5259",23.045712295823,9.21052631578947,32.3684210526316,NA -"5260",30,9.21052631578947,32.3684210526316,NA -"5261",0.2,11.3157894736842,32.3684210526316,NA -"5262",0.260352117694686,11.3157894736842,32.3684210526316,NA -"5263",0.338916125940539,11.3157894736842,32.3684210526316,NA -"5264",0.441187655547492,11.3157894736842,32.3684210526316,NA -"5265",0.574320702112717,11.3157894736842,32.3684210526316,NA -"5266",0.747628055154725,11.3157894736842,32.3684210526316,NA -"5267",0.973232737037462,11.3157894736842,32.3684210526316,NA -"5268",1.2669160204875,11.3157894736842,32.3684210526316,NA -"5269",1.64922134437622,11.3157894736842,32.3684210526316,NA -"5270",2.14689134777813,11.3157894736842,32.3684210526316,NA -"5271",2.79473854427218,11.3157894736842,32.3684210526316,NA -"5272",3.63808049202114,11.3157894736842,32.3684210526316,NA -"5273",4.73590980220715,11.3157894736842,32.3684210526316,NA -"5274",6.16502073107827,11.3157894736842,32.3684210526316,NA -"5275",8.02538101483936,11.3157894736842,32.3684210526316,NA -"5276",10.4471247126008,11.3157894736842,32.3684210526316,NA -"5277",13.5996552137305,11.3157894736842,32.3684210526316,NA -"5278",17.7034951740616,11.3157894736842,32.3684210526316,NA -"5279",23.045712295823,11.3157894736842,32.3684210526316,NA -"5280",30,11.3157894736842,32.3684210526316,NA -"5281",0.2,13.4210526315789,32.3684210526316,NA -"5282",0.260352117694686,13.4210526315789,32.3684210526316,NA -"5283",0.338916125940539,13.4210526315789,32.3684210526316,NA -"5284",0.441187655547492,13.4210526315789,32.3684210526316,NA -"5285",0.574320702112717,13.4210526315789,32.3684210526316,NA -"5286",0.747628055154725,13.4210526315789,32.3684210526316,NA -"5287",0.973232737037462,13.4210526315789,32.3684210526316,NA -"5288",1.2669160204875,13.4210526315789,32.3684210526316,NA -"5289",1.64922134437622,13.4210526315789,32.3684210526316,NA -"5290",2.14689134777813,13.4210526315789,32.3684210526316,NA -"5291",2.79473854427218,13.4210526315789,32.3684210526316,NA -"5292",3.63808049202114,13.4210526315789,32.3684210526316,NA -"5293",4.73590980220715,13.4210526315789,32.3684210526316,NA -"5294",6.16502073107827,13.4210526315789,32.3684210526316,NA -"5295",8.02538101483936,13.4210526315789,32.3684210526316,NA -"5296",10.4471247126008,13.4210526315789,32.3684210526316,NA -"5297",13.5996552137305,13.4210526315789,32.3684210526316,NA -"5298",17.7034951740616,13.4210526315789,32.3684210526316,NA -"5299",23.045712295823,13.4210526315789,32.3684210526316,NA -"5300",30,13.4210526315789,32.3684210526316,NA -"5301",0.2,15.5263157894737,32.3684210526316,NA -"5302",0.260352117694686,15.5263157894737,32.3684210526316,NA -"5303",0.338916125940539,15.5263157894737,32.3684210526316,NA -"5304",0.441187655547492,15.5263157894737,32.3684210526316,NA -"5305",0.574320702112717,15.5263157894737,32.3684210526316,NA -"5306",0.747628055154725,15.5263157894737,32.3684210526316,NA -"5307",0.973232737037462,15.5263157894737,32.3684210526316,NA -"5308",1.2669160204875,15.5263157894737,32.3684210526316,NA -"5309",1.64922134437622,15.5263157894737,32.3684210526316,NA -"5310",2.14689134777813,15.5263157894737,32.3684210526316,NA -"5311",2.79473854427218,15.5263157894737,32.3684210526316,NA -"5312",3.63808049202114,15.5263157894737,32.3684210526316,NA -"5313",4.73590980220715,15.5263157894737,32.3684210526316,NA -"5314",6.16502073107827,15.5263157894737,32.3684210526316,NA -"5315",8.02538101483936,15.5263157894737,32.3684210526316,NA -"5316",10.4471247126008,15.5263157894737,32.3684210526316,NA -"5317",13.5996552137305,15.5263157894737,32.3684210526316,NA -"5318",17.7034951740616,15.5263157894737,32.3684210526316,NA -"5319",23.045712295823,15.5263157894737,32.3684210526316,NA -"5320",30,15.5263157894737,32.3684210526316,NA -"5321",0.2,17.6315789473684,32.3684210526316,NA -"5322",0.260352117694686,17.6315789473684,32.3684210526316,NA -"5323",0.338916125940539,17.6315789473684,32.3684210526316,NA -"5324",0.441187655547492,17.6315789473684,32.3684210526316,NA -"5325",0.574320702112717,17.6315789473684,32.3684210526316,NA -"5326",0.747628055154725,17.6315789473684,32.3684210526316,NA -"5327",0.973232737037462,17.6315789473684,32.3684210526316,NA -"5328",1.2669160204875,17.6315789473684,32.3684210526316,NA -"5329",1.64922134437622,17.6315789473684,32.3684210526316,NA -"5330",2.14689134777813,17.6315789473684,32.3684210526316,NA -"5331",2.79473854427218,17.6315789473684,32.3684210526316,NA -"5332",3.63808049202114,17.6315789473684,32.3684210526316,NA -"5333",4.73590980220715,17.6315789473684,32.3684210526316,NA -"5334",6.16502073107827,17.6315789473684,32.3684210526316,NA -"5335",8.02538101483936,17.6315789473684,32.3684210526316,NA -"5336",10.4471247126008,17.6315789473684,32.3684210526316,NA -"5337",13.5996552137305,17.6315789473684,32.3684210526316,NA -"5338",17.7034951740616,17.6315789473684,32.3684210526316,NA -"5339",23.045712295823,17.6315789473684,32.3684210526316,NA -"5340",30,17.6315789473684,32.3684210526316,NA -"5341",0.2,19.7368421052632,32.3684210526316,NA -"5342",0.260352117694686,19.7368421052632,32.3684210526316,NA -"5343",0.338916125940539,19.7368421052632,32.3684210526316,NA -"5344",0.441187655547492,19.7368421052632,32.3684210526316,NA -"5345",0.574320702112717,19.7368421052632,32.3684210526316,NA -"5346",0.747628055154725,19.7368421052632,32.3684210526316,NA -"5347",0.973232737037462,19.7368421052632,32.3684210526316,NA -"5348",1.2669160204875,19.7368421052632,32.3684210526316,NA -"5349",1.64922134437622,19.7368421052632,32.3684210526316,NA -"5350",2.14689134777813,19.7368421052632,32.3684210526316,NA -"5351",2.79473854427218,19.7368421052632,32.3684210526316,NA -"5352",3.63808049202114,19.7368421052632,32.3684210526316,NA -"5353",4.73590980220715,19.7368421052632,32.3684210526316,NA -"5354",6.16502073107827,19.7368421052632,32.3684210526316,NA -"5355",8.02538101483936,19.7368421052632,32.3684210526316,NA -"5356",10.4471247126008,19.7368421052632,32.3684210526316,NA -"5357",13.5996552137305,19.7368421052632,32.3684210526316,NA -"5358",17.7034951740616,19.7368421052632,32.3684210526316,NA -"5359",23.045712295823,19.7368421052632,32.3684210526316,NA -"5360",30,19.7368421052632,32.3684210526316,NA -"5361",0.2,21.8421052631579,32.3684210526316,NA -"5362",0.260352117694686,21.8421052631579,32.3684210526316,NA -"5363",0.338916125940539,21.8421052631579,32.3684210526316,NA -"5364",0.441187655547492,21.8421052631579,32.3684210526316,NA -"5365",0.574320702112717,21.8421052631579,32.3684210526316,NA -"5366",0.747628055154725,21.8421052631579,32.3684210526316,NA -"5367",0.973232737037462,21.8421052631579,32.3684210526316,NA -"5368",1.2669160204875,21.8421052631579,32.3684210526316,NA -"5369",1.64922134437622,21.8421052631579,32.3684210526316,NA -"5370",2.14689134777813,21.8421052631579,32.3684210526316,NA -"5371",2.79473854427218,21.8421052631579,32.3684210526316,NA -"5372",3.63808049202114,21.8421052631579,32.3684210526316,NA -"5373",4.73590980220715,21.8421052631579,32.3684210526316,NA -"5374",6.16502073107827,21.8421052631579,32.3684210526316,NA -"5375",8.02538101483936,21.8421052631579,32.3684210526316,NA -"5376",10.4471247126008,21.8421052631579,32.3684210526316,NA -"5377",13.5996552137305,21.8421052631579,32.3684210526316,NA -"5378",17.7034951740616,21.8421052631579,32.3684210526316,NA -"5379",23.045712295823,21.8421052631579,32.3684210526316,NA -"5380",30,21.8421052631579,32.3684210526316,NA -"5381",0.2,23.9473684210526,32.3684210526316,NA -"5382",0.260352117694686,23.9473684210526,32.3684210526316,NA -"5383",0.338916125940539,23.9473684210526,32.3684210526316,NA -"5384",0.441187655547492,23.9473684210526,32.3684210526316,NA -"5385",0.574320702112717,23.9473684210526,32.3684210526316,NA -"5386",0.747628055154725,23.9473684210526,32.3684210526316,NA -"5387",0.973232737037462,23.9473684210526,32.3684210526316,NA -"5388",1.2669160204875,23.9473684210526,32.3684210526316,NA -"5389",1.64922134437622,23.9473684210526,32.3684210526316,NA -"5390",2.14689134777813,23.9473684210526,32.3684210526316,NA -"5391",2.79473854427218,23.9473684210526,32.3684210526316,NA -"5392",3.63808049202114,23.9473684210526,32.3684210526316,NA -"5393",4.73590980220715,23.9473684210526,32.3684210526316,NA -"5394",6.16502073107827,23.9473684210526,32.3684210526316,NA -"5395",8.02538101483936,23.9473684210526,32.3684210526316,NA -"5396",10.4471247126008,23.9473684210526,32.3684210526316,NA -"5397",13.5996552137305,23.9473684210526,32.3684210526316,NA -"5398",17.7034951740616,23.9473684210526,32.3684210526316,NA -"5399",23.045712295823,23.9473684210526,32.3684210526316,NA -"5400",30,23.9473684210526,32.3684210526316,NA -"5401",0.2,26.0526315789474,32.3684210526316,NA -"5402",0.260352117694686,26.0526315789474,32.3684210526316,NA -"5403",0.338916125940539,26.0526315789474,32.3684210526316,NA -"5404",0.441187655547492,26.0526315789474,32.3684210526316,NA -"5405",0.574320702112717,26.0526315789474,32.3684210526316,NA -"5406",0.747628055154725,26.0526315789474,32.3684210526316,NA -"5407",0.973232737037462,26.0526315789474,32.3684210526316,NA -"5408",1.2669160204875,26.0526315789474,32.3684210526316,NA -"5409",1.64922134437622,26.0526315789474,32.3684210526316,NA -"5410",2.14689134777813,26.0526315789474,32.3684210526316,NA -"5411",2.79473854427218,26.0526315789474,32.3684210526316,NA -"5412",3.63808049202114,26.0526315789474,32.3684210526316,NA -"5413",4.73590980220715,26.0526315789474,32.3684210526316,NA -"5414",6.16502073107827,26.0526315789474,32.3684210526316,NA -"5415",8.02538101483936,26.0526315789474,32.3684210526316,NA -"5416",10.4471247126008,26.0526315789474,32.3684210526316,NA -"5417",13.5996552137305,26.0526315789474,32.3684210526316,NA -"5418",17.7034951740616,26.0526315789474,32.3684210526316,NA -"5419",23.045712295823,26.0526315789474,32.3684210526316,NA -"5420",30,26.0526315789474,32.3684210526316,NA -"5421",0.2,28.1578947368421,32.3684210526316,NA -"5422",0.260352117694686,28.1578947368421,32.3684210526316,NA -"5423",0.338916125940539,28.1578947368421,32.3684210526316,NA -"5424",0.441187655547492,28.1578947368421,32.3684210526316,NA -"5425",0.574320702112717,28.1578947368421,32.3684210526316,NA -"5426",0.747628055154725,28.1578947368421,32.3684210526316,NA -"5427",0.973232737037462,28.1578947368421,32.3684210526316,NA -"5428",1.2669160204875,28.1578947368421,32.3684210526316,NA -"5429",1.64922134437622,28.1578947368421,32.3684210526316,NA -"5430",2.14689134777813,28.1578947368421,32.3684210526316,NA -"5431",2.79473854427218,28.1578947368421,32.3684210526316,NA -"5432",3.63808049202114,28.1578947368421,32.3684210526316,NA -"5433",4.73590980220715,28.1578947368421,32.3684210526316,NA -"5434",6.16502073107827,28.1578947368421,32.3684210526316,NA -"5435",8.02538101483936,28.1578947368421,32.3684210526316,NA -"5436",10.4471247126008,28.1578947368421,32.3684210526316,NA -"5437",13.5996552137305,28.1578947368421,32.3684210526316,NA -"5438",17.7034951740616,28.1578947368421,32.3684210526316,NA -"5439",23.045712295823,28.1578947368421,32.3684210526316,NA -"5440",30,28.1578947368421,32.3684210526316,NA -"5441",0.2,30.2631578947368,32.3684210526316,NA -"5442",0.260352117694686,30.2631578947368,32.3684210526316,NA -"5443",0.338916125940539,30.2631578947368,32.3684210526316,NA -"5444",0.441187655547492,30.2631578947368,32.3684210526316,NA -"5445",0.574320702112717,30.2631578947368,32.3684210526316,NA -"5446",0.747628055154725,30.2631578947368,32.3684210526316,NA -"5447",0.973232737037462,30.2631578947368,32.3684210526316,NA -"5448",1.2669160204875,30.2631578947368,32.3684210526316,NA -"5449",1.64922134437622,30.2631578947368,32.3684210526316,NA -"5450",2.14689134777813,30.2631578947368,32.3684210526316,NA -"5451",2.79473854427218,30.2631578947368,32.3684210526316,NA -"5452",3.63808049202114,30.2631578947368,32.3684210526316,NA -"5453",4.73590980220715,30.2631578947368,32.3684210526316,NA -"5454",6.16502073107827,30.2631578947368,32.3684210526316,NA -"5455",8.02538101483936,30.2631578947368,32.3684210526316,NA -"5456",10.4471247126008,30.2631578947368,32.3684210526316,NA -"5457",13.5996552137305,30.2631578947368,32.3684210526316,NA -"5458",17.7034951740616,30.2631578947368,32.3684210526316,NA -"5459",23.045712295823,30.2631578947368,32.3684210526316,NA -"5460",30,30.2631578947368,32.3684210526316,NA -"5461",0.2,32.3684210526316,32.3684210526316,NA -"5462",0.260352117694686,32.3684210526316,32.3684210526316,NA -"5463",0.338916125940539,32.3684210526316,32.3684210526316,NA -"5464",0.441187655547492,32.3684210526316,32.3684210526316,NA -"5465",0.574320702112717,32.3684210526316,32.3684210526316,NA -"5466",0.747628055154725,32.3684210526316,32.3684210526316,NA -"5467",0.973232737037462,32.3684210526316,32.3684210526316,NA -"5468",1.2669160204875,32.3684210526316,32.3684210526316,NA -"5469",1.64922134437622,32.3684210526316,32.3684210526316,NA -"5470",2.14689134777813,32.3684210526316,32.3684210526316,NA -"5471",2.79473854427218,32.3684210526316,32.3684210526316,NA -"5472",3.63808049202114,32.3684210526316,32.3684210526316,NA -"5473",4.73590980220715,32.3684210526316,32.3684210526316,NA -"5474",6.16502073107827,32.3684210526316,32.3684210526316,NA -"5475",8.02538101483936,32.3684210526316,32.3684210526316,NA -"5476",10.4471247126008,32.3684210526316,32.3684210526316,NA -"5477",13.5996552137305,32.3684210526316,32.3684210526316,NA -"5478",17.7034951740616,32.3684210526316,32.3684210526316,NA -"5479",23.045712295823,32.3684210526316,32.3684210526316,NA -"5480",30,32.3684210526316,32.3684210526316,NA -"5481",0.2,34.4736842105263,32.3684210526316,NA -"5482",0.260352117694686,34.4736842105263,32.3684210526316,NA -"5483",0.338916125940539,34.4736842105263,32.3684210526316,NA -"5484",0.441187655547492,34.4736842105263,32.3684210526316,NA -"5485",0.574320702112717,34.4736842105263,32.3684210526316,NA -"5486",0.747628055154725,34.4736842105263,32.3684210526316,NA -"5487",0.973232737037462,34.4736842105263,32.3684210526316,NA -"5488",1.2669160204875,34.4736842105263,32.3684210526316,NA -"5489",1.64922134437622,34.4736842105263,32.3684210526316,NA -"5490",2.14689134777813,34.4736842105263,32.3684210526316,NA -"5491",2.79473854427218,34.4736842105263,32.3684210526316,NA -"5492",3.63808049202114,34.4736842105263,32.3684210526316,NA -"5493",4.73590980220715,34.4736842105263,32.3684210526316,NA -"5494",6.16502073107827,34.4736842105263,32.3684210526316,NA -"5495",8.02538101483936,34.4736842105263,32.3684210526316,NA -"5496",10.4471247126008,34.4736842105263,32.3684210526316,NA -"5497",13.5996552137305,34.4736842105263,32.3684210526316,NA -"5498",17.7034951740616,34.4736842105263,32.3684210526316,NA -"5499",23.045712295823,34.4736842105263,32.3684210526316,NA -"5500",30,34.4736842105263,32.3684210526316,NA -"5501",0.2,36.5789473684211,32.3684210526316,NA -"5502",0.260352117694686,36.5789473684211,32.3684210526316,NA -"5503",0.338916125940539,36.5789473684211,32.3684210526316,NA -"5504",0.441187655547492,36.5789473684211,32.3684210526316,NA -"5505",0.574320702112717,36.5789473684211,32.3684210526316,NA -"5506",0.747628055154725,36.5789473684211,32.3684210526316,NA -"5507",0.973232737037462,36.5789473684211,32.3684210526316,NA -"5508",1.2669160204875,36.5789473684211,32.3684210526316,NA -"5509",1.64922134437622,36.5789473684211,32.3684210526316,NA -"5510",2.14689134777813,36.5789473684211,32.3684210526316,NA -"5511",2.79473854427218,36.5789473684211,32.3684210526316,NA -"5512",3.63808049202114,36.5789473684211,32.3684210526316,NA -"5513",4.73590980220715,36.5789473684211,32.3684210526316,NA -"5514",6.16502073107827,36.5789473684211,32.3684210526316,NA -"5515",8.02538101483936,36.5789473684211,32.3684210526316,NA -"5516",10.4471247126008,36.5789473684211,32.3684210526316,NA -"5517",13.5996552137305,36.5789473684211,32.3684210526316,NA -"5518",17.7034951740616,36.5789473684211,32.3684210526316,NA -"5519",23.045712295823,36.5789473684211,32.3684210526316,NA -"5520",30,36.5789473684211,32.3684210526316,NA -"5521",0.2,38.6842105263158,32.3684210526316,NA -"5522",0.260352117694686,38.6842105263158,32.3684210526316,NA -"5523",0.338916125940539,38.6842105263158,32.3684210526316,NA -"5524",0.441187655547492,38.6842105263158,32.3684210526316,NA -"5525",0.574320702112717,38.6842105263158,32.3684210526316,NA -"5526",0.747628055154725,38.6842105263158,32.3684210526316,NA -"5527",0.973232737037462,38.6842105263158,32.3684210526316,NA -"5528",1.2669160204875,38.6842105263158,32.3684210526316,NA -"5529",1.64922134437622,38.6842105263158,32.3684210526316,NA -"5530",2.14689134777813,38.6842105263158,32.3684210526316,NA -"5531",2.79473854427218,38.6842105263158,32.3684210526316,NA -"5532",3.63808049202114,38.6842105263158,32.3684210526316,NA -"5533",4.73590980220715,38.6842105263158,32.3684210526316,NA -"5534",6.16502073107827,38.6842105263158,32.3684210526316,NA -"5535",8.02538101483936,38.6842105263158,32.3684210526316,NA -"5536",10.4471247126008,38.6842105263158,32.3684210526316,NA -"5537",13.5996552137305,38.6842105263158,32.3684210526316,NA -"5538",17.7034951740616,38.6842105263158,32.3684210526316,NA -"5539",23.045712295823,38.6842105263158,32.3684210526316,NA -"5540",30,38.6842105263158,32.3684210526316,NA -"5541",0.2,40.7894736842105,32.3684210526316,NA -"5542",0.260352117694686,40.7894736842105,32.3684210526316,NA -"5543",0.338916125940539,40.7894736842105,32.3684210526316,NA -"5544",0.441187655547492,40.7894736842105,32.3684210526316,NA -"5545",0.574320702112717,40.7894736842105,32.3684210526316,NA -"5546",0.747628055154725,40.7894736842105,32.3684210526316,NA -"5547",0.973232737037462,40.7894736842105,32.3684210526316,NA -"5548",1.2669160204875,40.7894736842105,32.3684210526316,NA -"5549",1.64922134437622,40.7894736842105,32.3684210526316,NA -"5550",2.14689134777813,40.7894736842105,32.3684210526316,NA -"5551",2.79473854427218,40.7894736842105,32.3684210526316,NA -"5552",3.63808049202114,40.7894736842105,32.3684210526316,NA -"5553",4.73590980220715,40.7894736842105,32.3684210526316,NA -"5554",6.16502073107827,40.7894736842105,32.3684210526316,NA -"5555",8.02538101483936,40.7894736842105,32.3684210526316,NA -"5556",10.4471247126008,40.7894736842105,32.3684210526316,NA -"5557",13.5996552137305,40.7894736842105,32.3684210526316,NA -"5558",17.7034951740616,40.7894736842105,32.3684210526316,NA -"5559",23.045712295823,40.7894736842105,32.3684210526316,NA -"5560",30,40.7894736842105,32.3684210526316,NA -"5561",0.2,42.8947368421053,32.3684210526316,NA -"5562",0.260352117694686,42.8947368421053,32.3684210526316,NA -"5563",0.338916125940539,42.8947368421053,32.3684210526316,NA -"5564",0.441187655547492,42.8947368421053,32.3684210526316,NA -"5565",0.574320702112717,42.8947368421053,32.3684210526316,NA -"5566",0.747628055154725,42.8947368421053,32.3684210526316,NA -"5567",0.973232737037462,42.8947368421053,32.3684210526316,NA -"5568",1.2669160204875,42.8947368421053,32.3684210526316,NA -"5569",1.64922134437622,42.8947368421053,32.3684210526316,NA -"5570",2.14689134777813,42.8947368421053,32.3684210526316,NA -"5571",2.79473854427218,42.8947368421053,32.3684210526316,NA -"5572",3.63808049202114,42.8947368421053,32.3684210526316,NA -"5573",4.73590980220715,42.8947368421053,32.3684210526316,NA -"5574",6.16502073107827,42.8947368421053,32.3684210526316,NA -"5575",8.02538101483936,42.8947368421053,32.3684210526316,NA -"5576",10.4471247126008,42.8947368421053,32.3684210526316,NA -"5577",13.5996552137305,42.8947368421053,32.3684210526316,NA -"5578",17.7034951740616,42.8947368421053,32.3684210526316,NA -"5579",23.045712295823,42.8947368421053,32.3684210526316,NA -"5580",30,42.8947368421053,32.3684210526316,NA -"5581",0.2,45,32.3684210526316,NA -"5582",0.260352117694686,45,32.3684210526316,NA -"5583",0.338916125940539,45,32.3684210526316,NA -"5584",0.441187655547492,45,32.3684210526316,NA -"5585",0.574320702112717,45,32.3684210526316,NA -"5586",0.747628055154725,45,32.3684210526316,NA -"5587",0.973232737037462,45,32.3684210526316,NA -"5588",1.2669160204875,45,32.3684210526316,NA -"5589",1.64922134437622,45,32.3684210526316,NA -"5590",2.14689134777813,45,32.3684210526316,NA -"5591",2.79473854427218,45,32.3684210526316,NA -"5592",3.63808049202114,45,32.3684210526316,NA -"5593",4.73590980220715,45,32.3684210526316,NA -"5594",6.16502073107827,45,32.3684210526316,NA -"5595",8.02538101483936,45,32.3684210526316,NA -"5596",10.4471247126008,45,32.3684210526316,NA -"5597",13.5996552137305,45,32.3684210526316,NA -"5598",17.7034951740616,45,32.3684210526316,NA -"5599",23.045712295823,45,32.3684210526316,NA -"5600",30,45,32.3684210526316,NA -"5601",0.2,5,34.4736842105263,NA -"5602",0.260352117694686,5,34.4736842105263,NA -"5603",0.338916125940539,5,34.4736842105263,NA -"5604",0.441187655547492,5,34.4736842105263,NA -"5605",0.574320702112717,5,34.4736842105263,NA -"5606",0.747628055154725,5,34.4736842105263,NA -"5607",0.973232737037462,5,34.4736842105263,NA -"5608",1.2669160204875,5,34.4736842105263,NA -"5609",1.64922134437622,5,34.4736842105263,NA -"5610",2.14689134777813,5,34.4736842105263,NA -"5611",2.79473854427218,5,34.4736842105263,NA -"5612",3.63808049202114,5,34.4736842105263,NA -"5613",4.73590980220715,5,34.4736842105263,NA -"5614",6.16502073107827,5,34.4736842105263,NA -"5615",8.02538101483936,5,34.4736842105263,NA -"5616",10.4471247126008,5,34.4736842105263,NA -"5617",13.5996552137305,5,34.4736842105263,NA -"5618",17.7034951740616,5,34.4736842105263,NA -"5619",23.045712295823,5,34.4736842105263,NA -"5620",30,5,34.4736842105263,NA -"5621",0.2,7.10526315789474,34.4736842105263,NA -"5622",0.260352117694686,7.10526315789474,34.4736842105263,NA -"5623",0.338916125940539,7.10526315789474,34.4736842105263,NA -"5624",0.441187655547492,7.10526315789474,34.4736842105263,NA -"5625",0.574320702112717,7.10526315789474,34.4736842105263,NA -"5626",0.747628055154725,7.10526315789474,34.4736842105263,NA -"5627",0.973232737037462,7.10526315789474,34.4736842105263,NA -"5628",1.2669160204875,7.10526315789474,34.4736842105263,NA -"5629",1.64922134437622,7.10526315789474,34.4736842105263,NA -"5630",2.14689134777813,7.10526315789474,34.4736842105263,NA -"5631",2.79473854427218,7.10526315789474,34.4736842105263,NA -"5632",3.63808049202114,7.10526315789474,34.4736842105263,NA -"5633",4.73590980220715,7.10526315789474,34.4736842105263,NA -"5634",6.16502073107827,7.10526315789474,34.4736842105263,NA -"5635",8.02538101483936,7.10526315789474,34.4736842105263,NA -"5636",10.4471247126008,7.10526315789474,34.4736842105263,NA -"5637",13.5996552137305,7.10526315789474,34.4736842105263,NA -"5638",17.7034951740616,7.10526315789474,34.4736842105263,NA -"5639",23.045712295823,7.10526315789474,34.4736842105263,NA -"5640",30,7.10526315789474,34.4736842105263,NA -"5641",0.2,9.21052631578947,34.4736842105263,NA -"5642",0.260352117694686,9.21052631578947,34.4736842105263,NA -"5643",0.338916125940539,9.21052631578947,34.4736842105263,NA -"5644",0.441187655547492,9.21052631578947,34.4736842105263,NA -"5645",0.574320702112717,9.21052631578947,34.4736842105263,NA -"5646",0.747628055154725,9.21052631578947,34.4736842105263,NA -"5647",0.973232737037462,9.21052631578947,34.4736842105263,NA -"5648",1.2669160204875,9.21052631578947,34.4736842105263,NA -"5649",1.64922134437622,9.21052631578947,34.4736842105263,NA -"5650",2.14689134777813,9.21052631578947,34.4736842105263,NA -"5651",2.79473854427218,9.21052631578947,34.4736842105263,NA -"5652",3.63808049202114,9.21052631578947,34.4736842105263,NA -"5653",4.73590980220715,9.21052631578947,34.4736842105263,NA -"5654",6.16502073107827,9.21052631578947,34.4736842105263,NA -"5655",8.02538101483936,9.21052631578947,34.4736842105263,NA -"5656",10.4471247126008,9.21052631578947,34.4736842105263,NA -"5657",13.5996552137305,9.21052631578947,34.4736842105263,NA -"5658",17.7034951740616,9.21052631578947,34.4736842105263,NA -"5659",23.045712295823,9.21052631578947,34.4736842105263,NA -"5660",30,9.21052631578947,34.4736842105263,NA -"5661",0.2,11.3157894736842,34.4736842105263,NA -"5662",0.260352117694686,11.3157894736842,34.4736842105263,NA -"5663",0.338916125940539,11.3157894736842,34.4736842105263,NA -"5664",0.441187655547492,11.3157894736842,34.4736842105263,NA -"5665",0.574320702112717,11.3157894736842,34.4736842105263,NA -"5666",0.747628055154725,11.3157894736842,34.4736842105263,NA -"5667",0.973232737037462,11.3157894736842,34.4736842105263,NA -"5668",1.2669160204875,11.3157894736842,34.4736842105263,NA -"5669",1.64922134437622,11.3157894736842,34.4736842105263,NA -"5670",2.14689134777813,11.3157894736842,34.4736842105263,NA -"5671",2.79473854427218,11.3157894736842,34.4736842105263,NA -"5672",3.63808049202114,11.3157894736842,34.4736842105263,NA -"5673",4.73590980220715,11.3157894736842,34.4736842105263,NA -"5674",6.16502073107827,11.3157894736842,34.4736842105263,NA -"5675",8.02538101483936,11.3157894736842,34.4736842105263,NA -"5676",10.4471247126008,11.3157894736842,34.4736842105263,NA -"5677",13.5996552137305,11.3157894736842,34.4736842105263,NA -"5678",17.7034951740616,11.3157894736842,34.4736842105263,NA -"5679",23.045712295823,11.3157894736842,34.4736842105263,NA -"5680",30,11.3157894736842,34.4736842105263,NA -"5681",0.2,13.4210526315789,34.4736842105263,NA -"5682",0.260352117694686,13.4210526315789,34.4736842105263,NA -"5683",0.338916125940539,13.4210526315789,34.4736842105263,NA -"5684",0.441187655547492,13.4210526315789,34.4736842105263,NA -"5685",0.574320702112717,13.4210526315789,34.4736842105263,NA -"5686",0.747628055154725,13.4210526315789,34.4736842105263,NA -"5687",0.973232737037462,13.4210526315789,34.4736842105263,NA -"5688",1.2669160204875,13.4210526315789,34.4736842105263,NA -"5689",1.64922134437622,13.4210526315789,34.4736842105263,NA -"5690",2.14689134777813,13.4210526315789,34.4736842105263,NA -"5691",2.79473854427218,13.4210526315789,34.4736842105263,NA -"5692",3.63808049202114,13.4210526315789,34.4736842105263,NA -"5693",4.73590980220715,13.4210526315789,34.4736842105263,NA -"5694",6.16502073107827,13.4210526315789,34.4736842105263,NA -"5695",8.02538101483936,13.4210526315789,34.4736842105263,NA -"5696",10.4471247126008,13.4210526315789,34.4736842105263,NA -"5697",13.5996552137305,13.4210526315789,34.4736842105263,NA -"5698",17.7034951740616,13.4210526315789,34.4736842105263,NA -"5699",23.045712295823,13.4210526315789,34.4736842105263,NA -"5700",30,13.4210526315789,34.4736842105263,NA -"5701",0.2,15.5263157894737,34.4736842105263,NA -"5702",0.260352117694686,15.5263157894737,34.4736842105263,NA -"5703",0.338916125940539,15.5263157894737,34.4736842105263,NA -"5704",0.441187655547492,15.5263157894737,34.4736842105263,NA -"5705",0.574320702112717,15.5263157894737,34.4736842105263,NA -"5706",0.747628055154725,15.5263157894737,34.4736842105263,NA -"5707",0.973232737037462,15.5263157894737,34.4736842105263,NA -"5708",1.2669160204875,15.5263157894737,34.4736842105263,NA -"5709",1.64922134437622,15.5263157894737,34.4736842105263,NA -"5710",2.14689134777813,15.5263157894737,34.4736842105263,NA -"5711",2.79473854427218,15.5263157894737,34.4736842105263,NA -"5712",3.63808049202114,15.5263157894737,34.4736842105263,NA -"5713",4.73590980220715,15.5263157894737,34.4736842105263,NA -"5714",6.16502073107827,15.5263157894737,34.4736842105263,NA -"5715",8.02538101483936,15.5263157894737,34.4736842105263,NA -"5716",10.4471247126008,15.5263157894737,34.4736842105263,NA -"5717",13.5996552137305,15.5263157894737,34.4736842105263,NA -"5718",17.7034951740616,15.5263157894737,34.4736842105263,NA -"5719",23.045712295823,15.5263157894737,34.4736842105263,NA -"5720",30,15.5263157894737,34.4736842105263,NA -"5721",0.2,17.6315789473684,34.4736842105263,NA -"5722",0.260352117694686,17.6315789473684,34.4736842105263,NA -"5723",0.338916125940539,17.6315789473684,34.4736842105263,NA -"5724",0.441187655547492,17.6315789473684,34.4736842105263,NA -"5725",0.574320702112717,17.6315789473684,34.4736842105263,NA -"5726",0.747628055154725,17.6315789473684,34.4736842105263,NA -"5727",0.973232737037462,17.6315789473684,34.4736842105263,NA -"5728",1.2669160204875,17.6315789473684,34.4736842105263,NA -"5729",1.64922134437622,17.6315789473684,34.4736842105263,NA -"5730",2.14689134777813,17.6315789473684,34.4736842105263,NA -"5731",2.79473854427218,17.6315789473684,34.4736842105263,NA -"5732",3.63808049202114,17.6315789473684,34.4736842105263,NA -"5733",4.73590980220715,17.6315789473684,34.4736842105263,NA -"5734",6.16502073107827,17.6315789473684,34.4736842105263,NA -"5735",8.02538101483936,17.6315789473684,34.4736842105263,NA -"5736",10.4471247126008,17.6315789473684,34.4736842105263,NA -"5737",13.5996552137305,17.6315789473684,34.4736842105263,NA -"5738",17.7034951740616,17.6315789473684,34.4736842105263,NA -"5739",23.045712295823,17.6315789473684,34.4736842105263,NA -"5740",30,17.6315789473684,34.4736842105263,NA -"5741",0.2,19.7368421052632,34.4736842105263,NA -"5742",0.260352117694686,19.7368421052632,34.4736842105263,NA -"5743",0.338916125940539,19.7368421052632,34.4736842105263,NA -"5744",0.441187655547492,19.7368421052632,34.4736842105263,NA -"5745",0.574320702112717,19.7368421052632,34.4736842105263,NA -"5746",0.747628055154725,19.7368421052632,34.4736842105263,NA -"5747",0.973232737037462,19.7368421052632,34.4736842105263,NA -"5748",1.2669160204875,19.7368421052632,34.4736842105263,NA -"5749",1.64922134437622,19.7368421052632,34.4736842105263,NA -"5750",2.14689134777813,19.7368421052632,34.4736842105263,NA -"5751",2.79473854427218,19.7368421052632,34.4736842105263,NA -"5752",3.63808049202114,19.7368421052632,34.4736842105263,NA -"5753",4.73590980220715,19.7368421052632,34.4736842105263,NA -"5754",6.16502073107827,19.7368421052632,34.4736842105263,NA -"5755",8.02538101483936,19.7368421052632,34.4736842105263,NA -"5756",10.4471247126008,19.7368421052632,34.4736842105263,NA -"5757",13.5996552137305,19.7368421052632,34.4736842105263,NA -"5758",17.7034951740616,19.7368421052632,34.4736842105263,NA -"5759",23.045712295823,19.7368421052632,34.4736842105263,NA -"5760",30,19.7368421052632,34.4736842105263,NA -"5761",0.2,21.8421052631579,34.4736842105263,NA -"5762",0.260352117694686,21.8421052631579,34.4736842105263,NA -"5763",0.338916125940539,21.8421052631579,34.4736842105263,NA -"5764",0.441187655547492,21.8421052631579,34.4736842105263,NA -"5765",0.574320702112717,21.8421052631579,34.4736842105263,NA -"5766",0.747628055154725,21.8421052631579,34.4736842105263,NA -"5767",0.973232737037462,21.8421052631579,34.4736842105263,NA -"5768",1.2669160204875,21.8421052631579,34.4736842105263,NA -"5769",1.64922134437622,21.8421052631579,34.4736842105263,NA -"5770",2.14689134777813,21.8421052631579,34.4736842105263,NA -"5771",2.79473854427218,21.8421052631579,34.4736842105263,NA -"5772",3.63808049202114,21.8421052631579,34.4736842105263,NA -"5773",4.73590980220715,21.8421052631579,34.4736842105263,NA -"5774",6.16502073107827,21.8421052631579,34.4736842105263,NA -"5775",8.02538101483936,21.8421052631579,34.4736842105263,NA -"5776",10.4471247126008,21.8421052631579,34.4736842105263,NA -"5777",13.5996552137305,21.8421052631579,34.4736842105263,NA -"5778",17.7034951740616,21.8421052631579,34.4736842105263,NA -"5779",23.045712295823,21.8421052631579,34.4736842105263,NA -"5780",30,21.8421052631579,34.4736842105263,NA -"5781",0.2,23.9473684210526,34.4736842105263,NA -"5782",0.260352117694686,23.9473684210526,34.4736842105263,NA -"5783",0.338916125940539,23.9473684210526,34.4736842105263,NA -"5784",0.441187655547492,23.9473684210526,34.4736842105263,NA -"5785",0.574320702112717,23.9473684210526,34.4736842105263,NA -"5786",0.747628055154725,23.9473684210526,34.4736842105263,NA -"5787",0.973232737037462,23.9473684210526,34.4736842105263,NA -"5788",1.2669160204875,23.9473684210526,34.4736842105263,NA -"5789",1.64922134437622,23.9473684210526,34.4736842105263,NA -"5790",2.14689134777813,23.9473684210526,34.4736842105263,NA -"5791",2.79473854427218,23.9473684210526,34.4736842105263,NA -"5792",3.63808049202114,23.9473684210526,34.4736842105263,NA -"5793",4.73590980220715,23.9473684210526,34.4736842105263,NA -"5794",6.16502073107827,23.9473684210526,34.4736842105263,NA -"5795",8.02538101483936,23.9473684210526,34.4736842105263,NA -"5796",10.4471247126008,23.9473684210526,34.4736842105263,NA -"5797",13.5996552137305,23.9473684210526,34.4736842105263,NA -"5798",17.7034951740616,23.9473684210526,34.4736842105263,NA -"5799",23.045712295823,23.9473684210526,34.4736842105263,NA -"5800",30,23.9473684210526,34.4736842105263,NA -"5801",0.2,26.0526315789474,34.4736842105263,NA -"5802",0.260352117694686,26.0526315789474,34.4736842105263,NA -"5803",0.338916125940539,26.0526315789474,34.4736842105263,NA -"5804",0.441187655547492,26.0526315789474,34.4736842105263,NA -"5805",0.574320702112717,26.0526315789474,34.4736842105263,NA -"5806",0.747628055154725,26.0526315789474,34.4736842105263,NA -"5807",0.973232737037462,26.0526315789474,34.4736842105263,NA -"5808",1.2669160204875,26.0526315789474,34.4736842105263,NA -"5809",1.64922134437622,26.0526315789474,34.4736842105263,NA -"5810",2.14689134777813,26.0526315789474,34.4736842105263,NA -"5811",2.79473854427218,26.0526315789474,34.4736842105263,NA -"5812",3.63808049202114,26.0526315789474,34.4736842105263,NA -"5813",4.73590980220715,26.0526315789474,34.4736842105263,NA -"5814",6.16502073107827,26.0526315789474,34.4736842105263,NA -"5815",8.02538101483936,26.0526315789474,34.4736842105263,NA -"5816",10.4471247126008,26.0526315789474,34.4736842105263,NA -"5817",13.5996552137305,26.0526315789474,34.4736842105263,NA -"5818",17.7034951740616,26.0526315789474,34.4736842105263,NA -"5819",23.045712295823,26.0526315789474,34.4736842105263,NA -"5820",30,26.0526315789474,34.4736842105263,NA -"5821",0.2,28.1578947368421,34.4736842105263,NA -"5822",0.260352117694686,28.1578947368421,34.4736842105263,NA -"5823",0.338916125940539,28.1578947368421,34.4736842105263,NA -"5824",0.441187655547492,28.1578947368421,34.4736842105263,NA -"5825",0.574320702112717,28.1578947368421,34.4736842105263,NA -"5826",0.747628055154725,28.1578947368421,34.4736842105263,NA -"5827",0.973232737037462,28.1578947368421,34.4736842105263,NA -"5828",1.2669160204875,28.1578947368421,34.4736842105263,NA -"5829",1.64922134437622,28.1578947368421,34.4736842105263,NA -"5830",2.14689134777813,28.1578947368421,34.4736842105263,NA -"5831",2.79473854427218,28.1578947368421,34.4736842105263,NA -"5832",3.63808049202114,28.1578947368421,34.4736842105263,NA -"5833",4.73590980220715,28.1578947368421,34.4736842105263,NA -"5834",6.16502073107827,28.1578947368421,34.4736842105263,NA -"5835",8.02538101483936,28.1578947368421,34.4736842105263,NA -"5836",10.4471247126008,28.1578947368421,34.4736842105263,NA -"5837",13.5996552137305,28.1578947368421,34.4736842105263,NA -"5838",17.7034951740616,28.1578947368421,34.4736842105263,NA -"5839",23.045712295823,28.1578947368421,34.4736842105263,NA -"5840",30,28.1578947368421,34.4736842105263,NA -"5841",0.2,30.2631578947368,34.4736842105263,NA -"5842",0.260352117694686,30.2631578947368,34.4736842105263,NA -"5843",0.338916125940539,30.2631578947368,34.4736842105263,NA -"5844",0.441187655547492,30.2631578947368,34.4736842105263,NA -"5845",0.574320702112717,30.2631578947368,34.4736842105263,NA -"5846",0.747628055154725,30.2631578947368,34.4736842105263,NA -"5847",0.973232737037462,30.2631578947368,34.4736842105263,NA -"5848",1.2669160204875,30.2631578947368,34.4736842105263,NA -"5849",1.64922134437622,30.2631578947368,34.4736842105263,NA -"5850",2.14689134777813,30.2631578947368,34.4736842105263,NA -"5851",2.79473854427218,30.2631578947368,34.4736842105263,NA -"5852",3.63808049202114,30.2631578947368,34.4736842105263,NA -"5853",4.73590980220715,30.2631578947368,34.4736842105263,NA -"5854",6.16502073107827,30.2631578947368,34.4736842105263,NA -"5855",8.02538101483936,30.2631578947368,34.4736842105263,NA -"5856",10.4471247126008,30.2631578947368,34.4736842105263,NA -"5857",13.5996552137305,30.2631578947368,34.4736842105263,NA -"5858",17.7034951740616,30.2631578947368,34.4736842105263,NA -"5859",23.045712295823,30.2631578947368,34.4736842105263,NA -"5860",30,30.2631578947368,34.4736842105263,NA -"5861",0.2,32.3684210526316,34.4736842105263,NA -"5862",0.260352117694686,32.3684210526316,34.4736842105263,NA -"5863",0.338916125940539,32.3684210526316,34.4736842105263,NA -"5864",0.441187655547492,32.3684210526316,34.4736842105263,NA -"5865",0.574320702112717,32.3684210526316,34.4736842105263,NA -"5866",0.747628055154725,32.3684210526316,34.4736842105263,NA -"5867",0.973232737037462,32.3684210526316,34.4736842105263,NA -"5868",1.2669160204875,32.3684210526316,34.4736842105263,NA -"5869",1.64922134437622,32.3684210526316,34.4736842105263,NA -"5870",2.14689134777813,32.3684210526316,34.4736842105263,NA -"5871",2.79473854427218,32.3684210526316,34.4736842105263,NA -"5872",3.63808049202114,32.3684210526316,34.4736842105263,NA -"5873",4.73590980220715,32.3684210526316,34.4736842105263,NA -"5874",6.16502073107827,32.3684210526316,34.4736842105263,NA -"5875",8.02538101483936,32.3684210526316,34.4736842105263,NA -"5876",10.4471247126008,32.3684210526316,34.4736842105263,NA -"5877",13.5996552137305,32.3684210526316,34.4736842105263,NA -"5878",17.7034951740616,32.3684210526316,34.4736842105263,NA -"5879",23.045712295823,32.3684210526316,34.4736842105263,NA -"5880",30,32.3684210526316,34.4736842105263,NA -"5881",0.2,34.4736842105263,34.4736842105263,NA -"5882",0.260352117694686,34.4736842105263,34.4736842105263,NA -"5883",0.338916125940539,34.4736842105263,34.4736842105263,NA -"5884",0.441187655547492,34.4736842105263,34.4736842105263,NA -"5885",0.574320702112717,34.4736842105263,34.4736842105263,NA -"5886",0.747628055154725,34.4736842105263,34.4736842105263,NA -"5887",0.973232737037462,34.4736842105263,34.4736842105263,NA -"5888",1.2669160204875,34.4736842105263,34.4736842105263,NA -"5889",1.64922134437622,34.4736842105263,34.4736842105263,NA -"5890",2.14689134777813,34.4736842105263,34.4736842105263,NA -"5891",2.79473854427218,34.4736842105263,34.4736842105263,NA -"5892",3.63808049202114,34.4736842105263,34.4736842105263,NA -"5893",4.73590980220715,34.4736842105263,34.4736842105263,NA -"5894",6.16502073107827,34.4736842105263,34.4736842105263,NA -"5895",8.02538101483936,34.4736842105263,34.4736842105263,NA -"5896",10.4471247126008,34.4736842105263,34.4736842105263,NA -"5897",13.5996552137305,34.4736842105263,34.4736842105263,NA -"5898",17.7034951740616,34.4736842105263,34.4736842105263,NA -"5899",23.045712295823,34.4736842105263,34.4736842105263,NA -"5900",30,34.4736842105263,34.4736842105263,NA -"5901",0.2,36.5789473684211,34.4736842105263,NA -"5902",0.260352117694686,36.5789473684211,34.4736842105263,NA -"5903",0.338916125940539,36.5789473684211,34.4736842105263,NA -"5904",0.441187655547492,36.5789473684211,34.4736842105263,NA -"5905",0.574320702112717,36.5789473684211,34.4736842105263,NA -"5906",0.747628055154725,36.5789473684211,34.4736842105263,NA -"5907",0.973232737037462,36.5789473684211,34.4736842105263,NA -"5908",1.2669160204875,36.5789473684211,34.4736842105263,NA -"5909",1.64922134437622,36.5789473684211,34.4736842105263,NA -"5910",2.14689134777813,36.5789473684211,34.4736842105263,NA -"5911",2.79473854427218,36.5789473684211,34.4736842105263,NA -"5912",3.63808049202114,36.5789473684211,34.4736842105263,NA -"5913",4.73590980220715,36.5789473684211,34.4736842105263,NA -"5914",6.16502073107827,36.5789473684211,34.4736842105263,NA -"5915",8.02538101483936,36.5789473684211,34.4736842105263,NA -"5916",10.4471247126008,36.5789473684211,34.4736842105263,NA -"5917",13.5996552137305,36.5789473684211,34.4736842105263,NA -"5918",17.7034951740616,36.5789473684211,34.4736842105263,NA -"5919",23.045712295823,36.5789473684211,34.4736842105263,NA -"5920",30,36.5789473684211,34.4736842105263,NA -"5921",0.2,38.6842105263158,34.4736842105263,NA -"5922",0.260352117694686,38.6842105263158,34.4736842105263,NA -"5923",0.338916125940539,38.6842105263158,34.4736842105263,NA -"5924",0.441187655547492,38.6842105263158,34.4736842105263,NA -"5925",0.574320702112717,38.6842105263158,34.4736842105263,NA -"5926",0.747628055154725,38.6842105263158,34.4736842105263,NA -"5927",0.973232737037462,38.6842105263158,34.4736842105263,NA -"5928",1.2669160204875,38.6842105263158,34.4736842105263,NA -"5929",1.64922134437622,38.6842105263158,34.4736842105263,NA -"5930",2.14689134777813,38.6842105263158,34.4736842105263,NA -"5931",2.79473854427218,38.6842105263158,34.4736842105263,NA -"5932",3.63808049202114,38.6842105263158,34.4736842105263,NA -"5933",4.73590980220715,38.6842105263158,34.4736842105263,NA -"5934",6.16502073107827,38.6842105263158,34.4736842105263,NA -"5935",8.02538101483936,38.6842105263158,34.4736842105263,NA -"5936",10.4471247126008,38.6842105263158,34.4736842105263,NA -"5937",13.5996552137305,38.6842105263158,34.4736842105263,NA -"5938",17.7034951740616,38.6842105263158,34.4736842105263,NA -"5939",23.045712295823,38.6842105263158,34.4736842105263,NA -"5940",30,38.6842105263158,34.4736842105263,NA -"5941",0.2,40.7894736842105,34.4736842105263,NA -"5942",0.260352117694686,40.7894736842105,34.4736842105263,NA -"5943",0.338916125940539,40.7894736842105,34.4736842105263,NA -"5944",0.441187655547492,40.7894736842105,34.4736842105263,NA -"5945",0.574320702112717,40.7894736842105,34.4736842105263,NA -"5946",0.747628055154725,40.7894736842105,34.4736842105263,NA -"5947",0.973232737037462,40.7894736842105,34.4736842105263,NA -"5948",1.2669160204875,40.7894736842105,34.4736842105263,NA -"5949",1.64922134437622,40.7894736842105,34.4736842105263,NA -"5950",2.14689134777813,40.7894736842105,34.4736842105263,NA -"5951",2.79473854427218,40.7894736842105,34.4736842105263,NA -"5952",3.63808049202114,40.7894736842105,34.4736842105263,NA -"5953",4.73590980220715,40.7894736842105,34.4736842105263,NA -"5954",6.16502073107827,40.7894736842105,34.4736842105263,NA -"5955",8.02538101483936,40.7894736842105,34.4736842105263,NA -"5956",10.4471247126008,40.7894736842105,34.4736842105263,NA -"5957",13.5996552137305,40.7894736842105,34.4736842105263,NA -"5958",17.7034951740616,40.7894736842105,34.4736842105263,NA -"5959",23.045712295823,40.7894736842105,34.4736842105263,NA -"5960",30,40.7894736842105,34.4736842105263,NA -"5961",0.2,42.8947368421053,34.4736842105263,NA -"5962",0.260352117694686,42.8947368421053,34.4736842105263,NA -"5963",0.338916125940539,42.8947368421053,34.4736842105263,NA -"5964",0.441187655547492,42.8947368421053,34.4736842105263,NA -"5965",0.574320702112717,42.8947368421053,34.4736842105263,NA -"5966",0.747628055154725,42.8947368421053,34.4736842105263,NA -"5967",0.973232737037462,42.8947368421053,34.4736842105263,NA -"5968",1.2669160204875,42.8947368421053,34.4736842105263,NA -"5969",1.64922134437622,42.8947368421053,34.4736842105263,NA -"5970",2.14689134777813,42.8947368421053,34.4736842105263,NA -"5971",2.79473854427218,42.8947368421053,34.4736842105263,NA -"5972",3.63808049202114,42.8947368421053,34.4736842105263,NA -"5973",4.73590980220715,42.8947368421053,34.4736842105263,NA -"5974",6.16502073107827,42.8947368421053,34.4736842105263,NA -"5975",8.02538101483936,42.8947368421053,34.4736842105263,NA -"5976",10.4471247126008,42.8947368421053,34.4736842105263,NA -"5977",13.5996552137305,42.8947368421053,34.4736842105263,NA -"5978",17.7034951740616,42.8947368421053,34.4736842105263,NA -"5979",23.045712295823,42.8947368421053,34.4736842105263,NA -"5980",30,42.8947368421053,34.4736842105263,NA -"5981",0.2,45,34.4736842105263,NA -"5982",0.260352117694686,45,34.4736842105263,NA -"5983",0.338916125940539,45,34.4736842105263,NA -"5984",0.441187655547492,45,34.4736842105263,NA -"5985",0.574320702112717,45,34.4736842105263,NA -"5986",0.747628055154725,45,34.4736842105263,NA -"5987",0.973232737037462,45,34.4736842105263,NA -"5988",1.2669160204875,45,34.4736842105263,NA -"5989",1.64922134437622,45,34.4736842105263,NA -"5990",2.14689134777813,45,34.4736842105263,NA -"5991",2.79473854427218,45,34.4736842105263,NA -"5992",3.63808049202114,45,34.4736842105263,NA -"5993",4.73590980220715,45,34.4736842105263,NA -"5994",6.16502073107827,45,34.4736842105263,NA -"5995",8.02538101483936,45,34.4736842105263,NA -"5996",10.4471247126008,45,34.4736842105263,NA -"5997",13.5996552137305,45,34.4736842105263,NA -"5998",17.7034951740616,45,34.4736842105263,NA -"5999",23.045712295823,45,34.4736842105263,NA -"6000",30,45,34.4736842105263,NA -"6001",0.2,5,36.5789473684211,NA -"6002",0.260352117694686,5,36.5789473684211,NA -"6003",0.338916125940539,5,36.5789473684211,NA -"6004",0.441187655547492,5,36.5789473684211,NA -"6005",0.574320702112717,5,36.5789473684211,NA -"6006",0.747628055154725,5,36.5789473684211,NA -"6007",0.973232737037462,5,36.5789473684211,NA -"6008",1.2669160204875,5,36.5789473684211,NA -"6009",1.64922134437622,5,36.5789473684211,NA -"6010",2.14689134777813,5,36.5789473684211,NA -"6011",2.79473854427218,5,36.5789473684211,NA -"6012",3.63808049202114,5,36.5789473684211,NA -"6013",4.73590980220715,5,36.5789473684211,NA -"6014",6.16502073107827,5,36.5789473684211,NA -"6015",8.02538101483936,5,36.5789473684211,NA -"6016",10.4471247126008,5,36.5789473684211,NA -"6017",13.5996552137305,5,36.5789473684211,NA -"6018",17.7034951740616,5,36.5789473684211,NA -"6019",23.045712295823,5,36.5789473684211,NA -"6020",30,5,36.5789473684211,NA -"6021",0.2,7.10526315789474,36.5789473684211,NA -"6022",0.260352117694686,7.10526315789474,36.5789473684211,NA -"6023",0.338916125940539,7.10526315789474,36.5789473684211,NA -"6024",0.441187655547492,7.10526315789474,36.5789473684211,NA -"6025",0.574320702112717,7.10526315789474,36.5789473684211,NA -"6026",0.747628055154725,7.10526315789474,36.5789473684211,NA -"6027",0.973232737037462,7.10526315789474,36.5789473684211,NA -"6028",1.2669160204875,7.10526315789474,36.5789473684211,NA -"6029",1.64922134437622,7.10526315789474,36.5789473684211,NA -"6030",2.14689134777813,7.10526315789474,36.5789473684211,NA -"6031",2.79473854427218,7.10526315789474,36.5789473684211,NA -"6032",3.63808049202114,7.10526315789474,36.5789473684211,NA -"6033",4.73590980220715,7.10526315789474,36.5789473684211,NA -"6034",6.16502073107827,7.10526315789474,36.5789473684211,NA -"6035",8.02538101483936,7.10526315789474,36.5789473684211,NA -"6036",10.4471247126008,7.10526315789474,36.5789473684211,NA -"6037",13.5996552137305,7.10526315789474,36.5789473684211,NA -"6038",17.7034951740616,7.10526315789474,36.5789473684211,NA -"6039",23.045712295823,7.10526315789474,36.5789473684211,NA -"6040",30,7.10526315789474,36.5789473684211,NA -"6041",0.2,9.21052631578947,36.5789473684211,NA -"6042",0.260352117694686,9.21052631578947,36.5789473684211,NA -"6043",0.338916125940539,9.21052631578947,36.5789473684211,NA -"6044",0.441187655547492,9.21052631578947,36.5789473684211,NA -"6045",0.574320702112717,9.21052631578947,36.5789473684211,NA -"6046",0.747628055154725,9.21052631578947,36.5789473684211,NA -"6047",0.973232737037462,9.21052631578947,36.5789473684211,NA -"6048",1.2669160204875,9.21052631578947,36.5789473684211,NA -"6049",1.64922134437622,9.21052631578947,36.5789473684211,NA -"6050",2.14689134777813,9.21052631578947,36.5789473684211,NA -"6051",2.79473854427218,9.21052631578947,36.5789473684211,NA -"6052",3.63808049202114,9.21052631578947,36.5789473684211,NA -"6053",4.73590980220715,9.21052631578947,36.5789473684211,NA -"6054",6.16502073107827,9.21052631578947,36.5789473684211,NA -"6055",8.02538101483936,9.21052631578947,36.5789473684211,NA -"6056",10.4471247126008,9.21052631578947,36.5789473684211,NA -"6057",13.5996552137305,9.21052631578947,36.5789473684211,NA -"6058",17.7034951740616,9.21052631578947,36.5789473684211,NA -"6059",23.045712295823,9.21052631578947,36.5789473684211,NA -"6060",30,9.21052631578947,36.5789473684211,NA -"6061",0.2,11.3157894736842,36.5789473684211,NA -"6062",0.260352117694686,11.3157894736842,36.5789473684211,NA -"6063",0.338916125940539,11.3157894736842,36.5789473684211,NA -"6064",0.441187655547492,11.3157894736842,36.5789473684211,NA -"6065",0.574320702112717,11.3157894736842,36.5789473684211,NA -"6066",0.747628055154725,11.3157894736842,36.5789473684211,NA -"6067",0.973232737037462,11.3157894736842,36.5789473684211,NA -"6068",1.2669160204875,11.3157894736842,36.5789473684211,NA -"6069",1.64922134437622,11.3157894736842,36.5789473684211,NA -"6070",2.14689134777813,11.3157894736842,36.5789473684211,NA -"6071",2.79473854427218,11.3157894736842,36.5789473684211,NA -"6072",3.63808049202114,11.3157894736842,36.5789473684211,NA -"6073",4.73590980220715,11.3157894736842,36.5789473684211,NA -"6074",6.16502073107827,11.3157894736842,36.5789473684211,NA -"6075",8.02538101483936,11.3157894736842,36.5789473684211,NA -"6076",10.4471247126008,11.3157894736842,36.5789473684211,NA -"6077",13.5996552137305,11.3157894736842,36.5789473684211,NA -"6078",17.7034951740616,11.3157894736842,36.5789473684211,NA -"6079",23.045712295823,11.3157894736842,36.5789473684211,NA -"6080",30,11.3157894736842,36.5789473684211,NA -"6081",0.2,13.4210526315789,36.5789473684211,NA -"6082",0.260352117694686,13.4210526315789,36.5789473684211,NA -"6083",0.338916125940539,13.4210526315789,36.5789473684211,NA -"6084",0.441187655547492,13.4210526315789,36.5789473684211,NA -"6085",0.574320702112717,13.4210526315789,36.5789473684211,NA -"6086",0.747628055154725,13.4210526315789,36.5789473684211,NA -"6087",0.973232737037462,13.4210526315789,36.5789473684211,NA -"6088",1.2669160204875,13.4210526315789,36.5789473684211,NA -"6089",1.64922134437622,13.4210526315789,36.5789473684211,NA -"6090",2.14689134777813,13.4210526315789,36.5789473684211,NA -"6091",2.79473854427218,13.4210526315789,36.5789473684211,NA -"6092",3.63808049202114,13.4210526315789,36.5789473684211,NA -"6093",4.73590980220715,13.4210526315789,36.5789473684211,NA -"6094",6.16502073107827,13.4210526315789,36.5789473684211,NA -"6095",8.02538101483936,13.4210526315789,36.5789473684211,NA -"6096",10.4471247126008,13.4210526315789,36.5789473684211,NA -"6097",13.5996552137305,13.4210526315789,36.5789473684211,NA -"6098",17.7034951740616,13.4210526315789,36.5789473684211,NA -"6099",23.045712295823,13.4210526315789,36.5789473684211,NA -"6100",30,13.4210526315789,36.5789473684211,NA -"6101",0.2,15.5263157894737,36.5789473684211,NA -"6102",0.260352117694686,15.5263157894737,36.5789473684211,NA -"6103",0.338916125940539,15.5263157894737,36.5789473684211,NA -"6104",0.441187655547492,15.5263157894737,36.5789473684211,NA -"6105",0.574320702112717,15.5263157894737,36.5789473684211,NA -"6106",0.747628055154725,15.5263157894737,36.5789473684211,NA -"6107",0.973232737037462,15.5263157894737,36.5789473684211,NA -"6108",1.2669160204875,15.5263157894737,36.5789473684211,NA -"6109",1.64922134437622,15.5263157894737,36.5789473684211,NA -"6110",2.14689134777813,15.5263157894737,36.5789473684211,NA -"6111",2.79473854427218,15.5263157894737,36.5789473684211,NA -"6112",3.63808049202114,15.5263157894737,36.5789473684211,NA -"6113",4.73590980220715,15.5263157894737,36.5789473684211,NA -"6114",6.16502073107827,15.5263157894737,36.5789473684211,NA -"6115",8.02538101483936,15.5263157894737,36.5789473684211,NA -"6116",10.4471247126008,15.5263157894737,36.5789473684211,NA -"6117",13.5996552137305,15.5263157894737,36.5789473684211,NA -"6118",17.7034951740616,15.5263157894737,36.5789473684211,NA -"6119",23.045712295823,15.5263157894737,36.5789473684211,NA -"6120",30,15.5263157894737,36.5789473684211,NA -"6121",0.2,17.6315789473684,36.5789473684211,NA -"6122",0.260352117694686,17.6315789473684,36.5789473684211,NA -"6123",0.338916125940539,17.6315789473684,36.5789473684211,NA -"6124",0.441187655547492,17.6315789473684,36.5789473684211,NA -"6125",0.574320702112717,17.6315789473684,36.5789473684211,NA -"6126",0.747628055154725,17.6315789473684,36.5789473684211,NA -"6127",0.973232737037462,17.6315789473684,36.5789473684211,NA -"6128",1.2669160204875,17.6315789473684,36.5789473684211,NA -"6129",1.64922134437622,17.6315789473684,36.5789473684211,NA -"6130",2.14689134777813,17.6315789473684,36.5789473684211,NA -"6131",2.79473854427218,17.6315789473684,36.5789473684211,NA -"6132",3.63808049202114,17.6315789473684,36.5789473684211,NA -"6133",4.73590980220715,17.6315789473684,36.5789473684211,NA -"6134",6.16502073107827,17.6315789473684,36.5789473684211,NA -"6135",8.02538101483936,17.6315789473684,36.5789473684211,NA -"6136",10.4471247126008,17.6315789473684,36.5789473684211,NA -"6137",13.5996552137305,17.6315789473684,36.5789473684211,NA -"6138",17.7034951740616,17.6315789473684,36.5789473684211,NA -"6139",23.045712295823,17.6315789473684,36.5789473684211,NA -"6140",30,17.6315789473684,36.5789473684211,NA -"6141",0.2,19.7368421052632,36.5789473684211,NA -"6142",0.260352117694686,19.7368421052632,36.5789473684211,NA -"6143",0.338916125940539,19.7368421052632,36.5789473684211,NA -"6144",0.441187655547492,19.7368421052632,36.5789473684211,NA -"6145",0.574320702112717,19.7368421052632,36.5789473684211,NA -"6146",0.747628055154725,19.7368421052632,36.5789473684211,NA -"6147",0.973232737037462,19.7368421052632,36.5789473684211,NA -"6148",1.2669160204875,19.7368421052632,36.5789473684211,NA -"6149",1.64922134437622,19.7368421052632,36.5789473684211,NA -"6150",2.14689134777813,19.7368421052632,36.5789473684211,NA -"6151",2.79473854427218,19.7368421052632,36.5789473684211,NA -"6152",3.63808049202114,19.7368421052632,36.5789473684211,NA -"6153",4.73590980220715,19.7368421052632,36.5789473684211,NA -"6154",6.16502073107827,19.7368421052632,36.5789473684211,NA -"6155",8.02538101483936,19.7368421052632,36.5789473684211,NA -"6156",10.4471247126008,19.7368421052632,36.5789473684211,NA -"6157",13.5996552137305,19.7368421052632,36.5789473684211,NA -"6158",17.7034951740616,19.7368421052632,36.5789473684211,NA -"6159",23.045712295823,19.7368421052632,36.5789473684211,NA -"6160",30,19.7368421052632,36.5789473684211,NA -"6161",0.2,21.8421052631579,36.5789473684211,NA -"6162",0.260352117694686,21.8421052631579,36.5789473684211,NA -"6163",0.338916125940539,21.8421052631579,36.5789473684211,NA -"6164",0.441187655547492,21.8421052631579,36.5789473684211,NA -"6165",0.574320702112717,21.8421052631579,36.5789473684211,NA -"6166",0.747628055154725,21.8421052631579,36.5789473684211,NA -"6167",0.973232737037462,21.8421052631579,36.5789473684211,NA -"6168",1.2669160204875,21.8421052631579,36.5789473684211,NA -"6169",1.64922134437622,21.8421052631579,36.5789473684211,NA -"6170",2.14689134777813,21.8421052631579,36.5789473684211,NA -"6171",2.79473854427218,21.8421052631579,36.5789473684211,NA -"6172",3.63808049202114,21.8421052631579,36.5789473684211,NA -"6173",4.73590980220715,21.8421052631579,36.5789473684211,NA -"6174",6.16502073107827,21.8421052631579,36.5789473684211,NA -"6175",8.02538101483936,21.8421052631579,36.5789473684211,NA -"6176",10.4471247126008,21.8421052631579,36.5789473684211,NA -"6177",13.5996552137305,21.8421052631579,36.5789473684211,NA -"6178",17.7034951740616,21.8421052631579,36.5789473684211,NA -"6179",23.045712295823,21.8421052631579,36.5789473684211,NA -"6180",30,21.8421052631579,36.5789473684211,NA -"6181",0.2,23.9473684210526,36.5789473684211,NA -"6182",0.260352117694686,23.9473684210526,36.5789473684211,NA -"6183",0.338916125940539,23.9473684210526,36.5789473684211,NA -"6184",0.441187655547492,23.9473684210526,36.5789473684211,NA -"6185",0.574320702112717,23.9473684210526,36.5789473684211,NA -"6186",0.747628055154725,23.9473684210526,36.5789473684211,NA -"6187",0.973232737037462,23.9473684210526,36.5789473684211,NA -"6188",1.2669160204875,23.9473684210526,36.5789473684211,NA -"6189",1.64922134437622,23.9473684210526,36.5789473684211,NA -"6190",2.14689134777813,23.9473684210526,36.5789473684211,NA -"6191",2.79473854427218,23.9473684210526,36.5789473684211,NA -"6192",3.63808049202114,23.9473684210526,36.5789473684211,NA -"6193",4.73590980220715,23.9473684210526,36.5789473684211,NA -"6194",6.16502073107827,23.9473684210526,36.5789473684211,NA -"6195",8.02538101483936,23.9473684210526,36.5789473684211,NA -"6196",10.4471247126008,23.9473684210526,36.5789473684211,NA -"6197",13.5996552137305,23.9473684210526,36.5789473684211,NA -"6198",17.7034951740616,23.9473684210526,36.5789473684211,NA -"6199",23.045712295823,23.9473684210526,36.5789473684211,NA -"6200",30,23.9473684210526,36.5789473684211,NA -"6201",0.2,26.0526315789474,36.5789473684211,NA -"6202",0.260352117694686,26.0526315789474,36.5789473684211,NA -"6203",0.338916125940539,26.0526315789474,36.5789473684211,NA -"6204",0.441187655547492,26.0526315789474,36.5789473684211,NA -"6205",0.574320702112717,26.0526315789474,36.5789473684211,NA -"6206",0.747628055154725,26.0526315789474,36.5789473684211,NA -"6207",0.973232737037462,26.0526315789474,36.5789473684211,NA -"6208",1.2669160204875,26.0526315789474,36.5789473684211,NA -"6209",1.64922134437622,26.0526315789474,36.5789473684211,NA -"6210",2.14689134777813,26.0526315789474,36.5789473684211,NA -"6211",2.79473854427218,26.0526315789474,36.5789473684211,NA -"6212",3.63808049202114,26.0526315789474,36.5789473684211,NA -"6213",4.73590980220715,26.0526315789474,36.5789473684211,NA -"6214",6.16502073107827,26.0526315789474,36.5789473684211,NA -"6215",8.02538101483936,26.0526315789474,36.5789473684211,NA -"6216",10.4471247126008,26.0526315789474,36.5789473684211,NA -"6217",13.5996552137305,26.0526315789474,36.5789473684211,NA -"6218",17.7034951740616,26.0526315789474,36.5789473684211,NA -"6219",23.045712295823,26.0526315789474,36.5789473684211,NA -"6220",30,26.0526315789474,36.5789473684211,NA -"6221",0.2,28.1578947368421,36.5789473684211,NA -"6222",0.260352117694686,28.1578947368421,36.5789473684211,NA -"6223",0.338916125940539,28.1578947368421,36.5789473684211,NA -"6224",0.441187655547492,28.1578947368421,36.5789473684211,NA -"6225",0.574320702112717,28.1578947368421,36.5789473684211,NA -"6226",0.747628055154725,28.1578947368421,36.5789473684211,NA -"6227",0.973232737037462,28.1578947368421,36.5789473684211,NA -"6228",1.2669160204875,28.1578947368421,36.5789473684211,NA -"6229",1.64922134437622,28.1578947368421,36.5789473684211,NA -"6230",2.14689134777813,28.1578947368421,36.5789473684211,NA -"6231",2.79473854427218,28.1578947368421,36.5789473684211,NA -"6232",3.63808049202114,28.1578947368421,36.5789473684211,NA -"6233",4.73590980220715,28.1578947368421,36.5789473684211,NA -"6234",6.16502073107827,28.1578947368421,36.5789473684211,NA -"6235",8.02538101483936,28.1578947368421,36.5789473684211,NA -"6236",10.4471247126008,28.1578947368421,36.5789473684211,NA -"6237",13.5996552137305,28.1578947368421,36.5789473684211,NA -"6238",17.7034951740616,28.1578947368421,36.5789473684211,NA -"6239",23.045712295823,28.1578947368421,36.5789473684211,NA -"6240",30,28.1578947368421,36.5789473684211,NA -"6241",0.2,30.2631578947368,36.5789473684211,NA -"6242",0.260352117694686,30.2631578947368,36.5789473684211,NA -"6243",0.338916125940539,30.2631578947368,36.5789473684211,NA -"6244",0.441187655547492,30.2631578947368,36.5789473684211,NA -"6245",0.574320702112717,30.2631578947368,36.5789473684211,NA -"6246",0.747628055154725,30.2631578947368,36.5789473684211,NA -"6247",0.973232737037462,30.2631578947368,36.5789473684211,NA -"6248",1.2669160204875,30.2631578947368,36.5789473684211,NA -"6249",1.64922134437622,30.2631578947368,36.5789473684211,NA -"6250",2.14689134777813,30.2631578947368,36.5789473684211,NA -"6251",2.79473854427218,30.2631578947368,36.5789473684211,NA -"6252",3.63808049202114,30.2631578947368,36.5789473684211,NA -"6253",4.73590980220715,30.2631578947368,36.5789473684211,NA -"6254",6.16502073107827,30.2631578947368,36.5789473684211,NA -"6255",8.02538101483936,30.2631578947368,36.5789473684211,NA -"6256",10.4471247126008,30.2631578947368,36.5789473684211,NA -"6257",13.5996552137305,30.2631578947368,36.5789473684211,NA -"6258",17.7034951740616,30.2631578947368,36.5789473684211,NA -"6259",23.045712295823,30.2631578947368,36.5789473684211,NA -"6260",30,30.2631578947368,36.5789473684211,NA -"6261",0.2,32.3684210526316,36.5789473684211,NA -"6262",0.260352117694686,32.3684210526316,36.5789473684211,NA -"6263",0.338916125940539,32.3684210526316,36.5789473684211,NA -"6264",0.441187655547492,32.3684210526316,36.5789473684211,NA -"6265",0.574320702112717,32.3684210526316,36.5789473684211,NA -"6266",0.747628055154725,32.3684210526316,36.5789473684211,NA -"6267",0.973232737037462,32.3684210526316,36.5789473684211,NA -"6268",1.2669160204875,32.3684210526316,36.5789473684211,NA -"6269",1.64922134437622,32.3684210526316,36.5789473684211,NA -"6270",2.14689134777813,32.3684210526316,36.5789473684211,NA -"6271",2.79473854427218,32.3684210526316,36.5789473684211,NA -"6272",3.63808049202114,32.3684210526316,36.5789473684211,NA -"6273",4.73590980220715,32.3684210526316,36.5789473684211,NA -"6274",6.16502073107827,32.3684210526316,36.5789473684211,NA -"6275",8.02538101483936,32.3684210526316,36.5789473684211,NA -"6276",10.4471247126008,32.3684210526316,36.5789473684211,NA -"6277",13.5996552137305,32.3684210526316,36.5789473684211,NA -"6278",17.7034951740616,32.3684210526316,36.5789473684211,NA -"6279",23.045712295823,32.3684210526316,36.5789473684211,NA -"6280",30,32.3684210526316,36.5789473684211,NA -"6281",0.2,34.4736842105263,36.5789473684211,NA -"6282",0.260352117694686,34.4736842105263,36.5789473684211,NA -"6283",0.338916125940539,34.4736842105263,36.5789473684211,NA -"6284",0.441187655547492,34.4736842105263,36.5789473684211,NA -"6285",0.574320702112717,34.4736842105263,36.5789473684211,NA -"6286",0.747628055154725,34.4736842105263,36.5789473684211,NA -"6287",0.973232737037462,34.4736842105263,36.5789473684211,NA -"6288",1.2669160204875,34.4736842105263,36.5789473684211,NA -"6289",1.64922134437622,34.4736842105263,36.5789473684211,NA -"6290",2.14689134777813,34.4736842105263,36.5789473684211,NA -"6291",2.79473854427218,34.4736842105263,36.5789473684211,NA -"6292",3.63808049202114,34.4736842105263,36.5789473684211,NA -"6293",4.73590980220715,34.4736842105263,36.5789473684211,NA -"6294",6.16502073107827,34.4736842105263,36.5789473684211,NA -"6295",8.02538101483936,34.4736842105263,36.5789473684211,NA -"6296",10.4471247126008,34.4736842105263,36.5789473684211,NA -"6297",13.5996552137305,34.4736842105263,36.5789473684211,NA -"6298",17.7034951740616,34.4736842105263,36.5789473684211,NA -"6299",23.045712295823,34.4736842105263,36.5789473684211,NA -"6300",30,34.4736842105263,36.5789473684211,NA -"6301",0.2,36.5789473684211,36.5789473684211,NA -"6302",0.260352117694686,36.5789473684211,36.5789473684211,NA -"6303",0.338916125940539,36.5789473684211,36.5789473684211,NA -"6304",0.441187655547492,36.5789473684211,36.5789473684211,NA -"6305",0.574320702112717,36.5789473684211,36.5789473684211,NA -"6306",0.747628055154725,36.5789473684211,36.5789473684211,NA -"6307",0.973232737037462,36.5789473684211,36.5789473684211,NA -"6308",1.2669160204875,36.5789473684211,36.5789473684211,NA -"6309",1.64922134437622,36.5789473684211,36.5789473684211,NA -"6310",2.14689134777813,36.5789473684211,36.5789473684211,NA -"6311",2.79473854427218,36.5789473684211,36.5789473684211,NA -"6312",3.63808049202114,36.5789473684211,36.5789473684211,NA -"6313",4.73590980220715,36.5789473684211,36.5789473684211,NA -"6314",6.16502073107827,36.5789473684211,36.5789473684211,NA -"6315",8.02538101483936,36.5789473684211,36.5789473684211,NA -"6316",10.4471247126008,36.5789473684211,36.5789473684211,NA -"6317",13.5996552137305,36.5789473684211,36.5789473684211,NA -"6318",17.7034951740616,36.5789473684211,36.5789473684211,NA -"6319",23.045712295823,36.5789473684211,36.5789473684211,NA -"6320",30,36.5789473684211,36.5789473684211,NA -"6321",0.2,38.6842105263158,36.5789473684211,NA -"6322",0.260352117694686,38.6842105263158,36.5789473684211,NA -"6323",0.338916125940539,38.6842105263158,36.5789473684211,NA -"6324",0.441187655547492,38.6842105263158,36.5789473684211,NA -"6325",0.574320702112717,38.6842105263158,36.5789473684211,NA -"6326",0.747628055154725,38.6842105263158,36.5789473684211,NA -"6327",0.973232737037462,38.6842105263158,36.5789473684211,NA -"6328",1.2669160204875,38.6842105263158,36.5789473684211,NA -"6329",1.64922134437622,38.6842105263158,36.5789473684211,NA -"6330",2.14689134777813,38.6842105263158,36.5789473684211,NA -"6331",2.79473854427218,38.6842105263158,36.5789473684211,NA -"6332",3.63808049202114,38.6842105263158,36.5789473684211,NA -"6333",4.73590980220715,38.6842105263158,36.5789473684211,NA -"6334",6.16502073107827,38.6842105263158,36.5789473684211,NA -"6335",8.02538101483936,38.6842105263158,36.5789473684211,NA -"6336",10.4471247126008,38.6842105263158,36.5789473684211,NA -"6337",13.5996552137305,38.6842105263158,36.5789473684211,NA -"6338",17.7034951740616,38.6842105263158,36.5789473684211,NA -"6339",23.045712295823,38.6842105263158,36.5789473684211,NA -"6340",30,38.6842105263158,36.5789473684211,NA -"6341",0.2,40.7894736842105,36.5789473684211,NA -"6342",0.260352117694686,40.7894736842105,36.5789473684211,NA -"6343",0.338916125940539,40.7894736842105,36.5789473684211,NA -"6344",0.441187655547492,40.7894736842105,36.5789473684211,NA -"6345",0.574320702112717,40.7894736842105,36.5789473684211,NA -"6346",0.747628055154725,40.7894736842105,36.5789473684211,NA -"6347",0.973232737037462,40.7894736842105,36.5789473684211,NA -"6348",1.2669160204875,40.7894736842105,36.5789473684211,NA -"6349",1.64922134437622,40.7894736842105,36.5789473684211,NA -"6350",2.14689134777813,40.7894736842105,36.5789473684211,NA -"6351",2.79473854427218,40.7894736842105,36.5789473684211,NA -"6352",3.63808049202114,40.7894736842105,36.5789473684211,NA -"6353",4.73590980220715,40.7894736842105,36.5789473684211,NA -"6354",6.16502073107827,40.7894736842105,36.5789473684211,NA -"6355",8.02538101483936,40.7894736842105,36.5789473684211,NA -"6356",10.4471247126008,40.7894736842105,36.5789473684211,NA -"6357",13.5996552137305,40.7894736842105,36.5789473684211,NA -"6358",17.7034951740616,40.7894736842105,36.5789473684211,NA -"6359",23.045712295823,40.7894736842105,36.5789473684211,NA -"6360",30,40.7894736842105,36.5789473684211,NA -"6361",0.2,42.8947368421053,36.5789473684211,NA -"6362",0.260352117694686,42.8947368421053,36.5789473684211,NA -"6363",0.338916125940539,42.8947368421053,36.5789473684211,NA -"6364",0.441187655547492,42.8947368421053,36.5789473684211,NA -"6365",0.574320702112717,42.8947368421053,36.5789473684211,NA -"6366",0.747628055154725,42.8947368421053,36.5789473684211,NA -"6367",0.973232737037462,42.8947368421053,36.5789473684211,NA -"6368",1.2669160204875,42.8947368421053,36.5789473684211,NA -"6369",1.64922134437622,42.8947368421053,36.5789473684211,NA -"6370",2.14689134777813,42.8947368421053,36.5789473684211,NA -"6371",2.79473854427218,42.8947368421053,36.5789473684211,NA -"6372",3.63808049202114,42.8947368421053,36.5789473684211,NA -"6373",4.73590980220715,42.8947368421053,36.5789473684211,NA -"6374",6.16502073107827,42.8947368421053,36.5789473684211,NA -"6375",8.02538101483936,42.8947368421053,36.5789473684211,NA -"6376",10.4471247126008,42.8947368421053,36.5789473684211,NA -"6377",13.5996552137305,42.8947368421053,36.5789473684211,NA -"6378",17.7034951740616,42.8947368421053,36.5789473684211,NA -"6379",23.045712295823,42.8947368421053,36.5789473684211,NA -"6380",30,42.8947368421053,36.5789473684211,NA -"6381",0.2,45,36.5789473684211,NA -"6382",0.260352117694686,45,36.5789473684211,NA -"6383",0.338916125940539,45,36.5789473684211,NA -"6384",0.441187655547492,45,36.5789473684211,NA -"6385",0.574320702112717,45,36.5789473684211,NA -"6386",0.747628055154725,45,36.5789473684211,NA -"6387",0.973232737037462,45,36.5789473684211,NA -"6388",1.2669160204875,45,36.5789473684211,NA -"6389",1.64922134437622,45,36.5789473684211,NA -"6390",2.14689134777813,45,36.5789473684211,NA -"6391",2.79473854427218,45,36.5789473684211,NA -"6392",3.63808049202114,45,36.5789473684211,NA -"6393",4.73590980220715,45,36.5789473684211,NA -"6394",6.16502073107827,45,36.5789473684211,NA -"6395",8.02538101483936,45,36.5789473684211,NA -"6396",10.4471247126008,45,36.5789473684211,NA -"6397",13.5996552137305,45,36.5789473684211,NA -"6398",17.7034951740616,45,36.5789473684211,NA -"6399",23.045712295823,45,36.5789473684211,NA -"6400",30,45,36.5789473684211,NA -"6401",0.2,5,38.6842105263158,NA -"6402",0.260352117694686,5,38.6842105263158,NA -"6403",0.338916125940539,5,38.6842105263158,NA -"6404",0.441187655547492,5,38.6842105263158,NA -"6405",0.574320702112717,5,38.6842105263158,NA -"6406",0.747628055154725,5,38.6842105263158,NA -"6407",0.973232737037462,5,38.6842105263158,NA -"6408",1.2669160204875,5,38.6842105263158,NA -"6409",1.64922134437622,5,38.6842105263158,NA -"6410",2.14689134777813,5,38.6842105263158,NA -"6411",2.79473854427218,5,38.6842105263158,NA -"6412",3.63808049202114,5,38.6842105263158,NA -"6413",4.73590980220715,5,38.6842105263158,NA -"6414",6.16502073107827,5,38.6842105263158,NA -"6415",8.02538101483936,5,38.6842105263158,NA -"6416",10.4471247126008,5,38.6842105263158,NA -"6417",13.5996552137305,5,38.6842105263158,NA -"6418",17.7034951740616,5,38.6842105263158,NA -"6419",23.045712295823,5,38.6842105263158,NA -"6420",30,5,38.6842105263158,NA -"6421",0.2,7.10526315789474,38.6842105263158,NA -"6422",0.260352117694686,7.10526315789474,38.6842105263158,NA -"6423",0.338916125940539,7.10526315789474,38.6842105263158,NA -"6424",0.441187655547492,7.10526315789474,38.6842105263158,NA -"6425",0.574320702112717,7.10526315789474,38.6842105263158,NA -"6426",0.747628055154725,7.10526315789474,38.6842105263158,NA -"6427",0.973232737037462,7.10526315789474,38.6842105263158,NA -"6428",1.2669160204875,7.10526315789474,38.6842105263158,NA -"6429",1.64922134437622,7.10526315789474,38.6842105263158,NA -"6430",2.14689134777813,7.10526315789474,38.6842105263158,NA -"6431",2.79473854427218,7.10526315789474,38.6842105263158,NA -"6432",3.63808049202114,7.10526315789474,38.6842105263158,NA -"6433",4.73590980220715,7.10526315789474,38.6842105263158,NA -"6434",6.16502073107827,7.10526315789474,38.6842105263158,NA -"6435",8.02538101483936,7.10526315789474,38.6842105263158,NA -"6436",10.4471247126008,7.10526315789474,38.6842105263158,NA -"6437",13.5996552137305,7.10526315789474,38.6842105263158,NA -"6438",17.7034951740616,7.10526315789474,38.6842105263158,NA -"6439",23.045712295823,7.10526315789474,38.6842105263158,NA -"6440",30,7.10526315789474,38.6842105263158,NA -"6441",0.2,9.21052631578947,38.6842105263158,NA -"6442",0.260352117694686,9.21052631578947,38.6842105263158,NA -"6443",0.338916125940539,9.21052631578947,38.6842105263158,NA -"6444",0.441187655547492,9.21052631578947,38.6842105263158,NA -"6445",0.574320702112717,9.21052631578947,38.6842105263158,NA -"6446",0.747628055154725,9.21052631578947,38.6842105263158,NA -"6447",0.973232737037462,9.21052631578947,38.6842105263158,NA -"6448",1.2669160204875,9.21052631578947,38.6842105263158,NA -"6449",1.64922134437622,9.21052631578947,38.6842105263158,NA -"6450",2.14689134777813,9.21052631578947,38.6842105263158,NA -"6451",2.79473854427218,9.21052631578947,38.6842105263158,NA -"6452",3.63808049202114,9.21052631578947,38.6842105263158,NA -"6453",4.73590980220715,9.21052631578947,38.6842105263158,NA -"6454",6.16502073107827,9.21052631578947,38.6842105263158,NA -"6455",8.02538101483936,9.21052631578947,38.6842105263158,NA -"6456",10.4471247126008,9.21052631578947,38.6842105263158,NA -"6457",13.5996552137305,9.21052631578947,38.6842105263158,NA -"6458",17.7034951740616,9.21052631578947,38.6842105263158,NA -"6459",23.045712295823,9.21052631578947,38.6842105263158,NA -"6460",30,9.21052631578947,38.6842105263158,NA -"6461",0.2,11.3157894736842,38.6842105263158,NA -"6462",0.260352117694686,11.3157894736842,38.6842105263158,NA -"6463",0.338916125940539,11.3157894736842,38.6842105263158,NA -"6464",0.441187655547492,11.3157894736842,38.6842105263158,NA -"6465",0.574320702112717,11.3157894736842,38.6842105263158,NA -"6466",0.747628055154725,11.3157894736842,38.6842105263158,NA -"6467",0.973232737037462,11.3157894736842,38.6842105263158,NA -"6468",1.2669160204875,11.3157894736842,38.6842105263158,NA -"6469",1.64922134437622,11.3157894736842,38.6842105263158,NA -"6470",2.14689134777813,11.3157894736842,38.6842105263158,NA -"6471",2.79473854427218,11.3157894736842,38.6842105263158,NA -"6472",3.63808049202114,11.3157894736842,38.6842105263158,NA -"6473",4.73590980220715,11.3157894736842,38.6842105263158,NA -"6474",6.16502073107827,11.3157894736842,38.6842105263158,NA -"6475",8.02538101483936,11.3157894736842,38.6842105263158,NA -"6476",10.4471247126008,11.3157894736842,38.6842105263158,NA -"6477",13.5996552137305,11.3157894736842,38.6842105263158,NA -"6478",17.7034951740616,11.3157894736842,38.6842105263158,NA -"6479",23.045712295823,11.3157894736842,38.6842105263158,NA -"6480",30,11.3157894736842,38.6842105263158,NA -"6481",0.2,13.4210526315789,38.6842105263158,NA -"6482",0.260352117694686,13.4210526315789,38.6842105263158,NA -"6483",0.338916125940539,13.4210526315789,38.6842105263158,NA -"6484",0.441187655547492,13.4210526315789,38.6842105263158,NA -"6485",0.574320702112717,13.4210526315789,38.6842105263158,NA -"6486",0.747628055154725,13.4210526315789,38.6842105263158,NA -"6487",0.973232737037462,13.4210526315789,38.6842105263158,NA -"6488",1.2669160204875,13.4210526315789,38.6842105263158,NA -"6489",1.64922134437622,13.4210526315789,38.6842105263158,NA -"6490",2.14689134777813,13.4210526315789,38.6842105263158,NA -"6491",2.79473854427218,13.4210526315789,38.6842105263158,NA -"6492",3.63808049202114,13.4210526315789,38.6842105263158,NA -"6493",4.73590980220715,13.4210526315789,38.6842105263158,NA -"6494",6.16502073107827,13.4210526315789,38.6842105263158,NA -"6495",8.02538101483936,13.4210526315789,38.6842105263158,NA -"6496",10.4471247126008,13.4210526315789,38.6842105263158,NA -"6497",13.5996552137305,13.4210526315789,38.6842105263158,NA -"6498",17.7034951740616,13.4210526315789,38.6842105263158,NA -"6499",23.045712295823,13.4210526315789,38.6842105263158,NA -"6500",30,13.4210526315789,38.6842105263158,NA -"6501",0.2,15.5263157894737,38.6842105263158,NA -"6502",0.260352117694686,15.5263157894737,38.6842105263158,NA -"6503",0.338916125940539,15.5263157894737,38.6842105263158,NA -"6504",0.441187655547492,15.5263157894737,38.6842105263158,NA -"6505",0.574320702112717,15.5263157894737,38.6842105263158,NA -"6506",0.747628055154725,15.5263157894737,38.6842105263158,NA -"6507",0.973232737037462,15.5263157894737,38.6842105263158,NA -"6508",1.2669160204875,15.5263157894737,38.6842105263158,NA -"6509",1.64922134437622,15.5263157894737,38.6842105263158,NA -"6510",2.14689134777813,15.5263157894737,38.6842105263158,NA -"6511",2.79473854427218,15.5263157894737,38.6842105263158,NA -"6512",3.63808049202114,15.5263157894737,38.6842105263158,NA -"6513",4.73590980220715,15.5263157894737,38.6842105263158,NA -"6514",6.16502073107827,15.5263157894737,38.6842105263158,NA -"6515",8.02538101483936,15.5263157894737,38.6842105263158,NA -"6516",10.4471247126008,15.5263157894737,38.6842105263158,NA -"6517",13.5996552137305,15.5263157894737,38.6842105263158,NA -"6518",17.7034951740616,15.5263157894737,38.6842105263158,NA -"6519",23.045712295823,15.5263157894737,38.6842105263158,NA -"6520",30,15.5263157894737,38.6842105263158,NA -"6521",0.2,17.6315789473684,38.6842105263158,NA -"6522",0.260352117694686,17.6315789473684,38.6842105263158,NA -"6523",0.338916125940539,17.6315789473684,38.6842105263158,NA -"6524",0.441187655547492,17.6315789473684,38.6842105263158,NA -"6525",0.574320702112717,17.6315789473684,38.6842105263158,NA -"6526",0.747628055154725,17.6315789473684,38.6842105263158,NA -"6527",0.973232737037462,17.6315789473684,38.6842105263158,NA -"6528",1.2669160204875,17.6315789473684,38.6842105263158,NA -"6529",1.64922134437622,17.6315789473684,38.6842105263158,NA -"6530",2.14689134777813,17.6315789473684,38.6842105263158,NA -"6531",2.79473854427218,17.6315789473684,38.6842105263158,NA -"6532",3.63808049202114,17.6315789473684,38.6842105263158,NA -"6533",4.73590980220715,17.6315789473684,38.6842105263158,NA -"6534",6.16502073107827,17.6315789473684,38.6842105263158,NA -"6535",8.02538101483936,17.6315789473684,38.6842105263158,NA -"6536",10.4471247126008,17.6315789473684,38.6842105263158,NA -"6537",13.5996552137305,17.6315789473684,38.6842105263158,NA -"6538",17.7034951740616,17.6315789473684,38.6842105263158,NA -"6539",23.045712295823,17.6315789473684,38.6842105263158,NA -"6540",30,17.6315789473684,38.6842105263158,NA -"6541",0.2,19.7368421052632,38.6842105263158,NA -"6542",0.260352117694686,19.7368421052632,38.6842105263158,NA -"6543",0.338916125940539,19.7368421052632,38.6842105263158,NA -"6544",0.441187655547492,19.7368421052632,38.6842105263158,NA -"6545",0.574320702112717,19.7368421052632,38.6842105263158,NA -"6546",0.747628055154725,19.7368421052632,38.6842105263158,NA -"6547",0.973232737037462,19.7368421052632,38.6842105263158,NA -"6548",1.2669160204875,19.7368421052632,38.6842105263158,NA -"6549",1.64922134437622,19.7368421052632,38.6842105263158,NA -"6550",2.14689134777813,19.7368421052632,38.6842105263158,NA -"6551",2.79473854427218,19.7368421052632,38.6842105263158,NA -"6552",3.63808049202114,19.7368421052632,38.6842105263158,NA -"6553",4.73590980220715,19.7368421052632,38.6842105263158,NA -"6554",6.16502073107827,19.7368421052632,38.6842105263158,NA -"6555",8.02538101483936,19.7368421052632,38.6842105263158,NA -"6556",10.4471247126008,19.7368421052632,38.6842105263158,NA -"6557",13.5996552137305,19.7368421052632,38.6842105263158,NA -"6558",17.7034951740616,19.7368421052632,38.6842105263158,NA -"6559",23.045712295823,19.7368421052632,38.6842105263158,NA -"6560",30,19.7368421052632,38.6842105263158,NA -"6561",0.2,21.8421052631579,38.6842105263158,NA -"6562",0.260352117694686,21.8421052631579,38.6842105263158,NA -"6563",0.338916125940539,21.8421052631579,38.6842105263158,NA -"6564",0.441187655547492,21.8421052631579,38.6842105263158,NA -"6565",0.574320702112717,21.8421052631579,38.6842105263158,NA -"6566",0.747628055154725,21.8421052631579,38.6842105263158,NA -"6567",0.973232737037462,21.8421052631579,38.6842105263158,NA -"6568",1.2669160204875,21.8421052631579,38.6842105263158,NA -"6569",1.64922134437622,21.8421052631579,38.6842105263158,NA -"6570",2.14689134777813,21.8421052631579,38.6842105263158,NA -"6571",2.79473854427218,21.8421052631579,38.6842105263158,NA -"6572",3.63808049202114,21.8421052631579,38.6842105263158,NA -"6573",4.73590980220715,21.8421052631579,38.6842105263158,NA -"6574",6.16502073107827,21.8421052631579,38.6842105263158,NA -"6575",8.02538101483936,21.8421052631579,38.6842105263158,NA -"6576",10.4471247126008,21.8421052631579,38.6842105263158,NA -"6577",13.5996552137305,21.8421052631579,38.6842105263158,NA -"6578",17.7034951740616,21.8421052631579,38.6842105263158,NA -"6579",23.045712295823,21.8421052631579,38.6842105263158,NA -"6580",30,21.8421052631579,38.6842105263158,NA -"6581",0.2,23.9473684210526,38.6842105263158,NA -"6582",0.260352117694686,23.9473684210526,38.6842105263158,NA -"6583",0.338916125940539,23.9473684210526,38.6842105263158,NA -"6584",0.441187655547492,23.9473684210526,38.6842105263158,NA -"6585",0.574320702112717,23.9473684210526,38.6842105263158,NA -"6586",0.747628055154725,23.9473684210526,38.6842105263158,NA -"6587",0.973232737037462,23.9473684210526,38.6842105263158,NA -"6588",1.2669160204875,23.9473684210526,38.6842105263158,NA -"6589",1.64922134437622,23.9473684210526,38.6842105263158,NA -"6590",2.14689134777813,23.9473684210526,38.6842105263158,NA -"6591",2.79473854427218,23.9473684210526,38.6842105263158,NA -"6592",3.63808049202114,23.9473684210526,38.6842105263158,NA -"6593",4.73590980220715,23.9473684210526,38.6842105263158,NA -"6594",6.16502073107827,23.9473684210526,38.6842105263158,NA -"6595",8.02538101483936,23.9473684210526,38.6842105263158,NA -"6596",10.4471247126008,23.9473684210526,38.6842105263158,NA -"6597",13.5996552137305,23.9473684210526,38.6842105263158,NA -"6598",17.7034951740616,23.9473684210526,38.6842105263158,NA -"6599",23.045712295823,23.9473684210526,38.6842105263158,NA -"6600",30,23.9473684210526,38.6842105263158,NA -"6601",0.2,26.0526315789474,38.6842105263158,NA -"6602",0.260352117694686,26.0526315789474,38.6842105263158,NA -"6603",0.338916125940539,26.0526315789474,38.6842105263158,NA -"6604",0.441187655547492,26.0526315789474,38.6842105263158,NA -"6605",0.574320702112717,26.0526315789474,38.6842105263158,NA -"6606",0.747628055154725,26.0526315789474,38.6842105263158,NA -"6607",0.973232737037462,26.0526315789474,38.6842105263158,NA -"6608",1.2669160204875,26.0526315789474,38.6842105263158,NA -"6609",1.64922134437622,26.0526315789474,38.6842105263158,NA -"6610",2.14689134777813,26.0526315789474,38.6842105263158,NA -"6611",2.79473854427218,26.0526315789474,38.6842105263158,NA -"6612",3.63808049202114,26.0526315789474,38.6842105263158,NA -"6613",4.73590980220715,26.0526315789474,38.6842105263158,NA -"6614",6.16502073107827,26.0526315789474,38.6842105263158,NA -"6615",8.02538101483936,26.0526315789474,38.6842105263158,NA -"6616",10.4471247126008,26.0526315789474,38.6842105263158,NA -"6617",13.5996552137305,26.0526315789474,38.6842105263158,NA -"6618",17.7034951740616,26.0526315789474,38.6842105263158,NA -"6619",23.045712295823,26.0526315789474,38.6842105263158,NA -"6620",30,26.0526315789474,38.6842105263158,NA -"6621",0.2,28.1578947368421,38.6842105263158,NA -"6622",0.260352117694686,28.1578947368421,38.6842105263158,NA -"6623",0.338916125940539,28.1578947368421,38.6842105263158,NA -"6624",0.441187655547492,28.1578947368421,38.6842105263158,NA -"6625",0.574320702112717,28.1578947368421,38.6842105263158,NA -"6626",0.747628055154725,28.1578947368421,38.6842105263158,NA -"6627",0.973232737037462,28.1578947368421,38.6842105263158,NA -"6628",1.2669160204875,28.1578947368421,38.6842105263158,NA -"6629",1.64922134437622,28.1578947368421,38.6842105263158,NA -"6630",2.14689134777813,28.1578947368421,38.6842105263158,NA -"6631",2.79473854427218,28.1578947368421,38.6842105263158,NA -"6632",3.63808049202114,28.1578947368421,38.6842105263158,NA -"6633",4.73590980220715,28.1578947368421,38.6842105263158,NA -"6634",6.16502073107827,28.1578947368421,38.6842105263158,NA -"6635",8.02538101483936,28.1578947368421,38.6842105263158,NA -"6636",10.4471247126008,28.1578947368421,38.6842105263158,NA -"6637",13.5996552137305,28.1578947368421,38.6842105263158,NA -"6638",17.7034951740616,28.1578947368421,38.6842105263158,NA -"6639",23.045712295823,28.1578947368421,38.6842105263158,NA -"6640",30,28.1578947368421,38.6842105263158,NA -"6641",0.2,30.2631578947368,38.6842105263158,NA -"6642",0.260352117694686,30.2631578947368,38.6842105263158,NA -"6643",0.338916125940539,30.2631578947368,38.6842105263158,NA -"6644",0.441187655547492,30.2631578947368,38.6842105263158,NA -"6645",0.574320702112717,30.2631578947368,38.6842105263158,NA -"6646",0.747628055154725,30.2631578947368,38.6842105263158,NA -"6647",0.973232737037462,30.2631578947368,38.6842105263158,NA -"6648",1.2669160204875,30.2631578947368,38.6842105263158,NA -"6649",1.64922134437622,30.2631578947368,38.6842105263158,NA -"6650",2.14689134777813,30.2631578947368,38.6842105263158,NA -"6651",2.79473854427218,30.2631578947368,38.6842105263158,NA -"6652",3.63808049202114,30.2631578947368,38.6842105263158,NA -"6653",4.73590980220715,30.2631578947368,38.6842105263158,NA -"6654",6.16502073107827,30.2631578947368,38.6842105263158,NA -"6655",8.02538101483936,30.2631578947368,38.6842105263158,NA -"6656",10.4471247126008,30.2631578947368,38.6842105263158,NA -"6657",13.5996552137305,30.2631578947368,38.6842105263158,NA -"6658",17.7034951740616,30.2631578947368,38.6842105263158,NA -"6659",23.045712295823,30.2631578947368,38.6842105263158,NA -"6660",30,30.2631578947368,38.6842105263158,NA -"6661",0.2,32.3684210526316,38.6842105263158,NA -"6662",0.260352117694686,32.3684210526316,38.6842105263158,NA -"6663",0.338916125940539,32.3684210526316,38.6842105263158,NA -"6664",0.441187655547492,32.3684210526316,38.6842105263158,NA -"6665",0.574320702112717,32.3684210526316,38.6842105263158,NA -"6666",0.747628055154725,32.3684210526316,38.6842105263158,NA -"6667",0.973232737037462,32.3684210526316,38.6842105263158,NA -"6668",1.2669160204875,32.3684210526316,38.6842105263158,NA -"6669",1.64922134437622,32.3684210526316,38.6842105263158,NA -"6670",2.14689134777813,32.3684210526316,38.6842105263158,NA -"6671",2.79473854427218,32.3684210526316,38.6842105263158,NA -"6672",3.63808049202114,32.3684210526316,38.6842105263158,NA -"6673",4.73590980220715,32.3684210526316,38.6842105263158,NA -"6674",6.16502073107827,32.3684210526316,38.6842105263158,NA -"6675",8.02538101483936,32.3684210526316,38.6842105263158,NA -"6676",10.4471247126008,32.3684210526316,38.6842105263158,NA -"6677",13.5996552137305,32.3684210526316,38.6842105263158,NA -"6678",17.7034951740616,32.3684210526316,38.6842105263158,NA -"6679",23.045712295823,32.3684210526316,38.6842105263158,NA -"6680",30,32.3684210526316,38.6842105263158,NA -"6681",0.2,34.4736842105263,38.6842105263158,NA -"6682",0.260352117694686,34.4736842105263,38.6842105263158,NA -"6683",0.338916125940539,34.4736842105263,38.6842105263158,NA -"6684",0.441187655547492,34.4736842105263,38.6842105263158,NA -"6685",0.574320702112717,34.4736842105263,38.6842105263158,NA -"6686",0.747628055154725,34.4736842105263,38.6842105263158,NA -"6687",0.973232737037462,34.4736842105263,38.6842105263158,NA -"6688",1.2669160204875,34.4736842105263,38.6842105263158,NA -"6689",1.64922134437622,34.4736842105263,38.6842105263158,NA -"6690",2.14689134777813,34.4736842105263,38.6842105263158,NA -"6691",2.79473854427218,34.4736842105263,38.6842105263158,NA -"6692",3.63808049202114,34.4736842105263,38.6842105263158,NA -"6693",4.73590980220715,34.4736842105263,38.6842105263158,NA -"6694",6.16502073107827,34.4736842105263,38.6842105263158,NA -"6695",8.02538101483936,34.4736842105263,38.6842105263158,NA -"6696",10.4471247126008,34.4736842105263,38.6842105263158,NA -"6697",13.5996552137305,34.4736842105263,38.6842105263158,NA -"6698",17.7034951740616,34.4736842105263,38.6842105263158,NA -"6699",23.045712295823,34.4736842105263,38.6842105263158,NA -"6700",30,34.4736842105263,38.6842105263158,NA -"6701",0.2,36.5789473684211,38.6842105263158,NA -"6702",0.260352117694686,36.5789473684211,38.6842105263158,NA -"6703",0.338916125940539,36.5789473684211,38.6842105263158,NA -"6704",0.441187655547492,36.5789473684211,38.6842105263158,NA -"6705",0.574320702112717,36.5789473684211,38.6842105263158,NA -"6706",0.747628055154725,36.5789473684211,38.6842105263158,NA -"6707",0.973232737037462,36.5789473684211,38.6842105263158,NA -"6708",1.2669160204875,36.5789473684211,38.6842105263158,NA -"6709",1.64922134437622,36.5789473684211,38.6842105263158,NA -"6710",2.14689134777813,36.5789473684211,38.6842105263158,NA -"6711",2.79473854427218,36.5789473684211,38.6842105263158,NA -"6712",3.63808049202114,36.5789473684211,38.6842105263158,NA -"6713",4.73590980220715,36.5789473684211,38.6842105263158,NA -"6714",6.16502073107827,36.5789473684211,38.6842105263158,NA -"6715",8.02538101483936,36.5789473684211,38.6842105263158,NA -"6716",10.4471247126008,36.5789473684211,38.6842105263158,NA -"6717",13.5996552137305,36.5789473684211,38.6842105263158,NA -"6718",17.7034951740616,36.5789473684211,38.6842105263158,NA -"6719",23.045712295823,36.5789473684211,38.6842105263158,NA -"6720",30,36.5789473684211,38.6842105263158,NA -"6721",0.2,38.6842105263158,38.6842105263158,NA -"6722",0.260352117694686,38.6842105263158,38.6842105263158,NA -"6723",0.338916125940539,38.6842105263158,38.6842105263158,NA -"6724",0.441187655547492,38.6842105263158,38.6842105263158,NA -"6725",0.574320702112717,38.6842105263158,38.6842105263158,NA -"6726",0.747628055154725,38.6842105263158,38.6842105263158,NA -"6727",0.973232737037462,38.6842105263158,38.6842105263158,NA -"6728",1.2669160204875,38.6842105263158,38.6842105263158,NA -"6729",1.64922134437622,38.6842105263158,38.6842105263158,NA -"6730",2.14689134777813,38.6842105263158,38.6842105263158,NA -"6731",2.79473854427218,38.6842105263158,38.6842105263158,NA -"6732",3.63808049202114,38.6842105263158,38.6842105263158,NA -"6733",4.73590980220715,38.6842105263158,38.6842105263158,NA -"6734",6.16502073107827,38.6842105263158,38.6842105263158,NA -"6735",8.02538101483936,38.6842105263158,38.6842105263158,NA -"6736",10.4471247126008,38.6842105263158,38.6842105263158,NA -"6737",13.5996552137305,38.6842105263158,38.6842105263158,NA -"6738",17.7034951740616,38.6842105263158,38.6842105263158,NA -"6739",23.045712295823,38.6842105263158,38.6842105263158,NA -"6740",30,38.6842105263158,38.6842105263158,NA -"6741",0.2,40.7894736842105,38.6842105263158,NA -"6742",0.260352117694686,40.7894736842105,38.6842105263158,NA -"6743",0.338916125940539,40.7894736842105,38.6842105263158,NA -"6744",0.441187655547492,40.7894736842105,38.6842105263158,NA -"6745",0.574320702112717,40.7894736842105,38.6842105263158,NA -"6746",0.747628055154725,40.7894736842105,38.6842105263158,NA -"6747",0.973232737037462,40.7894736842105,38.6842105263158,NA -"6748",1.2669160204875,40.7894736842105,38.6842105263158,NA -"6749",1.64922134437622,40.7894736842105,38.6842105263158,NA -"6750",2.14689134777813,40.7894736842105,38.6842105263158,NA -"6751",2.79473854427218,40.7894736842105,38.6842105263158,NA -"6752",3.63808049202114,40.7894736842105,38.6842105263158,NA -"6753",4.73590980220715,40.7894736842105,38.6842105263158,NA -"6754",6.16502073107827,40.7894736842105,38.6842105263158,NA -"6755",8.02538101483936,40.7894736842105,38.6842105263158,NA -"6756",10.4471247126008,40.7894736842105,38.6842105263158,NA -"6757",13.5996552137305,40.7894736842105,38.6842105263158,NA -"6758",17.7034951740616,40.7894736842105,38.6842105263158,NA -"6759",23.045712295823,40.7894736842105,38.6842105263158,NA -"6760",30,40.7894736842105,38.6842105263158,NA -"6761",0.2,42.8947368421053,38.6842105263158,NA -"6762",0.260352117694686,42.8947368421053,38.6842105263158,NA -"6763",0.338916125940539,42.8947368421053,38.6842105263158,NA -"6764",0.441187655547492,42.8947368421053,38.6842105263158,NA -"6765",0.574320702112717,42.8947368421053,38.6842105263158,NA -"6766",0.747628055154725,42.8947368421053,38.6842105263158,NA -"6767",0.973232737037462,42.8947368421053,38.6842105263158,NA -"6768",1.2669160204875,42.8947368421053,38.6842105263158,NA -"6769",1.64922134437622,42.8947368421053,38.6842105263158,NA -"6770",2.14689134777813,42.8947368421053,38.6842105263158,NA -"6771",2.79473854427218,42.8947368421053,38.6842105263158,NA -"6772",3.63808049202114,42.8947368421053,38.6842105263158,NA -"6773",4.73590980220715,42.8947368421053,38.6842105263158,NA -"6774",6.16502073107827,42.8947368421053,38.6842105263158,NA -"6775",8.02538101483936,42.8947368421053,38.6842105263158,NA -"6776",10.4471247126008,42.8947368421053,38.6842105263158,NA -"6777",13.5996552137305,42.8947368421053,38.6842105263158,NA -"6778",17.7034951740616,42.8947368421053,38.6842105263158,NA -"6779",23.045712295823,42.8947368421053,38.6842105263158,NA -"6780",30,42.8947368421053,38.6842105263158,NA -"6781",0.2,45,38.6842105263158,NA -"6782",0.260352117694686,45,38.6842105263158,NA -"6783",0.338916125940539,45,38.6842105263158,NA -"6784",0.441187655547492,45,38.6842105263158,NA -"6785",0.574320702112717,45,38.6842105263158,NA -"6786",0.747628055154725,45,38.6842105263158,NA -"6787",0.973232737037462,45,38.6842105263158,NA -"6788",1.2669160204875,45,38.6842105263158,NA -"6789",1.64922134437622,45,38.6842105263158,NA -"6790",2.14689134777813,45,38.6842105263158,NA -"6791",2.79473854427218,45,38.6842105263158,NA -"6792",3.63808049202114,45,38.6842105263158,NA -"6793",4.73590980220715,45,38.6842105263158,NA -"6794",6.16502073107827,45,38.6842105263158,NA -"6795",8.02538101483936,45,38.6842105263158,NA -"6796",10.4471247126008,45,38.6842105263158,NA -"6797",13.5996552137305,45,38.6842105263158,NA -"6798",17.7034951740616,45,38.6842105263158,NA -"6799",23.045712295823,45,38.6842105263158,NA -"6800",30,45,38.6842105263158,NA -"6801",0.2,5,40.7894736842105,NA -"6802",0.260352117694686,5,40.7894736842105,NA -"6803",0.338916125940539,5,40.7894736842105,NA -"6804",0.441187655547492,5,40.7894736842105,NA -"6805",0.574320702112717,5,40.7894736842105,NA -"6806",0.747628055154725,5,40.7894736842105,NA -"6807",0.973232737037462,5,40.7894736842105,NA -"6808",1.2669160204875,5,40.7894736842105,NA -"6809",1.64922134437622,5,40.7894736842105,NA -"6810",2.14689134777813,5,40.7894736842105,NA -"6811",2.79473854427218,5,40.7894736842105,NA -"6812",3.63808049202114,5,40.7894736842105,NA -"6813",4.73590980220715,5,40.7894736842105,NA -"6814",6.16502073107827,5,40.7894736842105,NA -"6815",8.02538101483936,5,40.7894736842105,NA -"6816",10.4471247126008,5,40.7894736842105,NA -"6817",13.5996552137305,5,40.7894736842105,NA -"6818",17.7034951740616,5,40.7894736842105,NA -"6819",23.045712295823,5,40.7894736842105,NA -"6820",30,5,40.7894736842105,NA -"6821",0.2,7.10526315789474,40.7894736842105,NA -"6822",0.260352117694686,7.10526315789474,40.7894736842105,NA -"6823",0.338916125940539,7.10526315789474,40.7894736842105,NA -"6824",0.441187655547492,7.10526315789474,40.7894736842105,NA -"6825",0.574320702112717,7.10526315789474,40.7894736842105,NA -"6826",0.747628055154725,7.10526315789474,40.7894736842105,NA -"6827",0.973232737037462,7.10526315789474,40.7894736842105,NA -"6828",1.2669160204875,7.10526315789474,40.7894736842105,NA -"6829",1.64922134437622,7.10526315789474,40.7894736842105,NA -"6830",2.14689134777813,7.10526315789474,40.7894736842105,NA -"6831",2.79473854427218,7.10526315789474,40.7894736842105,NA -"6832",3.63808049202114,7.10526315789474,40.7894736842105,NA -"6833",4.73590980220715,7.10526315789474,40.7894736842105,NA -"6834",6.16502073107827,7.10526315789474,40.7894736842105,NA -"6835",8.02538101483936,7.10526315789474,40.7894736842105,NA -"6836",10.4471247126008,7.10526315789474,40.7894736842105,NA -"6837",13.5996552137305,7.10526315789474,40.7894736842105,NA -"6838",17.7034951740616,7.10526315789474,40.7894736842105,NA -"6839",23.045712295823,7.10526315789474,40.7894736842105,NA -"6840",30,7.10526315789474,40.7894736842105,NA -"6841",0.2,9.21052631578947,40.7894736842105,NA -"6842",0.260352117694686,9.21052631578947,40.7894736842105,NA -"6843",0.338916125940539,9.21052631578947,40.7894736842105,NA -"6844",0.441187655547492,9.21052631578947,40.7894736842105,NA -"6845",0.574320702112717,9.21052631578947,40.7894736842105,NA -"6846",0.747628055154725,9.21052631578947,40.7894736842105,NA -"6847",0.973232737037462,9.21052631578947,40.7894736842105,NA -"6848",1.2669160204875,9.21052631578947,40.7894736842105,NA -"6849",1.64922134437622,9.21052631578947,40.7894736842105,NA -"6850",2.14689134777813,9.21052631578947,40.7894736842105,NA -"6851",2.79473854427218,9.21052631578947,40.7894736842105,NA -"6852",3.63808049202114,9.21052631578947,40.7894736842105,NA -"6853",4.73590980220715,9.21052631578947,40.7894736842105,NA -"6854",6.16502073107827,9.21052631578947,40.7894736842105,NA -"6855",8.02538101483936,9.21052631578947,40.7894736842105,NA -"6856",10.4471247126008,9.21052631578947,40.7894736842105,NA -"6857",13.5996552137305,9.21052631578947,40.7894736842105,NA -"6858",17.7034951740616,9.21052631578947,40.7894736842105,NA -"6859",23.045712295823,9.21052631578947,40.7894736842105,NA -"6860",30,9.21052631578947,40.7894736842105,NA -"6861",0.2,11.3157894736842,40.7894736842105,NA -"6862",0.260352117694686,11.3157894736842,40.7894736842105,NA -"6863",0.338916125940539,11.3157894736842,40.7894736842105,NA -"6864",0.441187655547492,11.3157894736842,40.7894736842105,NA -"6865",0.574320702112717,11.3157894736842,40.7894736842105,NA -"6866",0.747628055154725,11.3157894736842,40.7894736842105,NA -"6867",0.973232737037462,11.3157894736842,40.7894736842105,NA -"6868",1.2669160204875,11.3157894736842,40.7894736842105,NA -"6869",1.64922134437622,11.3157894736842,40.7894736842105,NA -"6870",2.14689134777813,11.3157894736842,40.7894736842105,NA -"6871",2.79473854427218,11.3157894736842,40.7894736842105,NA -"6872",3.63808049202114,11.3157894736842,40.7894736842105,NA -"6873",4.73590980220715,11.3157894736842,40.7894736842105,NA -"6874",6.16502073107827,11.3157894736842,40.7894736842105,NA -"6875",8.02538101483936,11.3157894736842,40.7894736842105,NA -"6876",10.4471247126008,11.3157894736842,40.7894736842105,NA -"6877",13.5996552137305,11.3157894736842,40.7894736842105,NA -"6878",17.7034951740616,11.3157894736842,40.7894736842105,NA -"6879",23.045712295823,11.3157894736842,40.7894736842105,NA -"6880",30,11.3157894736842,40.7894736842105,NA -"6881",0.2,13.4210526315789,40.7894736842105,NA -"6882",0.260352117694686,13.4210526315789,40.7894736842105,NA -"6883",0.338916125940539,13.4210526315789,40.7894736842105,NA -"6884",0.441187655547492,13.4210526315789,40.7894736842105,NA -"6885",0.574320702112717,13.4210526315789,40.7894736842105,NA -"6886",0.747628055154725,13.4210526315789,40.7894736842105,NA -"6887",0.973232737037462,13.4210526315789,40.7894736842105,NA -"6888",1.2669160204875,13.4210526315789,40.7894736842105,NA -"6889",1.64922134437622,13.4210526315789,40.7894736842105,NA -"6890",2.14689134777813,13.4210526315789,40.7894736842105,NA -"6891",2.79473854427218,13.4210526315789,40.7894736842105,NA -"6892",3.63808049202114,13.4210526315789,40.7894736842105,NA -"6893",4.73590980220715,13.4210526315789,40.7894736842105,NA -"6894",6.16502073107827,13.4210526315789,40.7894736842105,NA -"6895",8.02538101483936,13.4210526315789,40.7894736842105,NA -"6896",10.4471247126008,13.4210526315789,40.7894736842105,NA -"6897",13.5996552137305,13.4210526315789,40.7894736842105,NA -"6898",17.7034951740616,13.4210526315789,40.7894736842105,NA -"6899",23.045712295823,13.4210526315789,40.7894736842105,NA -"6900",30,13.4210526315789,40.7894736842105,NA -"6901",0.2,15.5263157894737,40.7894736842105,NA -"6902",0.260352117694686,15.5263157894737,40.7894736842105,NA -"6903",0.338916125940539,15.5263157894737,40.7894736842105,NA -"6904",0.441187655547492,15.5263157894737,40.7894736842105,NA -"6905",0.574320702112717,15.5263157894737,40.7894736842105,NA -"6906",0.747628055154725,15.5263157894737,40.7894736842105,NA -"6907",0.973232737037462,15.5263157894737,40.7894736842105,NA -"6908",1.2669160204875,15.5263157894737,40.7894736842105,NA -"6909",1.64922134437622,15.5263157894737,40.7894736842105,NA -"6910",2.14689134777813,15.5263157894737,40.7894736842105,NA -"6911",2.79473854427218,15.5263157894737,40.7894736842105,NA -"6912",3.63808049202114,15.5263157894737,40.7894736842105,NA -"6913",4.73590980220715,15.5263157894737,40.7894736842105,NA -"6914",6.16502073107827,15.5263157894737,40.7894736842105,NA -"6915",8.02538101483936,15.5263157894737,40.7894736842105,NA -"6916",10.4471247126008,15.5263157894737,40.7894736842105,NA -"6917",13.5996552137305,15.5263157894737,40.7894736842105,NA -"6918",17.7034951740616,15.5263157894737,40.7894736842105,NA -"6919",23.045712295823,15.5263157894737,40.7894736842105,NA -"6920",30,15.5263157894737,40.7894736842105,NA -"6921",0.2,17.6315789473684,40.7894736842105,NA -"6922",0.260352117694686,17.6315789473684,40.7894736842105,NA -"6923",0.338916125940539,17.6315789473684,40.7894736842105,NA -"6924",0.441187655547492,17.6315789473684,40.7894736842105,NA -"6925",0.574320702112717,17.6315789473684,40.7894736842105,NA -"6926",0.747628055154725,17.6315789473684,40.7894736842105,NA -"6927",0.973232737037462,17.6315789473684,40.7894736842105,NA -"6928",1.2669160204875,17.6315789473684,40.7894736842105,NA -"6929",1.64922134437622,17.6315789473684,40.7894736842105,NA -"6930",2.14689134777813,17.6315789473684,40.7894736842105,NA -"6931",2.79473854427218,17.6315789473684,40.7894736842105,NA -"6932",3.63808049202114,17.6315789473684,40.7894736842105,NA -"6933",4.73590980220715,17.6315789473684,40.7894736842105,NA -"6934",6.16502073107827,17.6315789473684,40.7894736842105,NA -"6935",8.02538101483936,17.6315789473684,40.7894736842105,NA -"6936",10.4471247126008,17.6315789473684,40.7894736842105,NA -"6937",13.5996552137305,17.6315789473684,40.7894736842105,NA -"6938",17.7034951740616,17.6315789473684,40.7894736842105,NA -"6939",23.045712295823,17.6315789473684,40.7894736842105,NA -"6940",30,17.6315789473684,40.7894736842105,NA -"6941",0.2,19.7368421052632,40.7894736842105,NA -"6942",0.260352117694686,19.7368421052632,40.7894736842105,NA -"6943",0.338916125940539,19.7368421052632,40.7894736842105,NA -"6944",0.441187655547492,19.7368421052632,40.7894736842105,NA -"6945",0.574320702112717,19.7368421052632,40.7894736842105,NA -"6946",0.747628055154725,19.7368421052632,40.7894736842105,NA -"6947",0.973232737037462,19.7368421052632,40.7894736842105,NA -"6948",1.2669160204875,19.7368421052632,40.7894736842105,NA -"6949",1.64922134437622,19.7368421052632,40.7894736842105,NA -"6950",2.14689134777813,19.7368421052632,40.7894736842105,NA -"6951",2.79473854427218,19.7368421052632,40.7894736842105,NA -"6952",3.63808049202114,19.7368421052632,40.7894736842105,NA -"6953",4.73590980220715,19.7368421052632,40.7894736842105,NA -"6954",6.16502073107827,19.7368421052632,40.7894736842105,NA -"6955",8.02538101483936,19.7368421052632,40.7894736842105,NA -"6956",10.4471247126008,19.7368421052632,40.7894736842105,NA -"6957",13.5996552137305,19.7368421052632,40.7894736842105,NA -"6958",17.7034951740616,19.7368421052632,40.7894736842105,NA -"6959",23.045712295823,19.7368421052632,40.7894736842105,NA -"6960",30,19.7368421052632,40.7894736842105,NA -"6961",0.2,21.8421052631579,40.7894736842105,NA -"6962",0.260352117694686,21.8421052631579,40.7894736842105,NA -"6963",0.338916125940539,21.8421052631579,40.7894736842105,NA -"6964",0.441187655547492,21.8421052631579,40.7894736842105,NA -"6965",0.574320702112717,21.8421052631579,40.7894736842105,NA -"6966",0.747628055154725,21.8421052631579,40.7894736842105,NA -"6967",0.973232737037462,21.8421052631579,40.7894736842105,NA -"6968",1.2669160204875,21.8421052631579,40.7894736842105,NA -"6969",1.64922134437622,21.8421052631579,40.7894736842105,NA -"6970",2.14689134777813,21.8421052631579,40.7894736842105,NA -"6971",2.79473854427218,21.8421052631579,40.7894736842105,NA -"6972",3.63808049202114,21.8421052631579,40.7894736842105,NA -"6973",4.73590980220715,21.8421052631579,40.7894736842105,NA -"6974",6.16502073107827,21.8421052631579,40.7894736842105,NA -"6975",8.02538101483936,21.8421052631579,40.7894736842105,NA -"6976",10.4471247126008,21.8421052631579,40.7894736842105,NA -"6977",13.5996552137305,21.8421052631579,40.7894736842105,NA -"6978",17.7034951740616,21.8421052631579,40.7894736842105,NA -"6979",23.045712295823,21.8421052631579,40.7894736842105,NA -"6980",30,21.8421052631579,40.7894736842105,NA -"6981",0.2,23.9473684210526,40.7894736842105,NA -"6982",0.260352117694686,23.9473684210526,40.7894736842105,NA -"6983",0.338916125940539,23.9473684210526,40.7894736842105,NA -"6984",0.441187655547492,23.9473684210526,40.7894736842105,NA -"6985",0.574320702112717,23.9473684210526,40.7894736842105,NA -"6986",0.747628055154725,23.9473684210526,40.7894736842105,NA -"6987",0.973232737037462,23.9473684210526,40.7894736842105,NA -"6988",1.2669160204875,23.9473684210526,40.7894736842105,NA -"6989",1.64922134437622,23.9473684210526,40.7894736842105,NA -"6990",2.14689134777813,23.9473684210526,40.7894736842105,NA -"6991",2.79473854427218,23.9473684210526,40.7894736842105,NA -"6992",3.63808049202114,23.9473684210526,40.7894736842105,NA -"6993",4.73590980220715,23.9473684210526,40.7894736842105,NA -"6994",6.16502073107827,23.9473684210526,40.7894736842105,NA -"6995",8.02538101483936,23.9473684210526,40.7894736842105,NA -"6996",10.4471247126008,23.9473684210526,40.7894736842105,NA -"6997",13.5996552137305,23.9473684210526,40.7894736842105,NA -"6998",17.7034951740616,23.9473684210526,40.7894736842105,NA -"6999",23.045712295823,23.9473684210526,40.7894736842105,NA -"7000",30,23.9473684210526,40.7894736842105,NA -"7001",0.2,26.0526315789474,40.7894736842105,NA -"7002",0.260352117694686,26.0526315789474,40.7894736842105,NA -"7003",0.338916125940539,26.0526315789474,40.7894736842105,NA -"7004",0.441187655547492,26.0526315789474,40.7894736842105,NA -"7005",0.574320702112717,26.0526315789474,40.7894736842105,NA -"7006",0.747628055154725,26.0526315789474,40.7894736842105,NA -"7007",0.973232737037462,26.0526315789474,40.7894736842105,NA -"7008",1.2669160204875,26.0526315789474,40.7894736842105,NA -"7009",1.64922134437622,26.0526315789474,40.7894736842105,NA -"7010",2.14689134777813,26.0526315789474,40.7894736842105,NA -"7011",2.79473854427218,26.0526315789474,40.7894736842105,NA -"7012",3.63808049202114,26.0526315789474,40.7894736842105,NA -"7013",4.73590980220715,26.0526315789474,40.7894736842105,NA -"7014",6.16502073107827,26.0526315789474,40.7894736842105,NA -"7015",8.02538101483936,26.0526315789474,40.7894736842105,NA -"7016",10.4471247126008,26.0526315789474,40.7894736842105,NA -"7017",13.5996552137305,26.0526315789474,40.7894736842105,NA -"7018",17.7034951740616,26.0526315789474,40.7894736842105,NA -"7019",23.045712295823,26.0526315789474,40.7894736842105,NA -"7020",30,26.0526315789474,40.7894736842105,NA -"7021",0.2,28.1578947368421,40.7894736842105,NA -"7022",0.260352117694686,28.1578947368421,40.7894736842105,NA -"7023",0.338916125940539,28.1578947368421,40.7894736842105,NA -"7024",0.441187655547492,28.1578947368421,40.7894736842105,NA -"7025",0.574320702112717,28.1578947368421,40.7894736842105,NA -"7026",0.747628055154725,28.1578947368421,40.7894736842105,NA -"7027",0.973232737037462,28.1578947368421,40.7894736842105,NA -"7028",1.2669160204875,28.1578947368421,40.7894736842105,NA -"7029",1.64922134437622,28.1578947368421,40.7894736842105,NA -"7030",2.14689134777813,28.1578947368421,40.7894736842105,NA -"7031",2.79473854427218,28.1578947368421,40.7894736842105,NA -"7032",3.63808049202114,28.1578947368421,40.7894736842105,NA -"7033",4.73590980220715,28.1578947368421,40.7894736842105,NA -"7034",6.16502073107827,28.1578947368421,40.7894736842105,NA -"7035",8.02538101483936,28.1578947368421,40.7894736842105,NA -"7036",10.4471247126008,28.1578947368421,40.7894736842105,NA -"7037",13.5996552137305,28.1578947368421,40.7894736842105,NA -"7038",17.7034951740616,28.1578947368421,40.7894736842105,NA -"7039",23.045712295823,28.1578947368421,40.7894736842105,NA -"7040",30,28.1578947368421,40.7894736842105,NA -"7041",0.2,30.2631578947368,40.7894736842105,NA -"7042",0.260352117694686,30.2631578947368,40.7894736842105,NA -"7043",0.338916125940539,30.2631578947368,40.7894736842105,NA -"7044",0.441187655547492,30.2631578947368,40.7894736842105,NA -"7045",0.574320702112717,30.2631578947368,40.7894736842105,NA -"7046",0.747628055154725,30.2631578947368,40.7894736842105,NA -"7047",0.973232737037462,30.2631578947368,40.7894736842105,NA -"7048",1.2669160204875,30.2631578947368,40.7894736842105,NA -"7049",1.64922134437622,30.2631578947368,40.7894736842105,NA -"7050",2.14689134777813,30.2631578947368,40.7894736842105,NA -"7051",2.79473854427218,30.2631578947368,40.7894736842105,NA -"7052",3.63808049202114,30.2631578947368,40.7894736842105,NA -"7053",4.73590980220715,30.2631578947368,40.7894736842105,NA -"7054",6.16502073107827,30.2631578947368,40.7894736842105,NA -"7055",8.02538101483936,30.2631578947368,40.7894736842105,NA -"7056",10.4471247126008,30.2631578947368,40.7894736842105,NA -"7057",13.5996552137305,30.2631578947368,40.7894736842105,NA -"7058",17.7034951740616,30.2631578947368,40.7894736842105,NA -"7059",23.045712295823,30.2631578947368,40.7894736842105,NA -"7060",30,30.2631578947368,40.7894736842105,NA -"7061",0.2,32.3684210526316,40.7894736842105,NA -"7062",0.260352117694686,32.3684210526316,40.7894736842105,NA -"7063",0.338916125940539,32.3684210526316,40.7894736842105,NA -"7064",0.441187655547492,32.3684210526316,40.7894736842105,NA -"7065",0.574320702112717,32.3684210526316,40.7894736842105,NA -"7066",0.747628055154725,32.3684210526316,40.7894736842105,NA -"7067",0.973232737037462,32.3684210526316,40.7894736842105,NA -"7068",1.2669160204875,32.3684210526316,40.7894736842105,NA -"7069",1.64922134437622,32.3684210526316,40.7894736842105,NA -"7070",2.14689134777813,32.3684210526316,40.7894736842105,NA -"7071",2.79473854427218,32.3684210526316,40.7894736842105,NA -"7072",3.63808049202114,32.3684210526316,40.7894736842105,NA -"7073",4.73590980220715,32.3684210526316,40.7894736842105,NA -"7074",6.16502073107827,32.3684210526316,40.7894736842105,NA -"7075",8.02538101483936,32.3684210526316,40.7894736842105,NA -"7076",10.4471247126008,32.3684210526316,40.7894736842105,NA -"7077",13.5996552137305,32.3684210526316,40.7894736842105,NA -"7078",17.7034951740616,32.3684210526316,40.7894736842105,NA -"7079",23.045712295823,32.3684210526316,40.7894736842105,NA -"7080",30,32.3684210526316,40.7894736842105,NA -"7081",0.2,34.4736842105263,40.7894736842105,NA -"7082",0.260352117694686,34.4736842105263,40.7894736842105,NA -"7083",0.338916125940539,34.4736842105263,40.7894736842105,NA -"7084",0.441187655547492,34.4736842105263,40.7894736842105,NA -"7085",0.574320702112717,34.4736842105263,40.7894736842105,NA -"7086",0.747628055154725,34.4736842105263,40.7894736842105,NA -"7087",0.973232737037462,34.4736842105263,40.7894736842105,NA -"7088",1.2669160204875,34.4736842105263,40.7894736842105,NA -"7089",1.64922134437622,34.4736842105263,40.7894736842105,NA -"7090",2.14689134777813,34.4736842105263,40.7894736842105,NA -"7091",2.79473854427218,34.4736842105263,40.7894736842105,NA -"7092",3.63808049202114,34.4736842105263,40.7894736842105,NA -"7093",4.73590980220715,34.4736842105263,40.7894736842105,NA -"7094",6.16502073107827,34.4736842105263,40.7894736842105,NA -"7095",8.02538101483936,34.4736842105263,40.7894736842105,NA -"7096",10.4471247126008,34.4736842105263,40.7894736842105,NA -"7097",13.5996552137305,34.4736842105263,40.7894736842105,NA -"7098",17.7034951740616,34.4736842105263,40.7894736842105,NA -"7099",23.045712295823,34.4736842105263,40.7894736842105,NA -"7100",30,34.4736842105263,40.7894736842105,NA -"7101",0.2,36.5789473684211,40.7894736842105,NA -"7102",0.260352117694686,36.5789473684211,40.7894736842105,NA -"7103",0.338916125940539,36.5789473684211,40.7894736842105,NA -"7104",0.441187655547492,36.5789473684211,40.7894736842105,NA -"7105",0.574320702112717,36.5789473684211,40.7894736842105,NA -"7106",0.747628055154725,36.5789473684211,40.7894736842105,NA -"7107",0.973232737037462,36.5789473684211,40.7894736842105,NA -"7108",1.2669160204875,36.5789473684211,40.7894736842105,NA -"7109",1.64922134437622,36.5789473684211,40.7894736842105,NA -"7110",2.14689134777813,36.5789473684211,40.7894736842105,NA -"7111",2.79473854427218,36.5789473684211,40.7894736842105,NA -"7112",3.63808049202114,36.5789473684211,40.7894736842105,NA -"7113",4.73590980220715,36.5789473684211,40.7894736842105,NA -"7114",6.16502073107827,36.5789473684211,40.7894736842105,NA -"7115",8.02538101483936,36.5789473684211,40.7894736842105,NA -"7116",10.4471247126008,36.5789473684211,40.7894736842105,NA -"7117",13.5996552137305,36.5789473684211,40.7894736842105,NA -"7118",17.7034951740616,36.5789473684211,40.7894736842105,NA -"7119",23.045712295823,36.5789473684211,40.7894736842105,NA -"7120",30,36.5789473684211,40.7894736842105,NA -"7121",0.2,38.6842105263158,40.7894736842105,NA -"7122",0.260352117694686,38.6842105263158,40.7894736842105,NA -"7123",0.338916125940539,38.6842105263158,40.7894736842105,NA -"7124",0.441187655547492,38.6842105263158,40.7894736842105,NA -"7125",0.574320702112717,38.6842105263158,40.7894736842105,NA -"7126",0.747628055154725,38.6842105263158,40.7894736842105,NA -"7127",0.973232737037462,38.6842105263158,40.7894736842105,NA -"7128",1.2669160204875,38.6842105263158,40.7894736842105,NA -"7129",1.64922134437622,38.6842105263158,40.7894736842105,NA -"7130",2.14689134777813,38.6842105263158,40.7894736842105,NA -"7131",2.79473854427218,38.6842105263158,40.7894736842105,NA -"7132",3.63808049202114,38.6842105263158,40.7894736842105,NA -"7133",4.73590980220715,38.6842105263158,40.7894736842105,NA -"7134",6.16502073107827,38.6842105263158,40.7894736842105,NA -"7135",8.02538101483936,38.6842105263158,40.7894736842105,NA -"7136",10.4471247126008,38.6842105263158,40.7894736842105,NA -"7137",13.5996552137305,38.6842105263158,40.7894736842105,NA -"7138",17.7034951740616,38.6842105263158,40.7894736842105,NA -"7139",23.045712295823,38.6842105263158,40.7894736842105,NA -"7140",30,38.6842105263158,40.7894736842105,NA -"7141",0.2,40.7894736842105,40.7894736842105,NA -"7142",0.260352117694686,40.7894736842105,40.7894736842105,NA -"7143",0.338916125940539,40.7894736842105,40.7894736842105,NA -"7144",0.441187655547492,40.7894736842105,40.7894736842105,NA -"7145",0.574320702112717,40.7894736842105,40.7894736842105,NA -"7146",0.747628055154725,40.7894736842105,40.7894736842105,NA -"7147",0.973232737037462,40.7894736842105,40.7894736842105,NA -"7148",1.2669160204875,40.7894736842105,40.7894736842105,NA -"7149",1.64922134437622,40.7894736842105,40.7894736842105,NA -"7150",2.14689134777813,40.7894736842105,40.7894736842105,NA -"7151",2.79473854427218,40.7894736842105,40.7894736842105,NA -"7152",3.63808049202114,40.7894736842105,40.7894736842105,NA -"7153",4.73590980220715,40.7894736842105,40.7894736842105,NA -"7154",6.16502073107827,40.7894736842105,40.7894736842105,NA -"7155",8.02538101483936,40.7894736842105,40.7894736842105,NA -"7156",10.4471247126008,40.7894736842105,40.7894736842105,NA -"7157",13.5996552137305,40.7894736842105,40.7894736842105,NA -"7158",17.7034951740616,40.7894736842105,40.7894736842105,NA -"7159",23.045712295823,40.7894736842105,40.7894736842105,NA -"7160",30,40.7894736842105,40.7894736842105,NA -"7161",0.2,42.8947368421053,40.7894736842105,NA -"7162",0.260352117694686,42.8947368421053,40.7894736842105,NA -"7163",0.338916125940539,42.8947368421053,40.7894736842105,NA -"7164",0.441187655547492,42.8947368421053,40.7894736842105,NA -"7165",0.574320702112717,42.8947368421053,40.7894736842105,NA -"7166",0.747628055154725,42.8947368421053,40.7894736842105,NA -"7167",0.973232737037462,42.8947368421053,40.7894736842105,NA -"7168",1.2669160204875,42.8947368421053,40.7894736842105,NA -"7169",1.64922134437622,42.8947368421053,40.7894736842105,NA -"7170",2.14689134777813,42.8947368421053,40.7894736842105,NA -"7171",2.79473854427218,42.8947368421053,40.7894736842105,NA -"7172",3.63808049202114,42.8947368421053,40.7894736842105,NA -"7173",4.73590980220715,42.8947368421053,40.7894736842105,NA -"7174",6.16502073107827,42.8947368421053,40.7894736842105,NA -"7175",8.02538101483936,42.8947368421053,40.7894736842105,NA -"7176",10.4471247126008,42.8947368421053,40.7894736842105,NA -"7177",13.5996552137305,42.8947368421053,40.7894736842105,NA -"7178",17.7034951740616,42.8947368421053,40.7894736842105,NA -"7179",23.045712295823,42.8947368421053,40.7894736842105,NA -"7180",30,42.8947368421053,40.7894736842105,NA -"7181",0.2,45,40.7894736842105,NA -"7182",0.260352117694686,45,40.7894736842105,NA -"7183",0.338916125940539,45,40.7894736842105,NA -"7184",0.441187655547492,45,40.7894736842105,NA -"7185",0.574320702112717,45,40.7894736842105,NA -"7186",0.747628055154725,45,40.7894736842105,NA -"7187",0.973232737037462,45,40.7894736842105,NA -"7188",1.2669160204875,45,40.7894736842105,NA -"7189",1.64922134437622,45,40.7894736842105,NA -"7190",2.14689134777813,45,40.7894736842105,NA -"7191",2.79473854427218,45,40.7894736842105,NA -"7192",3.63808049202114,45,40.7894736842105,NA -"7193",4.73590980220715,45,40.7894736842105,NA -"7194",6.16502073107827,45,40.7894736842105,NA -"7195",8.02538101483936,45,40.7894736842105,NA -"7196",10.4471247126008,45,40.7894736842105,NA -"7197",13.5996552137305,45,40.7894736842105,NA -"7198",17.7034951740616,45,40.7894736842105,NA -"7199",23.045712295823,45,40.7894736842105,NA -"7200",30,45,40.7894736842105,NA -"7201",0.2,5,42.8947368421053,NA -"7202",0.260352117694686,5,42.8947368421053,NA -"7203",0.338916125940539,5,42.8947368421053,NA -"7204",0.441187655547492,5,42.8947368421053,NA -"7205",0.574320702112717,5,42.8947368421053,NA -"7206",0.747628055154725,5,42.8947368421053,NA -"7207",0.973232737037462,5,42.8947368421053,NA -"7208",1.2669160204875,5,42.8947368421053,NA -"7209",1.64922134437622,5,42.8947368421053,NA -"7210",2.14689134777813,5,42.8947368421053,NA -"7211",2.79473854427218,5,42.8947368421053,NA -"7212",3.63808049202114,5,42.8947368421053,NA -"7213",4.73590980220715,5,42.8947368421053,NA -"7214",6.16502073107827,5,42.8947368421053,NA -"7215",8.02538101483936,5,42.8947368421053,NA -"7216",10.4471247126008,5,42.8947368421053,NA -"7217",13.5996552137305,5,42.8947368421053,NA -"7218",17.7034951740616,5,42.8947368421053,NA -"7219",23.045712295823,5,42.8947368421053,NA -"7220",30,5,42.8947368421053,NA -"7221",0.2,7.10526315789474,42.8947368421053,NA -"7222",0.260352117694686,7.10526315789474,42.8947368421053,NA -"7223",0.338916125940539,7.10526315789474,42.8947368421053,NA -"7224",0.441187655547492,7.10526315789474,42.8947368421053,NA -"7225",0.574320702112717,7.10526315789474,42.8947368421053,NA -"7226",0.747628055154725,7.10526315789474,42.8947368421053,NA -"7227",0.973232737037462,7.10526315789474,42.8947368421053,NA -"7228",1.2669160204875,7.10526315789474,42.8947368421053,NA -"7229",1.64922134437622,7.10526315789474,42.8947368421053,NA -"7230",2.14689134777813,7.10526315789474,42.8947368421053,NA -"7231",2.79473854427218,7.10526315789474,42.8947368421053,NA -"7232",3.63808049202114,7.10526315789474,42.8947368421053,NA -"7233",4.73590980220715,7.10526315789474,42.8947368421053,NA -"7234",6.16502073107827,7.10526315789474,42.8947368421053,NA -"7235",8.02538101483936,7.10526315789474,42.8947368421053,NA -"7236",10.4471247126008,7.10526315789474,42.8947368421053,NA -"7237",13.5996552137305,7.10526315789474,42.8947368421053,NA -"7238",17.7034951740616,7.10526315789474,42.8947368421053,NA -"7239",23.045712295823,7.10526315789474,42.8947368421053,NA -"7240",30,7.10526315789474,42.8947368421053,NA -"7241",0.2,9.21052631578947,42.8947368421053,NA -"7242",0.260352117694686,9.21052631578947,42.8947368421053,NA -"7243",0.338916125940539,9.21052631578947,42.8947368421053,NA -"7244",0.441187655547492,9.21052631578947,42.8947368421053,NA -"7245",0.574320702112717,9.21052631578947,42.8947368421053,NA -"7246",0.747628055154725,9.21052631578947,42.8947368421053,NA -"7247",0.973232737037462,9.21052631578947,42.8947368421053,NA -"7248",1.2669160204875,9.21052631578947,42.8947368421053,NA -"7249",1.64922134437622,9.21052631578947,42.8947368421053,NA -"7250",2.14689134777813,9.21052631578947,42.8947368421053,NA -"7251",2.79473854427218,9.21052631578947,42.8947368421053,NA -"7252",3.63808049202114,9.21052631578947,42.8947368421053,NA -"7253",4.73590980220715,9.21052631578947,42.8947368421053,NA -"7254",6.16502073107827,9.21052631578947,42.8947368421053,NA -"7255",8.02538101483936,9.21052631578947,42.8947368421053,NA -"7256",10.4471247126008,9.21052631578947,42.8947368421053,NA -"7257",13.5996552137305,9.21052631578947,42.8947368421053,NA -"7258",17.7034951740616,9.21052631578947,42.8947368421053,NA -"7259",23.045712295823,9.21052631578947,42.8947368421053,NA -"7260",30,9.21052631578947,42.8947368421053,NA -"7261",0.2,11.3157894736842,42.8947368421053,NA -"7262",0.260352117694686,11.3157894736842,42.8947368421053,NA -"7263",0.338916125940539,11.3157894736842,42.8947368421053,NA -"7264",0.441187655547492,11.3157894736842,42.8947368421053,NA -"7265",0.574320702112717,11.3157894736842,42.8947368421053,NA -"7266",0.747628055154725,11.3157894736842,42.8947368421053,NA -"7267",0.973232737037462,11.3157894736842,42.8947368421053,NA -"7268",1.2669160204875,11.3157894736842,42.8947368421053,NA -"7269",1.64922134437622,11.3157894736842,42.8947368421053,NA -"7270",2.14689134777813,11.3157894736842,42.8947368421053,NA -"7271",2.79473854427218,11.3157894736842,42.8947368421053,NA -"7272",3.63808049202114,11.3157894736842,42.8947368421053,NA -"7273",4.73590980220715,11.3157894736842,42.8947368421053,NA -"7274",6.16502073107827,11.3157894736842,42.8947368421053,NA -"7275",8.02538101483936,11.3157894736842,42.8947368421053,NA -"7276",10.4471247126008,11.3157894736842,42.8947368421053,NA -"7277",13.5996552137305,11.3157894736842,42.8947368421053,NA -"7278",17.7034951740616,11.3157894736842,42.8947368421053,NA -"7279",23.045712295823,11.3157894736842,42.8947368421053,NA -"7280",30,11.3157894736842,42.8947368421053,NA -"7281",0.2,13.4210526315789,42.8947368421053,NA -"7282",0.260352117694686,13.4210526315789,42.8947368421053,NA -"7283",0.338916125940539,13.4210526315789,42.8947368421053,NA -"7284",0.441187655547492,13.4210526315789,42.8947368421053,NA -"7285",0.574320702112717,13.4210526315789,42.8947368421053,NA -"7286",0.747628055154725,13.4210526315789,42.8947368421053,NA -"7287",0.973232737037462,13.4210526315789,42.8947368421053,NA -"7288",1.2669160204875,13.4210526315789,42.8947368421053,NA -"7289",1.64922134437622,13.4210526315789,42.8947368421053,NA -"7290",2.14689134777813,13.4210526315789,42.8947368421053,NA -"7291",2.79473854427218,13.4210526315789,42.8947368421053,NA -"7292",3.63808049202114,13.4210526315789,42.8947368421053,NA -"7293",4.73590980220715,13.4210526315789,42.8947368421053,NA -"7294",6.16502073107827,13.4210526315789,42.8947368421053,NA -"7295",8.02538101483936,13.4210526315789,42.8947368421053,NA -"7296",10.4471247126008,13.4210526315789,42.8947368421053,NA -"7297",13.5996552137305,13.4210526315789,42.8947368421053,NA -"7298",17.7034951740616,13.4210526315789,42.8947368421053,NA -"7299",23.045712295823,13.4210526315789,42.8947368421053,NA -"7300",30,13.4210526315789,42.8947368421053,NA -"7301",0.2,15.5263157894737,42.8947368421053,NA -"7302",0.260352117694686,15.5263157894737,42.8947368421053,NA -"7303",0.338916125940539,15.5263157894737,42.8947368421053,NA -"7304",0.441187655547492,15.5263157894737,42.8947368421053,NA -"7305",0.574320702112717,15.5263157894737,42.8947368421053,NA -"7306",0.747628055154725,15.5263157894737,42.8947368421053,NA -"7307",0.973232737037462,15.5263157894737,42.8947368421053,NA -"7308",1.2669160204875,15.5263157894737,42.8947368421053,NA -"7309",1.64922134437622,15.5263157894737,42.8947368421053,NA -"7310",2.14689134777813,15.5263157894737,42.8947368421053,NA -"7311",2.79473854427218,15.5263157894737,42.8947368421053,NA -"7312",3.63808049202114,15.5263157894737,42.8947368421053,NA -"7313",4.73590980220715,15.5263157894737,42.8947368421053,NA -"7314",6.16502073107827,15.5263157894737,42.8947368421053,NA -"7315",8.02538101483936,15.5263157894737,42.8947368421053,NA -"7316",10.4471247126008,15.5263157894737,42.8947368421053,NA -"7317",13.5996552137305,15.5263157894737,42.8947368421053,NA -"7318",17.7034951740616,15.5263157894737,42.8947368421053,NA -"7319",23.045712295823,15.5263157894737,42.8947368421053,NA -"7320",30,15.5263157894737,42.8947368421053,NA -"7321",0.2,17.6315789473684,42.8947368421053,NA -"7322",0.260352117694686,17.6315789473684,42.8947368421053,NA -"7323",0.338916125940539,17.6315789473684,42.8947368421053,NA -"7324",0.441187655547492,17.6315789473684,42.8947368421053,NA -"7325",0.574320702112717,17.6315789473684,42.8947368421053,NA -"7326",0.747628055154725,17.6315789473684,42.8947368421053,NA -"7327",0.973232737037462,17.6315789473684,42.8947368421053,NA -"7328",1.2669160204875,17.6315789473684,42.8947368421053,NA -"7329",1.64922134437622,17.6315789473684,42.8947368421053,NA -"7330",2.14689134777813,17.6315789473684,42.8947368421053,NA -"7331",2.79473854427218,17.6315789473684,42.8947368421053,NA -"7332",3.63808049202114,17.6315789473684,42.8947368421053,NA -"7333",4.73590980220715,17.6315789473684,42.8947368421053,NA -"7334",6.16502073107827,17.6315789473684,42.8947368421053,NA -"7335",8.02538101483936,17.6315789473684,42.8947368421053,NA -"7336",10.4471247126008,17.6315789473684,42.8947368421053,NA -"7337",13.5996552137305,17.6315789473684,42.8947368421053,NA -"7338",17.7034951740616,17.6315789473684,42.8947368421053,NA -"7339",23.045712295823,17.6315789473684,42.8947368421053,NA -"7340",30,17.6315789473684,42.8947368421053,NA -"7341",0.2,19.7368421052632,42.8947368421053,NA -"7342",0.260352117694686,19.7368421052632,42.8947368421053,NA -"7343",0.338916125940539,19.7368421052632,42.8947368421053,NA -"7344",0.441187655547492,19.7368421052632,42.8947368421053,NA -"7345",0.574320702112717,19.7368421052632,42.8947368421053,NA -"7346",0.747628055154725,19.7368421052632,42.8947368421053,NA -"7347",0.973232737037462,19.7368421052632,42.8947368421053,NA -"7348",1.2669160204875,19.7368421052632,42.8947368421053,NA -"7349",1.64922134437622,19.7368421052632,42.8947368421053,NA -"7350",2.14689134777813,19.7368421052632,42.8947368421053,NA -"7351",2.79473854427218,19.7368421052632,42.8947368421053,NA -"7352",3.63808049202114,19.7368421052632,42.8947368421053,NA -"7353",4.73590980220715,19.7368421052632,42.8947368421053,NA -"7354",6.16502073107827,19.7368421052632,42.8947368421053,NA -"7355",8.02538101483936,19.7368421052632,42.8947368421053,NA -"7356",10.4471247126008,19.7368421052632,42.8947368421053,NA -"7357",13.5996552137305,19.7368421052632,42.8947368421053,NA -"7358",17.7034951740616,19.7368421052632,42.8947368421053,NA -"7359",23.045712295823,19.7368421052632,42.8947368421053,NA -"7360",30,19.7368421052632,42.8947368421053,NA -"7361",0.2,21.8421052631579,42.8947368421053,NA -"7362",0.260352117694686,21.8421052631579,42.8947368421053,NA -"7363",0.338916125940539,21.8421052631579,42.8947368421053,NA -"7364",0.441187655547492,21.8421052631579,42.8947368421053,NA -"7365",0.574320702112717,21.8421052631579,42.8947368421053,NA -"7366",0.747628055154725,21.8421052631579,42.8947368421053,NA -"7367",0.973232737037462,21.8421052631579,42.8947368421053,NA -"7368",1.2669160204875,21.8421052631579,42.8947368421053,NA -"7369",1.64922134437622,21.8421052631579,42.8947368421053,NA -"7370",2.14689134777813,21.8421052631579,42.8947368421053,NA -"7371",2.79473854427218,21.8421052631579,42.8947368421053,NA -"7372",3.63808049202114,21.8421052631579,42.8947368421053,NA -"7373",4.73590980220715,21.8421052631579,42.8947368421053,NA -"7374",6.16502073107827,21.8421052631579,42.8947368421053,NA -"7375",8.02538101483936,21.8421052631579,42.8947368421053,NA -"7376",10.4471247126008,21.8421052631579,42.8947368421053,NA -"7377",13.5996552137305,21.8421052631579,42.8947368421053,NA -"7378",17.7034951740616,21.8421052631579,42.8947368421053,NA -"7379",23.045712295823,21.8421052631579,42.8947368421053,NA -"7380",30,21.8421052631579,42.8947368421053,NA -"7381",0.2,23.9473684210526,42.8947368421053,NA -"7382",0.260352117694686,23.9473684210526,42.8947368421053,NA -"7383",0.338916125940539,23.9473684210526,42.8947368421053,NA -"7384",0.441187655547492,23.9473684210526,42.8947368421053,NA -"7385",0.574320702112717,23.9473684210526,42.8947368421053,NA -"7386",0.747628055154725,23.9473684210526,42.8947368421053,NA -"7387",0.973232737037462,23.9473684210526,42.8947368421053,NA -"7388",1.2669160204875,23.9473684210526,42.8947368421053,NA -"7389",1.64922134437622,23.9473684210526,42.8947368421053,NA -"7390",2.14689134777813,23.9473684210526,42.8947368421053,NA -"7391",2.79473854427218,23.9473684210526,42.8947368421053,NA -"7392",3.63808049202114,23.9473684210526,42.8947368421053,NA -"7393",4.73590980220715,23.9473684210526,42.8947368421053,NA -"7394",6.16502073107827,23.9473684210526,42.8947368421053,NA -"7395",8.02538101483936,23.9473684210526,42.8947368421053,NA -"7396",10.4471247126008,23.9473684210526,42.8947368421053,NA -"7397",13.5996552137305,23.9473684210526,42.8947368421053,NA -"7398",17.7034951740616,23.9473684210526,42.8947368421053,NA -"7399",23.045712295823,23.9473684210526,42.8947368421053,NA -"7400",30,23.9473684210526,42.8947368421053,NA -"7401",0.2,26.0526315789474,42.8947368421053,NA -"7402",0.260352117694686,26.0526315789474,42.8947368421053,NA -"7403",0.338916125940539,26.0526315789474,42.8947368421053,NA -"7404",0.441187655547492,26.0526315789474,42.8947368421053,NA -"7405",0.574320702112717,26.0526315789474,42.8947368421053,NA -"7406",0.747628055154725,26.0526315789474,42.8947368421053,NA -"7407",0.973232737037462,26.0526315789474,42.8947368421053,NA -"7408",1.2669160204875,26.0526315789474,42.8947368421053,NA -"7409",1.64922134437622,26.0526315789474,42.8947368421053,NA -"7410",2.14689134777813,26.0526315789474,42.8947368421053,NA -"7411",2.79473854427218,26.0526315789474,42.8947368421053,NA -"7412",3.63808049202114,26.0526315789474,42.8947368421053,NA -"7413",4.73590980220715,26.0526315789474,42.8947368421053,NA -"7414",6.16502073107827,26.0526315789474,42.8947368421053,NA -"7415",8.02538101483936,26.0526315789474,42.8947368421053,NA -"7416",10.4471247126008,26.0526315789474,42.8947368421053,NA -"7417",13.5996552137305,26.0526315789474,42.8947368421053,NA -"7418",17.7034951740616,26.0526315789474,42.8947368421053,NA -"7419",23.045712295823,26.0526315789474,42.8947368421053,NA -"7420",30,26.0526315789474,42.8947368421053,NA -"7421",0.2,28.1578947368421,42.8947368421053,NA -"7422",0.260352117694686,28.1578947368421,42.8947368421053,NA -"7423",0.338916125940539,28.1578947368421,42.8947368421053,NA -"7424",0.441187655547492,28.1578947368421,42.8947368421053,NA -"7425",0.574320702112717,28.1578947368421,42.8947368421053,NA -"7426",0.747628055154725,28.1578947368421,42.8947368421053,NA -"7427",0.973232737037462,28.1578947368421,42.8947368421053,NA -"7428",1.2669160204875,28.1578947368421,42.8947368421053,NA -"7429",1.64922134437622,28.1578947368421,42.8947368421053,NA -"7430",2.14689134777813,28.1578947368421,42.8947368421053,NA -"7431",2.79473854427218,28.1578947368421,42.8947368421053,NA -"7432",3.63808049202114,28.1578947368421,42.8947368421053,NA -"7433",4.73590980220715,28.1578947368421,42.8947368421053,NA -"7434",6.16502073107827,28.1578947368421,42.8947368421053,NA -"7435",8.02538101483936,28.1578947368421,42.8947368421053,NA -"7436",10.4471247126008,28.1578947368421,42.8947368421053,NA -"7437",13.5996552137305,28.1578947368421,42.8947368421053,NA -"7438",17.7034951740616,28.1578947368421,42.8947368421053,NA -"7439",23.045712295823,28.1578947368421,42.8947368421053,NA -"7440",30,28.1578947368421,42.8947368421053,NA -"7441",0.2,30.2631578947368,42.8947368421053,NA -"7442",0.260352117694686,30.2631578947368,42.8947368421053,NA -"7443",0.338916125940539,30.2631578947368,42.8947368421053,NA -"7444",0.441187655547492,30.2631578947368,42.8947368421053,NA -"7445",0.574320702112717,30.2631578947368,42.8947368421053,NA -"7446",0.747628055154725,30.2631578947368,42.8947368421053,NA -"7447",0.973232737037462,30.2631578947368,42.8947368421053,NA -"7448",1.2669160204875,30.2631578947368,42.8947368421053,NA -"7449",1.64922134437622,30.2631578947368,42.8947368421053,NA -"7450",2.14689134777813,30.2631578947368,42.8947368421053,NA -"7451",2.79473854427218,30.2631578947368,42.8947368421053,NA -"7452",3.63808049202114,30.2631578947368,42.8947368421053,NA -"7453",4.73590980220715,30.2631578947368,42.8947368421053,NA -"7454",6.16502073107827,30.2631578947368,42.8947368421053,NA -"7455",8.02538101483936,30.2631578947368,42.8947368421053,NA -"7456",10.4471247126008,30.2631578947368,42.8947368421053,NA -"7457",13.5996552137305,30.2631578947368,42.8947368421053,NA -"7458",17.7034951740616,30.2631578947368,42.8947368421053,NA -"7459",23.045712295823,30.2631578947368,42.8947368421053,NA -"7460",30,30.2631578947368,42.8947368421053,NA -"7461",0.2,32.3684210526316,42.8947368421053,NA -"7462",0.260352117694686,32.3684210526316,42.8947368421053,NA -"7463",0.338916125940539,32.3684210526316,42.8947368421053,NA -"7464",0.441187655547492,32.3684210526316,42.8947368421053,NA -"7465",0.574320702112717,32.3684210526316,42.8947368421053,NA -"7466",0.747628055154725,32.3684210526316,42.8947368421053,NA -"7467",0.973232737037462,32.3684210526316,42.8947368421053,NA -"7468",1.2669160204875,32.3684210526316,42.8947368421053,NA -"7469",1.64922134437622,32.3684210526316,42.8947368421053,NA -"7470",2.14689134777813,32.3684210526316,42.8947368421053,NA -"7471",2.79473854427218,32.3684210526316,42.8947368421053,NA -"7472",3.63808049202114,32.3684210526316,42.8947368421053,NA -"7473",4.73590980220715,32.3684210526316,42.8947368421053,NA -"7474",6.16502073107827,32.3684210526316,42.8947368421053,NA -"7475",8.02538101483936,32.3684210526316,42.8947368421053,NA -"7476",10.4471247126008,32.3684210526316,42.8947368421053,NA -"7477",13.5996552137305,32.3684210526316,42.8947368421053,NA -"7478",17.7034951740616,32.3684210526316,42.8947368421053,NA -"7479",23.045712295823,32.3684210526316,42.8947368421053,NA -"7480",30,32.3684210526316,42.8947368421053,NA -"7481",0.2,34.4736842105263,42.8947368421053,NA -"7482",0.260352117694686,34.4736842105263,42.8947368421053,NA -"7483",0.338916125940539,34.4736842105263,42.8947368421053,NA -"7484",0.441187655547492,34.4736842105263,42.8947368421053,NA -"7485",0.574320702112717,34.4736842105263,42.8947368421053,NA -"7486",0.747628055154725,34.4736842105263,42.8947368421053,NA -"7487",0.973232737037462,34.4736842105263,42.8947368421053,NA -"7488",1.2669160204875,34.4736842105263,42.8947368421053,NA -"7489",1.64922134437622,34.4736842105263,42.8947368421053,NA -"7490",2.14689134777813,34.4736842105263,42.8947368421053,NA -"7491",2.79473854427218,34.4736842105263,42.8947368421053,NA -"7492",3.63808049202114,34.4736842105263,42.8947368421053,NA -"7493",4.73590980220715,34.4736842105263,42.8947368421053,NA -"7494",6.16502073107827,34.4736842105263,42.8947368421053,NA -"7495",8.02538101483936,34.4736842105263,42.8947368421053,NA -"7496",10.4471247126008,34.4736842105263,42.8947368421053,NA -"7497",13.5996552137305,34.4736842105263,42.8947368421053,NA -"7498",17.7034951740616,34.4736842105263,42.8947368421053,NA -"7499",23.045712295823,34.4736842105263,42.8947368421053,NA -"7500",30,34.4736842105263,42.8947368421053,NA -"7501",0.2,36.5789473684211,42.8947368421053,NA -"7502",0.260352117694686,36.5789473684211,42.8947368421053,NA -"7503",0.338916125940539,36.5789473684211,42.8947368421053,NA -"7504",0.441187655547492,36.5789473684211,42.8947368421053,NA -"7505",0.574320702112717,36.5789473684211,42.8947368421053,NA -"7506",0.747628055154725,36.5789473684211,42.8947368421053,NA -"7507",0.973232737037462,36.5789473684211,42.8947368421053,NA -"7508",1.2669160204875,36.5789473684211,42.8947368421053,NA -"7509",1.64922134437622,36.5789473684211,42.8947368421053,NA -"7510",2.14689134777813,36.5789473684211,42.8947368421053,NA -"7511",2.79473854427218,36.5789473684211,42.8947368421053,NA -"7512",3.63808049202114,36.5789473684211,42.8947368421053,NA -"7513",4.73590980220715,36.5789473684211,42.8947368421053,NA -"7514",6.16502073107827,36.5789473684211,42.8947368421053,NA -"7515",8.02538101483936,36.5789473684211,42.8947368421053,NA -"7516",10.4471247126008,36.5789473684211,42.8947368421053,NA -"7517",13.5996552137305,36.5789473684211,42.8947368421053,NA -"7518",17.7034951740616,36.5789473684211,42.8947368421053,NA -"7519",23.045712295823,36.5789473684211,42.8947368421053,NA -"7520",30,36.5789473684211,42.8947368421053,NA -"7521",0.2,38.6842105263158,42.8947368421053,NA -"7522",0.260352117694686,38.6842105263158,42.8947368421053,NA -"7523",0.338916125940539,38.6842105263158,42.8947368421053,NA -"7524",0.441187655547492,38.6842105263158,42.8947368421053,NA -"7525",0.574320702112717,38.6842105263158,42.8947368421053,NA -"7526",0.747628055154725,38.6842105263158,42.8947368421053,NA -"7527",0.973232737037462,38.6842105263158,42.8947368421053,NA -"7528",1.2669160204875,38.6842105263158,42.8947368421053,NA -"7529",1.64922134437622,38.6842105263158,42.8947368421053,NA -"7530",2.14689134777813,38.6842105263158,42.8947368421053,NA -"7531",2.79473854427218,38.6842105263158,42.8947368421053,NA -"7532",3.63808049202114,38.6842105263158,42.8947368421053,NA -"7533",4.73590980220715,38.6842105263158,42.8947368421053,NA -"7534",6.16502073107827,38.6842105263158,42.8947368421053,NA -"7535",8.02538101483936,38.6842105263158,42.8947368421053,NA -"7536",10.4471247126008,38.6842105263158,42.8947368421053,NA -"7537",13.5996552137305,38.6842105263158,42.8947368421053,NA -"7538",17.7034951740616,38.6842105263158,42.8947368421053,NA -"7539",23.045712295823,38.6842105263158,42.8947368421053,NA -"7540",30,38.6842105263158,42.8947368421053,NA -"7541",0.2,40.7894736842105,42.8947368421053,NA -"7542",0.260352117694686,40.7894736842105,42.8947368421053,NA -"7543",0.338916125940539,40.7894736842105,42.8947368421053,NA -"7544",0.441187655547492,40.7894736842105,42.8947368421053,NA -"7545",0.574320702112717,40.7894736842105,42.8947368421053,NA -"7546",0.747628055154725,40.7894736842105,42.8947368421053,NA -"7547",0.973232737037462,40.7894736842105,42.8947368421053,NA -"7548",1.2669160204875,40.7894736842105,42.8947368421053,NA -"7549",1.64922134437622,40.7894736842105,42.8947368421053,NA -"7550",2.14689134777813,40.7894736842105,42.8947368421053,NA -"7551",2.79473854427218,40.7894736842105,42.8947368421053,NA -"7552",3.63808049202114,40.7894736842105,42.8947368421053,NA -"7553",4.73590980220715,40.7894736842105,42.8947368421053,NA -"7554",6.16502073107827,40.7894736842105,42.8947368421053,NA -"7555",8.02538101483936,40.7894736842105,42.8947368421053,NA -"7556",10.4471247126008,40.7894736842105,42.8947368421053,NA -"7557",13.5996552137305,40.7894736842105,42.8947368421053,NA -"7558",17.7034951740616,40.7894736842105,42.8947368421053,NA -"7559",23.045712295823,40.7894736842105,42.8947368421053,NA -"7560",30,40.7894736842105,42.8947368421053,NA -"7561",0.2,42.8947368421053,42.8947368421053,NA -"7562",0.260352117694686,42.8947368421053,42.8947368421053,NA -"7563",0.338916125940539,42.8947368421053,42.8947368421053,NA -"7564",0.441187655547492,42.8947368421053,42.8947368421053,NA -"7565",0.574320702112717,42.8947368421053,42.8947368421053,NA -"7566",0.747628055154725,42.8947368421053,42.8947368421053,NA -"7567",0.973232737037462,42.8947368421053,42.8947368421053,NA -"7568",1.2669160204875,42.8947368421053,42.8947368421053,NA -"7569",1.64922134437622,42.8947368421053,42.8947368421053,NA -"7570",2.14689134777813,42.8947368421053,42.8947368421053,NA -"7571",2.79473854427218,42.8947368421053,42.8947368421053,NA -"7572",3.63808049202114,42.8947368421053,42.8947368421053,NA -"7573",4.73590980220715,42.8947368421053,42.8947368421053,NA -"7574",6.16502073107827,42.8947368421053,42.8947368421053,NA -"7575",8.02538101483936,42.8947368421053,42.8947368421053,NA -"7576",10.4471247126008,42.8947368421053,42.8947368421053,NA -"7577",13.5996552137305,42.8947368421053,42.8947368421053,NA -"7578",17.7034951740616,42.8947368421053,42.8947368421053,NA -"7579",23.045712295823,42.8947368421053,42.8947368421053,NA -"7580",30,42.8947368421053,42.8947368421053,NA -"7581",0.2,45,42.8947368421053,NA -"7582",0.260352117694686,45,42.8947368421053,NA -"7583",0.338916125940539,45,42.8947368421053,NA -"7584",0.441187655547492,45,42.8947368421053,NA -"7585",0.574320702112717,45,42.8947368421053,NA -"7586",0.747628055154725,45,42.8947368421053,NA -"7587",0.973232737037462,45,42.8947368421053,NA -"7588",1.2669160204875,45,42.8947368421053,NA -"7589",1.64922134437622,45,42.8947368421053,NA -"7590",2.14689134777813,45,42.8947368421053,NA -"7591",2.79473854427218,45,42.8947368421053,NA -"7592",3.63808049202114,45,42.8947368421053,NA -"7593",4.73590980220715,45,42.8947368421053,NA -"7594",6.16502073107827,45,42.8947368421053,NA -"7595",8.02538101483936,45,42.8947368421053,NA -"7596",10.4471247126008,45,42.8947368421053,NA -"7597",13.5996552137305,45,42.8947368421053,NA -"7598",17.7034951740616,45,42.8947368421053,NA -"7599",23.045712295823,45,42.8947368421053,NA -"7600",30,45,42.8947368421053,NA -"7601",0.2,5,45,NA -"7602",0.260352117694686,5,45,NA -"7603",0.338916125940539,5,45,NA -"7604",0.441187655547492,5,45,NA -"7605",0.574320702112717,5,45,NA -"7606",0.747628055154725,5,45,NA -"7607",0.973232737037462,5,45,NA -"7608",1.2669160204875,5,45,NA -"7609",1.64922134437622,5,45,NA -"7610",2.14689134777813,5,45,NA -"7611",2.79473854427218,5,45,NA -"7612",3.63808049202114,5,45,NA -"7613",4.73590980220715,5,45,NA -"7614",6.16502073107827,5,45,NA -"7615",8.02538101483936,5,45,NA -"7616",10.4471247126008,5,45,NA -"7617",13.5996552137305,5,45,NA -"7618",17.7034951740616,5,45,NA -"7619",23.045712295823,5,45,NA -"7620",30,5,45,NA -"7621",0.2,7.10526315789474,45,NA -"7622",0.260352117694686,7.10526315789474,45,NA -"7623",0.338916125940539,7.10526315789474,45,NA -"7624",0.441187655547492,7.10526315789474,45,NA -"7625",0.574320702112717,7.10526315789474,45,NA -"7626",0.747628055154725,7.10526315789474,45,NA -"7627",0.973232737037462,7.10526315789474,45,NA -"7628",1.2669160204875,7.10526315789474,45,NA -"7629",1.64922134437622,7.10526315789474,45,NA -"7630",2.14689134777813,7.10526315789474,45,NA -"7631",2.79473854427218,7.10526315789474,45,NA -"7632",3.63808049202114,7.10526315789474,45,NA -"7633",4.73590980220715,7.10526315789474,45,NA -"7634",6.16502073107827,7.10526315789474,45,NA -"7635",8.02538101483936,7.10526315789474,45,NA -"7636",10.4471247126008,7.10526315789474,45,NA -"7637",13.5996552137305,7.10526315789474,45,NA -"7638",17.7034951740616,7.10526315789474,45,NA -"7639",23.045712295823,7.10526315789474,45,NA -"7640",30,7.10526315789474,45,NA -"7641",0.2,9.21052631578947,45,NA -"7642",0.260352117694686,9.21052631578947,45,NA -"7643",0.338916125940539,9.21052631578947,45,NA -"7644",0.441187655547492,9.21052631578947,45,NA -"7645",0.574320702112717,9.21052631578947,45,NA -"7646",0.747628055154725,9.21052631578947,45,NA -"7647",0.973232737037462,9.21052631578947,45,NA -"7648",1.2669160204875,9.21052631578947,45,NA -"7649",1.64922134437622,9.21052631578947,45,NA -"7650",2.14689134777813,9.21052631578947,45,NA -"7651",2.79473854427218,9.21052631578947,45,NA -"7652",3.63808049202114,9.21052631578947,45,NA -"7653",4.73590980220715,9.21052631578947,45,NA -"7654",6.16502073107827,9.21052631578947,45,NA -"7655",8.02538101483936,9.21052631578947,45,NA -"7656",10.4471247126008,9.21052631578947,45,NA -"7657",13.5996552137305,9.21052631578947,45,NA -"7658",17.7034951740616,9.21052631578947,45,NA -"7659",23.045712295823,9.21052631578947,45,NA -"7660",30,9.21052631578947,45,NA -"7661",0.2,11.3157894736842,45,NA -"7662",0.260352117694686,11.3157894736842,45,NA -"7663",0.338916125940539,11.3157894736842,45,NA -"7664",0.441187655547492,11.3157894736842,45,NA -"7665",0.574320702112717,11.3157894736842,45,NA -"7666",0.747628055154725,11.3157894736842,45,NA -"7667",0.973232737037462,11.3157894736842,45,NA -"7668",1.2669160204875,11.3157894736842,45,NA -"7669",1.64922134437622,11.3157894736842,45,NA -"7670",2.14689134777813,11.3157894736842,45,NA -"7671",2.79473854427218,11.3157894736842,45,NA -"7672",3.63808049202114,11.3157894736842,45,NA -"7673",4.73590980220715,11.3157894736842,45,NA -"7674",6.16502073107827,11.3157894736842,45,NA -"7675",8.02538101483936,11.3157894736842,45,NA -"7676",10.4471247126008,11.3157894736842,45,NA -"7677",13.5996552137305,11.3157894736842,45,NA -"7678",17.7034951740616,11.3157894736842,45,NA -"7679",23.045712295823,11.3157894736842,45,NA -"7680",30,11.3157894736842,45,NA -"7681",0.2,13.4210526315789,45,NA -"7682",0.260352117694686,13.4210526315789,45,NA -"7683",0.338916125940539,13.4210526315789,45,NA -"7684",0.441187655547492,13.4210526315789,45,NA -"7685",0.574320702112717,13.4210526315789,45,NA -"7686",0.747628055154725,13.4210526315789,45,NA -"7687",0.973232737037462,13.4210526315789,45,NA -"7688",1.2669160204875,13.4210526315789,45,NA -"7689",1.64922134437622,13.4210526315789,45,NA -"7690",2.14689134777813,13.4210526315789,45,NA -"7691",2.79473854427218,13.4210526315789,45,NA -"7692",3.63808049202114,13.4210526315789,45,NA -"7693",4.73590980220715,13.4210526315789,45,NA -"7694",6.16502073107827,13.4210526315789,45,NA -"7695",8.02538101483936,13.4210526315789,45,NA -"7696",10.4471247126008,13.4210526315789,45,NA -"7697",13.5996552137305,13.4210526315789,45,NA -"7698",17.7034951740616,13.4210526315789,45,NA -"7699",23.045712295823,13.4210526315789,45,NA -"7700",30,13.4210526315789,45,NA -"7701",0.2,15.5263157894737,45,NA -"7702",0.260352117694686,15.5263157894737,45,NA -"7703",0.338916125940539,15.5263157894737,45,NA -"7704",0.441187655547492,15.5263157894737,45,NA -"7705",0.574320702112717,15.5263157894737,45,NA -"7706",0.747628055154725,15.5263157894737,45,NA -"7707",0.973232737037462,15.5263157894737,45,NA -"7708",1.2669160204875,15.5263157894737,45,NA -"7709",1.64922134437622,15.5263157894737,45,NA -"7710",2.14689134777813,15.5263157894737,45,NA -"7711",2.79473854427218,15.5263157894737,45,NA -"7712",3.63808049202114,15.5263157894737,45,NA -"7713",4.73590980220715,15.5263157894737,45,NA -"7714",6.16502073107827,15.5263157894737,45,NA -"7715",8.02538101483936,15.5263157894737,45,NA -"7716",10.4471247126008,15.5263157894737,45,NA -"7717",13.5996552137305,15.5263157894737,45,NA -"7718",17.7034951740616,15.5263157894737,45,NA -"7719",23.045712295823,15.5263157894737,45,NA -"7720",30,15.5263157894737,45,NA -"7721",0.2,17.6315789473684,45,NA -"7722",0.260352117694686,17.6315789473684,45,NA -"7723",0.338916125940539,17.6315789473684,45,NA -"7724",0.441187655547492,17.6315789473684,45,NA -"7725",0.574320702112717,17.6315789473684,45,NA -"7726",0.747628055154725,17.6315789473684,45,NA -"7727",0.973232737037462,17.6315789473684,45,NA -"7728",1.2669160204875,17.6315789473684,45,NA -"7729",1.64922134437622,17.6315789473684,45,NA -"7730",2.14689134777813,17.6315789473684,45,NA -"7731",2.79473854427218,17.6315789473684,45,NA -"7732",3.63808049202114,17.6315789473684,45,NA -"7733",4.73590980220715,17.6315789473684,45,NA -"7734",6.16502073107827,17.6315789473684,45,NA -"7735",8.02538101483936,17.6315789473684,45,NA -"7736",10.4471247126008,17.6315789473684,45,NA -"7737",13.5996552137305,17.6315789473684,45,NA -"7738",17.7034951740616,17.6315789473684,45,NA -"7739",23.045712295823,17.6315789473684,45,NA -"7740",30,17.6315789473684,45,NA -"7741",0.2,19.7368421052632,45,NA -"7742",0.260352117694686,19.7368421052632,45,NA -"7743",0.338916125940539,19.7368421052632,45,NA -"7744",0.441187655547492,19.7368421052632,45,NA -"7745",0.574320702112717,19.7368421052632,45,NA -"7746",0.747628055154725,19.7368421052632,45,NA -"7747",0.973232737037462,19.7368421052632,45,NA -"7748",1.2669160204875,19.7368421052632,45,NA -"7749",1.64922134437622,19.7368421052632,45,NA -"7750",2.14689134777813,19.7368421052632,45,NA -"7751",2.79473854427218,19.7368421052632,45,NA -"7752",3.63808049202114,19.7368421052632,45,NA -"7753",4.73590980220715,19.7368421052632,45,NA -"7754",6.16502073107827,19.7368421052632,45,NA -"7755",8.02538101483936,19.7368421052632,45,NA -"7756",10.4471247126008,19.7368421052632,45,NA -"7757",13.5996552137305,19.7368421052632,45,NA -"7758",17.7034951740616,19.7368421052632,45,NA -"7759",23.045712295823,19.7368421052632,45,NA -"7760",30,19.7368421052632,45,NA -"7761",0.2,21.8421052631579,45,NA -"7762",0.260352117694686,21.8421052631579,45,NA -"7763",0.338916125940539,21.8421052631579,45,NA -"7764",0.441187655547492,21.8421052631579,45,NA -"7765",0.574320702112717,21.8421052631579,45,NA -"7766",0.747628055154725,21.8421052631579,45,NA -"7767",0.973232737037462,21.8421052631579,45,NA -"7768",1.2669160204875,21.8421052631579,45,NA -"7769",1.64922134437622,21.8421052631579,45,NA -"7770",2.14689134777813,21.8421052631579,45,NA -"7771",2.79473854427218,21.8421052631579,45,NA -"7772",3.63808049202114,21.8421052631579,45,NA -"7773",4.73590980220715,21.8421052631579,45,NA -"7774",6.16502073107827,21.8421052631579,45,NA -"7775",8.02538101483936,21.8421052631579,45,NA -"7776",10.4471247126008,21.8421052631579,45,NA -"7777",13.5996552137305,21.8421052631579,45,NA -"7778",17.7034951740616,21.8421052631579,45,NA -"7779",23.045712295823,21.8421052631579,45,NA -"7780",30,21.8421052631579,45,NA -"7781",0.2,23.9473684210526,45,NA -"7782",0.260352117694686,23.9473684210526,45,NA -"7783",0.338916125940539,23.9473684210526,45,NA -"7784",0.441187655547492,23.9473684210526,45,NA -"7785",0.574320702112717,23.9473684210526,45,NA -"7786",0.747628055154725,23.9473684210526,45,NA -"7787",0.973232737037462,23.9473684210526,45,NA -"7788",1.2669160204875,23.9473684210526,45,NA -"7789",1.64922134437622,23.9473684210526,45,NA -"7790",2.14689134777813,23.9473684210526,45,NA -"7791",2.79473854427218,23.9473684210526,45,NA -"7792",3.63808049202114,23.9473684210526,45,NA -"7793",4.73590980220715,23.9473684210526,45,NA -"7794",6.16502073107827,23.9473684210526,45,NA -"7795",8.02538101483936,23.9473684210526,45,NA -"7796",10.4471247126008,23.9473684210526,45,NA -"7797",13.5996552137305,23.9473684210526,45,NA -"7798",17.7034951740616,23.9473684210526,45,NA -"7799",23.045712295823,23.9473684210526,45,NA -"7800",30,23.9473684210526,45,NA -"7801",0.2,26.0526315789474,45,NA -"7802",0.260352117694686,26.0526315789474,45,NA -"7803",0.338916125940539,26.0526315789474,45,NA -"7804",0.441187655547492,26.0526315789474,45,NA -"7805",0.574320702112717,26.0526315789474,45,NA -"7806",0.747628055154725,26.0526315789474,45,NA -"7807",0.973232737037462,26.0526315789474,45,NA -"7808",1.2669160204875,26.0526315789474,45,NA -"7809",1.64922134437622,26.0526315789474,45,NA -"7810",2.14689134777813,26.0526315789474,45,NA -"7811",2.79473854427218,26.0526315789474,45,NA -"7812",3.63808049202114,26.0526315789474,45,NA -"7813",4.73590980220715,26.0526315789474,45,NA -"7814",6.16502073107827,26.0526315789474,45,NA -"7815",8.02538101483936,26.0526315789474,45,NA -"7816",10.4471247126008,26.0526315789474,45,NA -"7817",13.5996552137305,26.0526315789474,45,NA -"7818",17.7034951740616,26.0526315789474,45,NA -"7819",23.045712295823,26.0526315789474,45,NA -"7820",30,26.0526315789474,45,NA -"7821",0.2,28.1578947368421,45,NA -"7822",0.260352117694686,28.1578947368421,45,NA -"7823",0.338916125940539,28.1578947368421,45,NA -"7824",0.441187655547492,28.1578947368421,45,NA -"7825",0.574320702112717,28.1578947368421,45,NA -"7826",0.747628055154725,28.1578947368421,45,NA -"7827",0.973232737037462,28.1578947368421,45,NA -"7828",1.2669160204875,28.1578947368421,45,NA -"7829",1.64922134437622,28.1578947368421,45,NA -"7830",2.14689134777813,28.1578947368421,45,NA -"7831",2.79473854427218,28.1578947368421,45,NA -"7832",3.63808049202114,28.1578947368421,45,NA -"7833",4.73590980220715,28.1578947368421,45,NA -"7834",6.16502073107827,28.1578947368421,45,NA -"7835",8.02538101483936,28.1578947368421,45,NA -"7836",10.4471247126008,28.1578947368421,45,NA -"7837",13.5996552137305,28.1578947368421,45,NA -"7838",17.7034951740616,28.1578947368421,45,NA -"7839",23.045712295823,28.1578947368421,45,NA -"7840",30,28.1578947368421,45,NA -"7841",0.2,30.2631578947368,45,NA -"7842",0.260352117694686,30.2631578947368,45,NA -"7843",0.338916125940539,30.2631578947368,45,NA -"7844",0.441187655547492,30.2631578947368,45,NA -"7845",0.574320702112717,30.2631578947368,45,NA -"7846",0.747628055154725,30.2631578947368,45,NA -"7847",0.973232737037462,30.2631578947368,45,NA -"7848",1.2669160204875,30.2631578947368,45,NA -"7849",1.64922134437622,30.2631578947368,45,NA -"7850",2.14689134777813,30.2631578947368,45,NA -"7851",2.79473854427218,30.2631578947368,45,NA -"7852",3.63808049202114,30.2631578947368,45,NA -"7853",4.73590980220715,30.2631578947368,45,NA -"7854",6.16502073107827,30.2631578947368,45,NA -"7855",8.02538101483936,30.2631578947368,45,NA -"7856",10.4471247126008,30.2631578947368,45,NA -"7857",13.5996552137305,30.2631578947368,45,NA -"7858",17.7034951740616,30.2631578947368,45,NA -"7859",23.045712295823,30.2631578947368,45,NA -"7860",30,30.2631578947368,45,NA -"7861",0.2,32.3684210526316,45,NA -"7862",0.260352117694686,32.3684210526316,45,NA -"7863",0.338916125940539,32.3684210526316,45,NA -"7864",0.441187655547492,32.3684210526316,45,NA -"7865",0.574320702112717,32.3684210526316,45,NA -"7866",0.747628055154725,32.3684210526316,45,NA -"7867",0.973232737037462,32.3684210526316,45,NA -"7868",1.2669160204875,32.3684210526316,45,NA -"7869",1.64922134437622,32.3684210526316,45,NA -"7870",2.14689134777813,32.3684210526316,45,NA -"7871",2.79473854427218,32.3684210526316,45,NA -"7872",3.63808049202114,32.3684210526316,45,NA -"7873",4.73590980220715,32.3684210526316,45,NA -"7874",6.16502073107827,32.3684210526316,45,NA -"7875",8.02538101483936,32.3684210526316,45,NA -"7876",10.4471247126008,32.3684210526316,45,NA -"7877",13.5996552137305,32.3684210526316,45,NA -"7878",17.7034951740616,32.3684210526316,45,NA -"7879",23.045712295823,32.3684210526316,45,NA -"7880",30,32.3684210526316,45,NA -"7881",0.2,34.4736842105263,45,NA -"7882",0.260352117694686,34.4736842105263,45,NA -"7883",0.338916125940539,34.4736842105263,45,NA -"7884",0.441187655547492,34.4736842105263,45,NA -"7885",0.574320702112717,34.4736842105263,45,NA -"7886",0.747628055154725,34.4736842105263,45,NA -"7887",0.973232737037462,34.4736842105263,45,NA -"7888",1.2669160204875,34.4736842105263,45,NA -"7889",1.64922134437622,34.4736842105263,45,NA -"7890",2.14689134777813,34.4736842105263,45,NA -"7891",2.79473854427218,34.4736842105263,45,NA -"7892",3.63808049202114,34.4736842105263,45,NA -"7893",4.73590980220715,34.4736842105263,45,NA -"7894",6.16502073107827,34.4736842105263,45,NA -"7895",8.02538101483936,34.4736842105263,45,NA -"7896",10.4471247126008,34.4736842105263,45,NA -"7897",13.5996552137305,34.4736842105263,45,NA -"7898",17.7034951740616,34.4736842105263,45,NA -"7899",23.045712295823,34.4736842105263,45,NA -"7900",30,34.4736842105263,45,NA -"7901",0.2,36.5789473684211,45,NA -"7902",0.260352117694686,36.5789473684211,45,NA -"7903",0.338916125940539,36.5789473684211,45,NA -"7904",0.441187655547492,36.5789473684211,45,NA -"7905",0.574320702112717,36.5789473684211,45,NA -"7906",0.747628055154725,36.5789473684211,45,NA -"7907",0.973232737037462,36.5789473684211,45,NA -"7908",1.2669160204875,36.5789473684211,45,NA -"7909",1.64922134437622,36.5789473684211,45,NA -"7910",2.14689134777813,36.5789473684211,45,NA -"7911",2.79473854427218,36.5789473684211,45,NA -"7912",3.63808049202114,36.5789473684211,45,NA -"7913",4.73590980220715,36.5789473684211,45,NA -"7914",6.16502073107827,36.5789473684211,45,NA -"7915",8.02538101483936,36.5789473684211,45,NA -"7916",10.4471247126008,36.5789473684211,45,NA -"7917",13.5996552137305,36.5789473684211,45,NA -"7918",17.7034951740616,36.5789473684211,45,NA -"7919",23.045712295823,36.5789473684211,45,NA -"7920",30,36.5789473684211,45,NA -"7921",0.2,38.6842105263158,45,NA -"7922",0.260352117694686,38.6842105263158,45,NA -"7923",0.338916125940539,38.6842105263158,45,NA -"7924",0.441187655547492,38.6842105263158,45,NA -"7925",0.574320702112717,38.6842105263158,45,NA -"7926",0.747628055154725,38.6842105263158,45,NA -"7927",0.973232737037462,38.6842105263158,45,NA -"7928",1.2669160204875,38.6842105263158,45,NA -"7929",1.64922134437622,38.6842105263158,45,NA -"7930",2.14689134777813,38.6842105263158,45,NA -"7931",2.79473854427218,38.6842105263158,45,NA -"7932",3.63808049202114,38.6842105263158,45,NA -"7933",4.73590980220715,38.6842105263158,45,NA -"7934",6.16502073107827,38.6842105263158,45,NA -"7935",8.02538101483936,38.6842105263158,45,NA -"7936",10.4471247126008,38.6842105263158,45,NA -"7937",13.5996552137305,38.6842105263158,45,NA -"7938",17.7034951740616,38.6842105263158,45,NA -"7939",23.045712295823,38.6842105263158,45,NA -"7940",30,38.6842105263158,45,NA -"7941",0.2,40.7894736842105,45,NA -"7942",0.260352117694686,40.7894736842105,45,NA -"7943",0.338916125940539,40.7894736842105,45,NA -"7944",0.441187655547492,40.7894736842105,45,NA -"7945",0.574320702112717,40.7894736842105,45,NA -"7946",0.747628055154725,40.7894736842105,45,NA -"7947",0.973232737037462,40.7894736842105,45,NA -"7948",1.2669160204875,40.7894736842105,45,NA -"7949",1.64922134437622,40.7894736842105,45,NA -"7950",2.14689134777813,40.7894736842105,45,NA -"7951",2.79473854427218,40.7894736842105,45,NA -"7952",3.63808049202114,40.7894736842105,45,NA -"7953",4.73590980220715,40.7894736842105,45,NA -"7954",6.16502073107827,40.7894736842105,45,NA -"7955",8.02538101483936,40.7894736842105,45,NA -"7956",10.4471247126008,40.7894736842105,45,NA -"7957",13.5996552137305,40.7894736842105,45,NA -"7958",17.7034951740616,40.7894736842105,45,NA -"7959",23.045712295823,40.7894736842105,45,NA -"7960",30,40.7894736842105,45,NA -"7961",0.2,42.8947368421053,45,NA -"7962",0.260352117694686,42.8947368421053,45,NA -"7963",0.338916125940539,42.8947368421053,45,NA -"7964",0.441187655547492,42.8947368421053,45,NA -"7965",0.574320702112717,42.8947368421053,45,NA -"7966",0.747628055154725,42.8947368421053,45,NA -"7967",0.973232737037462,42.8947368421053,45,NA -"7968",1.2669160204875,42.8947368421053,45,NA -"7969",1.64922134437622,42.8947368421053,45,NA -"7970",2.14689134777813,42.8947368421053,45,NA -"7971",2.79473854427218,42.8947368421053,45,NA -"7972",3.63808049202114,42.8947368421053,45,NA -"7973",4.73590980220715,42.8947368421053,45,NA -"7974",6.16502073107827,42.8947368421053,45,NA -"7975",8.02538101483936,42.8947368421053,45,NA -"7976",10.4471247126008,42.8947368421053,45,NA -"7977",13.5996552137305,42.8947368421053,45,NA -"7978",17.7034951740616,42.8947368421053,45,NA -"7979",23.045712295823,42.8947368421053,45,NA -"7980",30,42.8947368421053,45,NA -"7981",0.2,45,45,NA -"7982",0.260352117694686,45,45,NA -"7983",0.338916125940539,45,45,NA -"7984",0.441187655547492,45,45,NA -"7985",0.574320702112717,45,45,NA -"7986",0.747628055154725,45,45,NA -"7987",0.973232737037462,45,45,NA -"7988",1.2669160204875,45,45,NA -"7989",1.64922134437622,45,45,NA -"7990",2.14689134777813,45,45,NA -"7991",2.79473854427218,45,45,NA -"7992",3.63808049202114,45,45,NA -"7993",4.73590980220715,45,45,NA -"7994",6.16502073107827,45,45,NA -"7995",8.02538101483936,45,45,NA -"7996",10.4471247126008,45,45,NA -"7997",13.5996552137305,45,45,NA -"7998",17.7034951740616,45,45,NA -"7999",23.045712295823,45,45,NA -"8000",30,45,45,NA +"temp","aridity_index","mean_gdd_temp","phio" +0,0.2,5,0.0150189600590777 +1,0.2,5,0.0170035547170646 +2,0.2,5,0.0192332352709473 +3,0.2,5,0.0217360643227769 +4,0.2,5,0.024543006070574 +5,0.2,5,0.0276881368424111 +6,0.2,5,0.0312088037406028 +7,0.2,5,0.0351456582790139 +8,0.2,5,0.0395424206049159 +9,0.2,5,0.0444450927333507 +10,0.2,5,0.0499000783715251 +11,0.2,5,0.0559501789959781 +12,0.2,5,0.0626265467550122 +13,0.2,5,0.0699331259947415 +14,0.2,5,0.077817639344329 +15,0.2,5,0.086119917160609 +16,0.2,5,0.0944863424652653 +17,0.2,5,0.102245986112935 +18,0.2,5,0.108278645046534 +19,0.2,5,0.110993670865875 +20,0.2,5,0.108656270648972 +21,0.2,5,0.100233466068612 +22,0.2,5,0.0863769414144302 +23,0.2,5,0.0695291602163739 +24,0.2,5,0.0527323208217483 +25,0.2,5,0.0381989078376782 +26,0.2,5,0.0268025777720468 +27,0.2,5,0.018427804600136 +28,0.2,5,0.0125189835189365 +29,0.2,5,0.00845045031413486 +30,0.2,5,0.0056877326986421 +31,0.2,5,0.00382552594257428 +32,0.2,5,0.00257458000318248 +33,0.2,5,0.0017351030307797 +34,0.2,5,0.00117151635254028 +35,0.2,5,0.000792669260635163 +36,0.2,5,0.000537553978366543 +37,0.2,5,0.000365404661290626 +38,0.2,5,0.000248980545228804 +39,0.2,5,0.000170060161455839 +40,0.2,5,0.00011643555265551 +41,0.2,5,7.99117417470755e-05 +42,0.2,5,5.49757747415985e-05 +43,0.2,5,3.79105727169236e-05 +44,0.2,5,2.62040988167543e-05 +45,0.2,5,1.81547071246715e-05 +46,0.2,5,1.26069903869731e-05 +47,0.2,5,8.77458695053462e-06 +48,0.2,5,6.12105026286057e-06 +49,0.2,5,4.27957031376439e-06 +50,0.2,5,2.99875068859148e-06 +0,0.5,5,0.0150087964558047 +1,0.5,5,0.0169920481025125 +2,0.5,5,0.0192202197910352 +3,0.5,5,0.0217213551329513 +4,0.5,5,0.0245263973722456 +5,0.5,5,0.0276693997769201 +6,0.5,5,0.0311876841758263 +7,0.5,5,0.0351218745732107 +8,0.5,5,0.0395156615301265 +9,0.5,5,0.0444150159312156 +10,0.5,5,0.0498663100814529 +11,0.5,5,0.0559123164928401 +12,0.5,5,0.0625841662324547 +13,0.5,5,0.0698858009772002 +14,0.5,5,0.0777649787332865 +15,0.5,5,0.0860616382472569 +16,0.5,5,0.0944224018398324 +17,0.5,5,0.102176794395598 +18,0.5,5,0.10820537091924 +19,0.5,5,0.110918559431258 +20,0.5,5,0.108582740975569 +21,0.5,5,0.10016563626017 +22,0.5,5,0.0863184885680936 +23,0.5,5,0.0694821085698177 +24,0.5,5,0.0526966359017281 +25,0.5,5,0.0381730579423994 +26,0.5,5,0.0267844399804756 +27,0.5,5,0.0184153341697992 +28,0.5,5,0.0125105116952305 +29,0.5,5,0.00844473174080269 +30,0.5,5,0.0056838837065385 +31,0.5,5,0.00382293713963202 +32,0.5,5,0.00257283773809596 +33,0.5,5,0.00173392885501965 +34,0.5,5,0.00117072356612975 +35,0.5,5,0.000792132846938071 +36,0.5,5,0.000537190205818216 +37,0.5,5,0.000365157385314337 +38,0.5,5,0.000248812055568106 +39,0.5,5,0.000169945078653383 +40,0.5,5,0.000116356758600569 +41,0.5,5,7.98576640188723e-05 +42,0.5,5,5.49385716355312e-05 +43,0.5,5,3.78849179432622e-05 +44,0.5,5,2.61863660267708e-05 +45,0.5,5,1.81424215043605e-05 +46,0.5,5,1.25984590074199e-05 +47,0.5,5,8.76864902804874e-06 +48,0.5,5,6.11690803688481e-06 +49,0.5,5,4.27667425074293e-06 +50,0.5,5,2.99672137949195e-06 +0,0.8,5,0.0147871102993512 +1,0.8,5,0.0167410684956392 +2,0.8,5,0.018936329163015 +3,0.8,5,0.0214005216972681 +4,0.8,5,0.0241641322978198 +5,0.8,5,0.027260711251762 +6,0.8,5,0.0307270291290353 +7,0.8,5,0.0346031099004733 +8,0.8,5,0.0389319987993988 +9,0.8,5,0.0437589877013968 +10,0.8,5,0.0491297639732404 +11,0.8,5,0.0550864683591668 +12,0.8,5,0.0616597721074645 +13,0.8,5,0.0688535586748324 +14,0.8,5,0.0766163577034236 +15,0.8,5,0.0847904721109644 +16,0.8,5,0.0930277437532484 +17,0.8,5,0.100667600710748 +18,0.8,5,0.10660713265561 +19,0.8,5,0.109280246246581 +20,0.8,5,0.106978928799494 +21,0.8,5,0.0986861482161674 +22,0.8,5,0.0850435286458984 +23,0.8,5,0.0684558289719509 +24,0.8,5,0.0519182847057823 +25,0.8,5,0.0376092260242143 +26,0.8,5,0.0263888226790141 +27,0.8,5,0.0181433320366548 +28,0.8,5,0.0123257262421698 +29,0.8,5,0.00831999954609194 +30,0.8,5,0.00559993038380929 +31,0.8,5,0.00376647077050349 +32,0.8,5,0.00253483585626509 +33,0.8,5,0.00170831800577101 +34,0.8,5,0.00115343149288397 +35,0.8,5,0.000780432715834597 +36,0.8,5,0.000529255683395783 +37,0.8,5,0.000359763859091944 +38,0.8,5,0.000245136998181552 +39,0.8,5,0.000167434919267466 +40,0.8,5,0.000114638120955805 +41,0.8,5,7.86781331582981e-05 +42,0.8,5,5.41271061177738e-05 +43,0.8,5,3.7325341972522e-05 +44,0.8,5,2.57995825259715e-05 +45,0.8,5,1.78744504046189e-05 +46,0.8,5,1.24123745360356e-05 +47,0.8,5,8.63913244049012e-06 +48,0.8,5,6.02655876497154e-06 +49,0.8,5,4.21350599605692e-06 +50,0.8,5,2.95245856024873e-06 +0,1,5,0.0142131114771569 +1,1,5,0.0160912218789413 +2,1,5,0.0182012679903981 +3,1,5,0.0205698067029317 +4,1,5,0.0232261408175705 +5,1,5,0.0262025182827559 +6,1,5,0.0295342823264114 +7,1,5,0.0332599032884279 +8,1,5,0.037420755493294 +9,1,5,0.0420603726986994 +10,1,5,0.0472226688015378 +11,1,5,0.0529481487472277 +12,1,5,0.0592662932025286 +13,1,5,0.0661808348780146 +14,1,5,0.07364230136704 +15,1,5,0.0814991169956155 +16,1,5,0.0894166382522564 +17,1,5,0.0967599349754323 +18,1,5,0.102468909071484 +19,1,5,0.105038259045241 +20,1,5,0.102826273014325 +21,1,5,0.0948553975355923 +22,1,5,0.0817423505056272 +23,1,5,0.0657985440523975 +24,1,5,0.049902946098835 +25,1,5,0.0361493294653519 +26,1,5,0.0253644742545951 +27,1,5,0.0174390530390079 +28,1,5,0.0118472722236043 +29,1,5,0.00799703786910195 +30,1,5,0.00538255502245704 +31,1,5,0.00362026574853964 +32,1,5,0.00243643983659003 +33,1,5,0.00164200535215613 +34,1,5,0.00110865815279288 +35,1,5,0.00075013826001312 +36,1,5,0.00050871129488722 +37,1,5,0.000345798721400645 +38,1,5,0.000235621389967103 +39,1,5,0.000160935512384842 +40,1,5,0.000110188154392013 +41,1,5,7.56240438297498e-05 +42,1,5,5.20260265605492e-05 +43,1,5,3.58764650860644e-05 +44,1,5,2.47981069378937e-05 +45,1,5,1.71806087227811e-05 +46,1,5,1.19305570463377e-05 +47,1,5,8.30378281874286e-06 +48,1,5,5.79262275158219e-06 +49,1,5,4.04994817914176e-06 +50,1,5,2.83785146651286e-06 +0,5,5,0.00623280751560459 +1,5,5,0.00705640625020894 +2,5,5,0.00798171463767199 +3,5,5,0.00902037854403804 +4,5,5,0.0101852479859112 +5,5,5,0.0114904645012463 +6,5,5,0.0129515269860437 +7,5,5,0.0145853056536965 +8,5,5,0.0164099441880168 +9,5,5,0.018444533238687 +10,5,5,0.0207083301560094 +11,5,5,0.0232190973791676 +12,5,5,0.0259897629233706 +13,5,5,0.0290219636762597 +14,5,5,0.0322940047409465 +15,5,5,0.0357394163650802 +16,5,5,0.0392114489367421 +17,5,5,0.042431669581538 +18,5,5,0.0449351985737262 +19,5,5,0.046061923278052 +20,5,5,0.0450919116672895 +21,5,5,0.0415964819248547 +22,5,5,0.0358460803880624 +23,5,5,0.0288543195165074 +24,5,5,0.0218836992867833 +25,5,5,0.0158523918381862 +26,5,5,0.0111229610784016 +27,5,5,0.00764746417568367 +28,5,5,0.00519532739002096 +29,5,5,0.00350690260983471 +30,5,5,0.00236038600351824 +31,5,5,0.0015875777518701 +32,5,5,0.00106844026019379 +33,5,5,0.000720060721118673 +34,5,5,0.000486174535257078 +35,5,5,0.000328954528518732 +36,5,5,0.000223082720989131 +37,5,5,0.000151641452548681 +38,5,5,0.000103325916537308 +39,5,5,7.05742773306221e-05 +40,5,5,4.83202821513731e-05 +41,5,5,3.31630487455209e-05 +42,5,5,2.28147235652654e-05 +43,5,5,1.57327339324069e-05 +44,5,5,1.08745947390675e-05 +45,5,5,7.534129830904e-06 +46,5,5,5.23184988334714e-06 +47,5,5,3.64141799941484e-06 +48,5,5,2.54021103536337e-06 +49,5,5,1.77600432455155e-06 +50,5,5,1.24446937442786e-06 +0,10,5,0.00426760974702343 +1,10,5,0.00483152865172792 +2,10,5,0.00546508826085325 +3,10,5,0.00617626251091497 +4,10,5,0.00697384982156139 +5,10,5,0.00786753291844417 +6,10,5,0.00886792391167172 +7,10,5,0.00998657385378817 +8,10,5,0.0112359057438496 +9,10,5,0.0126289909694224 +10,10,5,0.0141790150581591 +11,10,5,0.015898139970525 +12,10,5,0.0177952175318935 +13,10,5,0.0198713685209243 +14,10,5,0.0221117384192981 +15,10,5,0.0244708153188893 +16,10,5,0.0268481196087635 +17,10,5,0.0290530080120858 +18,10,5,0.0307671769002264 +19,10,5,0.0315386464696547 +20,10,5,0.0308744785173392 +21,10,5,0.0284811541604577 +22,10,5,0.0245438482856536 +23,10,5,0.0197565823914956 +24,10,5,0.0149837915166464 +25,10,5,0.0108541490737366 +26,10,5,0.00761590294503817 +27,10,5,0.00523622662410975 +28,10,5,0.00355724603288676 +29,10,5,0.00240117984104644 +30,10,5,0.00161615873587185 +31,10,5,0.00108701612733522 +32,10,5,0.000731562150298966 +33,10,5,0.000493026319872913 +34,10,5,0.000332884206711529 +35,10,5,0.000225235505623963 +36,10,5,0.000152744969598724 +37,10,5,0.00010382905926893 +38,10,5,7.07473618318486e-05 +39,10,5,4.83222806209317e-05 +40,10,5,3.3084947124044e-05 +41,10,5,2.2706773747315e-05 +42,10,5,1.56212648022594e-05 +43,10,5,1.0772219181993e-05 +44,10,5,7.44584625583012e-06 +45,10,5,5.15862648111748e-06 +46,10,5,3.58225302181016e-06 +47,10,5,2.49328266730244e-06 +48,10,5,1.73928512101045e-06 +49,10,5,1.21603199637343e-06 +50,10,5,8.52089466726507e-07 +0,0.2,10,0.0159348721317312 +1,0.2,10,0.0180400606834725 +2,0.2,10,0.0204048701222286 +3,0.2,10,0.0230587423802596 +4,0.2,10,0.0260339448554785 +5,0.2,10,0.0293656107576921 +6,0.2,10,0.0330916008876179 +7,0.2,10,0.0372520346890142 +8,0.2,10,0.0418882273335961 +9,0.2,10,0.0470405839181718 +10,0.2,10,0.0527446994022468 +11,0.2,10,0.0590244402441983 +12,0.2,10,0.0658800964135193 +13,0.2,10,0.0732688274311094 +14,0.2,10,0.0810738976499304 +15,0.2,10,0.0890596325661463 +16,0.2,10,0.0968131033894681 +17,0.2,10,0.103685681055626 +18,0.2,10,0.108771990658426 +19,0.2,10,0.110994287959672 +20,0.2,10,0.109361450681138 +21,0.2,10,0.103381358344563 +22,0.2,10,0.0934223095109367 +23,0.2,10,0.0807245799182078 +24,0.2,10,0.0669741885291157 +25,0.2,10,0.0537150069889818 +26,0.2,10,0.0419666864115946 +27,0.2,10,0.0321704918502215 +28,0.2,10,0.0243414293132923 +29,0.2,10,0.0182622219059435 +30,0.2,10,0.0136307381473869 +31,0.2,10,0.0101449626493986 +32,0.2,10,0.00754110550459295 +33,0.2,10,0.00560448586335027 +34,0.2,10,0.00416735303324539 +35,0.2,10,0.00310178079125282 +36,0.2,10,0.0023116409276084 +37,0.2,10,0.00172533486563622 +38,0.2,10,0.00128980580167562 +39,0.2,10,0.000965843289117765 +40,0.2,10,0.000724503101690771 +41,0.2,10,0.00054442221595272 +42,0.2,10,0.000409824764397559 +43,0.2,10,0.000309049548902073 +44,0.2,10,0.000233466057633311 +45,0.2,10,0.000176677619332255 +46,0.2,10,0.000133935832923386 +47,0.2,10,0.000101710093083305 +48,0.2,10,7.73708644180207e-05 +49,0.2,10,5.89563774371837e-05 +50,0.2,10,4.50005399308707e-05 +0,0.5,10,0.01592408871411 +1,0.5,10,0.0180278526464922 +2,0.5,10,0.0203910617757157 +3,0.5,10,0.0230431381101501 +4,0.5,10,0.0260163272117735 +5,0.5,10,0.029345738515111 +6,0.5,10,0.0330692071997882 +7,0.5,10,0.0372268255600065 +8,0.5,10,0.0418598808087534 +9,0.5,10,0.0470087506999734 +10,0.5,10,0.0527090061054162 +11,0.5,10,0.0589844973325925 +12,0.5,10,0.0658355141547679 +13,0.5,10,0.0732192450837728 +14,0.5,10,0.0810190334697031 +15,0.5,10,0.0889993642939438 +16,0.5,10,0.096747588202624 +17,0.5,10,0.103615515070552 +18,0.5,10,0.108698382675189 +19,0.5,10,0.110919176107456 +20,0.5,10,0.109287443799589 +21,0.5,10,0.103311398300199 +22,0.5,10,0.0933590889359449 +23,0.5,10,0.0806699521276393 +24,0.5,10,0.0669288658783422 +25,0.5,10,0.0536786570673698 +26,0.5,10,0.0419382867920676 +27,0.5,10,0.0321487214936205 +28,0.5,10,0.0243249570256196 +29,0.5,10,0.0182498635284257 +30,0.5,10,0.0136215139791154 +31,0.5,10,0.0101380973687678 +32,0.5,10,0.00753600230142264 +33,0.5,10,0.0056006932058933 +34,0.5,10,0.00416453290969744 +35,0.5,10,0.00309968175981003 +36,0.5,10,0.00231007659817378 +37,0.5,10,0.00172416730017108 +38,0.5,10,0.00128893296664471 +39,0.5,10,0.000965189685407799 +40,0.5,10,0.000724012817272499 +41,0.5,10,0.000544053795543173 +42,0.5,10,0.000409547428530069 +43,0.5,10,0.000308840409454709 +44,0.5,10,0.000233308066908377 +45,0.5,10,0.000176558058375768 +46,0.5,10,0.000133845196110683 +47,0.5,10,0.000101641264014522 +48,0.5,10,7.73185061476919e-05 +49,0.5,10,5.89164805849166e-05 +50,0.5,10,4.49700872475206e-05 +0,0.8,10,0.015688883310902 +1,0.8,10,0.017761573776359 +2,0.8,10,0.0200898773253586 +3,0.8,10,0.0227027813909882 +4,0.8,10,0.0256320552548849 +5,0.8,10,0.0289122897706457 +6,0.8,10,0.032580761276581 +7,0.8,10,0.0366769698870574 +8,0.8,10,0.0412415929857811 +9,0.8,10,0.0463144119305029 +10,0.8,10,0.0519304721964248 +11,0.8,10,0.0581132718121114 +12,0.8,10,0.0648630962707566 +13,0.8,10,0.0721377664276497 +14,0.8,10,0.0798223487000506 +15,0.8,10,0.087684806723973 +16,0.8,10,0.0953185861478663 +17,0.8,10,0.102085070883866 +18,0.8,10,0.107092862423186 +19,0.8,10,0.109280853814216 +20,0.8,10,0.107673222870156 +21,0.8,10,0.101785446044504 +22,0.8,10,0.0919801364225203 +23,0.8,10,0.0794784234343744 +24,0.8,10,0.0659402987353304 +25,0.8,10,0.0528858010109971 +26,0.8,10,0.0413188408801616 +27,0.8,10,0.0316738715265495 +28,0.8,10,0.0239656673087669 +29,0.8,10,0.0179803054653704 +30,0.8,10,0.0134203185609485 +31,0.8,10,0.009988353460517 +32,0.8,10,0.00742469241790557 +33,0.8,10,0.00551796864140568 +34,0.8,10,0.00410302102918834 +35,0.8,10,0.00305389817299248 +36,0.8,10,0.00227595580749811 +37,0.8,10,0.0016987006331413 +38,0.8,10,0.00126989489146372 +39,0.8,10,0.00095093343293368 +40,0.8,10,0.000713318847295837 +41,0.8,10,0.000536017895050215 +42,0.8,10,0.000403498242935236 +43,0.8,10,0.000304278708352883 +44,0.8,10,0.000229862009872771 +45,0.8,10,0.000173950222533136 +46,0.8,10,0.000131868246981356 +47,0.8,10,0.000100139980335794 +48,0.8,10,7.61764797033277e-05 +49,0.8,10,5.80462597000444e-05 +50,0.8,10,4.43058603838519e-05 +0,1,10,0.0150798799045774 +1,1,10,0.0170721136843222 +2,1,10,0.0193100382838326 +3,1,10,0.0218215159161824 +4,1,10,0.0246370826585575 +5,1,10,0.0277899866337021 +6,1,10,0.0313160572052403 +7,1,10,0.0352532611914002 +8,1,10,0.0396406969810833 +9,1,10,0.0445166017187335 +10,1,10,0.0499146605014209 +11,1,10,0.0558574592227188 +12,1,10,0.062345272293686 +13,1,10,0.0693375578590411 +14,1,10,0.0767238437716991 +15,1,10,0.0842811007418712 +16,1,10,0.0916185558461712 +17,1,10,0.0981223824839869 +18,1,10,0.102935784018285 +19,1,10,0.105038843028613 +20,1,10,0.103493616317005 +21,1,10,0.0978343883352343 +22,1,10,0.0884096964310015 +23,1,10,0.0763932688289341 +24,1,10,0.0633806604393419 +25,1,10,0.0508329058288701 +26,1,10,0.0397149463044452 +27,1,10,0.0304443706583932 +28,1,10,0.023035379745487 +29,1,10,0.0172823547535082 +30,1,10,0.0128993751926018 +31,1,10,0.00960063043648239 +32,1,10,0.0071364843355448 +33,1,10,0.0053037748309212 +34,1,10,0.00394375196373096 +35,1,10,0.00293535344593542 +36,1,10,0.00218760886705987 +37,1,10,0.00163276130199783 +38,1,10,0.00122060073207392 +39,1,10,0.000914020563587387 +40,1,10,0.000685629584829537 +41,1,10,0.000515211014313861 +42,1,10,0.00038783544530178 +43,1,10,0.000292467366131337 +44,1,10,0.000220939338690695 +45,1,10,0.000167197907791908 +46,1,10,0.000126749449804639 +47,1,10,9.62527955103834e-05 +48,1,10,7.32194983362149e-05 +49,1,10,5.5793048354074e-05 +50,1,10,4.25860171445846e-05 +0,5,10,0.00661290731130364 +1,5,10,0.00748655202275138 +2,5,10,0.00846793834942603 +3,5,10,0.00956928457381476 +4,5,10,0.010803981535192 +5,5,10,0.012186609373146 +6,5,10,0.0137328801664313 +7,5,10,0.0154594433215044 +8,5,10,0.0173834444670748 +9,5,10,0.0195216515544562 +10,5,10,0.0218888363474892 +11,5,10,0.0244949033296108 +12,5,10,0.0273399728369844 +13,5,10,0.0304062662445217 +14,5,10,0.0336453387321195 +15,5,10,0.0369593863364563 +16,5,10,0.0401770452841817 +17,5,10,0.0430291371441181 +18,5,10,0.0451399350019138 +19,5,10,0.0460621793694752 +20,5,10,0.0453845585208032 +21,5,10,0.0429028444531981 +22,5,10,0.0387698795758474 +23,5,10,0.0335003732901016 +24,5,10,0.0277940166279013 +25,5,10,0.0222915100609328 +26,5,10,0.0174160046662559 +27,5,10,0.0133506236514401 +28,5,10,0.0101015944491274 +29,5,10,0.0075787480291091 +30,5,10,0.0056567010521425 +31,5,10,0.00421011835692852 +32,5,10,0.00312952820169364 +33,5,10,0.00232583890447701 +34,5,10,0.00172943460822976 +35,5,10,0.00128722644919703 +36,5,10,0.000959321610171561 +37,5,10,0.000716006972198611 +38,5,10,0.000535264176929162 +39,5,10,0.000400821048037273 +40,5,10,0.000300665849002489 +41,5,10,0.000225933011733477 +42,5,10,0.000170075615193749 +43,5,10,0.000128254309453789 +44,5,10,9.68874671036868e-05 +45,5,10,7.33204955124456e-05 +46,5,10,5.5582827490714e-05 +47,5,10,4.22092761475389e-05 +48,5,10,3.210859495841e-05 +49,5,10,2.44666575407262e-05 +50,5,10,1.86750415730594e-05 +0,10,10,0.00452786446994014 +1,10,10,0.00512604990670767 +2,10,10,0.00579800613876307 +3,10,10,0.00655209903675189 +4,10,10,0.00739749732216368 +5,10,10,0.00834418403164184 +6,10,10,0.00940291724174672 +7,10,10,0.0105850968182849 +8,10,10,0.0119024623909524 +9,10,10,0.0133664949933419 +10,10,10,0.0149873088674205 +11,10,10,0.0167716856232329 +12,10,10,0.0187197076550747 +13,10,10,0.0208192019199751 +14,10,10,0.0230369981995457 +15,10,10,0.0253061300190281 +16,10,10,0.027509264425719 +17,10,10,0.0294620946696175 +18,10,10,0.0309073601441846 +19,10,10,0.0315388218157168 +20,10,10,0.0310748541203663 +21,10,10,0.0293756219336316 +22,10,10,0.0265457766110336 +23,10,10,0.0229377402115863 +24,10,10,0.0190305919079321 +25,10,10,0.0152630199751452 +26,10,10,0.0119247563929799 +27,10,10,0.00914118581090187 +28,10,10,0.00691657215847653 +29,10,10,0.00518917660753771 +30,10,10,0.00387314905613275 +31,10,10,0.00288267238979665 +32,10,10,0.00214279119380714 +33,10,10,0.00159250430145677 +34,10,10,0.00118414566348196 +35,10,10,0.000881365280006842 +36,10,10,0.000656848497863685 +37,10,10,0.000490250713798134 +38,10,10,0.000366495935094473 +39,10,10,0.000274442585806388 +40,10,10,0.000205866217525191 +41,10,10,0.000154696566616916 +42,10,10,0.000116450949482184 +43,10,10,8.78158582231872e-05 +44,10,10,6.63389488510456e-05 +45,10,10,5.02026190480147e-05 +46,10,10,3.80576194231282e-05 +47,10,10,2.89007349980015e-05 +48,10,10,2.19847881495897e-05 +49,10,10,1.6752345702394e-05 +50,10,10,1.27868202641784e-05 +0,0.2,15,0.0170945622854247 +1,0.2,15,0.0193493413561785 +2,0.2,15,0.0218799512564967 +3,0.2,15,0.0247163455278644 +4,0.2,15,0.0278905986332678 +5,0.2,15,0.0314364847603758 +6,0.2,15,0.0353886613709243 +7,0.2,15,0.0397812347943163 +8,0.2,15,0.0446453801309851 +9,0.2,15,0.0500055485134373 +10,0.2,15,0.0558736279336232 +11,0.2,15,0.0622402629616186 +12,0.2,15,0.0690624752007766 +13,0.2,15,0.0762469583009703 +14,0.2,15,0.0836293084111391 +15,0.2,15,0.0909515171379497 +16,0.2,15,0.097843783827486 +17,0.2,15,0.10382187168753 +18,0.2,15,0.10831563772517 +19,0.2,15,0.110742748979961 +20,0.2,15,0.110627302225695 +21,0.2,15,0.107735337686594 +22,0.2,15,0.102172574119513 +23,0.2,15,0.094390392987937 +24,0.2,15,0.0850865791376358 +25,0.2,15,0.0750429710943614 +26,0.2,15,0.0649695431068838 +27,0.2,15,0.0554065492919205 +28,0.2,15,0.0466961549794152 +29,0.2,15,0.0390045286588277 +30,0.2,15,0.0323668764812207 +31,0.2,15,0.0267344275981433 +32,0.2,15,0.0220127574537679 +33,0.2,15,0.0180886949726462 +34,0.2,15,0.0148471194278549 +35,0.2,15,0.0121802658967505 +36,0.2,15,0.0099920715527046 +37,0.2,15,0.00819951852655703 +38,0.2,15,0.00673231299532132 +39,0.2,15,0.00553174678885157 +40,0.2,15,0.00454924180911541 +41,0.2,15,0.00374485360671993 +42,0.2,15,0.00308587364625747 +43,0.2,15,0.00254559027056437 +44,0.2,15,0.00210222452463604 +45,0.2,15,0.00173803445252378 +46,0.2,15,0.00143857118027496 +47,0.2,15,0.00119206655139224 +48,0.2,15,0.00098893205661382 +49,0.2,15,0.000821350451036704 +50,0.2,15,0.00068294375913977 +0,0.5,15,0.0170829940843968 +1,0.5,15,0.0193362473051681 +2,0.5,15,0.0218651446957676 +3,0.5,15,0.0246996195275745 +4,0.5,15,0.0278717245582027 +5,0.5,15,0.0314152111197147 +6,0.5,15,0.0353647132205118 +7,0.5,15,0.039754314109624 +8,0.5,15,0.0446151677907274 +9,0.5,15,0.049971708849803 +10,0.5,15,0.0558358172339805 +11,0.5,15,0.0621981438443256 +12,0.5,15,0.0690157393684534 +13,0.5,15,0.0761953605983402 +14,0.5,15,0.0835727149379999 +15,0.5,15,0.0908899685930686 +16,0.5,15,0.0977775711604546 +17,0.5,15,0.103751613539779 +18,0.5,15,0.108242338564259 +19,0.5,15,0.110667807348745 +20,0.5,15,0.110552438719396 +21,0.5,15,0.107662431225266 +22,0.5,15,0.102103432081406 +23,0.5,15,0.0943265172932594 +24,0.5,15,0.085028999502907 +25,0.5,15,0.0749921881517591 +26,0.5,15,0.0649255770361061 +27,0.5,15,0.0553690546728849 +28,0.5,15,0.0466645548425405 +29,0.5,15,0.0389781335852954 +30,0.5,15,0.0323449732275702 +31,0.5,15,0.0267163359250336 +32,0.5,15,0.0219978610206711 +33,0.5,15,0.0180764540239584 +34,0.5,15,0.0148370721122606 +35,0.5,15,0.0121720232894164 +36,0.5,15,0.0099853097362581 +37,0.5,15,0.00819396976332673 +38,0.5,15,0.00672775711674352 +39,0.5,15,0.00552800335524849 +40,0.5,15,0.0045461632544912 +41,0.5,15,0.00374231939621373 +42,0.5,15,0.00308378537946885 +43,0.5,15,0.00254386762335685 +44,0.5,15,0.00210080191108789 +45,0.5,15,0.00173685829301735 +46,0.5,15,0.00143759767300823 +47,0.5,15,0.00119125985828861 +48,0.5,15,0.000988262828315202 +49,0.5,15,0.000820794628256727 +50,0.5,15,0.000682481598684031 +0,0.8,15,0.0168306711676033 +1,0.8,15,0.0190506429025806 +2,0.8,15,0.0215421874285292 +3,0.8,15,0.0243347958899793 +4,0.8,15,0.0274600476120044 +5,0.8,15,0.0309511954054759 +6,0.8,15,0.0348423617201086 +7,0.8,15,0.0391671263811903 +8,0.8,15,0.0439561832348253 +9,0.8,15,0.0492336059580123 +10,0.8,15,0.0550110990261289 +11,0.8,15,0.0612794514303141 +12,0.8,15,0.067996348237363 +13,0.8,15,0.075069923480156 +14,0.8,15,0.0823383112325766 +15,0.8,15,0.0895474860124761 +16,0.8,15,0.096333355829682 +17,0.8,15,0.102219159122184 +18,0.8,15,0.106643554273159 +19,0.8,15,0.109033197876459 +20,0.8,15,0.108919533289675 +21,0.8,15,0.106072212406386 +22,0.8,15,0.100595321988402 +23,0.8,15,0.092933275461247 +24,0.8,15,0.0837730858696992 +25,0.8,15,0.0738845223902602 +26,0.8,15,0.063966599301213 +27,0.8,15,0.0545512307418962 +28,0.8,15,0.0459752999888207 +29,0.8,15,0.0384024103655356 +30,0.8,15,0.03186722454089 +31,0.8,15,0.0263217245487529 +32,0.8,15,0.0216729434781999 +33,0.8,15,0.017809457291297 +34,0.8,15,0.0146179223956744 +35,0.8,15,0.0119922374506758 +36,0.8,15,0.00983782256478856 +37,0.8,15,0.00807294142715887 +38,0.8,15,0.00662838535024944 +39,0.8,15,0.00544635245004129 +40,0.8,15,0.00447901453530736 +41,0.8,15,0.00368704378463415 +42,0.8,15,0.00303823658879033 +43,0.8,15,0.00250629364215129 +44,0.8,15,0.00206977219444735 +45,0.8,15,0.00171120417475296 +46,0.8,15,0.0014163637583773 +47,0.8,15,0.0011736644554794 +48,0.8,15,0.000973665775938606 +49,0.8,15,0.000808671150740611 +50,0.8,15,0.000672401062052862 +0,1,15,0.0161773463981676 +1,1,15,0.0183111443550783 +2,1,15,0.0207059733230587 +3,1,15,0.0233901796738007 +4,1,15,0.0263941169015678 +5,1,15,0.0297497470258672 +6,1,15,0.0334898679478338 +7,1,15,0.0376467560075056 +8,1,15,0.0422499135922666 +9,1,15,0.047322479898885 +10,1,15,0.0528757050641321 +11,1,15,0.0589007356275883 +12,1,15,0.0653568992164494 +13,1,15,0.0721558958718192 +14,1,15,0.0791421429000089 +15,1,15,0.0860714754559116 +16,1,15,0.0925939346943237 +17,1,15,0.0982512657505899 +18,1,15,0.102503916892481 +19,1,15,0.104800800478035 +20,1,15,0.104691548067642 +21,1,15,0.101954753095118 +22,1,15,0.0966904619332135 +23,1,15,0.0893258369842539 +24,1,15,0.0805212231563397 +25,1,15,0.07101650910221 +26,1,15,0.061483575105452 +27,1,15,0.0524336877222519 +28,1,15,0.0441906532587037 +29,1,15,0.0369117243644845 +30,1,15,0.0306302181899009 +31,1,15,0.0252999807067683 +32,1,15,0.0208316537482844 +33,1,15,0.0171181384803746 +34,1,15,0.0140504910268549 +35,1,15,0.0115267286370664 +36,1,15,0.00945594277551063 +37,1,15,0.00775956993150995 +38,1,15,0.00637108792654249 +39,1,15,0.00523493860187947 +40,1,15,0.00430515033765066 +41,1,15,0.00354392192059747 +42,1,15,0.00292029980545613 +43,1,15,0.00240900556019716 +44,1,15,0.0019894287887533 +45,1,15,0.00164477948724079 +46,1,15,0.00136138404208053 +47,1,15,0.00112810572213269 +48,1,15,0.000935870493609222 +49,1,15,0.00077728054915106 +50,1,15,0.000646300126180522 +0,5,15,0.00709417402200009 +1,5,15,0.00802989819217845 +2,5,15,0.00908009103800289 +3,5,15,0.0102571831577141 +4,5,15,0.0115744853233745 +5,5,15,0.0130460136858964 +6,5,15,0.0146861509513481 +7,5,15,0.0165090511081146 +8,5,15,0.0185276516964461 +9,5,15,0.0207520998371722 +10,5,15,0.0231873289987407 +11,5,15,0.0258294567156739 +12,5,15,0.0286606471276607 +13,5,15,0.0316421784777994 +14,5,15,0.0347058238346345 +15,5,15,0.0377445107612773 +16,5,15,0.0406047734860675 +17,5,15,0.0430856557040414 +18,5,15,0.0449505503853377 +19,5,15,0.0459577917130036 +20,5,15,0.0459098817781737 +21,5,15,0.0447097282227167 +22,5,15,0.0424012039019879 +23,5,15,0.0391716302927709 +24,5,15,0.0353105852762157 +25,5,15,0.0311425286697884 +26,5,15,0.0269620969074505 +27,5,15,0.0229934932566566 +28,5,15,0.0193787149416928 +29,5,15,0.0161867212117937 +30,5,15,0.0134321224768732 +31,5,15,0.0110946790326125 +32,5,15,0.00913520507127915 +33,5,15,0.00750673505552366 +34,5,15,0.00616149435054132 +35,5,15,0.00505476095047227 +36,5,15,0.00414666917184548 +37,5,15,0.00340276693563576 +38,5,15,0.00279388259037809 +39,5,15,0.00229565248355104 +40,5,15,0.00188791690147809 +41,5,15,0.00155409905965462 +42,5,15,0.00128062504853487 +43,5,15,0.0010564096387242 +44,5,15,0.000872414652219563 +45,5,15,0.000721277249254177 +46,5,15,0.000597001205734652 +47,5,15,0.000494702784439968 +48,5,15,0.000410402792912376 +49,5,15,0.000340857106219721 +50,5,15,0.00028341889038641 +0,10,15,0.00485738828410318 +1,10,15,0.00549807959041752 +2,10,15,0.00621714771724061 +3,10,15,0.00702310390803386 +4,10,15,0.00792506206218389 +5,10,15,0.00893261905270503 +6,10,15,0.0100556227333054 +7,10,15,0.0113037643544594 +8,10,15,0.0126859022633461 +9,10,15,0.0142089842040836 +10,10,15,0.0158763881276167 +11,10,15,0.0176854557058204 +12,10,15,0.019623974706708 +13,10,15,0.021665432303313 +14,10,15,0.023763113445161 +15,10,15,0.025843705524064 +16,10,15,0.0278021303675718 +17,10,15,0.0295007929860043 +18,10,15,0.0307776883015016 +19,10,15,0.0314673474794547 +20,10,15,0.0314345434975658 +21,10,15,0.0306127971178853 +22,10,15,0.0290321481298141 +23,10,15,0.0268208557420872 +24,10,15,0.0241771942291824 +25,10,15,0.0213233215634213 +26,10,15,0.0184609756156194 +27,10,15,0.0157436685946986 +28,10,15,0.0132686261468696 +29,10,15,0.0110830647413473 +30,10,15,0.00919698814089816 +31,10,15,0.00759653819905922 +32,10,15,0.00625488435278064 +33,10,15,0.00513986925010433 +34,10,15,0.00421878154920837 +35,10,15,0.00346100004646404 +36,10,15,0.00283922866720083 +37,10,15,0.00232987803730685 +38,10,15,0.00191297429687752 +39,10,15,0.0015718356278536 +40,10,15,0.00129265865344738 +41,10,15,0.00106409323217784 +42,10,15,0.000876845294151467 +43,10,15,0.000723324771346094 +44,10,15,0.000597343213942829 +45,10,15,0.000493859277944474 +46,10,15,0.000408767342517684 +47,10,15,0.000338723507740291 +48,10,15,0.000281003216424309 +49,10,15,0.000233385212876156 +50,10,15,0.000194057207137462 +0,0.2,20,0.0180793195882987 +1,0.2,20,0.0204374745261926 +2,0.2,20,0.0230726715615305 +3,0.2,20,0.0260103778528718 +4,0.2,20,0.0292760792682837 +5,0.2,20,0.0328942299113683 +6,0.2,20,0.0368867473786228 +7,0.2,20,0.0412709284777743 +8,0.2,20,0.046056654960248 +9,0.2,20,0.0512427770299827 +10,0.2,20,0.0568126226963098 +11,0.2,20,0.0627287081452579 +12,0.2,20,0.0689269448667375 +13,0.2,20,0.0753109707167211 +14,0.2,20,0.0817476611094763 +15,0.2,20,0.0880653279894889 +16,0.2,20,0.0940564216417985 +17,0.2,20,0.0994864561691878 +18,0.2,20,0.10411010610807 +19,0.2,20,0.107693839114021 +20,0.2,20,0.110042292510351 +21,0.2,20,0.111023581204473 +22,0.2,20,0.110587839389611 +23,0.2,20,0.1087743022324 +24,0.2,20,0.10570505297568 +25,0.2,20,0.1015671507288 +26,0.2,20,0.0965877262956307 +27,0.2,20,0.0910077171758772 +28,0.2,20,0.0850591003252528 +29,0.2,20,0.0789485021803124 +30,0.2,20,0.0728479138507175 +31,0.2,20,0.0668916373821453 +32,0.2,20,0.0611777865511167 +33,0.2,20,0.055772544660263 +34,0.2,20,0.0507156705035933 +35,0.2,20,0.046026185115372 +36,0.2,20,0.0417075976165607 +37,0.2,20,0.0377523606629536 +38,0.2,20,0.0341454691884831 +39,0.2,20,0.0308672463206464 +40,0.2,20,0.0278954234243928 +41,0.2,20,0.0252066416179739 +42,0.2,20,0.022777498478599 +43,0.2,20,0.020585248573281 +44,0.2,20,0.0186082475100465 +45,0.2,20,0.0168262105312757 +46,0.2,20,0.0152203401871912 +47,0.2,20,0.0137733639799342 +48,0.2,20,0.0124695120332158 +49,0.2,20,0.0112944564907163 +50,0.2,20,0.0102352280499463 +0,0.5,20,0.0180670849841039 +1,0.5,20,0.0204236441156869 +2,0.5,20,0.0230570578652907 +3,0.5,20,0.0259927761573858 +4,0.5,20,0.029256267613289 +5,0.5,20,0.0328719697880659 +6,0.5,20,0.036861785446178 +7,0.5,20,0.041242999690288 +8,0.5,20,0.0460254875846605 +9,0.5,20,0.0512081001113219 +10,0.5,20,0.0567741765618431 +11,0.5,20,0.0626862584882307 +12,0.5,20,0.0688803007502549 +13,0.5,20,0.0752600064139028 +14,0.5,20,0.081692340981269 +15,0.5,20,0.088005732581267 +16,0.5,20,0.0939927719516014 +17,0.5,20,0.0994191318759239 +18,0.5,20,0.104039652906848 +19,0.5,20,0.107620960735532 +20,0.5,20,0.109967824890761 +21,0.5,20,0.110948449528987 +22,0.5,20,0.110513002588531 +23,0.5,20,0.108700692684879 +24,0.5,20,0.105633520444922 +25,0.5,20,0.101498418391706 +26,0.5,20,0.0965223636255626 +27,0.5,20,0.0909461305994088 +28,0.5,20,0.0850015392859358 +29,0.5,20,0.078895076293833 +30,0.5,20,0.0727986163432516 +31,0.5,20,0.0668463705952335 +32,0.5,20,0.0611363864309234 +33,0.5,20,0.0557348023655088 +34,0.5,20,0.0506813502875002 +35,0.5,20,0.0459950383592823 +36,0.5,20,0.0416793733271308 +37,0.5,20,0.0377268129542649 +38,0.5,20,0.034122362328818 +39,0.5,20,0.0308463578939845 +40,0.5,20,0.0278765460843039 +41,0.5,20,0.0251895838254076 +42,0.5,20,0.0227620845313499 +43,0.5,20,0.0205713181613915 +44,0.5,20,0.0185956549707127 +45,0.5,20,0.0168148239287576 +46,0.5,20,0.0152100403063251 +47,0.5,20,0.0137640432941693 +48,0.5,20,0.0124610736877635 +49,0.5,20,0.0112868133267087 +50,0.5,20,0.0102283016850782 +0,0.8,20,0.0178002266360519 +1,0.8,20,0.0201219784106376 +2,0.8,20,0.0227164955455649 +3,0.8,20,0.0256088520593507 +4,0.8,20,0.0288241403911987 +5,0.8,20,0.0323864371433378 +6,0.8,20,0.0363173215673027 +7,0.8,20,0.0406338234576117 +8,0.8,20,0.0453456720197292 +9,0.8,20,0.0504517352071544 +10,0.8,20,0.0559355983970403 +11,0.8,20,0.0617603564182261 +12,0.8,20,0.0678629101037998 +13,0.8,20,0.0741483848654534 +14,0.8,20,0.0804857111800618 +15,0.8,20,0.0867058513643244 +16,0.8,20,0.0926044596768819 +17,0.8,20,0.0979506700116821 +18,0.8,20,0.102502944028185 +19,0.8,20,0.106031354453006 +20,0.8,20,0.108343554450065 +21,0.8,20,0.109309694855154 +22,0.8,20,0.10888067964684 +23,0.8,20,0.107095138313075 +24,0.8,20,0.104073269480826 +25,0.8,20,0.0999992446021474 +26,0.8,20,0.0950966882313386 +27,0.8,20,0.0896028184826599 +28,0.8,20,0.0837460312515363 +29,0.8,20,0.0777297632536978 +30,0.8,20,0.0717233505483033 +31,0.8,20,0.0658590219418115 +32,0.8,20,0.0602333766148308 +33,0.8,20,0.0549115761892136 +34,0.8,20,0.0499327656969774 +35,0.8,20,0.0453156725420547 +36,0.8,20,0.0410637516746226 +37,0.8,20,0.0371695722598696 +38,0.8,20,0.0336183608670043 +39,0.8,20,0.0303907443781212 +40,0.8,20,0.0274647979221628 +41,0.8,20,0.0248175232116628 +42,0.8,20,0.0224258790902618 +43,0.8,20,0.0202674712493617 +44,0.8,20,0.0183209894244558 +45,0.8,20,0.0165664619965278 +46,0.8,20,0.0149853816946275 +47,0.8,20,0.01356074265883 +48,0.8,20,0.0122770184546035 +49,0.8,20,0.0111201024067243 +50,0.8,20,0.0100772254216157 +0,1,20,0.0171092661361945 +1,1,20,0.0193408932848688 +2,1,20,0.0218346977214079 +3,1,20,0.0246147801533299 +4,1,20,0.0277052589937942 +5,1,20,0.031129276251249 +6,1,20,0.0349075735243873 +7,1,20,0.0390565195534847 +8,1,20,0.0435854658804622 +9,1,20,0.0484933244020467 +10,1,20,0.0537643176702003 +11,1,20,0.0593629730806635 +12,1,20,0.0652286408191531 +13,1,20,0.071270129092772 +14,1,20,0.0773614561710992 +15,1,20,0.0833401459930278 +16,1,20,0.0890097850103375 +17,1,20,0.094148468764673 +18,1,20,0.0985240348327752 +19,1,20,0.101915481145808 +20,1,20,0.104137927293188 +21,1,20,0.105066564532116 +22,1,20,0.104654202626529 +23,1,20,0.102937971563791 +24,1,20,0.100033404159301 +25,1,20,0.0961175227876778 +26,1,20,0.0914052714545416 +27,1,20,0.0861246600573049 +28,1,20,0.080495218731125 +29,1,20,0.0747124872847056 +30,1,20,0.0689392285728038 +31,1,20,0.0633025386086798 +32,1,20,0.0578952668331503 +33,1,20,0.0527800454560705 +34,1,20,0.0479944999967324 +35,1,20,0.0435566309078535 +36,1,20,0.0394697590270429 +37,1,20,0.0357267419660042 +38,1,20,0.0323133797617635 +39,1,20,0.0292110513126399 +40,1,20,0.0263986828165076 +41,1,20,0.0238541687221855 +42,1,20,0.0215553622736632 +43,1,20,0.0194807384536712 +44,1,20,0.0176098142091377 +45,1,20,0.0159233931695946 +46,1,20,0.0144036864702924 +47,1,20,0.013034348376467 +48,1,20,0.0118004551511357 +49,1,20,0.0106884477051008 +50,1,20,0.00968605260922058 +0,5,20,0.00750284430904103 +1,5,20,0.00848146904484496 +2,5,20,0.00957506512755281 +3,5,20,0.0107942013246855 +4,5,20,0.0121494541681337 +5,5,20,0.0136509720117194 +6,5,20,0.015307850569103 +7,5,20,0.0171272679453445 +8,5,20,0.0191133250272103 +9,5,20,0.0212655446539978 +10,5,20,0.0235770080171924 +11,5,20,0.0260321594860104 +12,5,20,0.0286044025886734 +13,5,20,0.0312537474262038 +14,5,20,0.0339249478354049 +15,5,20,0.036546753969514 +16,5,20,0.0390330335385335 +17,5,20,0.0412864758460686 +18,5,20,0.0432052718196401 +19,5,20,0.044692506483395 +20,5,20,0.0456671051187944 +21,5,20,0.0460743359472701 +22,5,20,0.0458935048612395 +23,5,20,0.0451408942957388 +24,5,20,0.0438671683014424 +25,5,20,0.0421499556501172 +26,5,20,0.0400835147042488 +27,5,20,0.0377678335490998 +28,5,20,0.0352991816805162 +29,5,20,0.0327633082317015 +30,5,20,0.0302315888156607 +31,5,20,0.0277597582366921 +32,5,20,0.0253885333141547 +33,5,20,0.0231453798502362 +34,5,20,0.0210467975832099 +35,5,20,0.0191006801651562 +36,5,20,0.0173084838670431 +37,5,20,0.0156670765716333 +38,5,20,0.0141702312373611 +39,5,20,0.012809782041937 +40,5,20,0.0115764875921246 +41,5,20,0.0104606540467294 +42,5,20,0.00945256949520125 +43,5,20,0.00854279467509373 +44,5,20,0.00772234725151608 +45,5,20,0.00698280913232021 +46,5,20,0.00631637945208103 +47,5,20,0.00571589019423515 +48,5,20,0.00517479692407691 +49,5,20,0.00468715363933985 +50,5,20,0.00424757813208737 +0,10,20,0.00513720525196691 +1,10,20,0.00580727061989926 +2,10,20,0.00655605698787006 +3,10,20,0.00739080080192281 +4,10,20,0.00831874382437305 +5,10,20,0.00934683464357021 +6,10,20,0.0104813011040572 +7,10,20,0.0117270580617865 +8,10,20,0.013086913398165 +9,10,20,0.0145605404007667 +10,10,20,0.0161432017542515 +11,10,20,0.0178242465021463 +12,10,20,0.0195854640127393 +13,10,20,0.0213994731608742 +14,10,20,0.023228446841518 +15,10,20,0.0250236002109614 +16,10,20,0.0267259584012326 +17,10,20,0.0282688926779473 +18,10,20,0.0295826942639681 +19,10,20,0.0306010053751745 +20,10,20,0.0312683140679992 +21,10,20,0.0315471454370958 +22,10,20,0.0314233302056167 +23,10,20,0.0309080169736579 +24,10,20,0.0300358954690731 +25,10,20,0.0288601181921141 +26,10,20,0.0274452239409828 +27,10,20,0.0258596746609882 +28,10,20,0.0241693861754223 +29,10,20,0.0224330710044043 +30,10,20,0.0206996001039193 +31,10,20,0.0190071351520679 +32,10,20,0.0173835549971425 +33,10,20,0.0158476655022847 +34,10,20,0.0144107640553413 +35,10,20,0.0130782554480492 +36,10,20,0.0118511367906451 +37,10,20,0.0107272635192199 +38,10,20,0.0097023719719784 +39,10,20,0.00877087100196024 +40,10,20,0.00792643301766627 +41,10,20,0.0071624206360129 +42,10,20,0.00647218410180988 +43,10,20,0.00584926034230554 +44,10,20,0.00528749914351764 +45,10,20,0.004781136629053 +46,10,20,0.0043248315382935 +47,10,20,0.00391367592289065 +48,10,20,0.00354318880163834 +49,10,20,0.00320929894064003 +50,10,20,0.00290832113655948 +0,0.2,25,0.0127925805005904 +1,0.2,25,0.0143664079233124 +2,0.2,25,0.0161018645758265 +3,0.2,25,0.018009080650141 +4,0.2,25,0.0200973822913566 +5,0.2,25,0.0223748983986475 +6,0.2,25,0.0248481165148272 +7,0.2,25,0.0275213970805524 +8,0.2,25,0.0303964613598564 +9,0.2,25,0.0334718750766375 +10,0.2,25,0.0367425566819869 +11,0.2,25,0.0401993453805463 +12,0.2,25,0.0438286685296017 +13,0.2,25,0.0476123496072689 +14,0.2,25,0.0515275954972371 +15,0.2,25,0.0555471945268581 +16,0.2,25,0.0596399442653214 +17,0.2,25,0.0637713110890748 +18,0.2,25,0.0679043034234193 +19,0.2,25,0.0720005196842712 +20,0.2,25,0.0760213131193364 +21,0.2,25,0.0799290018661388 +22,0.2,25,0.083688045935608 +23,0.2,25,0.0872661147459629 +24,0.2,25,0.090634979135192 +25,0.2,25,0.0937711789482726 +26,0.2,25,0.0966564387403026 +27,0.2,25,0.0992778267575567 +28,0.2,25,0.101627673161807 +29,0.2,25,0.103703280095681 +30,0.2,25,0.105506467258237 +31,0.2,25,0.107043001816614 +32,0.2,25,0.108321961258184 +33,0.2,25,0.109355073332416 +34,0.2,25,0.110156069969142 +35,0.2,25,0.110740083410064 +36,0.2,25,0.11112310396252 +37,0.2,25,0.111321510669088 +38,0.2,25,0.111351679333482 +39,0.2,25,0.111229666998568 +40,0.2,25,0.110970968148306 +41,0.2,25,0.11059033545799 +42,0.2,25,0.110101656616918 +43,0.2,25,0.109517878335371 +44,0.2,25,0.108850968873321 +45,0.2,25,0.108111911072167 +46,0.2,25,0.107310718755317 +47,0.2,25,0.106456470353574 +48,0.2,25,0.105557354611084 +49,0.2,25,0.104620724174384 +50,0.2,25,0.103653153723559 +0,0.5,25,0.0127839235288337 +1,0.5,25,0.0143566859139312 +2,0.5,25,0.016090968151383 +3,0.5,25,0.0179968935779123 +4,0.5,25,0.0200837820274481 +5,0.5,25,0.0223597568981906 +6,0.5,25,0.0248313013427152 +7,0.5,25,0.0275027728508891 +8,0.5,25,0.030375891521935 +9,0.5,25,0.0334492240503518 +10,0.5,25,0.0367176923260074 +11,0.5,25,0.0401721417528202 +12,0.5,25,0.0437990088729301 +13,0.5,25,0.0475801294648357 +14,0.5,25,0.0514927258367424 +15,0.5,25,0.0555096047306355 +16,0.5,25,0.0595995848309565 +17,0.5,25,0.063728155883684 +18,0.5,25,0.06785835134699 +19,0.5,25,0.0719517956238409 +20,0.5,25,0.0759698681149023 +21,0.5,25,0.0798749124576993 +22,0.5,25,0.0836314127137182 +23,0.5,25,0.0872070601798703 +24,0.5,25,0.0905736447973311 +25,0.5,25,0.0937077222869912 +26,0.5,25,0.0965910295712743 +27,0.5,25,0.0992106436476078 +28,0.5,25,0.101558899868083 +29,0.5,25,0.103633102201016 +30,0.5,25,0.105435069114043 +31,0.5,25,0.106970563871555 +32,0.5,25,0.108248657818023 +33,0.5,25,0.109281070766535 +34,0.5,25,0.110081525354277 +35,0.5,25,0.110665143582688 +36,0.5,25,0.111047904938174 +37,0.5,25,0.111246177379317 +38,0.5,25,0.111276325628028 +39,0.5,25,0.111154395861079 +40,0.5,25,0.110895872077031 +41,0.5,25,0.110515496967775 +42,0.5,25,0.110027148824557 +43,0.5,25,0.109443765596385 +44,0.5,25,0.108777307444091 +45,0.5,25,0.108038749776785 +46,0.5,25,0.107238099641339 +47,0.5,25,0.106384429325017 +48,0.5,25,0.105485922030493 +49,0.5,25,0.104549925428635 +50,0.5,25,0.103583009750321 +0,0.8,25,0.0125950996694491 +1,0.8,25,0.0141446317009874 +2,0.8,25,0.0158532978695853 +3,0.8,25,0.0177310719860786 +4,0.8,25,0.0197871362265789 +5,0.8,25,0.0220294940033216 +6,0.8,25,0.024464532710026 +7,0.8,25,0.0270965454746248 +8,0.8,25,0.0299272269897605 +9,0.8,25,0.0329551651204497 +10,0.8,25,0.0361753567623556 +11,0.8,25,0.0395787825365824 +12,0.8,25,0.0431520793231755 +13,0.8,25,0.0468773511937279 +14,0.8,25,0.050732156892412 +15,0.8,25,0.0546897048169267 +16,0.8,25,0.0587192742126931 +17,0.8,25,0.062786864556473 +18,0.8,25,0.0668560553176127 +19,0.8,25,0.0708890377225831 +20,0.8,25,0.0748477616143402 +21,0.8,25,0.0786951268305207 +22,0.8,25,0.0823961420177718 +23,0.8,25,0.0859189756859662 +24,0.8,25,0.0892358344505635 +25,0.8,25,0.0923236203141924 +26,0.8,25,0.0951643399525167 +27,0.8,25,0.0977452612410785 +28,0.8,25,0.100058832742002 +29,0.8,25,0.10210239824511 +30,0.8,25,0.103877749358516 +31,0.8,25,0.105390564220805 +32,0.8,25,0.106649780188921 +33,0.8,25,0.107666943969447 +34,0.8,25,0.108455575510518 +35,0.8,25,0.109030573455332 +36,0.8,25,0.109407681266646 +37,0.8,25,0.109603025141496 +38,0.8,25,0.109632728088053 +39,0.8,25,0.109512599274396 +40,0.8,25,0.109257893993997 +41,0.8,25,0.108883137183067 +42,0.8,25,0.108402002144723 +43,0.8,25,0.107827235729097 +44,0.8,25,0.107170621440477 +45,0.8,25,0.106442972576622 +46,0.8,25,0.105654148376168 +47,0.8,25,0.104813087124928 +48,0.8,25,0.103927851156272 +49,0.8,25,0.103005679612922 +50,0.8,25,0.102053045680714 +0,1,25,0.0121061892448071 +1,1,25,0.0135955722990909 +2,1,25,0.0152379122992594 +3,1,25,0.0170427958976329 +4,1,25,0.0190190488410974 +5,1,25,0.0211743638693427 +6,1,25,0.02351488043336 +7,1,25,0.0260447250125394 +8,1,25,0.0287655265157727 +9,1,25,0.0316759276236421 +10,1,25,0.0347711194398704 +11,1,25,0.0380424326954047 +12,1,25,0.041477022993351 +13,1,25,0.045057689080707 +14,1,25,0.0487628608153481 +15,1,25,0.0525667865783002 +16,1,25,0.0564399381182249 +17,1,25,0.0603496347275812 +18,1,25,0.0642608696300782 +19,1,25,0.0681373016946832 +20,1,25,0.071942357776756 +21,1,25,0.0756403778499078 +22,1,25,0.0791977288380422 +23,1,25,0.0825838148702621 +24,1,25,0.0857719214320475 +25,1,25,0.0887398471328027 +26,1,25,0.0914702971042636 +27,1,25,0.0939510334513581 +28,1,25,0.0961747978642359 +29,1,25,0.0981390372401889 +30,1,25,0.0998454736415624 +31,1,25,0.101299564795731 +32,1,25,0.102509901133686 +33,1,25,0.103487581147596 +34,1,25,0.104245599974853 +35,1,25,0.104798277930406 +36,1,25,0.105160747354966 +37,1,25,0.105348508466732 +38,1,25,0.105377058418823 +39,1,25,0.105261592706757 +40,1,25,0.105016774451476 +41,1,25,0.104656564767316 +42,1,25,0.104194106193794 +43,1,25,0.103641650780042 +44,1,25,0.103010524624037 +45,1,25,0.102311121278229 +46,1,25,0.101552917270147 +47,1,25,0.10074450392359 +48,1,25,0.0998936306122144 +49,1,25,0.0990072554732343 +50,1,25,0.0980916004195226 +0,5,25,0.00530886902784351 +1,5,25,0.00596200102566634 +2,5,25,0.00668220849837069 +3,5,25,0.00747369543455732 +4,5,25,0.00834033214662123 +5,5,25,0.00928549209475316 +6,5,25,0.0103118675829107 +7,5,25,0.0114212681762827 +8,5,25,0.0126144081924625 +9,5,25,0.0138906924126846 +10,5,25,0.0152480120147599 +11,5,25,0.0166825653057659 +12,5,25,0.0181887196940198 +13,5,25,0.019758931996654 +14,5,25,0.0213837431628362 +15,5,25,0.0230518604587735 +16,5,25,0.0247503350022199 +17,5,25,0.0264648354794515 +18,5,25,0.028180010536986 +19,5,25,0.0298799236731654 +20,5,25,0.0315485366425182 +21,5,25,0.0331702116249343 +22,5,25,0.0347301996690809 +23,5,25,0.0362150837146344 +24,5,25,0.0376131487738426 +25,5,25,0.0389146589775129 +26,5,25,0.0401120300901265 +27,5,25,0.0411998954863316 +28,5,25,0.0421750722143686 +29,5,25,0.0430364406743685 +30,5,25,0.0437847560340613 +31,5,25,0.0444224116444211 +32,5,25,0.0449531746258934 +33,5,25,0.0453819119469469 +34,5,25,0.0457143223027716 +35,5,25,0.0459566855123065 +36,5,25,0.0461156374882483 +37,5,25,0.0461979754668419 +38,5,25,0.0462104953402173 +39,5,25,0.0461598607160452 +40,5,25,0.0460525017423312 +41,5,25,0.0458945407194939 +42,5,25,0.0456917409822702 +43,5,25,0.0454494753629225 +44,5,25,0.045172710640802 +45,5,25,0.0448660046505482 +46,5,25,0.0445335130882655 +47,5,25,0.0441790034659191 +48,5,25,0.0438058740791207 +49,5,25,0.0434171762463654 +50,5,25,0.0430156384332238 +0,10,25,0.00363498810963971 +1,10,25,0.00408218826350669 +2,10,25,0.00457531506434197 +3,10,25,0.00511724698748498 +4,10,25,0.00571063403983221 +5,10,25,0.00635778603306246 +6,10,25,0.00706054639047774 +7,10,25,0.00782015412323297 +8,10,25,0.0086370983253224 +9,10,25,0.00951097144984222 +10,10,25,0.0104403295840602 +11,10,25,0.0114225697049038 +12,10,25,0.0124538351710267 +13,10,25,0.0135289611573243 +14,10,25,0.0146414710419167 +15,10,25,0.0157836326783057 +16,10,25,0.0169465799534358 +17,10,25,0.0181205002019901 +18,10,25,0.019294882336375 +19,10,25,0.0204588146174361 +20,10,25,0.0216013156419249 +21,10,25,0.0227116781782516 +22,10,25,0.0237798036041969 +23,10,25,0.0247965052446917 +24,10,25,0.0257537618355157 +25,10,25,0.0266449072169715 +26,10,25,0.0274647484551616 +27,10,25,0.0282096110161618 +28,10,25,0.0288773155296129 +29,10,25,0.0294670954043276 +30,10,25,0.029979467704431 +31,10,25,0.0304160711598085 +32,10,25,0.0307794851217221 +33,10,25,0.0310730420085118 +34,10,25,0.0313006437226634 +35,10,25,0.0314665900626942 +36,10,25,0.0315754246448853 +37,10,25,0.0316318015439178 +38,10,25,0.0316403739141562 +39,10,25,0.0316057043346588 +40,10,25,0.0315321955344103 +41,10,25,0.031424039458834 +42,10,25,0.0312851822691803 +43,10,25,0.0311193027492515 +44,10,25,0.0309298016580022 +45,10,25,0.0307197997495202 +46,10,25,0.0304921424332229 +47,10,25,0.0302494093284461 +48,10,25,0.0299939272517069 +49,10,25,0.0297277854439324 +50,10,25,0.0294528520883184 +0,0.2,30,-0.0208874524761045 +1,0.2,30,-0.0212868152392032 +2,0.2,30,-0.0216880194780002 +3,0.2,30,-0.0220909634527265 +4,0.2,30,-0.0224955461692694 +5,0.2,30,-0.0229016674866775 +6,0.2,30,-0.0233092282198144 +7,0.2,30,-0.0237181302370645 +8,0.2,30,-0.024128276553014 +9,0.2,30,-0.024539571416051 +10,0.2,30,-0.0249519203908483 +11,0.2,30,-0.0253652304357143 +12,0.2,30,-0.0257794099748105 +13,0.2,30,-0.0261943689652586 +14,0.2,30,-0.0266100189591685 +15,0.2,30,-0.027026273160642 +16,0.2,30,-0.0274430464778148 +17,0.2,30,-0.0278602555700164 +18,0.2,30,-0.0282778188901401 +19,0.2,30,-0.028695656722323 +20,0.2,30,-0.0291136912150502 +21,0.2,30,-0.0295318464098046 +22,0.2,30,-0.0299500482653908 +23,0.2,30,-0.0303682246780716 +24,0.2,30,-0.0307863054976591 +25,0.2,30,-0.031204222539709 +26,0.2,30,-0.0316219095939703 +27,0.2,30,-0.0320393024292476 +28,0.2,30,-0.0324563387948326 +29,0.2,30,-0.0328729584186677 +30,0.2,30,-0.0332891030024021 +31,0.2,30,-0.0337047162135015 +32,0.2,30,-0.034119743674576 +33,0.2,30,-0.0345341329500841 +34,0.2,30,-0.0349478335305746 +35,0.2,30,-0.0353607968146231 +36,0.2,30,-0.0357729760886187 +37,0.2,30,-0.0361843265045531 +38,0.2,30,-0.0365948050559628 +39,0.2,30,-0.0370043705521675 +40,0.2,30,-0.0374129835909507 +41,0.2,30,-0.0378206065298163 +42,0.2,30,-0.0382272034559585 +43,0.2,30,-0.0386327401550721 +44,0.2,30,-0.0390371840791282 +45,0.2,30,-0.0394405043132367 +46,0.2,30,-0.0398426715417078 +47,0.2,30,-0.0402436580134261 +48,0.2,30,-0.0406434375066399 +49,0.2,30,-0.0410419852932668 +50,0.2,30,-0.0414392781028119 +0,0.5,30,-0.0208733175573408 +1,0.5,30,-0.0212724100643985 +2,0.5,30,-0.0216733428009944 +3,0.5,30,-0.0220760140962086 +4,0.5,30,-0.0224803230242731 +5,0.5,30,-0.0228861695120036 +6,0.5,30,-0.0232934544413841 +7,0.5,30,-0.0237020797472065 +8,0.5,30,-0.0241119485096888 +9,0.5,30,-0.0245229650420158 +10,0.5,30,-0.0249350349727665 +11,0.5,30,-0.0253480653232123 +12,0.5,30,-0.0257619645794859 +13,0.5,30,-0.0261766427596424 +14,0.5,30,-0.0265920114756461 +15,0.5,30,-0.0270079839903352 +16,0.5,30,-0.0274244752694285 +17,0.5,30,-0.0278414020286538 +18,0.5,30,-0.0282586827760887 +19,0.5,30,-0.0286762378498154 +20,0.5,30,-0.0290939894510028 +21,0.5,30,-0.0295118616725361 +22,0.5,30,-0.0299297805233249 +23,0.5,30,-0.030347673948426 +24,0.5,30,-0.0307654718451234 +25,0.5,30,-0.0311831060751144 +26,0.5,30,-0.0316005104729538 +27,0.5,30,-0.0320176208509124 +28,0.5,30,-0.0324343750004083 +29,0.5,30,-0.0328507126901711 +30,0.5,30,-0.0332665756613013 +31,0.5,30,-0.0336819076193861 +32,0.5,30,-0.0340966542238338 +33,0.5,30,-0.0345107630745867 +34,0.5,30,-0.0349241836963745 +35,0.5,30,-0.0353368675206623 +36,0.5,30,-0.0357487678654509 +37,0.5,30,-0.0361598399130818 +38,0.5,30,-0.0365700406861943 +39,0.5,30,-0.0369793290219831 +40,0.5,30,-0.0373876655448956 +41,0.5,30,-0.037795012637909 +42,0.5,30,-0.0382013344125206 +43,0.5,30,-0.0386065966775783 +44,0.5,30,-0.0390107669070794 +45,0.5,30,-0.0394138142070543 +46,0.5,30,-0.0398157092816517 +47,0.5,30,-0.0402164243985359 +48,0.5,30,-0.0406159333536997 +49,0.5,30,-0.041014211435795 +50,0.5,30,-0.0414112353900743 +0,0.8,30,-0.0205650099888195 +1,0.8,30,-0.0209582077338142 +2,0.8,30,-0.0213532185273926 +3,0.8,30,-0.0217499422003566 +4,0.8,30,-0.0221482793176536 +5,0.8,30,-0.0225481312842217 +6,0.8,30,-0.0229494004460594 +7,0.8,30,-0.0233519901864223 +8,0.8,30,-0.0237558050170738 +9,0.8,30,-0.0241607506645328 +10,0.8,30,-0.0245667341512834 +11,0.8,30,-0.0249736638719313 +12,0.8,30,-0.025381449664307 +13,0.8,30,-0.0257900028755365 +14,0.8,30,-0.026199236423112 +15,0.8,30,-0.0266090648510155 +16,0.8,30,-0.0270194043809575 +17,0.8,30,-0.0274301729588091 +18,0.8,30,-0.0278412902963175 +19,0.8,30,-0.0282526779082044 +20,0.8,30,-0.0286642591447598 +21,0.8,30,-0.0290759592200485 +22,0.8,30,-0.0294877052358593 +23,0.8,30,-0.0298994262015303 +24,0.8,30,-0.0303110530497919 +25,0.8,30,-0.0307225186487722 +26,0.8,30,-0.0311337578103172 +27,0.8,30,-0.0315447072947772 +28,0.8,30,-0.0319553058124168 +29,0.8,30,-0.0323654940216065 +30,0.8,30,-0.032775214523955 +31,0.8,30,-0.0331844118565413 +32,0.8,30,-0.0335930324814067 +33,0.8,30,-0.0340010247724643 +34,0.8,30,-0.0344083389999845 +35,0.8,30,-0.0348149273128095 +36,0.8,30,-0.0352207437184531 +37,0.8,30,-0.0356257440612319 +38,0.8,30,-0.0360298859985788 +39,0.8,30,-0.0364331289756801 +40,0.8,30,-0.0368354341985766 +41,0.8,30,-0.0372367646058646 +42,0.8,30,-0.0376370848391291 +43,0.8,30,-0.0380363612122361 +44,0.8,30,-0.0384345616796051 +45,0.8,30,-0.0388316558035832 +46,0.8,30,-0.0392276147210312 +47,0.8,30,-0.0396224111092314 +48,0.8,30,-0.0400160191512208 +49,0.8,30,-0.040408414500648 +50,0.8,30,-0.0407995742462478 +0,1,30,-0.0197667274797268 +1,1,30,-0.0201446622667839 +2,1,30,-0.0205243397243908 +3,1,30,-0.0209056635716682 +4,1,30,-0.0212885382333849 +5,1,30,-0.0216728689416939 +6,1,30,-0.022058561833279 +7,1,30,-0.0224455240418173 +8,1,30,-0.0228336637856881 +9,1,30,-0.0232228904508721 +10,1,30,-0.0236131146690092 +11,1,30,-0.0240042483905985 +12,1,30,-0.0243962049533416 +13,1,30,-0.0247888991456484 +14,1,30,-0.0251822472653373 +15,1,30,-0.0255761671735804 +16,1,30,-0.0259705783441528 +17,1,30,-0.0263654019080626 +18,1,30,-0.0267605606936473 +19,1,30,-0.0271559792622318 +20,1,30,-0.027551583939457 +21,1,30,-0.0279473028423916 +22,1,30,-0.0283430659025515 +23,1,30,-0.0287388048849558 +24,1,30,-0.0291344534033542 +25,1,30,-0.0295299469317672 +26,1,30,-0.0299252228124826 +27,1,30,-0.0303202202606565 +28,1,30,-0.0307148803656686 +29,1,30,-0.0311091460893837 +30,1,30,-0.0315029622614732 +31,1,30,-0.0318962755719487 +32,1,30,-0.0322890345610618 +33,1,30,-0.0326811896067219 +34,1,30,-0.0330726929095835 +35,1,30,-0.0334634984759521 +36,1,30,-0.0338535620986549 +37,1,30,-0.0342428413360224 +38,1,30,-0.0346312954891208 +39,1,30,-0.0350188855773731 +40,1,30,-0.035405574312705 +41,1,30,-0.0357913260723444 +42,1,30,-0.0361761068704021 +43,1,30,-0.0365598843283556 +44,1,30,-0.0369426276445544 +45,1,30,-0.0373243075628595 +46,1,30,-0.0377048963405269 +47,1,30,-0.0380843677154388 +48,1,30,-0.0384626968727824 +49,1,30,-0.0388398604112711 +50,1,30,-0.0392158363089981 +0,5,30,-0.00866820806918722 +1,5,30,-0.00883394199627025 +2,5,30,-0.00900044012830005 +3,5,30,-0.00916766024368503 +4,5,30,-0.00933556043027807 +5,5,30,-0.00950409912999041 +6,5,30,-0.00967323518139266 +7,5,30,-0.00984292786026239 +8,5,30,-0.0100131369180462 +9,5,30,-0.0101838226182133 +10,5,30,-0.0103549457704861 +11,5,30,-0.0105264677629398 +12,5,30,-0.0106983505919729 +13,5,30,-0.0108705568901559 +14,5,30,-0.0110430499519732 +15,5,30,-0.0112157937574792 +16,5,30,-0.011388752993895 +17,5,30,-0.0115618930751805 +18,5,30,-0.0117351801596171 +19,5,30,-0.011908581165445 +20,5,30,-0.0120820637846013 +21,5,30,-0.0122555964946094 +22,5,30,-0.0124291485686734 +23,5,30,-0.0126026900840348 +24,5,30,-0.0127761919286502 +25,5,30,-0.0129496258062517 +26,5,30,-0.0131229642398537 +27,5,30,-0.0132961805737704 +28,5,30,-0.0134692489742105 +29,5,30,-0.0136421444285145 +30,5,30,-0.0138148427431032 +31,5,30,-0.0139873205402034 +32,5,30,-0.0141595552534187 +33,5,30,-0.0143315251222121 +34,5,30,-0.0145032091853662 +35,5,30,-0.0146745872734869 +36,5,30,-0.0148456400006152 +37,5,30,-0.0150163487550095 +38,5,30,-0.0151866956891619 +39,5,30,-0.0153566637091071 +40,5,30,-0.015526236463085 +41,5,30,-0.0156953983296124 +42,5,30,-0.0158641344050205 +43,5,30,-0.0160324304905115 +44,5,30,-0.0162002730787854 +45,5,30,-0.0163676493402881 +46,5,30,-0.0165345471091273 +47,5,30,-0.0167009548687026 +48,5,30,-0.0168668617370933 +49,5,30,-0.0170322574522457 +50,5,30,-0.0171971323569986 +0,10,30,-0.00593513102284568 +1,10,30,-0.00604860921399168 +2,10,30,-0.00616261065705448 +3,10,30,-0.00627710644286667 +4,10,30,-0.00639206787413783 +5,10,30,-0.00650746649600161 +6,10,30,-0.0066232741251848 +7,10,30,-0.0067394628777702 +8,10,30,-0.00685600519553168 +9,10,30,-0.00697287387082563 +10,10,30,-0.00709004207002839 +11,10,30,-0.00720748335551516 +12,10,30,-0.00732517170618071 +13,10,30,-0.00744308153650754 +14,10,30,-0.00756118771419114 +15,10,30,-0.00767946557633741 +16,10,30,-0.00779789094425032 +17,10,30,-0.00791644013683241 +18,10,30,-0.00803508998262399 +19,10,30,-0.0081538178305099 +20,10,30,-0.00827260155912608 +21,10,30,-0.00839141958500024 +22,10,30,-0.00851025086946352 +23,10,30,-0.00862907492437225 +24,10,30,-0.00874787181668018 +25,10,30,-0.00886662217190342 +26,10,30,-0.00898530717652155 +27,10,30,-0.00910390857935905 +28,10,30,-0.00922240869199221 +29,10,30,-0.00934079038822726 +30,10,30,-0.00945903710269551 +31,10,30,-0.00957713282861146 +32,10,30,-0.00969506211474028 +33,10,30,-0.00981281006161968 +34,10,30,-0.0099303623170825 +35,10,30,-0.0100477050711238 +36,10,30,-0.0101648250501573 +37,10,30,-0.0102817095107044 +38,10,30,-0.0103983462325579 +39,10,30,-0.0105147235114623 +40,10,30,-0.0106308301513503 +41,10,30,-0.0107466554561764 +42,10,30,-0.010862189221383 +43,10,30,-0.0109774217250388 +44,10,30,-0.0110923437186813 +45,10,30,-0.0112069464179016 +46,10,30,-0.0113212214927008 +47,10,30,-0.0114351610576506 +48,10,30,-0.0115487576618887 +49,10,30,-0.0116620042789763 +50,10,30,-0.0117748942966451 From 592500b172df06c81850c69e43c84ad965b6e4ec Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 17:51:24 +0000 Subject: [PATCH 022/241] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.5.2 → v0.5.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.2...v0.5.5) - [github.com/pre-commit/mirrors-mypy: v1.10.1 → v1.11.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.10.1...v1.11.0) - [github.com/mwouts/jupytext: v1.16.3d → v1.16.4](https://github.com/mwouts/jupytext/compare/v1.16.3d...v1.16.4) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 171d5eff..278a608b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ repos: - id: debug-statements - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.5.2 + rev: v0.5.5 hooks: # Run the linter. - id: ruff @@ -14,7 +14,7 @@ repos: # Run the formatter. - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.10.1" + rev: "v1.11.0" hooks: - id: mypy additional_dependencies: [numpy, types-tabulate, pandas-stubs] @@ -25,7 +25,7 @@ repos: hooks: - id: markdownlint - repo: https://github.com/mwouts/jupytext - rev: v1.16.3d + rev: v1.16.4 hooks: - id: jupytext args: [--pipe, black] From 7d043b0e4ca24c03dc9cadb94b702d18c77c12c1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 17:52:24 +0000 Subject: [PATCH 023/241] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/source/api/constants_api.md | 2 +- docs/source/api/core_api.md | 2 +- docs/source/api/pmodel_api.md | 2 +- docs/source/api/splash_api.md | 2 +- docs/source/api/tmodel_api.md | 2 +- docs/source/development/code_qa_and_typing.md | 2 +- docs/source/development/code_testing.md | 2 +- docs/source/development/documentation.md | 2 +- docs/source/development/github_actions.md | 2 +- docs/source/development/overview.md | 2 +- docs/source/development/profiling_and_benchmarking.md | 2 +- docs/source/development/pyrealm_build_data.md | 2 +- docs/source/development/release_process.md | 2 +- docs/source/index.md | 2 +- docs/source/users/constants.md | 2 +- docs/source/users/hygro.md | 2 +- docs/source/users/pmodel/c3c4model.md | 2 +- docs/source/users/pmodel/isotopic_discrimination.md | 2 +- docs/source/users/pmodel/module_overview.md | 2 +- .../users/pmodel/pmodel_details/envt_variation_outputs.md | 2 +- docs/source/users/pmodel/pmodel_details/extreme_values.md | 2 +- docs/source/users/pmodel/pmodel_details/lue_limitation.md | 2 +- docs/source/users/pmodel/pmodel_details/optimal_chi.md | 2 +- .../users/pmodel/pmodel_details/photosynthetic_environment.md | 2 +- docs/source/users/pmodel/pmodel_details/pmodel_overview.md | 2 +- docs/source/users/pmodel/pmodel_details/rpmodel.md | 2 +- docs/source/users/pmodel/pmodel_details/soil_moisture.md | 2 +- docs/source/users/pmodel/pmodel_details/worked_examples.md | 2 +- docs/source/users/pmodel/subdaily_details/acclimation.md | 2 +- .../users/pmodel/subdaily_details/subdaily_calculations.md | 2 +- .../pmodel/subdaily_details/subdaily_model_and_missing_data.md | 2 +- docs/source/users/pmodel/subdaily_details/subdaily_overview.md | 2 +- docs/source/users/pmodel/subdaily_details/worked_example.md | 2 +- docs/source/users/splash.md | 2 +- docs/source/users/tmodel/tmodel.md | 2 +- 35 files changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/source/api/constants_api.md b/docs/source/api/constants_api.md index b1a27dc5..80bd4ba2 100644 --- a/docs/source/api/constants_api.md +++ b/docs/source/api/constants_api.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/core_api.md b/docs/source/api/core_api.md index 3c68bc84..89843589 100644 --- a/docs/source/api/core_api.md +++ b/docs/source/api/core_api.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/pmodel_api.md b/docs/source/api/pmodel_api.md index 3c40d1aa..ca593ae4 100644 --- a/docs/source/api/pmodel_api.md +++ b/docs/source/api/pmodel_api.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/splash_api.md b/docs/source/api/splash_api.md index 1799cf3f..e8177ab3 100644 --- a/docs/source/api/splash_api.md +++ b/docs/source/api/splash_api.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/tmodel_api.md b/docs/source/api/tmodel_api.md index fa78f23f..d74b7989 100644 --- a/docs/source/api/tmodel_api.md +++ b/docs/source/api/tmodel_api.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/code_qa_and_typing.md b/docs/source/development/code_qa_and_typing.md index a29ea075..b951cd8a 100644 --- a/docs/source/development/code_qa_and_typing.md +++ b/docs/source/development/code_qa_and_typing.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/code_testing.md b/docs/source/development/code_testing.md index c195cff9..9d126f5a 100644 --- a/docs/source/development/code_testing.md +++ b/docs/source/development/code_testing.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/documentation.md b/docs/source/development/documentation.md index e70aba23..cbe8cc3f 100644 --- a/docs/source/development/documentation.md +++ b/docs/source/development/documentation.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/github_actions.md b/docs/source/development/github_actions.md index 2a23986a..fda8ad3d 100644 --- a/docs/source/development/github_actions.md +++ b/docs/source/development/github_actions.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/overview.md b/docs/source/development/overview.md index 897e8923..72207d53 100644 --- a/docs/source/development/overview.md +++ b/docs/source/development/overview.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/profiling_and_benchmarking.md b/docs/source/development/profiling_and_benchmarking.md index 37188736..ccafd4f3 100644 --- a/docs/source/development/profiling_and_benchmarking.md +++ b/docs/source/development/profiling_and_benchmarking.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/pyrealm_build_data.md b/docs/source/development/pyrealm_build_data.md index 74d09f1f..0f9dd7c1 100644 --- a/docs/source/development/pyrealm_build_data.md +++ b/docs/source/development/pyrealm_build_data.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/release_process.md b/docs/source/development/release_process.md index 44a777fe..9396484c 100644 --- a/docs/source/development/release_process.md +++ b/docs/source/development/release_process.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/index.md b/docs/source/index.md index 972ada94..10234635 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/constants.md b/docs/source/users/constants.md index 692fc4db..7997e3a9 100644 --- a/docs/source/users/constants.md +++ b/docs/source/users/constants.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/hygro.md b/docs/source/users/hygro.md index 1e40d663..39322beb 100644 --- a/docs/source/users/hygro.md +++ b/docs/source/users/hygro.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/c3c4model.md b/docs/source/users/pmodel/c3c4model.md index 4bd3ba13..4a400e50 100644 --- a/docs/source/users/pmodel/c3c4model.md +++ b/docs/source/users/pmodel/c3c4model.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/isotopic_discrimination.md b/docs/source/users/pmodel/isotopic_discrimination.md index e5e3607b..5020de17 100644 --- a/docs/source/users/pmodel/isotopic_discrimination.md +++ b/docs/source/users/pmodel/isotopic_discrimination.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/module_overview.md b/docs/source/users/pmodel/module_overview.md index aa6dfcda..5be8782d 100644 --- a/docs/source/users/pmodel/module_overview.md +++ b/docs/source/users/pmodel/module_overview.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md b/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md index fd3f32e5..eae62e95 100644 --- a/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md +++ b/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/extreme_values.md b/docs/source/users/pmodel/pmodel_details/extreme_values.md index 2f4ce6c2..de08db01 100644 --- a/docs/source/users/pmodel/pmodel_details/extreme_values.md +++ b/docs/source/users/pmodel/pmodel_details/extreme_values.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/lue_limitation.md b/docs/source/users/pmodel/pmodel_details/lue_limitation.md index eb082d02..ec41094c 100644 --- a/docs/source/users/pmodel/pmodel_details/lue_limitation.md +++ b/docs/source/users/pmodel/pmodel_details/lue_limitation.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/optimal_chi.md b/docs/source/users/pmodel/pmodel_details/optimal_chi.md index 3d8de605..4c794fe0 100644 --- a/docs/source/users/pmodel/pmodel_details/optimal_chi.md +++ b/docs/source/users/pmodel/pmodel_details/optimal_chi.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md b/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md index 3a1a6557..adbbca1a 100644 --- a/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md +++ b/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md index 4307e981..ef50e665 100644 --- a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md +++ b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/rpmodel.md b/docs/source/users/pmodel/pmodel_details/rpmodel.md index 1f172baf..f2b4eb93 100644 --- a/docs/source/users/pmodel/pmodel_details/rpmodel.md +++ b/docs/source/users/pmodel/pmodel_details/rpmodel.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/soil_moisture.md b/docs/source/users/pmodel/pmodel_details/soil_moisture.md index b1950df1..afe55613 100644 --- a/docs/source/users/pmodel/pmodel_details/soil_moisture.md +++ b/docs/source/users/pmodel/pmodel_details/soil_moisture.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/worked_examples.md b/docs/source/users/pmodel/pmodel_details/worked_examples.md index 49e348d0..4fe2823a 100644 --- a/docs/source/users/pmodel/pmodel_details/worked_examples.md +++ b/docs/source/users/pmodel/pmodel_details/worked_examples.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/acclimation.md b/docs/source/users/pmodel/subdaily_details/acclimation.md index 4d910f60..09512e49 100644 --- a/docs/source/users/pmodel/subdaily_details/acclimation.md +++ b/docs/source/users/pmodel/subdaily_details/acclimation.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md index 781372e2..661fd643 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md b/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md index 43c6bea0..5f1e995b 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_overview.md b/docs/source/users/pmodel/subdaily_details/subdaily_overview.md index e1ea618f..31234000 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_overview.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_overview.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/worked_example.md b/docs/source/users/pmodel/subdaily_details/worked_example.md index ce2483ae..e53936e5 100644 --- a/docs/source/users/pmodel/subdaily_details/worked_example.md +++ b/docs/source/users/pmodel/subdaily_details/worked_example.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/splash.md b/docs/source/users/splash.md index 3047a89a..e852f49c 100644 --- a/docs/source/users/splash.md +++ b/docs/source/users/splash.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/tmodel/tmodel.md b/docs/source/users/tmodel/tmodel.md index 9a247463..ca6c5eec 100644 --- a/docs/source/users/tmodel/tmodel.md +++ b/docs/source/users/tmodel/tmodel.md @@ -5,7 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.3 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python From 29b6959814a938a8236a7199337df085387b37c1 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 31 Jul 2024 16:06:43 +0100 Subject: [PATCH 024/241] Added sandoval parameters to PModelConsts, update regresssion test values --- pyrealm/constants/pmodel_const.py | 16 + pyrealm/pmodel/quantum_yield.py | 83 +- pyrealm_build_data/sandoval_kphio/calc_phi0.R | 6 +- .../sandoval_kphio/sandoval_kphio.csv | 3672 ++++++++--------- 4 files changed, 1903 insertions(+), 1874 deletions(-) diff --git a/pyrealm/constants/pmodel_const.py b/pyrealm/constants/pmodel_const.py index 970179d3..817636e0 100644 --- a/pyrealm/constants/pmodel_const.py +++ b/pyrealm/constants/pmodel_const.py @@ -89,6 +89,22 @@ class PModelConst(ConstantsClass): """ + sandoval_peak_phio: tuple[float, float] = (6.8681, 0.07956432) + """Curvature parameters for calculation of peak phio in the Sandoval method for + estimation of quantum yield efficiency.""" + + sandoval_kinetics: tuple[float, float, float, float] = ( + 1558.853, + -50.223, + 294.804, + 75000.0, + ) + """Enzyme kinetics parameters for estimation of kphion from mean growth temperature + in the Sandoval method for estimation of quantum yield efficiency. Values are: the + intercept and slope of activation entropy as a function of the mean growth + temperature (J/mol/K), the deactivation energy constant (J/mol) and the activation + energy (J/mol). """ + plant_T_ref: float = 25.0 """Standard baseline reference temperature of photosynthetic processes (Prentice, unpublished) (:math:`T_o` , 25.0, °C)""" diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index c3fc7b1d..41895561 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -7,7 +7,6 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Any from warnings import warn import numpy as np @@ -74,10 +73,14 @@ class QuantumYieldABC(ABC): :class:`~pyrealm.pmodel.pmodel_environment.PModelEnvironment` that must be populated to use a method. """ + default_reference_kphio: float + """A default value for the reference kphio value for use with a given + implementation.""" def __init__( self, env: PModelEnvironment, + reference_kphio: float | None = None, pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), ): @@ -90,12 +93,14 @@ def __init__( """The PModelConst used for calculating quantum yield""" self.core_const: CoreConst = core_const """The CoreConst used for calculating quantum yield""" + self.reference_kphio: float = reference_kphio or self.default_reference_kphio + """The reference value for kphio for the method.""" # Declare attributes populated by methods. These are typed but not assigned a # default value as they must are populated by the subclass specific # calculate_kphio method, which is called below to populate the values. self.kphio: NDArray - """The intrinsic quantum yield of photosynthesis.""" + """The calculated intrinsic quantum yield of photosynthesis.""" # Run the calculation methods after checking for any required variables self._check_requires() @@ -105,14 +110,14 @@ def __init__( _ = check_input_shapes(env.ca, self.kphio) @abstractmethod - def _calculate_kphio(self, **kwargs: Any) -> None: + def _calculate_kphio(self) -> None: """Calculate the intrinsic quantum yield of photosynthesis.""" def _check_requires(self) -> None: """Check additional required variables are present.""" for required_var in self.requires: - if getattr(self.env, required_var) is None: + if not hasattr(self.env, required_var): raise ValueError( f"{self.__class__.__name__} (method {self.method}) requires " f"{required_var} to be provided in the PModelEnvironment." @@ -137,12 +142,19 @@ def summarize(self, dp: int = 2) -> None: summarize_attrs(self, attrs, dp=dp) @classmethod - def __init_subclass__(cls, method: str, is_c4: bool, requires: list[str]) -> None: + def __init_subclass__( + cls, + method: str, + is_c4: bool, + requires: list[str], + default_reference_kphio: float, + ) -> None: """Initialise a subclass deriving from this ABC.""" cls.method = method cls.is_c4 = is_c4 cls.requires = requires + cls.default_reference_kphio = default_reference_kphio QUANTUM_YIELD_CLASS_REGISTRY[cls.method] = cls @@ -151,16 +163,14 @@ class QuantumYieldConstant( method="constant", is_c4=False, requires=[], + default_reference_kphio=0.049977, ): """Constant kphio.""" - def _calculate_kphio(self, **kwargs: Any) -> None: + def _calculate_kphio(self) -> None: """Constant kphio.""" - if "init_kphio" not in kwargs: - raise ValueError("Missing definition of initial kphio.") - - self.kphio = np.array([kwargs["init_kphio"]]) + self.kphio = np.array([self.reference_kphio]) class QuantumYieldBernacchiC3( @@ -168,19 +178,19 @@ class QuantumYieldBernacchiC3( method="bernacchi_c3", is_c4=False, requires=[], + default_reference_kphio=0.081785, ): """Calculate kphio following Bernacchi for C3 plants.""" - def _calculate_kphio(self, **kwargs: Any) -> None: + def _calculate_kphio( + self, + ) -> None: """Calculate kphio.""" - if "init_kphio" not in kwargs: - raise ValueError("Missing definition of constant kphio.") - ftemp = evaluate_horner_polynomial(self.env.tc, self.pmodel_const.kphio_C3) ftemp = np.clip(ftemp, 0.0, None) - self.kphio = ftemp * kwargs["init_kphio"] + self.kphio = ftemp * self.reference_kphio class QuantumYieldBernacchiC4( @@ -188,19 +198,17 @@ class QuantumYieldBernacchiC4( method="bernacchi_c4", is_c4=True, requires=[], + default_reference_kphio=0.081785, ): """Calculate kphio following Bernacchi.""" - def _calculate_kphio(self, **kwargs: Any) -> None: + def _calculate_kphio(self) -> None: """Calculate kphio.""" - if "init_kphio" not in kwargs: - raise ValueError("Missing definition of constant kphio.") - ftemp = evaluate_horner_polynomial(self.env.tc, self.pmodel_const.kphio_C4) ftemp = np.clip(ftemp, 0.0, None) - self.kphio = ftemp * kwargs["init_kphio"] + self.kphio = ftemp * self.reference_kphio class QuantumYieldSandoval( @@ -208,38 +216,39 @@ class QuantumYieldSandoval( method="sandoval", is_c4=False, requires=["aridity_index", "mean_growth_temperature"], + default_reference_kphio=1.0 / 9.0, ): - """Calculate kphio following Sandoval.""" + """Calculate kphio following Sandoval. - def _calculate_kphio(self, **kwargs: Any) -> None: - """Constant kphio.""" + Reference kphio is the theoretical maximum quantum yield, defaulting to the ratio of + 1/9 in the absence of a Q cycle (Long, 1993). + """ + + def _calculate_kphio(self) -> None: + """Calculate kphio.""" # Warn that this is an experimental feature. warn( - "The sandoval method for calculating kphi0 is experimental, " + "The sandoval method for calculating kphio is experimental, " "see the class documentation", ExperimentalFeatureWarning, ) - # Calculate activation entropy as a function of mean growth temperature, J/mol/K - deltaS = 1558.853 - 50.223 * self.env.mean_growth_temperature + # Calculate enzyme kinetics + a_ent, b_ent, Hd_base, Ha = self.pmodel_const.sandoval_kinetics + # Calculate activation entropy as a linear function of + # mean growth temperature, J/mol/K + deltaS = a_ent + b_ent * self.env.mean_growth_temperature # Calculate deaactivation energy J/mol - Hd = 294.804 * deltaS - # activation energy J/mol - Ha = 75000.0 - - # theoretical maximum phi0 and curvature parameters (Long, 1993;Sandoval et al., - # in.prep.) - phi_o_theo = 0.111 - m = 6.8681 - n = 0.07956432 + Hd = Hd_base * deltaS # Calculate the optimal temperature to be used as the reference temperature in # the modified Arrhenius calculation Topt = Hd / (deltaS - self.core_const.k_R * np.log(Ha / (Hd - Ha))) # Calculate peak kphio given the aridity index - kphio_peak = phi_o_theo / (1 + (self.env.aridity_index) ** m) ** n + m, n = self.pmodel_const.sandoval_peak_phio + kphio_peak = self.reference_kphio / (1 + (self.env.aridity_index) ** m) ** n # Calculate the modified Arrhenius factor using the f_kphio = calc_modified_arrhenius_factor( @@ -252,4 +261,4 @@ def _calculate_kphio(self, **kwargs: Any) -> None: ) # Apply the factor and store it. - self.kphio = kphio_peak * f_kphio + self.kphio = np.array([kphio_peak * f_kphio]) diff --git a/pyrealm_build_data/sandoval_kphio/calc_phi0.R b/pyrealm_build_data/sandoval_kphio/calc_phi0.R index 836c74e1..6be1fc27 100644 --- a/pyrealm_build_data/sandoval_kphio/calc_phi0.R +++ b/pyrealm_build_data/sandoval_kphio/calc_phi0.R @@ -16,7 +16,10 @@ calc_phi0 <- function(AI, tc, mGDD0 = NA) { ############################################################################################### # 01.define the parameters/constants ############################################################################################### - phi_o_theo <- 0.111 # theoretical maximum phi0 (Long, 1993;Sandoval et al., in.prep.) + + # DO change here to avoid imprecision in theoretical maxmimum + # phi_o_theo <- 0.111 # theoretical maximum phi0 (Long, 1993;Sandoval et al., in.prep.) + phi_o_theo <- 1 / 9 m <- 6.8681 # curvature parameter phio max (Sandoval et al., in.prep.) n <- 0.07956432 # curvature parameter phio max (Sandoval et al., in.prep.) Rgas <- 8.3145 # ideal gas constant J/mol/K @@ -89,4 +92,5 @@ for (row_idx in seq_along(data$aridity_index)) { ) } +data$phio <- round(data$phio, digits = 8) write.csv(data, "sandoval_kphio.csv", row.names = FALSE) diff --git a/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv b/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv index bb4af59e..b9adec24 100644 --- a/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv +++ b/pyrealm_build_data/sandoval_kphio/sandoval_kphio.csv @@ -1,1837 +1,1837 @@ "temp","aridity_index","mean_gdd_temp","phio" -0,0.2,5,0.0150189600590777 -1,0.2,5,0.0170035547170646 -2,0.2,5,0.0192332352709473 -3,0.2,5,0.0217360643227769 -4,0.2,5,0.024543006070574 -5,0.2,5,0.0276881368424111 -6,0.2,5,0.0312088037406028 -7,0.2,5,0.0351456582790139 -8,0.2,5,0.0395424206049159 -9,0.2,5,0.0444450927333507 -10,0.2,5,0.0499000783715251 -11,0.2,5,0.0559501789959781 -12,0.2,5,0.0626265467550122 -13,0.2,5,0.0699331259947415 -14,0.2,5,0.077817639344329 -15,0.2,5,0.086119917160609 -16,0.2,5,0.0944863424652653 -17,0.2,5,0.102245986112935 -18,0.2,5,0.108278645046534 -19,0.2,5,0.110993670865875 -20,0.2,5,0.108656270648972 -21,0.2,5,0.100233466068612 -22,0.2,5,0.0863769414144302 -23,0.2,5,0.0695291602163739 -24,0.2,5,0.0527323208217483 -25,0.2,5,0.0381989078376782 -26,0.2,5,0.0268025777720468 -27,0.2,5,0.018427804600136 -28,0.2,5,0.0125189835189365 -29,0.2,5,0.00845045031413486 -30,0.2,5,0.0056877326986421 -31,0.2,5,0.00382552594257428 -32,0.2,5,0.00257458000318248 -33,0.2,5,0.0017351030307797 -34,0.2,5,0.00117151635254028 -35,0.2,5,0.000792669260635163 -36,0.2,5,0.000537553978366543 -37,0.2,5,0.000365404661290626 -38,0.2,5,0.000248980545228804 -39,0.2,5,0.000170060161455839 -40,0.2,5,0.00011643555265551 -41,0.2,5,7.99117417470755e-05 -42,0.2,5,5.49757747415985e-05 -43,0.2,5,3.79105727169236e-05 -44,0.2,5,2.62040988167543e-05 -45,0.2,5,1.81547071246715e-05 -46,0.2,5,1.26069903869731e-05 -47,0.2,5,8.77458695053462e-06 -48,0.2,5,6.12105026286057e-06 -49,0.2,5,4.27957031376439e-06 -50,0.2,5,2.99875068859148e-06 -0,0.5,5,0.0150087964558047 -1,0.5,5,0.0169920481025125 -2,0.5,5,0.0192202197910352 -3,0.5,5,0.0217213551329513 -4,0.5,5,0.0245263973722456 -5,0.5,5,0.0276693997769201 -6,0.5,5,0.0311876841758263 -7,0.5,5,0.0351218745732107 -8,0.5,5,0.0395156615301265 -9,0.5,5,0.0444150159312156 -10,0.5,5,0.0498663100814529 -11,0.5,5,0.0559123164928401 -12,0.5,5,0.0625841662324547 -13,0.5,5,0.0698858009772002 -14,0.5,5,0.0777649787332865 -15,0.5,5,0.0860616382472569 -16,0.5,5,0.0944224018398324 -17,0.5,5,0.102176794395598 -18,0.5,5,0.10820537091924 -19,0.5,5,0.110918559431258 -20,0.5,5,0.108582740975569 -21,0.5,5,0.10016563626017 -22,0.5,5,0.0863184885680936 -23,0.5,5,0.0694821085698177 -24,0.5,5,0.0526966359017281 -25,0.5,5,0.0381730579423994 -26,0.5,5,0.0267844399804756 -27,0.5,5,0.0184153341697992 -28,0.5,5,0.0125105116952305 -29,0.5,5,0.00844473174080269 -30,0.5,5,0.0056838837065385 -31,0.5,5,0.00382293713963202 -32,0.5,5,0.00257283773809596 -33,0.5,5,0.00173392885501965 -34,0.5,5,0.00117072356612975 -35,0.5,5,0.000792132846938071 -36,0.5,5,0.000537190205818216 -37,0.5,5,0.000365157385314337 -38,0.5,5,0.000248812055568106 -39,0.5,5,0.000169945078653383 -40,0.5,5,0.000116356758600569 -41,0.5,5,7.98576640188723e-05 -42,0.5,5,5.49385716355312e-05 -43,0.5,5,3.78849179432622e-05 -44,0.5,5,2.61863660267708e-05 -45,0.5,5,1.81424215043605e-05 -46,0.5,5,1.25984590074199e-05 -47,0.5,5,8.76864902804874e-06 -48,0.5,5,6.11690803688481e-06 -49,0.5,5,4.27667425074293e-06 -50,0.5,5,2.99672137949195e-06 -0,0.8,5,0.0147871102993512 -1,0.8,5,0.0167410684956392 -2,0.8,5,0.018936329163015 -3,0.8,5,0.0214005216972681 -4,0.8,5,0.0241641322978198 -5,0.8,5,0.027260711251762 -6,0.8,5,0.0307270291290353 -7,0.8,5,0.0346031099004733 -8,0.8,5,0.0389319987993988 -9,0.8,5,0.0437589877013968 -10,0.8,5,0.0491297639732404 -11,0.8,5,0.0550864683591668 -12,0.8,5,0.0616597721074645 -13,0.8,5,0.0688535586748324 -14,0.8,5,0.0766163577034236 -15,0.8,5,0.0847904721109644 -16,0.8,5,0.0930277437532484 -17,0.8,5,0.100667600710748 -18,0.8,5,0.10660713265561 -19,0.8,5,0.109280246246581 -20,0.8,5,0.106978928799494 -21,0.8,5,0.0986861482161674 -22,0.8,5,0.0850435286458984 -23,0.8,5,0.0684558289719509 -24,0.8,5,0.0519182847057823 -25,0.8,5,0.0376092260242143 -26,0.8,5,0.0263888226790141 -27,0.8,5,0.0181433320366548 -28,0.8,5,0.0123257262421698 -29,0.8,5,0.00831999954609194 -30,0.8,5,0.00559993038380929 -31,0.8,5,0.00376647077050349 -32,0.8,5,0.00253483585626509 -33,0.8,5,0.00170831800577101 -34,0.8,5,0.00115343149288397 -35,0.8,5,0.000780432715834597 -36,0.8,5,0.000529255683395783 -37,0.8,5,0.000359763859091944 -38,0.8,5,0.000245136998181552 -39,0.8,5,0.000167434919267466 -40,0.8,5,0.000114638120955805 -41,0.8,5,7.86781331582981e-05 -42,0.8,5,5.41271061177738e-05 -43,0.8,5,3.7325341972522e-05 -44,0.8,5,2.57995825259715e-05 -45,0.8,5,1.78744504046189e-05 -46,0.8,5,1.24123745360356e-05 -47,0.8,5,8.63913244049012e-06 -48,0.8,5,6.02655876497154e-06 -49,0.8,5,4.21350599605692e-06 -50,0.8,5,2.95245856024873e-06 -0,1,5,0.0142131114771569 -1,1,5,0.0160912218789413 -2,1,5,0.0182012679903981 -3,1,5,0.0205698067029317 -4,1,5,0.0232261408175705 -5,1,5,0.0262025182827559 -6,1,5,0.0295342823264114 -7,1,5,0.0332599032884279 -8,1,5,0.037420755493294 -9,1,5,0.0420603726986994 -10,1,5,0.0472226688015378 -11,1,5,0.0529481487472277 -12,1,5,0.0592662932025286 -13,1,5,0.0661808348780146 -14,1,5,0.07364230136704 -15,1,5,0.0814991169956155 -16,1,5,0.0894166382522564 -17,1,5,0.0967599349754323 -18,1,5,0.102468909071484 -19,1,5,0.105038259045241 -20,1,5,0.102826273014325 -21,1,5,0.0948553975355923 -22,1,5,0.0817423505056272 -23,1,5,0.0657985440523975 -24,1,5,0.049902946098835 -25,1,5,0.0361493294653519 -26,1,5,0.0253644742545951 -27,1,5,0.0174390530390079 -28,1,5,0.0118472722236043 -29,1,5,0.00799703786910195 -30,1,5,0.00538255502245704 -31,1,5,0.00362026574853964 -32,1,5,0.00243643983659003 -33,1,5,0.00164200535215613 -34,1,5,0.00110865815279288 -35,1,5,0.00075013826001312 -36,1,5,0.00050871129488722 -37,1,5,0.000345798721400645 -38,1,5,0.000235621389967103 -39,1,5,0.000160935512384842 -40,1,5,0.000110188154392013 -41,1,5,7.56240438297498e-05 -42,1,5,5.20260265605492e-05 -43,1,5,3.58764650860644e-05 -44,1,5,2.47981069378937e-05 -45,1,5,1.71806087227811e-05 -46,1,5,1.19305570463377e-05 -47,1,5,8.30378281874286e-06 -48,1,5,5.79262275158219e-06 -49,1,5,4.04994817914176e-06 -50,1,5,2.83785146651286e-06 -0,5,5,0.00623280751560459 -1,5,5,0.00705640625020894 -2,5,5,0.00798171463767199 -3,5,5,0.00902037854403804 -4,5,5,0.0101852479859112 -5,5,5,0.0114904645012463 -6,5,5,0.0129515269860437 -7,5,5,0.0145853056536965 -8,5,5,0.0164099441880168 -9,5,5,0.018444533238687 -10,5,5,0.0207083301560094 -11,5,5,0.0232190973791676 -12,5,5,0.0259897629233706 -13,5,5,0.0290219636762597 -14,5,5,0.0322940047409465 -15,5,5,0.0357394163650802 -16,5,5,0.0392114489367421 -17,5,5,0.042431669581538 -18,5,5,0.0449351985737262 -19,5,5,0.046061923278052 -20,5,5,0.0450919116672895 -21,5,5,0.0415964819248547 -22,5,5,0.0358460803880624 -23,5,5,0.0288543195165074 -24,5,5,0.0218836992867833 -25,5,5,0.0158523918381862 -26,5,5,0.0111229610784016 -27,5,5,0.00764746417568367 -28,5,5,0.00519532739002096 -29,5,5,0.00350690260983471 -30,5,5,0.00236038600351824 -31,5,5,0.0015875777518701 -32,5,5,0.00106844026019379 -33,5,5,0.000720060721118673 -34,5,5,0.000486174535257078 -35,5,5,0.000328954528518732 -36,5,5,0.000223082720989131 -37,5,5,0.000151641452548681 -38,5,5,0.000103325916537308 -39,5,5,7.05742773306221e-05 -40,5,5,4.83202821513731e-05 -41,5,5,3.31630487455209e-05 -42,5,5,2.28147235652654e-05 -43,5,5,1.57327339324069e-05 -44,5,5,1.08745947390675e-05 -45,5,5,7.534129830904e-06 -46,5,5,5.23184988334714e-06 -47,5,5,3.64141799941484e-06 -48,5,5,2.54021103536337e-06 -49,5,5,1.77600432455155e-06 -50,5,5,1.24446937442786e-06 -0,10,5,0.00426760974702343 -1,10,5,0.00483152865172792 -2,10,5,0.00546508826085325 -3,10,5,0.00617626251091497 -4,10,5,0.00697384982156139 -5,10,5,0.00786753291844417 -6,10,5,0.00886792391167172 -7,10,5,0.00998657385378817 -8,10,5,0.0112359057438496 -9,10,5,0.0126289909694224 -10,10,5,0.0141790150581591 -11,10,5,0.015898139970525 -12,10,5,0.0177952175318935 -13,10,5,0.0198713685209243 -14,10,5,0.0221117384192981 -15,10,5,0.0244708153188893 -16,10,5,0.0268481196087635 -17,10,5,0.0290530080120858 -18,10,5,0.0307671769002264 -19,10,5,0.0315386464696547 -20,10,5,0.0308744785173392 -21,10,5,0.0284811541604577 -22,10,5,0.0245438482856536 -23,10,5,0.0197565823914956 -24,10,5,0.0149837915166464 -25,10,5,0.0108541490737366 -26,10,5,0.00761590294503817 -27,10,5,0.00523622662410975 -28,10,5,0.00355724603288676 -29,10,5,0.00240117984104644 -30,10,5,0.00161615873587185 -31,10,5,0.00108701612733522 -32,10,5,0.000731562150298966 -33,10,5,0.000493026319872913 -34,10,5,0.000332884206711529 -35,10,5,0.000225235505623963 -36,10,5,0.000152744969598724 -37,10,5,0.00010382905926893 -38,10,5,7.07473618318486e-05 -39,10,5,4.83222806209317e-05 -40,10,5,3.3084947124044e-05 -41,10,5,2.2706773747315e-05 -42,10,5,1.56212648022594e-05 -43,10,5,1.0772219181993e-05 -44,10,5,7.44584625583012e-06 -45,10,5,5.15862648111748e-06 -46,10,5,3.58225302181016e-06 -47,10,5,2.49328266730244e-06 -48,10,5,1.73928512101045e-06 -49,10,5,1.21603199637343e-06 -50,10,5,8.52089466726507e-07 -0,0.2,10,0.0159348721317312 -1,0.2,10,0.0180400606834725 -2,0.2,10,0.0204048701222286 -3,0.2,10,0.0230587423802596 -4,0.2,10,0.0260339448554785 -5,0.2,10,0.0293656107576921 -6,0.2,10,0.0330916008876179 -7,0.2,10,0.0372520346890142 -8,0.2,10,0.0418882273335961 -9,0.2,10,0.0470405839181718 -10,0.2,10,0.0527446994022468 -11,0.2,10,0.0590244402441983 -12,0.2,10,0.0658800964135193 -13,0.2,10,0.0732688274311094 -14,0.2,10,0.0810738976499304 -15,0.2,10,0.0890596325661463 -16,0.2,10,0.0968131033894681 -17,0.2,10,0.103685681055626 -18,0.2,10,0.108771990658426 -19,0.2,10,0.110994287959672 -20,0.2,10,0.109361450681138 -21,0.2,10,0.103381358344563 -22,0.2,10,0.0934223095109367 -23,0.2,10,0.0807245799182078 -24,0.2,10,0.0669741885291157 -25,0.2,10,0.0537150069889818 -26,0.2,10,0.0419666864115946 -27,0.2,10,0.0321704918502215 -28,0.2,10,0.0243414293132923 -29,0.2,10,0.0182622219059435 -30,0.2,10,0.0136307381473869 -31,0.2,10,0.0101449626493986 -32,0.2,10,0.00754110550459295 -33,0.2,10,0.00560448586335027 -34,0.2,10,0.00416735303324539 -35,0.2,10,0.00310178079125282 -36,0.2,10,0.0023116409276084 -37,0.2,10,0.00172533486563622 -38,0.2,10,0.00128980580167562 -39,0.2,10,0.000965843289117765 -40,0.2,10,0.000724503101690771 -41,0.2,10,0.00054442221595272 -42,0.2,10,0.000409824764397559 -43,0.2,10,0.000309049548902073 -44,0.2,10,0.000233466057633311 -45,0.2,10,0.000176677619332255 -46,0.2,10,0.000133935832923386 -47,0.2,10,0.000101710093083305 -48,0.2,10,7.73708644180207e-05 -49,0.2,10,5.89563774371837e-05 -50,0.2,10,4.50005399308707e-05 -0,0.5,10,0.01592408871411 -1,0.5,10,0.0180278526464922 -2,0.5,10,0.0203910617757157 -3,0.5,10,0.0230431381101501 -4,0.5,10,0.0260163272117735 -5,0.5,10,0.029345738515111 -6,0.5,10,0.0330692071997882 -7,0.5,10,0.0372268255600065 -8,0.5,10,0.0418598808087534 -9,0.5,10,0.0470087506999734 -10,0.5,10,0.0527090061054162 -11,0.5,10,0.0589844973325925 -12,0.5,10,0.0658355141547679 -13,0.5,10,0.0732192450837728 -14,0.5,10,0.0810190334697031 -15,0.5,10,0.0889993642939438 -16,0.5,10,0.096747588202624 -17,0.5,10,0.103615515070552 -18,0.5,10,0.108698382675189 -19,0.5,10,0.110919176107456 -20,0.5,10,0.109287443799589 -21,0.5,10,0.103311398300199 -22,0.5,10,0.0933590889359449 -23,0.5,10,0.0806699521276393 -24,0.5,10,0.0669288658783422 -25,0.5,10,0.0536786570673698 -26,0.5,10,0.0419382867920676 -27,0.5,10,0.0321487214936205 -28,0.5,10,0.0243249570256196 -29,0.5,10,0.0182498635284257 -30,0.5,10,0.0136215139791154 -31,0.5,10,0.0101380973687678 -32,0.5,10,0.00753600230142264 -33,0.5,10,0.0056006932058933 -34,0.5,10,0.00416453290969744 -35,0.5,10,0.00309968175981003 -36,0.5,10,0.00231007659817378 -37,0.5,10,0.00172416730017108 -38,0.5,10,0.00128893296664471 -39,0.5,10,0.000965189685407799 -40,0.5,10,0.000724012817272499 -41,0.5,10,0.000544053795543173 -42,0.5,10,0.000409547428530069 -43,0.5,10,0.000308840409454709 -44,0.5,10,0.000233308066908377 -45,0.5,10,0.000176558058375768 -46,0.5,10,0.000133845196110683 -47,0.5,10,0.000101641264014522 -48,0.5,10,7.73185061476919e-05 -49,0.5,10,5.89164805849166e-05 -50,0.5,10,4.49700872475206e-05 -0,0.8,10,0.015688883310902 -1,0.8,10,0.017761573776359 -2,0.8,10,0.0200898773253586 -3,0.8,10,0.0227027813909882 -4,0.8,10,0.0256320552548849 -5,0.8,10,0.0289122897706457 -6,0.8,10,0.032580761276581 -7,0.8,10,0.0366769698870574 -8,0.8,10,0.0412415929857811 -9,0.8,10,0.0463144119305029 -10,0.8,10,0.0519304721964248 -11,0.8,10,0.0581132718121114 -12,0.8,10,0.0648630962707566 -13,0.8,10,0.0721377664276497 -14,0.8,10,0.0798223487000506 -15,0.8,10,0.087684806723973 -16,0.8,10,0.0953185861478663 -17,0.8,10,0.102085070883866 -18,0.8,10,0.107092862423186 -19,0.8,10,0.109280853814216 -20,0.8,10,0.107673222870156 -21,0.8,10,0.101785446044504 -22,0.8,10,0.0919801364225203 -23,0.8,10,0.0794784234343744 -24,0.8,10,0.0659402987353304 -25,0.8,10,0.0528858010109971 -26,0.8,10,0.0413188408801616 -27,0.8,10,0.0316738715265495 -28,0.8,10,0.0239656673087669 -29,0.8,10,0.0179803054653704 -30,0.8,10,0.0134203185609485 -31,0.8,10,0.009988353460517 -32,0.8,10,0.00742469241790557 -33,0.8,10,0.00551796864140568 -34,0.8,10,0.00410302102918834 -35,0.8,10,0.00305389817299248 -36,0.8,10,0.00227595580749811 -37,0.8,10,0.0016987006331413 -38,0.8,10,0.00126989489146372 -39,0.8,10,0.00095093343293368 -40,0.8,10,0.000713318847295837 -41,0.8,10,0.000536017895050215 -42,0.8,10,0.000403498242935236 -43,0.8,10,0.000304278708352883 -44,0.8,10,0.000229862009872771 -45,0.8,10,0.000173950222533136 -46,0.8,10,0.000131868246981356 -47,0.8,10,0.000100139980335794 -48,0.8,10,7.61764797033277e-05 -49,0.8,10,5.80462597000444e-05 -50,0.8,10,4.43058603838519e-05 -0,1,10,0.0150798799045774 -1,1,10,0.0170721136843222 -2,1,10,0.0193100382838326 -3,1,10,0.0218215159161824 -4,1,10,0.0246370826585575 -5,1,10,0.0277899866337021 -6,1,10,0.0313160572052403 -7,1,10,0.0352532611914002 -8,1,10,0.0396406969810833 -9,1,10,0.0445166017187335 -10,1,10,0.0499146605014209 -11,1,10,0.0558574592227188 -12,1,10,0.062345272293686 -13,1,10,0.0693375578590411 -14,1,10,0.0767238437716991 -15,1,10,0.0842811007418712 -16,1,10,0.0916185558461712 -17,1,10,0.0981223824839869 -18,1,10,0.102935784018285 -19,1,10,0.105038843028613 -20,1,10,0.103493616317005 -21,1,10,0.0978343883352343 -22,1,10,0.0884096964310015 -23,1,10,0.0763932688289341 -24,1,10,0.0633806604393419 -25,1,10,0.0508329058288701 -26,1,10,0.0397149463044452 -27,1,10,0.0304443706583932 -28,1,10,0.023035379745487 -29,1,10,0.0172823547535082 -30,1,10,0.0128993751926018 -31,1,10,0.00960063043648239 -32,1,10,0.0071364843355448 -33,1,10,0.0053037748309212 -34,1,10,0.00394375196373096 -35,1,10,0.00293535344593542 -36,1,10,0.00218760886705987 -37,1,10,0.00163276130199783 -38,1,10,0.00122060073207392 -39,1,10,0.000914020563587387 -40,1,10,0.000685629584829537 -41,1,10,0.000515211014313861 -42,1,10,0.00038783544530178 -43,1,10,0.000292467366131337 -44,1,10,0.000220939338690695 -45,1,10,0.000167197907791908 -46,1,10,0.000126749449804639 -47,1,10,9.62527955103834e-05 -48,1,10,7.32194983362149e-05 -49,1,10,5.5793048354074e-05 -50,1,10,4.25860171445846e-05 -0,5,10,0.00661290731130364 -1,5,10,0.00748655202275138 -2,5,10,0.00846793834942603 -3,5,10,0.00956928457381476 -4,5,10,0.010803981535192 -5,5,10,0.012186609373146 -6,5,10,0.0137328801664313 -7,5,10,0.0154594433215044 -8,5,10,0.0173834444670748 -9,5,10,0.0195216515544562 -10,5,10,0.0218888363474892 -11,5,10,0.0244949033296108 -12,5,10,0.0273399728369844 -13,5,10,0.0304062662445217 -14,5,10,0.0336453387321195 -15,5,10,0.0369593863364563 -16,5,10,0.0401770452841817 -17,5,10,0.0430291371441181 -18,5,10,0.0451399350019138 -19,5,10,0.0460621793694752 -20,5,10,0.0453845585208032 -21,5,10,0.0429028444531981 -22,5,10,0.0387698795758474 -23,5,10,0.0335003732901016 -24,5,10,0.0277940166279013 -25,5,10,0.0222915100609328 -26,5,10,0.0174160046662559 -27,5,10,0.0133506236514401 -28,5,10,0.0101015944491274 -29,5,10,0.0075787480291091 -30,5,10,0.0056567010521425 -31,5,10,0.00421011835692852 -32,5,10,0.00312952820169364 -33,5,10,0.00232583890447701 -34,5,10,0.00172943460822976 -35,5,10,0.00128722644919703 -36,5,10,0.000959321610171561 -37,5,10,0.000716006972198611 -38,5,10,0.000535264176929162 -39,5,10,0.000400821048037273 -40,5,10,0.000300665849002489 -41,5,10,0.000225933011733477 -42,5,10,0.000170075615193749 -43,5,10,0.000128254309453789 -44,5,10,9.68874671036868e-05 -45,5,10,7.33204955124456e-05 -46,5,10,5.5582827490714e-05 -47,5,10,4.22092761475389e-05 -48,5,10,3.210859495841e-05 -49,5,10,2.44666575407262e-05 -50,5,10,1.86750415730594e-05 -0,10,10,0.00452786446994014 -1,10,10,0.00512604990670767 -2,10,10,0.00579800613876307 -3,10,10,0.00655209903675189 -4,10,10,0.00739749732216368 -5,10,10,0.00834418403164184 -6,10,10,0.00940291724174672 -7,10,10,0.0105850968182849 -8,10,10,0.0119024623909524 -9,10,10,0.0133664949933419 -10,10,10,0.0149873088674205 -11,10,10,0.0167716856232329 -12,10,10,0.0187197076550747 -13,10,10,0.0208192019199751 -14,10,10,0.0230369981995457 -15,10,10,0.0253061300190281 -16,10,10,0.027509264425719 -17,10,10,0.0294620946696175 -18,10,10,0.0309073601441846 -19,10,10,0.0315388218157168 -20,10,10,0.0310748541203663 -21,10,10,0.0293756219336316 -22,10,10,0.0265457766110336 -23,10,10,0.0229377402115863 -24,10,10,0.0190305919079321 -25,10,10,0.0152630199751452 -26,10,10,0.0119247563929799 -27,10,10,0.00914118581090187 -28,10,10,0.00691657215847653 -29,10,10,0.00518917660753771 -30,10,10,0.00387314905613275 -31,10,10,0.00288267238979665 -32,10,10,0.00214279119380714 -33,10,10,0.00159250430145677 -34,10,10,0.00118414566348196 -35,10,10,0.000881365280006842 -36,10,10,0.000656848497863685 -37,10,10,0.000490250713798134 -38,10,10,0.000366495935094473 -39,10,10,0.000274442585806388 -40,10,10,0.000205866217525191 -41,10,10,0.000154696566616916 -42,10,10,0.000116450949482184 -43,10,10,8.78158582231872e-05 -44,10,10,6.63389488510456e-05 -45,10,10,5.02026190480147e-05 -46,10,10,3.80576194231282e-05 -47,10,10,2.89007349980015e-05 -48,10,10,2.19847881495897e-05 -49,10,10,1.6752345702394e-05 -50,10,10,1.27868202641784e-05 -0,0.2,15,0.0170945622854247 -1,0.2,15,0.0193493413561785 -2,0.2,15,0.0218799512564967 -3,0.2,15,0.0247163455278644 -4,0.2,15,0.0278905986332678 -5,0.2,15,0.0314364847603758 -6,0.2,15,0.0353886613709243 -7,0.2,15,0.0397812347943163 -8,0.2,15,0.0446453801309851 -9,0.2,15,0.0500055485134373 -10,0.2,15,0.0558736279336232 -11,0.2,15,0.0622402629616186 -12,0.2,15,0.0690624752007766 -13,0.2,15,0.0762469583009703 -14,0.2,15,0.0836293084111391 -15,0.2,15,0.0909515171379497 -16,0.2,15,0.097843783827486 -17,0.2,15,0.10382187168753 -18,0.2,15,0.10831563772517 -19,0.2,15,0.110742748979961 -20,0.2,15,0.110627302225695 -21,0.2,15,0.107735337686594 -22,0.2,15,0.102172574119513 -23,0.2,15,0.094390392987937 -24,0.2,15,0.0850865791376358 -25,0.2,15,0.0750429710943614 -26,0.2,15,0.0649695431068838 -27,0.2,15,0.0554065492919205 -28,0.2,15,0.0466961549794152 -29,0.2,15,0.0390045286588277 -30,0.2,15,0.0323668764812207 -31,0.2,15,0.0267344275981433 -32,0.2,15,0.0220127574537679 -33,0.2,15,0.0180886949726462 -34,0.2,15,0.0148471194278549 -35,0.2,15,0.0121802658967505 -36,0.2,15,0.0099920715527046 -37,0.2,15,0.00819951852655703 -38,0.2,15,0.00673231299532132 -39,0.2,15,0.00553174678885157 -40,0.2,15,0.00454924180911541 -41,0.2,15,0.00374485360671993 -42,0.2,15,0.00308587364625747 -43,0.2,15,0.00254559027056437 -44,0.2,15,0.00210222452463604 -45,0.2,15,0.00173803445252378 -46,0.2,15,0.00143857118027496 -47,0.2,15,0.00119206655139224 -48,0.2,15,0.00098893205661382 -49,0.2,15,0.000821350451036704 -50,0.2,15,0.00068294375913977 -0,0.5,15,0.0170829940843968 -1,0.5,15,0.0193362473051681 -2,0.5,15,0.0218651446957676 -3,0.5,15,0.0246996195275745 -4,0.5,15,0.0278717245582027 -5,0.5,15,0.0314152111197147 -6,0.5,15,0.0353647132205118 -7,0.5,15,0.039754314109624 -8,0.5,15,0.0446151677907274 -9,0.5,15,0.049971708849803 -10,0.5,15,0.0558358172339805 -11,0.5,15,0.0621981438443256 -12,0.5,15,0.0690157393684534 -13,0.5,15,0.0761953605983402 -14,0.5,15,0.0835727149379999 -15,0.5,15,0.0908899685930686 -16,0.5,15,0.0977775711604546 -17,0.5,15,0.103751613539779 -18,0.5,15,0.108242338564259 -19,0.5,15,0.110667807348745 -20,0.5,15,0.110552438719396 -21,0.5,15,0.107662431225266 -22,0.5,15,0.102103432081406 -23,0.5,15,0.0943265172932594 -24,0.5,15,0.085028999502907 -25,0.5,15,0.0749921881517591 -26,0.5,15,0.0649255770361061 -27,0.5,15,0.0553690546728849 -28,0.5,15,0.0466645548425405 -29,0.5,15,0.0389781335852954 -30,0.5,15,0.0323449732275702 -31,0.5,15,0.0267163359250336 -32,0.5,15,0.0219978610206711 -33,0.5,15,0.0180764540239584 -34,0.5,15,0.0148370721122606 -35,0.5,15,0.0121720232894164 -36,0.5,15,0.0099853097362581 -37,0.5,15,0.00819396976332673 -38,0.5,15,0.00672775711674352 -39,0.5,15,0.00552800335524849 -40,0.5,15,0.0045461632544912 -41,0.5,15,0.00374231939621373 -42,0.5,15,0.00308378537946885 -43,0.5,15,0.00254386762335685 -44,0.5,15,0.00210080191108789 -45,0.5,15,0.00173685829301735 -46,0.5,15,0.00143759767300823 -47,0.5,15,0.00119125985828861 -48,0.5,15,0.000988262828315202 -49,0.5,15,0.000820794628256727 -50,0.5,15,0.000682481598684031 -0,0.8,15,0.0168306711676033 -1,0.8,15,0.0190506429025806 -2,0.8,15,0.0215421874285292 -3,0.8,15,0.0243347958899793 -4,0.8,15,0.0274600476120044 -5,0.8,15,0.0309511954054759 -6,0.8,15,0.0348423617201086 -7,0.8,15,0.0391671263811903 -8,0.8,15,0.0439561832348253 -9,0.8,15,0.0492336059580123 -10,0.8,15,0.0550110990261289 -11,0.8,15,0.0612794514303141 -12,0.8,15,0.067996348237363 -13,0.8,15,0.075069923480156 -14,0.8,15,0.0823383112325766 -15,0.8,15,0.0895474860124761 -16,0.8,15,0.096333355829682 -17,0.8,15,0.102219159122184 -18,0.8,15,0.106643554273159 -19,0.8,15,0.109033197876459 -20,0.8,15,0.108919533289675 -21,0.8,15,0.106072212406386 -22,0.8,15,0.100595321988402 -23,0.8,15,0.092933275461247 -24,0.8,15,0.0837730858696992 -25,0.8,15,0.0738845223902602 -26,0.8,15,0.063966599301213 -27,0.8,15,0.0545512307418962 -28,0.8,15,0.0459752999888207 -29,0.8,15,0.0384024103655356 -30,0.8,15,0.03186722454089 -31,0.8,15,0.0263217245487529 -32,0.8,15,0.0216729434781999 -33,0.8,15,0.017809457291297 -34,0.8,15,0.0146179223956744 -35,0.8,15,0.0119922374506758 -36,0.8,15,0.00983782256478856 -37,0.8,15,0.00807294142715887 -38,0.8,15,0.00662838535024944 -39,0.8,15,0.00544635245004129 -40,0.8,15,0.00447901453530736 -41,0.8,15,0.00368704378463415 -42,0.8,15,0.00303823658879033 -43,0.8,15,0.00250629364215129 -44,0.8,15,0.00206977219444735 -45,0.8,15,0.00171120417475296 -46,0.8,15,0.0014163637583773 -47,0.8,15,0.0011736644554794 -48,0.8,15,0.000973665775938606 -49,0.8,15,0.000808671150740611 -50,0.8,15,0.000672401062052862 -0,1,15,0.0161773463981676 -1,1,15,0.0183111443550783 -2,1,15,0.0207059733230587 -3,1,15,0.0233901796738007 -4,1,15,0.0263941169015678 -5,1,15,0.0297497470258672 -6,1,15,0.0334898679478338 -7,1,15,0.0376467560075056 -8,1,15,0.0422499135922666 -9,1,15,0.047322479898885 -10,1,15,0.0528757050641321 -11,1,15,0.0589007356275883 -12,1,15,0.0653568992164494 -13,1,15,0.0721558958718192 -14,1,15,0.0791421429000089 -15,1,15,0.0860714754559116 -16,1,15,0.0925939346943237 -17,1,15,0.0982512657505899 -18,1,15,0.102503916892481 -19,1,15,0.104800800478035 -20,1,15,0.104691548067642 -21,1,15,0.101954753095118 -22,1,15,0.0966904619332135 -23,1,15,0.0893258369842539 -24,1,15,0.0805212231563397 -25,1,15,0.07101650910221 -26,1,15,0.061483575105452 -27,1,15,0.0524336877222519 -28,1,15,0.0441906532587037 -29,1,15,0.0369117243644845 -30,1,15,0.0306302181899009 -31,1,15,0.0252999807067683 -32,1,15,0.0208316537482844 -33,1,15,0.0171181384803746 -34,1,15,0.0140504910268549 -35,1,15,0.0115267286370664 -36,1,15,0.00945594277551063 -37,1,15,0.00775956993150995 -38,1,15,0.00637108792654249 -39,1,15,0.00523493860187947 -40,1,15,0.00430515033765066 -41,1,15,0.00354392192059747 -42,1,15,0.00292029980545613 -43,1,15,0.00240900556019716 -44,1,15,0.0019894287887533 -45,1,15,0.00164477948724079 -46,1,15,0.00136138404208053 -47,1,15,0.00112810572213269 -48,1,15,0.000935870493609222 -49,1,15,0.00077728054915106 -50,1,15,0.000646300126180522 -0,5,15,0.00709417402200009 -1,5,15,0.00802989819217845 -2,5,15,0.00908009103800289 -3,5,15,0.0102571831577141 -4,5,15,0.0115744853233745 -5,5,15,0.0130460136858964 -6,5,15,0.0146861509513481 -7,5,15,0.0165090511081146 -8,5,15,0.0185276516964461 -9,5,15,0.0207520998371722 -10,5,15,0.0231873289987407 -11,5,15,0.0258294567156739 -12,5,15,0.0286606471276607 -13,5,15,0.0316421784777994 -14,5,15,0.0347058238346345 -15,5,15,0.0377445107612773 -16,5,15,0.0406047734860675 -17,5,15,0.0430856557040414 -18,5,15,0.0449505503853377 -19,5,15,0.0459577917130036 -20,5,15,0.0459098817781737 -21,5,15,0.0447097282227167 -22,5,15,0.0424012039019879 -23,5,15,0.0391716302927709 -24,5,15,0.0353105852762157 -25,5,15,0.0311425286697884 -26,5,15,0.0269620969074505 -27,5,15,0.0229934932566566 -28,5,15,0.0193787149416928 -29,5,15,0.0161867212117937 -30,5,15,0.0134321224768732 -31,5,15,0.0110946790326125 -32,5,15,0.00913520507127915 -33,5,15,0.00750673505552366 -34,5,15,0.00616149435054132 -35,5,15,0.00505476095047227 -36,5,15,0.00414666917184548 -37,5,15,0.00340276693563576 -38,5,15,0.00279388259037809 -39,5,15,0.00229565248355104 -40,5,15,0.00188791690147809 -41,5,15,0.00155409905965462 -42,5,15,0.00128062504853487 -43,5,15,0.0010564096387242 -44,5,15,0.000872414652219563 -45,5,15,0.000721277249254177 -46,5,15,0.000597001205734652 -47,5,15,0.000494702784439968 -48,5,15,0.000410402792912376 -49,5,15,0.000340857106219721 -50,5,15,0.00028341889038641 -0,10,15,0.00485738828410318 -1,10,15,0.00549807959041752 -2,10,15,0.00621714771724061 -3,10,15,0.00702310390803386 -4,10,15,0.00792506206218389 -5,10,15,0.00893261905270503 -6,10,15,0.0100556227333054 -7,10,15,0.0113037643544594 -8,10,15,0.0126859022633461 -9,10,15,0.0142089842040836 -10,10,15,0.0158763881276167 -11,10,15,0.0176854557058204 -12,10,15,0.019623974706708 -13,10,15,0.021665432303313 -14,10,15,0.023763113445161 -15,10,15,0.025843705524064 -16,10,15,0.0278021303675718 -17,10,15,0.0295007929860043 -18,10,15,0.0307776883015016 -19,10,15,0.0314673474794547 -20,10,15,0.0314345434975658 -21,10,15,0.0306127971178853 -22,10,15,0.0290321481298141 -23,10,15,0.0268208557420872 -24,10,15,0.0241771942291824 -25,10,15,0.0213233215634213 -26,10,15,0.0184609756156194 -27,10,15,0.0157436685946986 -28,10,15,0.0132686261468696 -29,10,15,0.0110830647413473 -30,10,15,0.00919698814089816 -31,10,15,0.00759653819905922 -32,10,15,0.00625488435278064 -33,10,15,0.00513986925010433 -34,10,15,0.00421878154920837 -35,10,15,0.00346100004646404 -36,10,15,0.00283922866720083 -37,10,15,0.00232987803730685 -38,10,15,0.00191297429687752 -39,10,15,0.0015718356278536 -40,10,15,0.00129265865344738 -41,10,15,0.00106409323217784 -42,10,15,0.000876845294151467 -43,10,15,0.000723324771346094 -44,10,15,0.000597343213942829 -45,10,15,0.000493859277944474 -46,10,15,0.000408767342517684 -47,10,15,0.000338723507740291 -48,10,15,0.000281003216424309 -49,10,15,0.000233385212876156 -50,10,15,0.000194057207137462 -0,0.2,20,0.0180793195882987 -1,0.2,20,0.0204374745261926 -2,0.2,20,0.0230726715615305 -3,0.2,20,0.0260103778528718 -4,0.2,20,0.0292760792682837 -5,0.2,20,0.0328942299113683 -6,0.2,20,0.0368867473786228 -7,0.2,20,0.0412709284777743 -8,0.2,20,0.046056654960248 -9,0.2,20,0.0512427770299827 -10,0.2,20,0.0568126226963098 -11,0.2,20,0.0627287081452579 -12,0.2,20,0.0689269448667375 -13,0.2,20,0.0753109707167211 -14,0.2,20,0.0817476611094763 -15,0.2,20,0.0880653279894889 -16,0.2,20,0.0940564216417985 -17,0.2,20,0.0994864561691878 -18,0.2,20,0.10411010610807 -19,0.2,20,0.107693839114021 -20,0.2,20,0.110042292510351 -21,0.2,20,0.111023581204473 -22,0.2,20,0.110587839389611 -23,0.2,20,0.1087743022324 -24,0.2,20,0.10570505297568 -25,0.2,20,0.1015671507288 -26,0.2,20,0.0965877262956307 -27,0.2,20,0.0910077171758772 -28,0.2,20,0.0850591003252528 -29,0.2,20,0.0789485021803124 -30,0.2,20,0.0728479138507175 -31,0.2,20,0.0668916373821453 -32,0.2,20,0.0611777865511167 -33,0.2,20,0.055772544660263 -34,0.2,20,0.0507156705035933 -35,0.2,20,0.046026185115372 -36,0.2,20,0.0417075976165607 -37,0.2,20,0.0377523606629536 -38,0.2,20,0.0341454691884831 -39,0.2,20,0.0308672463206464 -40,0.2,20,0.0278954234243928 -41,0.2,20,0.0252066416179739 -42,0.2,20,0.022777498478599 -43,0.2,20,0.020585248573281 -44,0.2,20,0.0186082475100465 -45,0.2,20,0.0168262105312757 -46,0.2,20,0.0152203401871912 -47,0.2,20,0.0137733639799342 -48,0.2,20,0.0124695120332158 -49,0.2,20,0.0112944564907163 -50,0.2,20,0.0102352280499463 -0,0.5,20,0.0180670849841039 -1,0.5,20,0.0204236441156869 -2,0.5,20,0.0230570578652907 -3,0.5,20,0.0259927761573858 -4,0.5,20,0.029256267613289 -5,0.5,20,0.0328719697880659 -6,0.5,20,0.036861785446178 -7,0.5,20,0.041242999690288 -8,0.5,20,0.0460254875846605 -9,0.5,20,0.0512081001113219 -10,0.5,20,0.0567741765618431 -11,0.5,20,0.0626862584882307 -12,0.5,20,0.0688803007502549 -13,0.5,20,0.0752600064139028 -14,0.5,20,0.081692340981269 -15,0.5,20,0.088005732581267 -16,0.5,20,0.0939927719516014 -17,0.5,20,0.0994191318759239 -18,0.5,20,0.104039652906848 -19,0.5,20,0.107620960735532 -20,0.5,20,0.109967824890761 -21,0.5,20,0.110948449528987 -22,0.5,20,0.110513002588531 -23,0.5,20,0.108700692684879 -24,0.5,20,0.105633520444922 -25,0.5,20,0.101498418391706 -26,0.5,20,0.0965223636255626 -27,0.5,20,0.0909461305994088 -28,0.5,20,0.0850015392859358 -29,0.5,20,0.078895076293833 -30,0.5,20,0.0727986163432516 -31,0.5,20,0.0668463705952335 -32,0.5,20,0.0611363864309234 -33,0.5,20,0.0557348023655088 -34,0.5,20,0.0506813502875002 -35,0.5,20,0.0459950383592823 -36,0.5,20,0.0416793733271308 -37,0.5,20,0.0377268129542649 -38,0.5,20,0.034122362328818 -39,0.5,20,0.0308463578939845 -40,0.5,20,0.0278765460843039 -41,0.5,20,0.0251895838254076 -42,0.5,20,0.0227620845313499 -43,0.5,20,0.0205713181613915 -44,0.5,20,0.0185956549707127 -45,0.5,20,0.0168148239287576 -46,0.5,20,0.0152100403063251 -47,0.5,20,0.0137640432941693 -48,0.5,20,0.0124610736877635 -49,0.5,20,0.0112868133267087 -50,0.5,20,0.0102283016850782 -0,0.8,20,0.0178002266360519 -1,0.8,20,0.0201219784106376 -2,0.8,20,0.0227164955455649 -3,0.8,20,0.0256088520593507 -4,0.8,20,0.0288241403911987 -5,0.8,20,0.0323864371433378 -6,0.8,20,0.0363173215673027 -7,0.8,20,0.0406338234576117 -8,0.8,20,0.0453456720197292 -9,0.8,20,0.0504517352071544 -10,0.8,20,0.0559355983970403 -11,0.8,20,0.0617603564182261 -12,0.8,20,0.0678629101037998 -13,0.8,20,0.0741483848654534 -14,0.8,20,0.0804857111800618 -15,0.8,20,0.0867058513643244 -16,0.8,20,0.0926044596768819 -17,0.8,20,0.0979506700116821 -18,0.8,20,0.102502944028185 -19,0.8,20,0.106031354453006 -20,0.8,20,0.108343554450065 -21,0.8,20,0.109309694855154 -22,0.8,20,0.10888067964684 -23,0.8,20,0.107095138313075 -24,0.8,20,0.104073269480826 -25,0.8,20,0.0999992446021474 -26,0.8,20,0.0950966882313386 -27,0.8,20,0.0896028184826599 -28,0.8,20,0.0837460312515363 -29,0.8,20,0.0777297632536978 -30,0.8,20,0.0717233505483033 -31,0.8,20,0.0658590219418115 -32,0.8,20,0.0602333766148308 -33,0.8,20,0.0549115761892136 -34,0.8,20,0.0499327656969774 -35,0.8,20,0.0453156725420547 -36,0.8,20,0.0410637516746226 -37,0.8,20,0.0371695722598696 -38,0.8,20,0.0336183608670043 -39,0.8,20,0.0303907443781212 -40,0.8,20,0.0274647979221628 -41,0.8,20,0.0248175232116628 -42,0.8,20,0.0224258790902618 -43,0.8,20,0.0202674712493617 -44,0.8,20,0.0183209894244558 -45,0.8,20,0.0165664619965278 -46,0.8,20,0.0149853816946275 -47,0.8,20,0.01356074265883 -48,0.8,20,0.0122770184546035 -49,0.8,20,0.0111201024067243 -50,0.8,20,0.0100772254216157 -0,1,20,0.0171092661361945 -1,1,20,0.0193408932848688 -2,1,20,0.0218346977214079 -3,1,20,0.0246147801533299 -4,1,20,0.0277052589937942 -5,1,20,0.031129276251249 -6,1,20,0.0349075735243873 -7,1,20,0.0390565195534847 -8,1,20,0.0435854658804622 -9,1,20,0.0484933244020467 -10,1,20,0.0537643176702003 -11,1,20,0.0593629730806635 -12,1,20,0.0652286408191531 -13,1,20,0.071270129092772 -14,1,20,0.0773614561710992 -15,1,20,0.0833401459930278 -16,1,20,0.0890097850103375 -17,1,20,0.094148468764673 -18,1,20,0.0985240348327752 -19,1,20,0.101915481145808 -20,1,20,0.104137927293188 -21,1,20,0.105066564532116 -22,1,20,0.104654202626529 -23,1,20,0.102937971563791 -24,1,20,0.100033404159301 -25,1,20,0.0961175227876778 -26,1,20,0.0914052714545416 -27,1,20,0.0861246600573049 -28,1,20,0.080495218731125 -29,1,20,0.0747124872847056 -30,1,20,0.0689392285728038 -31,1,20,0.0633025386086798 -32,1,20,0.0578952668331503 -33,1,20,0.0527800454560705 -34,1,20,0.0479944999967324 -35,1,20,0.0435566309078535 -36,1,20,0.0394697590270429 -37,1,20,0.0357267419660042 -38,1,20,0.0323133797617635 -39,1,20,0.0292110513126399 -40,1,20,0.0263986828165076 -41,1,20,0.0238541687221855 -42,1,20,0.0215553622736632 -43,1,20,0.0194807384536712 -44,1,20,0.0176098142091377 -45,1,20,0.0159233931695946 -46,1,20,0.0144036864702924 -47,1,20,0.013034348376467 -48,1,20,0.0118004551511357 -49,1,20,0.0106884477051008 -50,1,20,0.00968605260922058 -0,5,20,0.00750284430904103 -1,5,20,0.00848146904484496 -2,5,20,0.00957506512755281 -3,5,20,0.0107942013246855 -4,5,20,0.0121494541681337 -5,5,20,0.0136509720117194 -6,5,20,0.015307850569103 -7,5,20,0.0171272679453445 -8,5,20,0.0191133250272103 -9,5,20,0.0212655446539978 -10,5,20,0.0235770080171924 -11,5,20,0.0260321594860104 -12,5,20,0.0286044025886734 -13,5,20,0.0312537474262038 -14,5,20,0.0339249478354049 -15,5,20,0.036546753969514 -16,5,20,0.0390330335385335 -17,5,20,0.0412864758460686 -18,5,20,0.0432052718196401 -19,5,20,0.044692506483395 -20,5,20,0.0456671051187944 -21,5,20,0.0460743359472701 -22,5,20,0.0458935048612395 -23,5,20,0.0451408942957388 -24,5,20,0.0438671683014424 -25,5,20,0.0421499556501172 -26,5,20,0.0400835147042488 -27,5,20,0.0377678335490998 -28,5,20,0.0352991816805162 -29,5,20,0.0327633082317015 -30,5,20,0.0302315888156607 -31,5,20,0.0277597582366921 -32,5,20,0.0253885333141547 -33,5,20,0.0231453798502362 -34,5,20,0.0210467975832099 -35,5,20,0.0191006801651562 -36,5,20,0.0173084838670431 -37,5,20,0.0156670765716333 -38,5,20,0.0141702312373611 -39,5,20,0.012809782041937 -40,5,20,0.0115764875921246 -41,5,20,0.0104606540467294 -42,5,20,0.00945256949520125 -43,5,20,0.00854279467509373 -44,5,20,0.00772234725151608 -45,5,20,0.00698280913232021 -46,5,20,0.00631637945208103 -47,5,20,0.00571589019423515 -48,5,20,0.00517479692407691 -49,5,20,0.00468715363933985 -50,5,20,0.00424757813208737 -0,10,20,0.00513720525196691 -1,10,20,0.00580727061989926 -2,10,20,0.00655605698787006 -3,10,20,0.00739080080192281 -4,10,20,0.00831874382437305 -5,10,20,0.00934683464357021 -6,10,20,0.0104813011040572 -7,10,20,0.0117270580617865 -8,10,20,0.013086913398165 -9,10,20,0.0145605404007667 -10,10,20,0.0161432017542515 -11,10,20,0.0178242465021463 -12,10,20,0.0195854640127393 -13,10,20,0.0213994731608742 -14,10,20,0.023228446841518 -15,10,20,0.0250236002109614 -16,10,20,0.0267259584012326 -17,10,20,0.0282688926779473 -18,10,20,0.0295826942639681 -19,10,20,0.0306010053751745 -20,10,20,0.0312683140679992 -21,10,20,0.0315471454370958 -22,10,20,0.0314233302056167 -23,10,20,0.0309080169736579 -24,10,20,0.0300358954690731 -25,10,20,0.0288601181921141 -26,10,20,0.0274452239409828 -27,10,20,0.0258596746609882 -28,10,20,0.0241693861754223 -29,10,20,0.0224330710044043 -30,10,20,0.0206996001039193 -31,10,20,0.0190071351520679 -32,10,20,0.0173835549971425 -33,10,20,0.0158476655022847 -34,10,20,0.0144107640553413 -35,10,20,0.0130782554480492 -36,10,20,0.0118511367906451 -37,10,20,0.0107272635192199 -38,10,20,0.0097023719719784 -39,10,20,0.00877087100196024 -40,10,20,0.00792643301766627 -41,10,20,0.0071624206360129 -42,10,20,0.00647218410180988 -43,10,20,0.00584926034230554 -44,10,20,0.00528749914351764 -45,10,20,0.004781136629053 -46,10,20,0.0043248315382935 -47,10,20,0.00391367592289065 -48,10,20,0.00354318880163834 -49,10,20,0.00320929894064003 -50,10,20,0.00290832113655948 -0,0.2,25,0.0127925805005904 -1,0.2,25,0.0143664079233124 -2,0.2,25,0.0161018645758265 -3,0.2,25,0.018009080650141 -4,0.2,25,0.0200973822913566 -5,0.2,25,0.0223748983986475 -6,0.2,25,0.0248481165148272 -7,0.2,25,0.0275213970805524 -8,0.2,25,0.0303964613598564 -9,0.2,25,0.0334718750766375 -10,0.2,25,0.0367425566819869 -11,0.2,25,0.0401993453805463 -12,0.2,25,0.0438286685296017 -13,0.2,25,0.0476123496072689 -14,0.2,25,0.0515275954972371 -15,0.2,25,0.0555471945268581 -16,0.2,25,0.0596399442653214 -17,0.2,25,0.0637713110890748 -18,0.2,25,0.0679043034234193 -19,0.2,25,0.0720005196842712 -20,0.2,25,0.0760213131193364 -21,0.2,25,0.0799290018661388 -22,0.2,25,0.083688045935608 -23,0.2,25,0.0872661147459629 -24,0.2,25,0.090634979135192 -25,0.2,25,0.0937711789482726 -26,0.2,25,0.0966564387403026 -27,0.2,25,0.0992778267575567 -28,0.2,25,0.101627673161807 -29,0.2,25,0.103703280095681 -30,0.2,25,0.105506467258237 -31,0.2,25,0.107043001816614 -32,0.2,25,0.108321961258184 -33,0.2,25,0.109355073332416 -34,0.2,25,0.110156069969142 -35,0.2,25,0.110740083410064 -36,0.2,25,0.11112310396252 -37,0.2,25,0.111321510669088 -38,0.2,25,0.111351679333482 -39,0.2,25,0.111229666998568 -40,0.2,25,0.110970968148306 -41,0.2,25,0.11059033545799 -42,0.2,25,0.110101656616918 -43,0.2,25,0.109517878335371 -44,0.2,25,0.108850968873321 -45,0.2,25,0.108111911072167 -46,0.2,25,0.107310718755317 -47,0.2,25,0.106456470353574 -48,0.2,25,0.105557354611084 -49,0.2,25,0.104620724174384 -50,0.2,25,0.103653153723559 -0,0.5,25,0.0127839235288337 -1,0.5,25,0.0143566859139312 -2,0.5,25,0.016090968151383 -3,0.5,25,0.0179968935779123 -4,0.5,25,0.0200837820274481 -5,0.5,25,0.0223597568981906 -6,0.5,25,0.0248313013427152 -7,0.5,25,0.0275027728508891 -8,0.5,25,0.030375891521935 -9,0.5,25,0.0334492240503518 -10,0.5,25,0.0367176923260074 -11,0.5,25,0.0401721417528202 -12,0.5,25,0.0437990088729301 -13,0.5,25,0.0475801294648357 -14,0.5,25,0.0514927258367424 -15,0.5,25,0.0555096047306355 -16,0.5,25,0.0595995848309565 -17,0.5,25,0.063728155883684 -18,0.5,25,0.06785835134699 -19,0.5,25,0.0719517956238409 -20,0.5,25,0.0759698681149023 -21,0.5,25,0.0798749124576993 -22,0.5,25,0.0836314127137182 -23,0.5,25,0.0872070601798703 -24,0.5,25,0.0905736447973311 -25,0.5,25,0.0937077222869912 -26,0.5,25,0.0965910295712743 -27,0.5,25,0.0992106436476078 -28,0.5,25,0.101558899868083 -29,0.5,25,0.103633102201016 -30,0.5,25,0.105435069114043 -31,0.5,25,0.106970563871555 -32,0.5,25,0.108248657818023 -33,0.5,25,0.109281070766535 -34,0.5,25,0.110081525354277 -35,0.5,25,0.110665143582688 -36,0.5,25,0.111047904938174 -37,0.5,25,0.111246177379317 -38,0.5,25,0.111276325628028 -39,0.5,25,0.111154395861079 -40,0.5,25,0.110895872077031 -41,0.5,25,0.110515496967775 -42,0.5,25,0.110027148824557 -43,0.5,25,0.109443765596385 -44,0.5,25,0.108777307444091 -45,0.5,25,0.108038749776785 -46,0.5,25,0.107238099641339 -47,0.5,25,0.106384429325017 -48,0.5,25,0.105485922030493 -49,0.5,25,0.104549925428635 -50,0.5,25,0.103583009750321 -0,0.8,25,0.0125950996694491 -1,0.8,25,0.0141446317009874 -2,0.8,25,0.0158532978695853 -3,0.8,25,0.0177310719860786 -4,0.8,25,0.0197871362265789 -5,0.8,25,0.0220294940033216 -6,0.8,25,0.024464532710026 -7,0.8,25,0.0270965454746248 -8,0.8,25,0.0299272269897605 -9,0.8,25,0.0329551651204497 -10,0.8,25,0.0361753567623556 -11,0.8,25,0.0395787825365824 -12,0.8,25,0.0431520793231755 -13,0.8,25,0.0468773511937279 -14,0.8,25,0.050732156892412 -15,0.8,25,0.0546897048169267 -16,0.8,25,0.0587192742126931 -17,0.8,25,0.062786864556473 -18,0.8,25,0.0668560553176127 -19,0.8,25,0.0708890377225831 -20,0.8,25,0.0748477616143402 -21,0.8,25,0.0786951268305207 -22,0.8,25,0.0823961420177718 -23,0.8,25,0.0859189756859662 -24,0.8,25,0.0892358344505635 -25,0.8,25,0.0923236203141924 -26,0.8,25,0.0951643399525167 -27,0.8,25,0.0977452612410785 -28,0.8,25,0.100058832742002 -29,0.8,25,0.10210239824511 -30,0.8,25,0.103877749358516 -31,0.8,25,0.105390564220805 -32,0.8,25,0.106649780188921 -33,0.8,25,0.107666943969447 -34,0.8,25,0.108455575510518 -35,0.8,25,0.109030573455332 -36,0.8,25,0.109407681266646 -37,0.8,25,0.109603025141496 -38,0.8,25,0.109632728088053 -39,0.8,25,0.109512599274396 -40,0.8,25,0.109257893993997 -41,0.8,25,0.108883137183067 -42,0.8,25,0.108402002144723 -43,0.8,25,0.107827235729097 -44,0.8,25,0.107170621440477 -45,0.8,25,0.106442972576622 -46,0.8,25,0.105654148376168 -47,0.8,25,0.104813087124928 -48,0.8,25,0.103927851156272 -49,0.8,25,0.103005679612922 -50,0.8,25,0.102053045680714 -0,1,25,0.0121061892448071 -1,1,25,0.0135955722990909 -2,1,25,0.0152379122992594 -3,1,25,0.0170427958976329 -4,1,25,0.0190190488410974 -5,1,25,0.0211743638693427 -6,1,25,0.02351488043336 -7,1,25,0.0260447250125394 -8,1,25,0.0287655265157727 -9,1,25,0.0316759276236421 -10,1,25,0.0347711194398704 -11,1,25,0.0380424326954047 -12,1,25,0.041477022993351 -13,1,25,0.045057689080707 -14,1,25,0.0487628608153481 -15,1,25,0.0525667865783002 -16,1,25,0.0564399381182249 -17,1,25,0.0603496347275812 -18,1,25,0.0642608696300782 -19,1,25,0.0681373016946832 -20,1,25,0.071942357776756 -21,1,25,0.0756403778499078 -22,1,25,0.0791977288380422 -23,1,25,0.0825838148702621 -24,1,25,0.0857719214320475 -25,1,25,0.0887398471328027 -26,1,25,0.0914702971042636 -27,1,25,0.0939510334513581 -28,1,25,0.0961747978642359 -29,1,25,0.0981390372401889 -30,1,25,0.0998454736415624 -31,1,25,0.101299564795731 -32,1,25,0.102509901133686 -33,1,25,0.103487581147596 -34,1,25,0.104245599974853 -35,1,25,0.104798277930406 -36,1,25,0.105160747354966 -37,1,25,0.105348508466732 -38,1,25,0.105377058418823 -39,1,25,0.105261592706757 -40,1,25,0.105016774451476 -41,1,25,0.104656564767316 -42,1,25,0.104194106193794 -43,1,25,0.103641650780042 -44,1,25,0.103010524624037 -45,1,25,0.102311121278229 -46,1,25,0.101552917270147 -47,1,25,0.10074450392359 -48,1,25,0.0998936306122144 -49,1,25,0.0990072554732343 -50,1,25,0.0980916004195226 -0,5,25,0.00530886902784351 -1,5,25,0.00596200102566634 -2,5,25,0.00668220849837069 -3,5,25,0.00747369543455732 -4,5,25,0.00834033214662123 -5,5,25,0.00928549209475316 -6,5,25,0.0103118675829107 -7,5,25,0.0114212681762827 -8,5,25,0.0126144081924625 -9,5,25,0.0138906924126846 -10,5,25,0.0152480120147599 -11,5,25,0.0166825653057659 -12,5,25,0.0181887196940198 -13,5,25,0.019758931996654 -14,5,25,0.0213837431628362 -15,5,25,0.0230518604587735 -16,5,25,0.0247503350022199 -17,5,25,0.0264648354794515 -18,5,25,0.028180010536986 -19,5,25,0.0298799236731654 -20,5,25,0.0315485366425182 -21,5,25,0.0331702116249343 -22,5,25,0.0347301996690809 -23,5,25,0.0362150837146344 -24,5,25,0.0376131487738426 -25,5,25,0.0389146589775129 -26,5,25,0.0401120300901265 -27,5,25,0.0411998954863316 -28,5,25,0.0421750722143686 -29,5,25,0.0430364406743685 -30,5,25,0.0437847560340613 -31,5,25,0.0444224116444211 -32,5,25,0.0449531746258934 -33,5,25,0.0453819119469469 -34,5,25,0.0457143223027716 -35,5,25,0.0459566855123065 -36,5,25,0.0461156374882483 -37,5,25,0.0461979754668419 -38,5,25,0.0462104953402173 -39,5,25,0.0461598607160452 -40,5,25,0.0460525017423312 -41,5,25,0.0458945407194939 -42,5,25,0.0456917409822702 -43,5,25,0.0454494753629225 -44,5,25,0.045172710640802 -45,5,25,0.0448660046505482 -46,5,25,0.0445335130882655 -47,5,25,0.0441790034659191 -48,5,25,0.0438058740791207 -49,5,25,0.0434171762463654 -50,5,25,0.0430156384332238 -0,10,25,0.00363498810963971 -1,10,25,0.00408218826350669 -2,10,25,0.00457531506434197 -3,10,25,0.00511724698748498 -4,10,25,0.00571063403983221 -5,10,25,0.00635778603306246 -6,10,25,0.00706054639047774 -7,10,25,0.00782015412323297 -8,10,25,0.0086370983253224 -9,10,25,0.00951097144984222 -10,10,25,0.0104403295840602 -11,10,25,0.0114225697049038 -12,10,25,0.0124538351710267 -13,10,25,0.0135289611573243 -14,10,25,0.0146414710419167 -15,10,25,0.0157836326783057 -16,10,25,0.0169465799534358 -17,10,25,0.0181205002019901 -18,10,25,0.019294882336375 -19,10,25,0.0204588146174361 -20,10,25,0.0216013156419249 -21,10,25,0.0227116781782516 -22,10,25,0.0237798036041969 -23,10,25,0.0247965052446917 -24,10,25,0.0257537618355157 -25,10,25,0.0266449072169715 -26,10,25,0.0274647484551616 -27,10,25,0.0282096110161618 -28,10,25,0.0288773155296129 -29,10,25,0.0294670954043276 -30,10,25,0.029979467704431 -31,10,25,0.0304160711598085 -32,10,25,0.0307794851217221 -33,10,25,0.0310730420085118 -34,10,25,0.0313006437226634 -35,10,25,0.0314665900626942 -36,10,25,0.0315754246448853 -37,10,25,0.0316318015439178 -38,10,25,0.0316403739141562 -39,10,25,0.0316057043346588 -40,10,25,0.0315321955344103 -41,10,25,0.031424039458834 -42,10,25,0.0312851822691803 -43,10,25,0.0311193027492515 -44,10,25,0.0309298016580022 -45,10,25,0.0307197997495202 -46,10,25,0.0304921424332229 -47,10,25,0.0302494093284461 -48,10,25,0.0299939272517069 -49,10,25,0.0297277854439324 -50,10,25,0.0294528520883184 -0,0.2,30,-0.0208874524761045 -1,0.2,30,-0.0212868152392032 -2,0.2,30,-0.0216880194780002 -3,0.2,30,-0.0220909634527265 -4,0.2,30,-0.0224955461692694 -5,0.2,30,-0.0229016674866775 -6,0.2,30,-0.0233092282198144 -7,0.2,30,-0.0237181302370645 -8,0.2,30,-0.024128276553014 -9,0.2,30,-0.024539571416051 -10,0.2,30,-0.0249519203908483 -11,0.2,30,-0.0253652304357143 -12,0.2,30,-0.0257794099748105 -13,0.2,30,-0.0261943689652586 -14,0.2,30,-0.0266100189591685 -15,0.2,30,-0.027026273160642 -16,0.2,30,-0.0274430464778148 -17,0.2,30,-0.0278602555700164 -18,0.2,30,-0.0282778188901401 -19,0.2,30,-0.028695656722323 -20,0.2,30,-0.0291136912150502 -21,0.2,30,-0.0295318464098046 -22,0.2,30,-0.0299500482653908 -23,0.2,30,-0.0303682246780716 -24,0.2,30,-0.0307863054976591 -25,0.2,30,-0.031204222539709 -26,0.2,30,-0.0316219095939703 -27,0.2,30,-0.0320393024292476 -28,0.2,30,-0.0324563387948326 -29,0.2,30,-0.0328729584186677 -30,0.2,30,-0.0332891030024021 -31,0.2,30,-0.0337047162135015 -32,0.2,30,-0.034119743674576 -33,0.2,30,-0.0345341329500841 -34,0.2,30,-0.0349478335305746 -35,0.2,30,-0.0353607968146231 -36,0.2,30,-0.0357729760886187 -37,0.2,30,-0.0361843265045531 -38,0.2,30,-0.0365948050559628 -39,0.2,30,-0.0370043705521675 -40,0.2,30,-0.0374129835909507 -41,0.2,30,-0.0378206065298163 -42,0.2,30,-0.0382272034559585 -43,0.2,30,-0.0386327401550721 -44,0.2,30,-0.0390371840791282 -45,0.2,30,-0.0394405043132367 -46,0.2,30,-0.0398426715417078 -47,0.2,30,-0.0402436580134261 -48,0.2,30,-0.0406434375066399 -49,0.2,30,-0.0410419852932668 -50,0.2,30,-0.0414392781028119 -0,0.5,30,-0.0208733175573408 -1,0.5,30,-0.0212724100643985 -2,0.5,30,-0.0216733428009944 -3,0.5,30,-0.0220760140962086 -4,0.5,30,-0.0224803230242731 -5,0.5,30,-0.0228861695120036 -6,0.5,30,-0.0232934544413841 -7,0.5,30,-0.0237020797472065 -8,0.5,30,-0.0241119485096888 -9,0.5,30,-0.0245229650420158 -10,0.5,30,-0.0249350349727665 -11,0.5,30,-0.0253480653232123 -12,0.5,30,-0.0257619645794859 -13,0.5,30,-0.0261766427596424 -14,0.5,30,-0.0265920114756461 -15,0.5,30,-0.0270079839903352 -16,0.5,30,-0.0274244752694285 -17,0.5,30,-0.0278414020286538 -18,0.5,30,-0.0282586827760887 -19,0.5,30,-0.0286762378498154 -20,0.5,30,-0.0290939894510028 -21,0.5,30,-0.0295118616725361 -22,0.5,30,-0.0299297805233249 -23,0.5,30,-0.030347673948426 -24,0.5,30,-0.0307654718451234 -25,0.5,30,-0.0311831060751144 -26,0.5,30,-0.0316005104729538 -27,0.5,30,-0.0320176208509124 -28,0.5,30,-0.0324343750004083 -29,0.5,30,-0.0328507126901711 -30,0.5,30,-0.0332665756613013 -31,0.5,30,-0.0336819076193861 -32,0.5,30,-0.0340966542238338 -33,0.5,30,-0.0345107630745867 -34,0.5,30,-0.0349241836963745 -35,0.5,30,-0.0353368675206623 -36,0.5,30,-0.0357487678654509 -37,0.5,30,-0.0361598399130818 -38,0.5,30,-0.0365700406861943 -39,0.5,30,-0.0369793290219831 -40,0.5,30,-0.0373876655448956 -41,0.5,30,-0.037795012637909 -42,0.5,30,-0.0382013344125206 -43,0.5,30,-0.0386065966775783 -44,0.5,30,-0.0390107669070794 -45,0.5,30,-0.0394138142070543 -46,0.5,30,-0.0398157092816517 -47,0.5,30,-0.0402164243985359 -48,0.5,30,-0.0406159333536997 -49,0.5,30,-0.041014211435795 -50,0.5,30,-0.0414112353900743 -0,0.8,30,-0.0205650099888195 -1,0.8,30,-0.0209582077338142 -2,0.8,30,-0.0213532185273926 -3,0.8,30,-0.0217499422003566 -4,0.8,30,-0.0221482793176536 -5,0.8,30,-0.0225481312842217 -6,0.8,30,-0.0229494004460594 -7,0.8,30,-0.0233519901864223 -8,0.8,30,-0.0237558050170738 -9,0.8,30,-0.0241607506645328 -10,0.8,30,-0.0245667341512834 -11,0.8,30,-0.0249736638719313 -12,0.8,30,-0.025381449664307 -13,0.8,30,-0.0257900028755365 -14,0.8,30,-0.026199236423112 -15,0.8,30,-0.0266090648510155 -16,0.8,30,-0.0270194043809575 -17,0.8,30,-0.0274301729588091 -18,0.8,30,-0.0278412902963175 -19,0.8,30,-0.0282526779082044 -20,0.8,30,-0.0286642591447598 -21,0.8,30,-0.0290759592200485 -22,0.8,30,-0.0294877052358593 -23,0.8,30,-0.0298994262015303 -24,0.8,30,-0.0303110530497919 -25,0.8,30,-0.0307225186487722 -26,0.8,30,-0.0311337578103172 -27,0.8,30,-0.0315447072947772 -28,0.8,30,-0.0319553058124168 -29,0.8,30,-0.0323654940216065 -30,0.8,30,-0.032775214523955 -31,0.8,30,-0.0331844118565413 -32,0.8,30,-0.0335930324814067 -33,0.8,30,-0.0340010247724643 -34,0.8,30,-0.0344083389999845 -35,0.8,30,-0.0348149273128095 -36,0.8,30,-0.0352207437184531 -37,0.8,30,-0.0356257440612319 -38,0.8,30,-0.0360298859985788 -39,0.8,30,-0.0364331289756801 -40,0.8,30,-0.0368354341985766 -41,0.8,30,-0.0372367646058646 -42,0.8,30,-0.0376370848391291 -43,0.8,30,-0.0380363612122361 -44,0.8,30,-0.0384345616796051 -45,0.8,30,-0.0388316558035832 -46,0.8,30,-0.0392276147210312 -47,0.8,30,-0.0396224111092314 -48,0.8,30,-0.0400160191512208 -49,0.8,30,-0.040408414500648 -50,0.8,30,-0.0407995742462478 -0,1,30,-0.0197667274797268 -1,1,30,-0.0201446622667839 -2,1,30,-0.0205243397243908 -3,1,30,-0.0209056635716682 -4,1,30,-0.0212885382333849 -5,1,30,-0.0216728689416939 -6,1,30,-0.022058561833279 -7,1,30,-0.0224455240418173 -8,1,30,-0.0228336637856881 -9,1,30,-0.0232228904508721 -10,1,30,-0.0236131146690092 -11,1,30,-0.0240042483905985 -12,1,30,-0.0243962049533416 -13,1,30,-0.0247888991456484 -14,1,30,-0.0251822472653373 -15,1,30,-0.0255761671735804 -16,1,30,-0.0259705783441528 -17,1,30,-0.0263654019080626 -18,1,30,-0.0267605606936473 -19,1,30,-0.0271559792622318 -20,1,30,-0.027551583939457 -21,1,30,-0.0279473028423916 -22,1,30,-0.0283430659025515 -23,1,30,-0.0287388048849558 -24,1,30,-0.0291344534033542 -25,1,30,-0.0295299469317672 -26,1,30,-0.0299252228124826 -27,1,30,-0.0303202202606565 -28,1,30,-0.0307148803656686 -29,1,30,-0.0311091460893837 -30,1,30,-0.0315029622614732 -31,1,30,-0.0318962755719487 -32,1,30,-0.0322890345610618 -33,1,30,-0.0326811896067219 -34,1,30,-0.0330726929095835 -35,1,30,-0.0334634984759521 -36,1,30,-0.0338535620986549 -37,1,30,-0.0342428413360224 -38,1,30,-0.0346312954891208 -39,1,30,-0.0350188855773731 -40,1,30,-0.035405574312705 -41,1,30,-0.0357913260723444 -42,1,30,-0.0361761068704021 -43,1,30,-0.0365598843283556 -44,1,30,-0.0369426276445544 -45,1,30,-0.0373243075628595 -46,1,30,-0.0377048963405269 -47,1,30,-0.0380843677154388 -48,1,30,-0.0384626968727824 -49,1,30,-0.0388398604112711 -50,1,30,-0.0392158363089981 -0,5,30,-0.00866820806918722 -1,5,30,-0.00883394199627025 -2,5,30,-0.00900044012830005 -3,5,30,-0.00916766024368503 -4,5,30,-0.00933556043027807 -5,5,30,-0.00950409912999041 -6,5,30,-0.00967323518139266 -7,5,30,-0.00984292786026239 -8,5,30,-0.0100131369180462 -9,5,30,-0.0101838226182133 -10,5,30,-0.0103549457704861 -11,5,30,-0.0105264677629398 -12,5,30,-0.0106983505919729 -13,5,30,-0.0108705568901559 -14,5,30,-0.0110430499519732 -15,5,30,-0.0112157937574792 -16,5,30,-0.011388752993895 -17,5,30,-0.0115618930751805 -18,5,30,-0.0117351801596171 -19,5,30,-0.011908581165445 -20,5,30,-0.0120820637846013 -21,5,30,-0.0122555964946094 -22,5,30,-0.0124291485686734 -23,5,30,-0.0126026900840348 -24,5,30,-0.0127761919286502 -25,5,30,-0.0129496258062517 -26,5,30,-0.0131229642398537 -27,5,30,-0.0132961805737704 -28,5,30,-0.0134692489742105 -29,5,30,-0.0136421444285145 -30,5,30,-0.0138148427431032 -31,5,30,-0.0139873205402034 -32,5,30,-0.0141595552534187 -33,5,30,-0.0143315251222121 -34,5,30,-0.0145032091853662 -35,5,30,-0.0146745872734869 -36,5,30,-0.0148456400006152 -37,5,30,-0.0150163487550095 -38,5,30,-0.0151866956891619 -39,5,30,-0.0153566637091071 -40,5,30,-0.015526236463085 -41,5,30,-0.0156953983296124 -42,5,30,-0.0158641344050205 -43,5,30,-0.0160324304905115 -44,5,30,-0.0162002730787854 -45,5,30,-0.0163676493402881 -46,5,30,-0.0165345471091273 -47,5,30,-0.0167009548687026 -48,5,30,-0.0168668617370933 -49,5,30,-0.0170322574522457 -50,5,30,-0.0171971323569986 -0,10,30,-0.00593513102284568 -1,10,30,-0.00604860921399168 -2,10,30,-0.00616261065705448 -3,10,30,-0.00627710644286667 -4,10,30,-0.00639206787413783 -5,10,30,-0.00650746649600161 -6,10,30,-0.0066232741251848 -7,10,30,-0.0067394628777702 -8,10,30,-0.00685600519553168 -9,10,30,-0.00697287387082563 -10,10,30,-0.00709004207002839 -11,10,30,-0.00720748335551516 -12,10,30,-0.00732517170618071 -13,10,30,-0.00744308153650754 -14,10,30,-0.00756118771419114 -15,10,30,-0.00767946557633741 -16,10,30,-0.00779789094425032 -17,10,30,-0.00791644013683241 -18,10,30,-0.00803508998262399 -19,10,30,-0.0081538178305099 -20,10,30,-0.00827260155912608 -21,10,30,-0.00839141958500024 -22,10,30,-0.00851025086946352 -23,10,30,-0.00862907492437225 -24,10,30,-0.00874787181668018 -25,10,30,-0.00886662217190342 -26,10,30,-0.00898530717652155 -27,10,30,-0.00910390857935905 -28,10,30,-0.00922240869199221 -29,10,30,-0.00934079038822726 -30,10,30,-0.00945903710269551 -31,10,30,-0.00957713282861146 -32,10,30,-0.00969506211474028 -33,10,30,-0.00981281006161968 -34,10,30,-0.0099303623170825 -35,10,30,-0.0100477050711238 -36,10,30,-0.0101648250501573 -37,10,30,-0.0102817095107044 -38,10,30,-0.0103983462325579 -39,10,30,-0.0105147235114623 -40,10,30,-0.0106308301513503 -41,10,30,-0.0107466554561764 -42,10,30,-0.010862189221383 -43,10,30,-0.0109774217250388 -44,10,30,-0.0110923437186813 -45,10,30,-0.0112069464179016 -46,10,30,-0.0113212214927008 -47,10,30,-0.0114351610576506 -48,10,30,-0.0115487576618887 -49,10,30,-0.0116620042789763 -50,10,30,-0.0117748942966451 +0,0.2,5,0.01503399 +1,0.2,5,0.01702058 +2,0.2,5,0.01925249 +3,0.2,5,0.02175782 +4,0.2,5,0.02456757 +5,0.2,5,0.02771585 +6,0.2,5,0.03124004 +7,0.2,5,0.03518084 +8,0.2,5,0.039582 +9,0.2,5,0.04448958 +10,0.2,5,0.04995003 +11,0.2,5,0.05600619 +12,0.2,5,0.06268924 +13,0.2,5,0.07000313 +14,0.2,5,0.07789553 +15,0.2,5,0.08620612 +16,0.2,5,0.09458092 +17,0.2,5,0.10234833 +18,0.2,5,0.10838703 +19,0.2,5,0.11110478 +20,0.2,5,0.10876504 +21,0.2,5,0.1003338 +22,0.2,5,0.0864634 +23,0.2,5,0.06959876 +24,0.2,5,0.05278511 +25,0.2,5,0.03823714 +26,0.2,5,0.02682941 +27,0.2,5,0.01844625 +28,0.2,5,0.01253152 +29,0.2,5,0.00845891 +30,0.2,5,0.00569343 +31,0.2,5,0.00382936 +32,0.2,5,0.00257716 +33,0.2,5,0.00173684 +34,0.2,5,0.00117269 +35,0.2,5,0.00079346 +36,0.2,5,0.00053809 +37,0.2,5,0.00036577 +38,0.2,5,0.00024923 +39,0.2,5,0.00017023 +40,0.2,5,0.00011655 +41,0.2,5,7.999e-05 +42,0.2,5,5.503e-05 +43,0.2,5,3.795e-05 +44,0.2,5,2.623e-05 +45,0.2,5,1.817e-05 +46,0.2,5,1.262e-05 +47,0.2,5,8.78e-06 +48,0.2,5,6.13e-06 +49,0.2,5,4.28e-06 +50,0.2,5,3e-06 +0,0.5,5,0.01502382 +1,0.5,5,0.01700906 +2,0.5,5,0.01923946 +3,0.5,5,0.0217431 +4,0.5,5,0.02455095 +5,0.5,5,0.0276971 +6,0.5,5,0.0312189 +7,0.5,5,0.03515703 +8,0.5,5,0.03955522 +9,0.5,5,0.04445948 +10,0.5,5,0.04991623 +11,0.5,5,0.05596828 +12,0.5,5,0.06264681 +13,0.5,5,0.06995576 +14,0.5,5,0.07784282 +15,0.5,5,0.08614779 +16,0.5,5,0.09451692 +17,0.5,5,0.10227907 +18,0.5,5,0.10831368 +19,0.5,5,0.11102959 +20,0.5,5,0.10869143 +21,0.5,5,0.1002659 +22,0.5,5,0.08640489 +23,0.5,5,0.06955166 +24,0.5,5,0.05274939 +25,0.5,5,0.03821127 +26,0.5,5,0.02681125 +27,0.5,5,0.01843377 +28,0.5,5,0.01252303 +29,0.5,5,0.00845318 +30,0.5,5,0.00568957 +31,0.5,5,0.00382676 +32,0.5,5,0.00257541 +33,0.5,5,0.00173566 +34,0.5,5,0.0011719 +35,0.5,5,0.00079293 +36,0.5,5,0.00053773 +37,0.5,5,0.00036552 +38,0.5,5,0.00024906 +39,0.5,5,0.00017012 +40,0.5,5,0.00011647 +41,0.5,5,7.994e-05 +42,0.5,5,5.499e-05 +43,0.5,5,3.792e-05 +44,0.5,5,2.621e-05 +45,0.5,5,1.816e-05 +46,0.5,5,1.261e-05 +47,0.5,5,8.78e-06 +48,0.5,5,6.12e-06 +49,0.5,5,4.28e-06 +50,0.5,5,3e-06 +0,0.8,5,0.01480191 +1,0.8,5,0.01675783 +2,0.8,5,0.01895528 +3,0.8,5,0.02142194 +4,0.8,5,0.02418832 +5,0.8,5,0.027288 +6,0.8,5,0.03075779 +7,0.8,5,0.03463775 +8,0.8,5,0.03897097 +9,0.8,5,0.04380279 +10,0.8,5,0.04917894 +11,0.8,5,0.05514161 +12,0.8,5,0.06172149 +13,0.8,5,0.06892248 +14,0.8,5,0.07669305 +15,0.8,5,0.08487535 +16,0.8,5,0.09312086 +17,0.8,5,0.10076837 +18,0.8,5,0.10671385 +19,0.8,5,0.10938964 +20,0.8,5,0.10708601 +21,0.8,5,0.09878493 +22,0.8,5,0.08512866 +23,0.8,5,0.06852435 +24,0.8,5,0.05197025 +25,0.8,5,0.03764687 +26,0.8,5,0.02641524 +27,0.8,5,0.01816149 +28,0.8,5,0.01233806 +29,0.8,5,0.00832833 +30,0.8,5,0.00560554 +31,0.8,5,0.00377024 +32,0.8,5,0.00253737 +33,0.8,5,0.00171003 +34,0.8,5,0.00115459 +35,0.8,5,0.00078121 +36,0.8,5,0.00052979 +37,0.8,5,0.00036012 +38,0.8,5,0.00024538 +39,0.8,5,0.0001676 +40,0.8,5,0.00011475 +41,0.8,5,7.876e-05 +42,0.8,5,5.418e-05 +43,0.8,5,3.736e-05 +44,0.8,5,2.583e-05 +45,0.8,5,1.789e-05 +46,0.8,5,1.242e-05 +47,0.8,5,8.65e-06 +48,0.8,5,6.03e-06 +49,0.8,5,4.22e-06 +50,0.8,5,2.96e-06 +0,1,5,0.01422734 +1,1,5,0.01610733 +2,1,5,0.01821949 +3,1,5,0.0205904 +4,1,5,0.02324939 +5,1,5,0.02622875 +6,1,5,0.02956385 +7,1,5,0.0332932 +8,1,5,0.03745821 +9,1,5,0.04210248 +10,1,5,0.04726994 +11,1,5,0.05300115 +12,1,5,0.05932562 +13,1,5,0.06624708 +14,1,5,0.07371602 +15,1,5,0.0815807 +16,1,5,0.08950614 +17,1,5,0.09685679 +18,1,5,0.10257148 +19,1,5,0.1051434 +20,1,5,0.1029292 +21,1,5,0.09495035 +22,1,5,0.08182417 +23,1,5,0.06586441 +24,1,5,0.0499529 +25,1,5,0.03618551 +26,1,5,0.02538986 +27,1,5,0.01745651 +28,1,5,0.01185913 +29,1,5,0.00800504 +30,1,5,0.00538794 +31,1,5,0.00362389 +32,1,5,0.00243888 +33,1,5,0.00164365 +34,1,5,0.00110977 +35,1,5,0.00075089 +36,1,5,0.00050922 +37,1,5,0.00034614 +38,1,5,0.00023586 +39,1,5,0.0001611 +40,1,5,0.0001103 +41,1,5,7.57e-05 +42,1,5,5.208e-05 +43,1,5,3.591e-05 +44,1,5,2.482e-05 +45,1,5,1.72e-05 +46,1,5,1.194e-05 +47,1,5,8.31e-06 +48,1,5,5.8e-06 +49,1,5,4.05e-06 +50,1,5,2.84e-06 +0,5,5,0.00623905 +1,5,5,0.00706347 +2,5,5,0.0079897 +3,5,5,0.00902941 +4,5,5,0.01019544 +5,5,5,0.01150197 +6,5,5,0.01296449 +7,5,5,0.01459991 +8,5,5,0.01642637 +9,5,5,0.018463 +10,5,5,0.02072906 +11,5,5,0.02324234 +12,5,5,0.02601578 +13,5,5,0.02905101 +14,5,5,0.03232633 +15,5,5,0.03577519 +16,5,5,0.0392507 +17,5,5,0.04247414 +18,5,5,0.04498018 +19,5,5,0.04610803 +20,5,5,0.04513705 +21,5,5,0.04163812 +22,5,5,0.03588196 +23,5,5,0.0288832 +24,5,5,0.0219056 +25,5,5,0.01586826 +26,5,5,0.0111341 +27,5,5,0.00765512 +28,5,5,0.00520053 +29,5,5,0.00351041 +30,5,5,0.00236275 +31,5,5,0.00158917 +32,5,5,0.00106951 +33,5,5,0.00072078 +34,5,5,0.00048666 +35,5,5,0.00032928 +36,5,5,0.00022331 +37,5,5,0.00015179 +38,5,5,0.00010343 +39,5,5,7.064e-05 +40,5,5,4.837e-05 +41,5,5,3.32e-05 +42,5,5,2.284e-05 +43,5,5,1.575e-05 +44,5,5,1.089e-05 +45,5,5,7.54e-06 +46,5,5,5.24e-06 +47,5,5,3.65e-06 +48,5,5,2.54e-06 +49,5,5,1.78e-06 +50,5,5,1.25e-06 +0,10,5,0.00427188 +1,10,5,0.00483637 +2,10,5,0.00547056 +3,10,5,0.00618244 +4,10,5,0.00698083 +5,10,5,0.00787541 +6,10,5,0.0088768 +7,10,5,0.00999657 +8,10,5,0.01124715 +9,10,5,0.01264163 +10,10,5,0.01419321 +11,10,5,0.01591405 +12,10,5,0.01781303 +13,10,5,0.01989126 +14,10,5,0.02213387 +15,10,5,0.02449531 +16,10,5,0.02687499 +17,10,5,0.02908209 +18,10,5,0.03079797 +19,10,5,0.03157022 +20,10,5,0.03090538 +21,10,5,0.02850966 +22,10,5,0.02456842 +23,10,5,0.01977636 +24,10,5,0.01499879 +25,10,5,0.01086501 +26,10,5,0.00762353 +27,10,5,0.00524147 +28,10,5,0.00356081 +29,10,5,0.00240358 +30,10,5,0.00161778 +31,10,5,0.0010881 +32,10,5,0.00073229 +33,10,5,0.00049352 +34,10,5,0.00033322 +35,10,5,0.00022546 +36,10,5,0.0001529 +37,10,5,0.00010393 +38,10,5,7.082e-05 +39,10,5,4.837e-05 +40,10,5,3.312e-05 +41,10,5,2.273e-05 +42,10,5,1.564e-05 +43,10,5,1.078e-05 +44,10,5,7.45e-06 +45,10,5,5.16e-06 +46,10,5,3.59e-06 +47,10,5,2.5e-06 +48,10,5,1.74e-06 +49,10,5,1.22e-06 +50,10,5,8.5e-07 +0,0.2,10,0.01595082 +1,0.2,10,0.01805812 +2,0.2,10,0.0204253 +3,0.2,10,0.02308182 +4,0.2,10,0.02606 +5,0.2,10,0.02939501 +6,0.2,10,0.03312473 +7,0.2,10,0.03728932 +8,0.2,10,0.04193016 +9,0.2,10,0.04708767 +10,0.2,10,0.0527975 +11,0.2,10,0.05908352 +12,0.2,10,0.06594604 +13,0.2,10,0.07334217 +14,0.2,10,0.08115505 +15,0.2,10,0.08914878 +16,0.2,10,0.09691001 +17,0.2,10,0.10378947 +18,0.2,10,0.10888087 +19,0.2,10,0.11110539 +20,0.2,10,0.10947092 +21,0.2,10,0.10348484 +22,0.2,10,0.09351583 +23,0.2,10,0.08080539 +24,0.2,10,0.06704123 +25,0.2,10,0.05376878 +26,0.2,10,0.0420087 +27,0.2,10,0.03220269 +28,0.2,10,0.0243658 +29,0.2,10,0.0182805 +30,0.2,10,0.01364438 +31,0.2,10,0.01015512 +32,0.2,10,0.00754865 +33,0.2,10,0.0056101 +34,0.2,10,0.00417152 +35,0.2,10,0.00310489 +36,0.2,10,0.00231395 +37,0.2,10,0.00172706 +38,0.2,10,0.0012911 +39,0.2,10,0.00096681 +40,0.2,10,0.00072523 +41,0.2,10,0.00054497 +42,0.2,10,0.00041023 +43,0.2,10,0.00030936 +44,0.2,10,0.0002337 +45,0.2,10,0.00017685 +46,0.2,10,0.00013407 +47,0.2,10,0.00010181 +48,0.2,10,7.745e-05 +49,0.2,10,5.902e-05 +50,0.2,10,4.505e-05 +0,0.5,10,0.01594003 +1,0.5,10,0.0180459 +2,0.5,10,0.02041147 +3,0.5,10,0.0230662 +4,0.5,10,0.02604237 +5,0.5,10,0.02937511 +6,0.5,10,0.03310231 +7,0.5,10,0.03726409 +8,0.5,10,0.04190178 +9,0.5,10,0.04705581 +10,0.5,10,0.05276177 +11,0.5,10,0.05904354 +12,0.5,10,0.06590142 +13,0.5,10,0.07329254 +14,0.5,10,0.08110013 +15,0.5,10,0.08908845 +16,0.5,10,0.09684443 +17,0.5,10,0.10371923 +18,0.5,10,0.10880719 +19,0.5,10,0.11103021 +20,0.5,10,0.10939684 +21,0.5,10,0.10341481 +22,0.5,10,0.09345254 +23,0.5,10,0.0807507 +24,0.5,10,0.06699586 +25,0.5,10,0.05373239 +26,0.5,10,0.04198027 +27,0.5,10,0.0321809 +28,0.5,10,0.02434931 +29,0.5,10,0.01826813 +30,0.5,10,0.01363515 +31,0.5,10,0.01014825 +32,0.5,10,0.00754355 +33,0.5,10,0.0056063 +34,0.5,10,0.0041687 +35,0.5,10,0.00310278 +36,0.5,10,0.00231239 +37,0.5,10,0.00172589 +38,0.5,10,0.00129022 +39,0.5,10,0.00096616 +40,0.5,10,0.00072474 +41,0.5,10,0.0005446 +42,0.5,10,0.00040996 +43,0.5,10,0.00030915 +44,0.5,10,0.00023354 +45,0.5,10,0.00017673 +46,0.5,10,0.00013398 +47,0.5,10,0.00010174 +48,0.5,10,7.74e-05 +49,0.5,10,5.898e-05 +50,0.5,10,4.502e-05 +0,0.8,10,0.01570459 +1,0.8,10,0.01777935 +2,0.8,10,0.02010999 +3,0.8,10,0.02272551 +4,0.8,10,0.02565771 +5,0.8,10,0.02894123 +6,0.8,10,0.03261337 +7,0.8,10,0.03671368 +8,0.8,10,0.04128288 +9,0.8,10,0.04636077 +10,0.8,10,0.05198245 +11,0.8,10,0.05817144 +12,0.8,10,0.06492802 +13,0.8,10,0.07220998 +14,0.8,10,0.07990225 +15,0.8,10,0.08777258 +16,0.8,10,0.095414 +17,0.8,10,0.10218726 +18,0.8,10,0.10720006 +19,0.8,10,0.10939024 +20,0.8,10,0.107781 +21,0.8,10,0.10188733 +22,0.8,10,0.09207221 +23,0.8,10,0.07955798 +24,0.8,10,0.06600631 +25,0.8,10,0.05293874 +26,0.8,10,0.0413602 +27,0.8,10,0.03170558 +28,0.8,10,0.02398966 +29,0.8,10,0.0179983 +30,0.8,10,0.01343375 +31,0.8,10,0.00999835 +32,0.8,10,0.00743212 +33,0.8,10,0.00552349 +34,0.8,10,0.00410713 +35,0.8,10,0.00305696 +36,0.8,10,0.00227823 +37,0.8,10,0.0017004 +38,0.8,10,0.00127117 +39,0.8,10,0.00095189 +40,0.8,10,0.00071403 +41,0.8,10,0.00053655 +42,0.8,10,0.0004039 +43,0.8,10,0.00030458 +44,0.8,10,0.00023009 +45,0.8,10,0.00017412 +46,0.8,10,0.000132 +47,0.8,10,0.00010024 +48,0.8,10,7.625e-05 +49,0.8,10,5.81e-05 +50,0.8,10,4.435e-05 +0,1,10,0.01509497 +1,1,10,0.0170892 +2,1,10,0.01932937 +3,1,10,0.02184336 +4,1,10,0.02466174 +5,1,10,0.0278178 +6,1,10,0.0313474 +7,1,10,0.03528855 +8,1,10,0.03968038 +9,1,10,0.04456116 +10,1,10,0.04996463 +11,1,10,0.05591337 +12,1,10,0.06240768 +13,1,10,0.06940696 +14,1,10,0.07680064 +15,1,10,0.08436547 +16,1,10,0.09171027 +17,1,10,0.0982206 +18,1,10,0.10303882 +19,1,10,0.10514399 +20,1,10,0.10359721 +21,1,10,0.09793232 +22,1,10,0.08849819 +23,1,10,0.07646974 +24,1,10,0.0634441 +25,1,10,0.05088379 +26,1,10,0.0397547 +27,1,10,0.03047485 +28,1,10,0.02305844 +29,1,10,0.01729965 +30,1,10,0.01291229 +31,1,10,0.00961024 +32,1,10,0.00714363 +33,1,10,0.00530908 +34,1,10,0.0039477 +35,1,10,0.00293829 +36,1,10,0.0021898 +37,1,10,0.0016344 +38,1,10,0.00122182 +39,1,10,0.00091494 +40,1,10,0.00068632 +41,1,10,0.00051573 +42,1,10,0.00038822 +43,1,10,0.00029276 +44,1,10,0.00022116 +45,1,10,0.00016737 +46,1,10,0.00012688 +47,1,10,9.635e-05 +48,1,10,7.329e-05 +49,1,10,5.585e-05 +50,1,10,4.263e-05 +0,5,10,0.00661953 +1,5,10,0.00749405 +2,5,10,0.00847641 +3,5,10,0.00957886 +4,5,10,0.0108148 +5,5,10,0.01219881 +6,5,10,0.01374663 +7,5,10,0.01547492 +8,5,10,0.01740085 +9,5,10,0.01954119 +10,5,10,0.02191075 +11,5,10,0.02451942 +12,5,10,0.02736734 +13,5,10,0.0304367 +14,5,10,0.03367902 +15,5,10,0.03699638 +16,5,10,0.04021726 +17,5,10,0.04307221 +18,5,10,0.04518512 +19,5,10,0.04610829 +20,5,10,0.04542999 +21,5,10,0.04294579 +22,5,10,0.03880869 +23,5,10,0.03353391 +24,5,10,0.02782184 +25,5,10,0.02231382 +26,5,10,0.01743344 +27,5,10,0.01336399 +28,5,10,0.01011171 +29,5,10,0.00758633 +30,5,10,0.00566236 +31,5,10,0.00421433 +32,5,10,0.00313266 +33,5,10,0.00232817 +34,5,10,0.00173117 +35,5,10,0.00128851 +36,5,10,0.00096028 +37,5,10,0.00071672 +38,5,10,0.0005358 +39,5,10,0.00040122 +40,5,10,0.00030097 +41,5,10,0.00022616 +42,5,10,0.00017025 +43,5,10,0.00012838 +44,5,10,9.698e-05 +45,5,10,7.339e-05 +46,5,10,5.564e-05 +47,5,10,4.225e-05 +48,5,10,3.214e-05 +49,5,10,2.449e-05 +50,5,10,1.869e-05 +0,10,10,0.0045324 +1,10,10,0.00513118 +2,10,10,0.00580381 +3,10,10,0.00655866 +4,10,10,0.0074049 +5,10,10,0.00835254 +6,10,10,0.00941233 +7,10,10,0.01059569 +8,10,10,0.01191438 +9,10,10,0.01337987 +10,10,10,0.01500231 +11,10,10,0.01678847 +12,10,10,0.01873845 +13,10,10,0.02084004 +14,10,10,0.02306006 +15,10,10,0.02533146 +16,10,10,0.0275368 +17,10,10,0.02949159 +18,10,10,0.0309383 +19,10,10,0.03157039 +20,10,10,0.03110596 +21,10,10,0.02940503 +22,10,10,0.02657235 +23,10,10,0.0229607 +24,10,10,0.01904964 +25,10,10,0.0152783 +26,10,10,0.01193669 +27,10,10,0.00915034 +28,10,10,0.0069235 +29,10,10,0.00519437 +30,10,10,0.00387703 +31,10,10,0.00288556 +32,10,10,0.00214494 +33,10,10,0.0015941 +34,10,10,0.00118533 +35,10,10,0.00088225 +36,10,10,0.00065751 +37,10,10,0.00049074 +38,10,10,0.00036686 +39,10,10,0.00027472 +40,10,10,0.00020607 +41,10,10,0.00015485 +42,10,10,0.00011657 +43,10,10,8.79e-05 +44,10,10,6.641e-05 +45,10,10,5.025e-05 +46,10,10,3.81e-05 +47,10,10,2.893e-05 +48,10,10,2.201e-05 +49,10,10,1.677e-05 +50,10,10,1.28e-05 +0,0.2,15,0.01711167 +1,0.2,15,0.01936871 +2,0.2,15,0.02190185 +3,0.2,15,0.02474109 +4,0.2,15,0.02791852 +5,0.2,15,0.03146795 +6,0.2,15,0.03542409 +7,0.2,15,0.03982106 +8,0.2,15,0.04469007 +9,0.2,15,0.0500556 +10,0.2,15,0.05592956 +11,0.2,15,0.06230257 +12,0.2,15,0.06913161 +13,0.2,15,0.07632328 +14,0.2,15,0.08371302 +15,0.2,15,0.09104256 +16,0.2,15,0.09794173 +17,0.2,15,0.1039258 +18,0.2,15,0.10842406 +19,0.2,15,0.1108536 +20,0.2,15,0.11073804 +21,0.2,15,0.10784318 +22,0.2,15,0.10227485 +23,0.2,15,0.09448488 +24,0.2,15,0.08517175 +25,0.2,15,0.07511809 +26,0.2,15,0.06503458 +27,0.2,15,0.05546201 +28,0.2,15,0.0467429 +29,0.2,15,0.03904357 +30,0.2,15,0.03239928 +31,0.2,15,0.02676119 +32,0.2,15,0.02203479 +33,0.2,15,0.0181068 +34,0.2,15,0.01486198 +35,0.2,15,0.01219246 +36,0.2,15,0.01000207 +37,0.2,15,0.00820773 +38,0.2,15,0.00673905 +39,0.2,15,0.00553728 +40,0.2,15,0.0045538 +41,0.2,15,0.0037486 +42,0.2,15,0.00308896 +43,0.2,15,0.00254814 +44,0.2,15,0.00210433 +45,0.2,15,0.00173977 +46,0.2,15,0.00144001 +47,0.2,15,0.00119326 +48,0.2,15,0.00098992 +49,0.2,15,0.00082217 +50,0.2,15,0.00068363 +0,0.5,15,0.01710009 +1,0.5,15,0.0193556 +2,0.5,15,0.02188703 +3,0.5,15,0.02472434 +4,0.5,15,0.02789962 +5,0.5,15,0.03144666 +6,0.5,15,0.03540011 +7,0.5,15,0.03979411 +8,0.5,15,0.04465983 +9,0.5,15,0.05002173 +10,0.5,15,0.05589171 +11,0.5,15,0.0622604 +12,0.5,15,0.06908482 +13,0.5,15,0.07627163 +14,0.5,15,0.08365637 +15,0.5,15,0.09098095 +16,0.5,15,0.09787545 +17,0.5,15,0.10385547 +18,0.5,15,0.10835069 +19,0.5,15,0.11077859 +20,0.5,15,0.1106631 +21,0.5,15,0.1077702 +22,0.5,15,0.10220564 +23,0.5,15,0.09442094 +24,0.5,15,0.08511411 +25,0.5,15,0.07506726 +26,0.5,15,0.06499057 +27,0.5,15,0.05542448 +28,0.5,15,0.04671127 +29,0.5,15,0.03901715 +30,0.5,15,0.03237735 +31,0.5,15,0.02674308 +32,0.5,15,0.02201988 +33,0.5,15,0.01809455 +34,0.5,15,0.01485192 +35,0.5,15,0.01218421 +36,0.5,15,0.00999531 +37,0.5,15,0.00820217 +38,0.5,15,0.00673449 +39,0.5,15,0.00553354 +40,0.5,15,0.00455071 +41,0.5,15,0.00374607 +42,0.5,15,0.00308687 +43,0.5,15,0.00254641 +44,0.5,15,0.0021029 +45,0.5,15,0.0017386 +46,0.5,15,0.00143904 +47,0.5,15,0.00119245 +48,0.5,15,0.00098925 +49,0.5,15,0.00082162 +50,0.5,15,0.00068316 +0,0.8,15,0.01684752 +1,0.8,15,0.01906971 +2,0.8,15,0.02156375 +3,0.8,15,0.02435916 +4,0.8,15,0.02748754 +5,0.8,15,0.03098218 +6,0.8,15,0.03487724 +7,0.8,15,0.03920633 +8,0.8,15,0.04400018 +9,0.8,15,0.04928289 +10,0.8,15,0.05506617 +11,0.8,15,0.06134079 +12,0.8,15,0.06806441 +13,0.8,15,0.07514507 +14,0.8,15,0.08242073 +15,0.8,15,0.08963712 +16,0.8,15,0.09642979 +17,0.8,15,0.10232148 +18,0.8,15,0.1067503 +19,0.8,15,0.10914234 +20,0.8,15,0.10902856 +21,0.8,15,0.10617839 +22,0.8,15,0.10069602 +23,0.8,15,0.0930263 +24,0.8,15,0.08385694 +25,0.8,15,0.07395848 +26,0.8,15,0.06403063 +27,0.8,15,0.05460584 +28,0.8,15,0.04602132 +29,0.8,15,0.03844085 +30,0.8,15,0.03189912 +31,0.8,15,0.02634807 +32,0.8,15,0.02169464 +33,0.8,15,0.01782728 +34,0.8,15,0.01463255 +35,0.8,15,0.01200424 +36,0.8,15,0.00984767 +37,0.8,15,0.00808102 +38,0.8,15,0.00663502 +39,0.8,15,0.0054518 +40,0.8,15,0.0044835 +41,0.8,15,0.00369073 +42,0.8,15,0.00304128 +43,0.8,15,0.0025088 +44,0.8,15,0.00207184 +45,0.8,15,0.00171292 +46,0.8,15,0.00141778 +47,0.8,15,0.00117484 +48,0.8,15,0.00097464 +49,0.8,15,0.00080948 +50,0.8,15,0.00067307 +0,1,15,0.01619354 +1,1,15,0.01832947 +2,1,15,0.0207267 +3,1,15,0.02341359 +4,1,15,0.02642054 +5,1,15,0.02977953 +6,1,15,0.03352339 +7,1,15,0.03768444 +8,1,15,0.04229221 +9,1,15,0.04736985 +10,1,15,0.05292863 +11,1,15,0.0589597 +12,1,15,0.06542232 +13,1,15,0.07222812 +14,1,15,0.07922136 +15,1,15,0.08615763 +16,1,15,0.09268662 +17,1,15,0.09834962 +18,1,15,0.10260652 +19,1,15,0.10490571 +20,1,15,0.10479634 +21,1,15,0.10205681 +22,1,15,0.09678725 +23,1,15,0.08941525 +24,1,15,0.08060182 +25,1,15,0.0710876 +26,1,15,0.06154512 +27,1,15,0.05248617 +28,1,15,0.04423489 +29,1,15,0.03694867 +30,1,15,0.03066088 +31,1,15,0.02532531 +32,1,15,0.02085251 +33,1,15,0.01713527 +34,1,15,0.01406456 +35,1,15,0.01153827 +36,1,15,0.00946541 +37,1,15,0.00776734 +38,1,15,0.00637747 +39,1,15,0.00524018 +40,1,15,0.00430946 +41,1,15,0.00354747 +42,1,15,0.00292322 +43,1,15,0.00241142 +44,1,15,0.00199142 +45,1,15,0.00164643 +46,1,15,0.00136275 +47,1,15,0.00112923 +48,1,15,0.00093681 +49,1,15,0.00077806 +50,1,15,0.00064695 +0,5,15,0.00710128 +1,5,15,0.00803794 +2,5,15,0.00908918 +3,5,15,0.01026745 +4,5,15,0.01158607 +5,5,15,0.01305907 +6,5,15,0.01470085 +7,5,15,0.01652558 +8,5,15,0.0185462 +9,5,15,0.02077287 +10,5,15,0.02321054 +11,5,15,0.02585531 +12,5,15,0.02868934 +13,5,15,0.03167385 +14,5,15,0.03474056 +15,5,15,0.03778229 +16,5,15,0.04064542 +17,5,15,0.04312878 +18,5,15,0.04499555 +19,5,15,0.0460038 +20,5,15,0.04595584 +21,5,15,0.04475448 +22,5,15,0.04244365 +23,5,15,0.03921084 +24,5,15,0.03534593 +25,5,15,0.0311737 +26,5,15,0.02698909 +27,5,15,0.02301651 +28,5,15,0.01939811 +29,5,15,0.01620292 +30,5,15,0.01344557 +31,5,15,0.01110578 +32,5,15,0.00914435 +33,5,15,0.00751425 +34,5,15,0.00616766 +35,5,15,0.00505982 +36,5,15,0.00415082 +37,5,15,0.00340617 +38,5,15,0.00279668 +39,5,15,0.00229795 +40,5,15,0.00188981 +41,5,15,0.00155565 +42,5,15,0.00128191 +43,5,15,0.00105747 +44,5,15,0.00087329 +45,5,15,0.000722 +46,5,15,0.0005976 +47,5,15,0.0004952 +48,5,15,0.00041081 +49,5,15,0.0003412 +50,5,15,0.0002837 +0,10,15,0.00486225 +1,10,15,0.00550358 +2,10,15,0.00622337 +3,10,15,0.00703013 +4,10,15,0.007933 +5,10,15,0.00894156 +6,10,15,0.01006569 +7,10,15,0.01131508 +8,10,15,0.0126986 +9,10,15,0.01422321 +10,10,15,0.01589228 +11,10,15,0.01770316 +12,10,15,0.01964362 +13,10,15,0.02168712 +14,10,15,0.0237869 +15,10,15,0.02586958 +16,10,15,0.02782996 +17,10,15,0.02953032 +18,10,15,0.0308085 +19,10,15,0.03149885 +20,10,15,0.03146601 +21,10,15,0.03064344 +22,10,15,0.02906121 +23,10,15,0.0268477 +24,10,15,0.0242014 +25,10,15,0.02134467 +26,10,15,0.01847946 +27,10,15,0.01575943 +28,10,15,0.01328191 +29,10,15,0.01109416 +30,10,15,0.00920619 +31,10,15,0.00760414 +32,10,15,0.00626115 +33,10,15,0.00514501 +34,10,15,0.004223 +35,10,15,0.00346446 +36,10,15,0.00284207 +37,10,15,0.00233221 +38,10,15,0.00191489 +39,10,15,0.00157341 +40,10,15,0.00129395 +41,10,15,0.00106516 +42,10,15,0.00087772 +43,10,15,0.00072405 +44,10,15,0.00059794 +45,10,15,0.00049435 +46,10,15,0.00040918 +47,10,15,0.00033906 +48,10,15,0.00028128 +49,10,15,0.00023362 +50,10,15,0.00019425 +0,0.2,20,0.01809742 +1,0.2,20,0.02045793 +2,0.2,20,0.02309577 +3,0.2,20,0.02603641 +4,0.2,20,0.02930538 +5,0.2,20,0.03292716 +6,0.2,20,0.03692367 +7,0.2,20,0.04131224 +8,0.2,20,0.04610276 +9,0.2,20,0.05129407 +10,0.2,20,0.05686949 +11,0.2,20,0.0627915 +12,0.2,20,0.06899594 +13,0.2,20,0.07538636 +14,0.2,20,0.08182949 +15,0.2,20,0.08815348 +16,0.2,20,0.09415057 +17,0.2,20,0.09958604 +18,0.2,20,0.10421432 +19,0.2,20,0.10780164 +20,0.2,20,0.11015244 +21,0.2,20,0.11113472 +22,0.2,20,0.11069854 +23,0.2,20,0.10888319 +24,0.2,20,0.10581086 +25,0.2,20,0.10166882 +26,0.2,20,0.09668441 +27,0.2,20,0.09109882 +28,0.2,20,0.08514424 +29,0.2,20,0.07902753 +30,0.2,20,0.07292083 +31,0.2,20,0.0669586 +32,0.2,20,0.06123903 +33,0.2,20,0.05582837 +34,0.2,20,0.05076644 +35,0.2,20,0.04607226 +36,0.2,20,0.04174935 +37,0.2,20,0.03779015 +38,0.2,20,0.03417965 +39,0.2,20,0.03089814 +40,0.2,20,0.02792335 +41,0.2,20,0.02523187 +42,0.2,20,0.0228003 +43,0.2,20,0.02060585 +44,0.2,20,0.01862687 +45,0.2,20,0.01684305 +46,0.2,20,0.01523558 +47,0.2,20,0.01378715 +48,0.2,20,0.01248199 +49,0.2,20,0.01130576 +50,0.2,20,0.01024547 +0,0.5,20,0.01808517 +1,0.5,20,0.02044409 +2,0.5,20,0.02308014 +3,0.5,20,0.02601879 +4,0.5,20,0.02928555 +5,0.5,20,0.03290487 +6,0.5,20,0.03689868 +7,0.5,20,0.04128428 +8,0.5,20,0.04607156 +9,0.5,20,0.05125936 +10,0.5,20,0.05683101 +11,0.5,20,0.06274901 +12,0.5,20,0.06894925 +13,0.5,20,0.07533534 +14,0.5,20,0.08177412 +15,0.5,20,0.08809383 +16,0.5,20,0.09408686 +17,0.5,20,0.09951865 +18,0.5,20,0.1041438 +19,0.5,20,0.10772869 +20,0.5,20,0.1100779 +21,0.5,20,0.11105951 +22,0.5,20,0.11062363 +23,0.5,20,0.1088095 +24,0.5,20,0.10573926 +25,0.5,20,0.10160002 +26,0.5,20,0.09661898 +27,0.5,20,0.09103717 +28,0.5,20,0.08508663 +29,0.5,20,0.07897405 +30,0.5,20,0.07287149 +31,0.5,20,0.06691328 +32,0.5,20,0.06119758 +33,0.5,20,0.05579059 +34,0.5,20,0.05073208 +35,0.5,20,0.04604108 +36,0.5,20,0.04172109 +37,0.5,20,0.03776458 +38,0.5,20,0.03415652 +39,0.5,20,0.03087724 +40,0.5,20,0.02790445 +41,0.5,20,0.0252148 +42,0.5,20,0.02278487 +43,0.5,20,0.02059191 +44,0.5,20,0.01861427 +45,0.5,20,0.01683166 +46,0.5,20,0.01522527 +47,0.5,20,0.01377782 +48,0.5,20,0.01247355 +49,0.5,20,0.01129811 +50,0.5,20,0.01023854 +0,0.8,20,0.01781804 +1,0.8,20,0.02014212 +2,0.8,20,0.02273923 +3,0.8,20,0.02563449 +4,0.8,20,0.02885299 +5,0.8,20,0.03241886 +6,0.8,20,0.03635368 +7,0.8,20,0.0406745 +8,0.8,20,0.04539106 +9,0.8,20,0.05050224 +10,0.8,20,0.05599159 +11,0.8,20,0.06182218 +12,0.8,20,0.06793084 +13,0.8,20,0.07422261 +14,0.8,20,0.08056628 +15,0.8,20,0.08679264 +16,0.8,20,0.09269716 +17,0.8,20,0.09804872 +18,0.8,20,0.10260555 +19,0.8,20,0.10613749 +20,0.8,20,0.10845201 +21,0.8,20,0.10941911 +22,0.8,20,0.10898967 +23,0.8,20,0.10720234 +24,0.8,20,0.10417745 +25,0.8,20,0.10009934 +26,0.8,20,0.09519188 +27,0.8,20,0.08969251 +28,0.8,20,0.08382986 +29,0.8,20,0.07780757 +30,0.8,20,0.07179515 +31,0.8,20,0.06592495 +32,0.8,20,0.06029367 +33,0.8,20,0.05496654 +34,0.8,20,0.04998275 +35,0.8,20,0.04536103 +36,0.8,20,0.04110486 +37,0.8,20,0.03720678 +38,0.8,20,0.03365201 +39,0.8,20,0.03042117 +40,0.8,20,0.02749229 +41,0.8,20,0.02484237 +42,0.8,20,0.02244833 +43,0.8,20,0.02028776 +44,0.8,20,0.01833933 +45,0.8,20,0.01658305 +46,0.8,20,0.01500038 +47,0.8,20,0.01357432 +48,0.8,20,0.01228931 +49,0.8,20,0.01113123 +50,0.8,20,0.01008731 +0,1,20,0.01712639 +1,1,20,0.01936025 +2,1,20,0.02185655 +3,1,20,0.02463942 +4,1,20,0.02773299 +5,1,20,0.03116044 +6,1,20,0.03494252 +7,1,20,0.03909562 +8,1,20,0.04362909 +9,1,20,0.04854187 +10,1,20,0.05381814 +11,1,20,0.0594224 +12,1,20,0.06529393 +13,1,20,0.07134147 +14,1,20,0.0774389 +15,1,20,0.08342357 +16,1,20,0.08909888 +17,1,20,0.09424271 +18,1,20,0.09862266 +19,1,20,0.1020175 +20,1,20,0.10424217 +21,1,20,0.10517174 +22,1,20,0.10475896 +23,1,20,0.10304101 +24,1,20,0.10013354 +25,1,20,0.09621374 +26,1,20,0.09149677 +27,1,20,0.08621087 +28,1,20,0.08057579 +29,1,20,0.07478727 +30,1,20,0.06900824 +31,1,20,0.0633659 +32,1,20,0.05795322 +33,1,20,0.05283288 +34,1,20,0.04804254 +35,1,20,0.04360023 +36,1,20,0.03950927 +37,1,20,0.0357625 +38,1,20,0.03234573 +39,1,20,0.02924029 +40,1,20,0.02642511 +41,1,20,0.02387805 +42,1,20,0.02157694 +43,1,20,0.01950024 +44,1,20,0.01762744 +45,1,20,0.01593933 +46,1,20,0.0144181 +47,1,20,0.0130474 +48,1,20,0.01181227 +49,1,20,0.01069915 +50,1,20,0.00969575 +0,5,20,0.00751035 +1,5,20,0.00848996 +2,5,20,0.00958465 +3,5,20,0.01080501 +4,5,20,0.01216162 +5,5,20,0.01366464 +6,5,20,0.01532317 +7,5,20,0.01714441 +8,5,20,0.01913246 +9,5,20,0.02128683 +10,5,20,0.02360061 +11,5,20,0.02605822 +12,5,20,0.02863304 +13,5,20,0.03128503 +14,5,20,0.03395891 +15,5,20,0.03658334 +16,5,20,0.03907211 +17,5,20,0.0413278 +18,5,20,0.04324852 +19,5,20,0.04473724 +20,5,20,0.04571282 +21,5,20,0.04612046 +22,5,20,0.04593944 +23,5,20,0.04518608 +24,5,20,0.04391108 +25,5,20,0.04219215 +26,5,20,0.04012364 +27,5,20,0.03780564 +28,5,20,0.03533452 +29,5,20,0.0327961 +30,5,20,0.03026185 +31,5,20,0.02778755 +32,5,20,0.02541395 +33,5,20,0.02316855 +34,5,20,0.02106787 +35,5,20,0.0191198 +36,5,20,0.01732581 +37,5,20,0.01568276 +38,5,20,0.01418442 +39,5,20,0.0128226 +40,5,20,0.01158808 +41,5,20,0.01047113 +42,5,20,0.00946203 +43,5,20,0.00855135 +44,5,20,0.00773008 +45,5,20,0.0069898 +46,5,20,0.0063227 +47,5,20,0.00572161 +48,5,20,0.00517998 +49,5,20,0.00469185 +50,5,20,0.00425183 +0,10,20,0.00514235 +1,10,20,0.00581308 +2,10,20,0.00656262 +3,10,20,0.0073982 +4,10,20,0.00832707 +5,10,20,0.00935619 +6,10,20,0.01049179 +7,10,20,0.0117388 +8,10,20,0.01310001 +9,10,20,0.01457512 +10,10,20,0.01615936 +11,10,20,0.01784209 +12,10,20,0.01960507 +13,10,20,0.02142089 +14,10,20,0.0232517 +15,10,20,0.02504865 +16,10,20,0.02675271 +17,10,20,0.02829719 +18,10,20,0.02961231 +19,10,20,0.03063164 +20,10,20,0.03129961 +21,10,20,0.03157872 +22,10,20,0.03145478 +23,10,20,0.03093896 +24,10,20,0.03006596 +25,10,20,0.02888901 +26,10,20,0.0274727 +27,10,20,0.02588556 +28,10,20,0.02419358 +29,10,20,0.02245553 +30,10,20,0.02072032 +31,10,20,0.01902616 +32,10,20,0.01740096 +33,10,20,0.01586353 +34,10,20,0.01442519 +35,10,20,0.01309135 +36,10,20,0.011863 +37,10,20,0.010738 +38,10,20,0.00971208 +39,10,20,0.00877965 +40,10,20,0.00793437 +41,10,20,0.00716959 +42,10,20,0.00647866 +43,10,20,0.00585512 +44,10,20,0.00529279 +45,10,20,0.00478592 +46,10,20,0.00432916 +47,10,20,0.00391759 +48,10,20,0.00354674 +49,10,20,0.00321251 +50,10,20,0.00291123 +0,0.2,25,0.01280539 +1,0.2,25,0.01438079 +2,0.2,25,0.01611798 +3,0.2,25,0.01802711 +4,0.2,25,0.0201175 +5,0.2,25,0.0223973 +6,0.2,25,0.02487299 +7,0.2,25,0.02754895 +8,0.2,25,0.03042689 +9,0.2,25,0.03350538 +10,0.2,25,0.03677934 +11,0.2,25,0.04023958 +12,0.2,25,0.04387254 +13,0.2,25,0.04766001 +14,0.2,25,0.05157917 +15,0.2,25,0.0556028 +16,0.2,25,0.05969964 +17,0.2,25,0.06383515 +18,0.2,25,0.06797228 +19,0.2,25,0.07207259 +20,0.2,25,0.07609741 +21,0.2,25,0.08000901 +22,0.2,25,0.08377182 +23,0.2,25,0.08735347 +24,0.2,25,0.0907257 +25,0.2,25,0.09386504 +26,0.2,25,0.09675319 +27,0.2,25,0.0993772 +28,0.2,25,0.1017294 +29,0.2,25,0.10380709 +30,0.2,25,0.10561208 +31,0.2,25,0.10715015 +32,0.2,25,0.10843039 +33,0.2,25,0.10946454 +34,0.2,25,0.11026634 +35,0.2,25,0.11085093 +36,0.2,25,0.11123434 +37,0.2,25,0.11143294 +38,0.2,25,0.11146314 +39,0.2,25,0.11134101 +40,0.2,25,0.11108205 +41,0.2,25,0.11070104 +42,0.2,25,0.11021187 +43,0.2,25,0.10962751 +44,0.2,25,0.10895993 +45,0.2,25,0.10822013 +46,0.2,25,0.10741814 +47,0.2,25,0.10656303 +48,0.2,25,0.10566302 +49,0.2,25,0.10472545 +50,0.2,25,0.10375691 +0,0.5,25,0.01279672 +1,0.5,25,0.01437106 +2,0.5,25,0.01610708 +3,0.5,25,0.01801491 +4,0.5,25,0.02010389 +5,0.5,25,0.02238214 +6,0.5,25,0.02485616 +7,0.5,25,0.0275303 +8,0.5,25,0.0304063 +9,0.5,25,0.03348271 +10,0.5,25,0.03675445 +11,0.5,25,0.04021235 +12,0.5,25,0.04384285 +13,0.5,25,0.04762776 +14,0.5,25,0.05154427 +15,0.5,25,0.05556517 +16,0.5,25,0.05965924 +17,0.5,25,0.06379195 +18,0.5,25,0.06792628 +19,0.5,25,0.07202382 +20,0.5,25,0.07604591 +21,0.5,25,0.07995487 +22,0.5,25,0.08371513 +23,0.5,25,0.08729435 +24,0.5,25,0.09066431 +25,0.5,25,0.09380152 +26,0.5,25,0.09668772 +27,0.5,25,0.09930995 +28,0.5,25,0.10166056 +29,0.5,25,0.10373684 +30,0.5,25,0.10554061 +31,0.5,25,0.10707764 +32,0.5,25,0.10835701 +33,0.5,25,0.10939046 +34,0.5,25,0.11019172 +35,0.5,25,0.11077592 +36,0.5,25,0.11115906 +37,0.5,25,0.11135753 +38,0.5,25,0.11138771 +39,0.5,25,0.11126566 +40,0.5,25,0.11100688 +41,0.5,25,0.11062612 +42,0.5,25,0.11013729 +43,0.5,25,0.10955332 +44,0.5,25,0.10888619 +45,0.5,25,0.1081469 +46,0.5,25,0.10734545 +47,0.5,25,0.10649092 +48,0.5,25,0.10559151 +49,0.5,25,0.10465458 +50,0.5,25,0.1036867 +0,0.8,25,0.01260771 +1,0.8,25,0.01415879 +2,0.8,25,0.01586917 +3,0.8,25,0.01774882 +4,0.8,25,0.01980694 +5,0.8,25,0.02205155 +6,0.8,25,0.02448902 +7,0.8,25,0.02712367 +8,0.8,25,0.02995718 +9,0.8,25,0.03298815 +10,0.8,25,0.03621157 +11,0.8,25,0.0396184 +12,0.8,25,0.04319527 +13,0.8,25,0.04692428 +14,0.8,25,0.05078294 +15,0.8,25,0.05474445 +16,0.8,25,0.05877805 +17,0.8,25,0.06284971 +18,0.8,25,0.06692298 +19,0.8,25,0.07096 +20,0.8,25,0.07492268 +21,0.8,25,0.0787739 +22,0.8,25,0.08247862 +23,0.8,25,0.08600498 +24,0.8,25,0.08932516 +25,0.8,25,0.09241604 +26,0.8,25,0.0952596 +27,0.8,25,0.0978431 +28,0.8,25,0.10015899 +29,0.8,25,0.1022046 +30,0.8,25,0.10398173 +31,0.8,25,0.10549606 +32,0.8,25,0.10675654 +33,0.8,25,0.10777472 +34,0.8,25,0.10856414 +35,0.8,25,0.10913971 +36,0.8,25,0.1095172 +37,0.8,25,0.10971274 +38,0.8,25,0.10974247 +39,0.8,25,0.10962222 +40,0.8,25,0.10936726 +41,0.8,25,0.10899213 +42,0.8,25,0.10851051 +43,0.8,25,0.10793517 +44,0.8,25,0.1072779 +45,0.8,25,0.10654952 +46,0.8,25,0.10575991 +47,0.8,25,0.10491801 +48,0.8,25,0.10403188 +49,0.8,25,0.10310879 +50,0.8,25,0.1021552 +0,1,25,0.01211831 +1,1,25,0.01360918 +2,1,25,0.01525317 +3,1,25,0.01705986 +4,1,25,0.01903809 +5,1,25,0.02119556 +6,1,25,0.02353842 +7,1,25,0.0260708 +8,1,25,0.02879432 +9,1,25,0.03170764 +10,1,25,0.03480593 +11,1,25,0.03808051 +12,1,25,0.04151854 +13,1,25,0.04510279 +14,1,25,0.04881167 +15,1,25,0.05261941 +16,1,25,0.05649643 +17,1,25,0.06041004 +18,1,25,0.06432519 +19,1,25,0.06820551 +20,1,25,0.07201437 +21,1,25,0.07571609 +22,1,25,0.07927701 +23,1,25,0.08266648 +24,1,25,0.08585778 +25,1,25,0.08882868 +26,1,25,0.09156186 +27,1,25,0.09404508 +28,1,25,0.09627107 +29,1,25,0.09823727 +30,1,25,0.09994542 +31,1,25,0.10140097 +32,1,25,0.10261251 +33,1,25,0.10359117 +34,1,25,0.10434995 +35,1,25,0.10490318 +36,1,25,0.10526601 +37,1,25,0.10545396 +38,1,25,0.10548254 +39,1,25,0.10536696 +40,1,25,0.1051219 +41,1,25,0.10476133 +42,1,25,0.1042984 +43,1,25,0.1037454 +44,1,25,0.10311364 +45,1,25,0.10241353 +46,1,25,0.10165457 +47,1,25,0.10084535 +48,1,25,0.09999362 +49,1,25,0.09910636 +50,1,25,0.09818979 +0,5,25,0.00531418 +1,5,25,0.00596797 +2,5,25,0.0066889 +3,5,25,0.00748118 +4,5,25,0.00834868 +5,5,25,0.00929479 +6,5,25,0.01032219 +7,5,25,0.0114327 +8,5,25,0.01262704 +9,5,25,0.0139046 +10,5,25,0.01526328 +11,5,25,0.01669926 +12,5,25,0.01820693 +13,5,25,0.01977871 +14,5,25,0.02140515 +15,5,25,0.02307494 +16,5,25,0.02477511 +17,5,25,0.02649133 +18,5,25,0.02820822 +19,5,25,0.02990983 +20,5,25,0.03158012 +21,5,25,0.03320342 +22,5,25,0.03476496 +23,5,25,0.03625134 +24,5,25,0.0376508 +25,5,25,0.03895361 +26,5,25,0.04015218 +27,5,25,0.04124114 +28,5,25,0.04221729 +29,5,25,0.04307952 +30,5,25,0.04382858 +31,5,25,0.04446688 +32,5,25,0.04499817 +33,5,25,0.04542734 +34,5,25,0.04576008 +35,5,25,0.04600269 +36,5,25,0.0461618 +37,5,25,0.04624422 +38,5,25,0.04625675 +39,5,25,0.04620607 +40,5,25,0.0460986 +41,5,25,0.04594048 +42,5,25,0.04573748 +43,5,25,0.04549497 +44,5,25,0.04521793 +45,5,25,0.04491092 +46,5,25,0.04457809 +47,5,25,0.04422323 +48,5,25,0.04384972 +49,5,25,0.04346064 +50,5,25,0.0430587 +0,10,25,0.00363863 +1,10,25,0.00408627 +2,10,25,0.00457989 +3,10,25,0.00512237 +4,10,25,0.00571635 +5,10,25,0.00636415 +6,10,25,0.00706761 +7,10,25,0.00782798 +8,10,25,0.00864574 +9,10,25,0.00952049 +10,10,25,0.01045078 +11,10,25,0.011434 +12,10,25,0.0124663 +13,10,25,0.0135425 +14,10,25,0.01465613 +15,10,25,0.01579943 +16,10,25,0.01696354 +17,10,25,0.01813864 +18,10,25,0.0193142 +19,10,25,0.02047929 +20,10,25,0.02162294 +21,10,25,0.02273441 +22,10,25,0.02380361 +23,10,25,0.02482133 +24,10,25,0.02577954 +25,10,25,0.02667158 +26,10,25,0.02749224 +27,10,25,0.02823785 +28,10,25,0.02890622 +29,10,25,0.02949659 +30,10,25,0.03000948 +31,10,25,0.03044652 +32,10,25,0.0308103 +33,10,25,0.03110415 +34,10,25,0.03133198 +35,10,25,0.03149809 +36,10,25,0.03160703 +37,10,25,0.03166347 +38,10,25,0.03167205 +39,10,25,0.03163734 +40,10,25,0.03156376 +41,10,25,0.03145549 +42,10,25,0.0313165 +43,10,25,0.03115045 +44,10,25,0.03096076 +45,10,25,0.03075055 +46,10,25,0.03052267 +47,10,25,0.03027969 +48,10,25,0.03002395 +49,10,25,0.02975754 +50,10,25,0.02948233 +0,0.2,30,-0.02090836 +1,0.2,30,-0.02130812 +2,0.2,30,-0.02170973 +3,0.2,30,-0.02211308 +4,0.2,30,-0.02251806 +5,0.2,30,-0.02292459 +6,0.2,30,-0.02333256 +7,0.2,30,-0.02374187 +8,0.2,30,-0.02415243 +9,0.2,30,-0.02456414 +10,0.2,30,-0.0249769 +11,0.2,30,-0.02539062 +12,0.2,30,-0.02580522 +13,0.2,30,-0.02622059 +14,0.2,30,-0.02663666 +15,0.2,30,-0.02705333 +16,0.2,30,-0.02747052 +17,0.2,30,-0.02788814 +18,0.2,30,-0.02830613 +19,0.2,30,-0.02872438 +20,0.2,30,-0.02914283 +21,0.2,30,-0.02956141 +22,0.2,30,-0.02998003 +23,0.2,30,-0.03039862 +24,0.2,30,-0.03081712 +25,0.2,30,-0.03123546 +26,0.2,30,-0.03165356 +27,0.2,30,-0.03207137 +28,0.2,30,-0.03248883 +29,0.2,30,-0.03290586 +30,0.2,30,-0.03332243 +31,0.2,30,-0.03373845 +32,0.2,30,-0.0341539 +33,0.2,30,-0.0345687 +34,0.2,30,-0.03498282 +35,0.2,30,-0.03539619 +36,0.2,30,-0.03580878 +37,0.2,30,-0.03622055 +38,0.2,30,-0.03663144 +39,0.2,30,-0.03704141 +40,0.2,30,-0.03745043 +41,0.2,30,-0.03785846 +42,0.2,30,-0.03826547 +43,0.2,30,-0.03867141 +44,0.2,30,-0.03907626 +45,0.2,30,-0.03947998 +46,0.2,30,-0.03988255 +47,0.2,30,-0.04028394 +48,0.2,30,-0.04068412 +49,0.2,30,-0.04108307 +50,0.2,30,-0.04148076 +0,0.5,30,-0.02089421 +1,0.5,30,-0.0212937 +2,0.5,30,-0.02169504 +3,0.5,30,-0.02209811 +4,0.5,30,-0.02250283 +5,0.5,30,-0.02290908 +6,0.5,30,-0.02331677 +7,0.5,30,-0.02372581 +8,0.5,30,-0.02413608 +9,0.5,30,-0.02454751 +10,0.5,30,-0.02495999 +11,0.5,30,-0.02537344 +12,0.5,30,-0.02578775 +13,0.5,30,-0.02620285 +14,0.5,30,-0.02661863 +15,0.5,30,-0.02703502 +16,0.5,30,-0.02745193 +17,0.5,30,-0.02786927 +18,0.5,30,-0.02828697 +19,0.5,30,-0.02870494 +20,0.5,30,-0.02912311 +21,0.5,30,-0.0295414 +22,0.5,30,-0.02995974 +23,0.5,30,-0.03037805 +24,0.5,30,-0.03079627 +25,0.5,30,-0.03121432 +26,0.5,30,-0.03163214 +27,0.5,30,-0.03204967 +28,0.5,30,-0.03246684 +29,0.5,30,-0.0328836 +30,0.5,30,-0.03329988 +31,0.5,30,-0.03371562 +32,0.5,30,-0.03413079 +33,0.5,30,-0.03454531 +34,0.5,30,-0.03495914 +35,0.5,30,-0.03537224 +36,0.5,30,-0.03578455 +37,0.5,30,-0.03619604 +38,0.5,30,-0.03660665 +39,0.5,30,-0.03701635 +40,0.5,30,-0.03742509 +41,0.5,30,-0.03783285 +42,0.5,30,-0.03823957 +43,0.5,30,-0.03864524 +44,0.5,30,-0.03904982 +45,0.5,30,-0.03945327 +46,0.5,30,-0.03985556 +47,0.5,30,-0.04025668 +48,0.5,30,-0.04065659 +49,0.5,30,-0.04105527 +50,0.5,30,-0.04145269 +0,0.8,30,-0.0205856 +1,0.8,30,-0.02097919 +2,0.8,30,-0.02137459 +3,0.8,30,-0.02177171 +4,0.8,30,-0.02217045 +5,0.8,30,-0.0225707 +6,0.8,30,-0.02297237 +7,0.8,30,-0.02337537 +8,0.8,30,-0.02377958 +9,0.8,30,-0.02418494 +10,0.8,30,-0.02459133 +11,0.8,30,-0.02499866 +12,0.8,30,-0.02540686 +13,0.8,30,-0.02581582 +14,0.8,30,-0.02622546 +15,0.8,30,-0.0266357 +16,0.8,30,-0.02704645 +17,0.8,30,-0.02745763 +18,0.8,30,-0.02786916 +19,0.8,30,-0.02828096 +20,0.8,30,-0.02869295 +21,0.8,30,-0.02910506 +22,0.8,30,-0.02951722 +23,0.8,30,-0.02992936 +24,0.8,30,-0.03034139 +25,0.8,30,-0.03075327 +26,0.8,30,-0.03116492 +27,0.8,30,-0.03157628 +28,0.8,30,-0.03198729 +29,0.8,30,-0.03239789 +30,0.8,30,-0.03280802 +31,0.8,30,-0.03321763 +32,0.8,30,-0.03362666 +33,0.8,30,-0.03403506 +34,0.8,30,-0.03444278 +35,0.8,30,-0.03484978 +36,0.8,30,-0.035256 +37,0.8,30,-0.03566141 +38,0.8,30,-0.03606595 +39,0.8,30,-0.0364696 +40,0.8,30,-0.03687231 +41,0.8,30,-0.03727404 +42,0.8,30,-0.03767476 +43,0.8,30,-0.03807444 +44,0.8,30,-0.03847303 +45,0.8,30,-0.03887053 +46,0.8,30,-0.03926688 +47,0.8,30,-0.03966207 +48,0.8,30,-0.04005608 +49,0.8,30,-0.04044886 +50,0.8,30,-0.04084041 +0,1,30,-0.01978651 +1,1,30,-0.02016483 +2,1,30,-0.02054488 +3,1,30,-0.02092659 +4,1,30,-0.02130985 +5,1,30,-0.02169456 +6,1,30,-0.02208064 +7,1,30,-0.02246799 +8,1,30,-0.02285652 +9,1,30,-0.02324614 +10,1,30,-0.02363675 +11,1,30,-0.02402828 +12,1,30,-0.02442063 +13,1,30,-0.02481371 +14,1,30,-0.02520745 +15,1,30,-0.02560177 +16,1,30,-0.02599657 +17,1,30,-0.02639179 +18,1,30,-0.02678735 +19,1,30,-0.02718316 +20,1,30,-0.02757916 +21,1,30,-0.02797528 +22,1,30,-0.02837144 +23,1,30,-0.02876757 +24,1,30,-0.02916362 +25,1,30,-0.02955951 +26,1,30,-0.02995518 +27,1,30,-0.03035057 +28,1,30,-0.03074563 +29,1,30,-0.03114029 +30,1,30,-0.0315345 +31,1,30,-0.0319282 +32,1,30,-0.03232136 +33,1,30,-0.0327139 +34,1,30,-0.0331058 +35,1,30,-0.033497 +36,1,30,-0.03388745 +37,1,30,-0.03427712 +38,1,30,-0.03466596 +39,1,30,-0.03505394 +40,1,30,-0.03544102 +41,1,30,-0.03582715 +42,1,30,-0.03621232 +43,1,30,-0.03659648 +44,1,30,-0.03697961 +45,1,30,-0.03736167 +46,1,30,-0.03774264 +47,1,30,-0.03812249 +48,1,30,-0.0385012 +49,1,30,-0.03887874 +50,1,30,-0.03925509 +0,5,30,-0.00867688 +1,5,30,-0.00884278 +2,5,30,-0.00900945 +3,5,30,-0.00917684 +4,5,30,-0.00934491 +5,5,30,-0.00951361 +6,5,30,-0.00968292 +7,5,30,-0.00985278 +8,5,30,-0.01002316 +9,5,30,-0.01019402 +10,5,30,-0.01036531 +11,5,30,-0.010537 +12,5,30,-0.01070906 +13,5,30,-0.01088144 +14,5,30,-0.0110541 +15,5,30,-0.01122702 +16,5,30,-0.01140015 +17,5,30,-0.01157347 +18,5,30,-0.01174693 +19,5,30,-0.0119205 +20,5,30,-0.01209416 +21,5,30,-0.01226786 +22,5,30,-0.01244159 +23,5,30,-0.01261531 +24,5,30,-0.01278898 +25,5,30,-0.01296259 +26,5,30,-0.0131361 +27,5,30,-0.01330949 +28,5,30,-0.01348273 +29,5,30,-0.0136558 +30,5,30,-0.01382867 +31,5,30,-0.01400132 +32,5,30,-0.01417373 +33,5,30,-0.01434587 +34,5,30,-0.01451773 +35,5,30,-0.01468928 +36,5,30,-0.0148605 +37,5,30,-0.01503138 +38,5,30,-0.0152019 +39,5,30,-0.01537204 +40,5,30,-0.01554178 +41,5,30,-0.01571111 +42,5,30,-0.01588001 +43,5,30,-0.01604848 +44,5,30,-0.01621649 +45,5,30,-0.01638403 +46,5,30,-0.0165511 +47,5,30,-0.01671767 +48,5,30,-0.01688375 +49,5,30,-0.01704931 +50,5,30,-0.01721435 +0,10,30,-0.00594107 +1,10,30,-0.00605466 +2,10,30,-0.00616878 +3,10,30,-0.00628339 +4,10,30,-0.00639847 +5,10,30,-0.00651398 +6,10,30,-0.0066299 +7,10,30,-0.00674621 +8,10,30,-0.00686287 +9,10,30,-0.00697985 +10,10,30,-0.00709714 +11,10,30,-0.0072147 +12,10,30,-0.0073325 +13,10,30,-0.00745053 +14,10,30,-0.00756876 +15,10,30,-0.00768715 +16,10,30,-0.0078057 +17,10,30,-0.00792436 +18,10,30,-0.00804313 +19,10,30,-0.00816198 +20,10,30,-0.00828088 +21,10,30,-0.00839982 +22,10,30,-0.00851877 +23,10,30,-0.00863771 +24,10,30,-0.00875663 +25,10,30,-0.0088755 +26,10,30,-0.0089943 +27,10,30,-0.00911302 +28,10,30,-0.00923164 +29,10,30,-0.00935014 +30,10,30,-0.00946851 +31,10,30,-0.00958672 +32,10,30,-0.00970477 +33,10,30,-0.00982263 +34,10,30,-0.0099403 +35,10,30,-0.01005776 +36,10,30,-0.010175 +37,10,30,-0.010292 +38,10,30,-0.01040875 +39,10,30,-0.01052525 +40,10,30,-0.01064147 +41,10,30,-0.01075741 +42,10,30,-0.01087306 +43,10,30,-0.01098841 +44,10,30,-0.01110345 +45,10,30,-0.01121816 +46,10,30,-0.01133255 +47,10,30,-0.01144661 +48,10,30,-0.01156032 +49,10,30,-0.01167368 +50,10,30,-0.01178668 From 0ad2fb536d6be1b9461b71eaac36936a150233f3 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 31 Jul 2024 17:08:26 +0100 Subject: [PATCH 025/241] Rework reference code files, initial unit test suite --- pyproject.toml | 1 + pyrealm_build_data/sandoval_kphio/calc_phi0.R | 168 ++++++++---------- .../sandoval_kphio/create_test_inputs.R | 24 +++ tests/unit/pmodel/test_quantum_yield.py | 147 +++++++++++++++ 4 files changed, 244 insertions(+), 96 deletions(-) create mode 100644 pyrealm_build_data/sandoval_kphio/create_test_inputs.R create mode 100644 tests/unit/pmodel/test_quantum_yield.py diff --git a/pyproject.toml b/pyproject.toml index 8c28b9aa..4e22dcb1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -106,6 +106,7 @@ addopts = """ --doctest-modules --ignore=pyrealm/__main__.py --ignore=tests/pmodel/generate_test_inputs.py + --import-mode importlib """ python_files = 'test_*.py' testpaths = ['tests', 'pyrealm'] diff --git a/pyrealm_build_data/sandoval_kphio/calc_phi0.R b/pyrealm_build_data/sandoval_kphio/calc_phi0.R index 6be1fc27..e688ee28 100644 --- a/pyrealm_build_data/sandoval_kphio/calc_phi0.R +++ b/pyrealm_build_data/sandoval_kphio/calc_phi0.R @@ -1,96 +1,72 @@ -# calc_phi0 -calc_phi0 <- function(AI, tc, mGDD0 = NA) { - # ************************************************************************ - # Name: calc_phi0 - # Inputs: - double - scalar (AI), climatological aridity index, defined as PET/P - # - double - vector (tc), air temperature, degrees C - # - double - scalar (mGDD0), mean temperature during growing degree days with tc>0 - # Returns: double, intrinsic quantum yield at temperature tc, mol CO2/mol photon - # Features: This function calculates the temperature and aridity dependence of the - # Intrinsic quantum Yield - # * Ref: Sandoval, Flo, Morfopoulus and Prentice - # The temperature effect on the intrinsic quantum yield at the ecosystem level - # in prep.; - # doi: - # ************************************************************************ - ############################################################################################### - # 01.define the parameters/constants - ############################################################################################### - - # DO change here to avoid imprecision in theoretical maxmimum - # phi_o_theo <- 0.111 # theoretical maximum phi0 (Long, 1993;Sandoval et al., in.prep.) - phi_o_theo <- 1 / 9 - m <- 6.8681 # curvature parameter phio max (Sandoval et al., in.prep.) - n <- 0.07956432 # curvature parameter phio max (Sandoval et al., in.prep.) - Rgas <- 8.3145 # ideal gas constant J/mol/K - Ha <- 75000 # activation energy J/mol (Sandoval et al., in.prep.) - # if mGDD0 is missing, calculate - if (is.na(mGDD0)) { - mGDD0 <- mean(tc[tc > 0], na.rm = T) - } - ## calc activation entropy, J/mol/K (Sandoval et al., in.prep.) - DeltaS <- 1558.853 - 50.223 * mGDD0 - ## calc deaactivation energy J/mol (Sandoval et al., in.prep.) - Hd <- 294.804 * DeltaS - - ############################################################################################### - # 02.define the functions - ############################################################################################### - - no_acc_f_arr <- function(tcleaf, Ha = 71513, Hd = 2e+05, dent = 649) { - ### 10.1111/nph.16883 - - ## fix for optimization - if (!is.na(Ha) & !is.na(Hd) & Ha > Hd) { - Ha <- Hd - 1 - } - - Top <- Hd / (dent - Rgas * log(Ha / (Hd - Ha))) - tkleaf <- tcleaf + 273.15 - - f1 <- (tkleaf / Top) * exp((Ha * (tkleaf - Top)) / (Top * Rgas * tkleaf)) - f2 <- 1 + exp((Top * dent - Hd) / (Top * Rgas)) - f3 <- 1 + exp((tkleaf * dent - Hd) / (tkleaf * Rgas)) - - farr <- f1 * (f2 / f3) - - return(farr) - } - ############################################################################################### - # 03.calculate maximum phi0 - ############################################################################################### - phi_o_peak <- (phi_o_theo / (1 + (AI)^m)^n) - ############################################################################################### - # 04.calculate temperature dependence of phi0 - ############################################################################################### - phi0_fT <- no_acc_f_arr(tcleaf = tc, Ha = Ha, Hd = Hd, dent = DeltaS) - ############################################################################################### - # 05.calculate phi0 - ############################################################################################### - phi0 <- phi_o_peak * phi0_fT - return(phi0) -} - - -aridity_index <- c(0.2, 0.5, 0.8, 1.0, 5.0, 10.0) -temp <- seq(0, 50, by = 1) -mean_gdd_temp <- seq(5, 30, by = 5) - -data <- expand.grid( - temp = temp, - aridity_index = aridity_index, - mean_gdd_temp = mean_gdd_temp -) - -# Function is not parallelised so loop over inputs -data$phio <- NA - -for (row_idx in seq_along(data$aridity_index)) { - data$phio[row_idx] <- with( - data[row_idx, ], - calc_phi0(AI = aridity_index, tc = temp, mGDD0 = mean_gdd_temp) - ) -} - -data$phio <- round(data$phio, digits = 8) -write.csv(data, "sandoval_kphio.csv", row.names = FALSE) +# calc_phi0 +calc_phi0 <- function(AI, tc, mGDD0 = NA, phi_o_theo = 1 / 9) { + # ************************************************************************ + # Name: calc_phi0 + # Inputs: - double - scalar (AI), climatological aridity index, defined as PET/P + # - double - vector (tc), air temperature, degrees C + # - double - scalar (mGDD0), mean temperature during growing degree days with tc>0 + # Returns: double, intrinsic quantum yield at temperature tc, mol CO2/mol photon + # Features: This function calculates the temperature and aridity dependence of the + # Intrinsic quantum Yield + # * Ref: Sandoval, Flo, Morfopoulus and Prentice + # The temperature effect on the intrinsic quantum yield at the ecosystem level + # in prep.; + # doi: + # ************************************************************************ + ############################################################################################### + # 01.define the parameters/constants + ############################################################################################### + + # DO change here to avoid imprecision in theoretical maxmimum and to allow alternatives + # phi_o_theo <- 0.111 # theoretical maximum phi0 (Long, 1993;Sandoval et al., in.prep.) + + m <- 6.8681 # curvature parameter phio max (Sandoval et al., in.prep.) + n <- 0.07956432 # curvature parameter phio max (Sandoval et al., in.prep.) + Rgas <- 8.3145 # ideal gas constant J/mol/K + Ha <- 75000 # activation energy J/mol (Sandoval et al., in.prep.) + # if mGDD0 is missing, calculate + if (is.na(mGDD0)) { + mGDD0 <- mean(tc[tc > 0], na.rm = T) + } + ## calc activation entropy, J/mol/K (Sandoval et al., in.prep.) + DeltaS <- 1558.853 - 50.223 * mGDD0 + ## calc deaactivation energy J/mol (Sandoval et al., in.prep.) + Hd <- 294.804 * DeltaS + + ############################################################################################### + # 02.define the functions + ############################################################################################### + + no_acc_f_arr <- function(tcleaf, Ha = 71513, Hd = 2e+05, dent = 649) { + ### 10.1111/nph.16883 + + ## fix for optimization + if (!is.na(Ha) & !is.na(Hd) & Ha > Hd) { + Ha <- Hd - 1 + } + + Top <- Hd / (dent - Rgas * log(Ha / (Hd - Ha))) + tkleaf <- tcleaf + 273.15 + + f1 <- (tkleaf / Top) * exp((Ha * (tkleaf - Top)) / (Top * Rgas * tkleaf)) + f2 <- 1 + exp((Top * dent - Hd) / (Top * Rgas)) + f3 <- 1 + exp((tkleaf * dent - Hd) / (tkleaf * Rgas)) + + farr <- f1 * (f2 / f3) + + return(farr) + } + ############################################################################################### + # 03.calculate maximum phi0 + ############################################################################################### + phi_o_peak <- (phi_o_theo / (1 + (AI)^m)^n) + ############################################################################################### + # 04.calculate temperature dependence of phi0 + ############################################################################################### + phi0_fT <- no_acc_f_arr(tcleaf = tc, Ha = Ha, Hd = Hd, dent = DeltaS) + ############################################################################################### + # 05.calculate phi0 + ############################################################################################### + phi0 <- phi_o_peak * phi0_fT + return(phi0) +} diff --git a/pyrealm_build_data/sandoval_kphio/create_test_inputs.R b/pyrealm_build_data/sandoval_kphio/create_test_inputs.R new file mode 100644 index 00000000..79adb1a7 --- /dev/null +++ b/pyrealm_build_data/sandoval_kphio/create_test_inputs.R @@ -0,0 +1,24 @@ +source("calc_phi0.R") + +aridity_index <- c(0.2, 0.5, 0.8, 1.0, 5.0, 10.0) +temp <- seq(0, 50, by = 1) +mean_gdd_temp <- seq(5, 30, by = 5) + +data <- expand.grid( + temp = temp, + aridity_index = aridity_index, + mean_gdd_temp = mean_gdd_temp +) + +# Function is not parallelised so loop over inputs +data$phio <- NA + +for (row_idx in seq_along(data$aridity_index)) { + data$phio[row_idx] <- with( + data[row_idx, ], + calc_phi0(AI = aridity_index, tc = temp, mGDD0 = mean_gdd_temp) + ) +} + +data$phio <- round(data$phio, digits = 8) +write.csv(data, "sandoval_kphio.csv", row.names = FALSE) diff --git a/tests/unit/pmodel/test_quantum_yield.py b/tests/unit/pmodel/test_quantum_yield.py new file mode 100644 index 00000000..ece4682e --- /dev/null +++ b/tests/unit/pmodel/test_quantum_yield.py @@ -0,0 +1,147 @@ +"""Test the quantum yield implementations.""" + +import numpy as np +import pytest + + +@pytest.fixture +def quantum_yield_env(): + """Simple fixture for providing the quantum yield inputs.""" + from pyrealm.pmodel import PModelEnvironment + + return PModelEnvironment( + tc=np.array([5, 10, 15, 20, 25, 30]), + patm=101325, + vpd=820, + co2=400, + mean_growth_temperature=np.array([10, 20, 10, 20, 10, 20]), + aridity_index=np.array([0.9, 0.9, 2, 2, 5, 5]), + ) + + +@pytest.mark.parametrize( + argnames="reference_kphio, expected_kphio", + argvalues=( + pytest.param(None, 0.049977, id="default"), + pytest.param(0.1, 0.1, id="provided"), + ), +) +def test_QuantumYieldConstant(quantum_yield_env, reference_kphio, expected_kphio): + """Test the constant method.""" + + from pyrealm.pmodel.quantum_yield import QuantumYieldConstant + + qy = QuantumYieldConstant( + env=quantum_yield_env, + reference_kphio=reference_kphio, + ) + + # Should be a scalar + assert np.allclose(qy.kphio, np.array([expected_kphio])) + + +@pytest.mark.parametrize( + argnames="reference_kphio, expected_kphio_factor", + argvalues=( + pytest.param( + None, np.array([0.4535, 0.538, 0.6055, 0.656, 0.6895, 0.706]), id="default" + ), + pytest.param( + 0.1, np.array([0.4535, 0.538, 0.6055, 0.656, 0.6895, 0.706]), id="provided" + ), + ), +) +def test_QuantumYieldBernacchiC3( + quantum_yield_env, reference_kphio, expected_kphio_factor +): + """Test the Bernacchi temperature method for C3 plants.""" + + from pyrealm.pmodel.quantum_yield import QuantumYieldBernacchiC3 + + qy = QuantumYieldBernacchiC3( + env=quantum_yield_env, + reference_kphio=reference_kphio, + ) + + # The expected_kphio_factor values are the output of the previous implementation + # (calc_ftemp_kphio), which returned the temperature factors that then needed + # multiplying by the reference kphio. + assert np.allclose(qy.kphio, qy.reference_kphio * expected_kphio_factor) + + +@pytest.mark.parametrize( + argnames="reference_kphio, expected_kphio_factor", + argvalues=( + pytest.param( + None, + np.array([0.0744, 0.1896, 0.2816, 0.3504, 0.396, 0.4184]), + id="default", + ), + pytest.param( + 0.1, + np.array([0.0744, 0.1896, 0.2816, 0.3504, 0.396, 0.4184]), + id="provided", + ), + ), +) +def test_QuantumYieldBernacchiC4( + quantum_yield_env, reference_kphio, expected_kphio_factor +): + """Test the Bernacchi temperature method for C4 plants.""" + + from pyrealm.pmodel.quantum_yield import QuantumYieldBernacchiC4 + + qy = QuantumYieldBernacchiC4( + env=quantum_yield_env, + reference_kphio=reference_kphio, + ) + + # The expected_kphio_factor values are the output of the previous implementation + # (calc_ftemp_kphio), which returned the temperature factors that then needed + # multiplying by the reference kphio. + assert np.allclose(qy.kphio, qy.reference_kphio * expected_kphio_factor) + + +@pytest.mark.parametrize( + argnames="reference_kphio, expected_kphio", + argvalues=( + pytest.param( + None, + np.array( + [0.02848466, 0.05510828, 0.06099888, 0.07537036, 0.02231382, 0.03026185] + ), + id="default", + ), + pytest.param( + 1 / 8, + np.array( + [0.03204524, 0.06199681, 0.06862374, 0.08479165, 0.02510305, 0.03404458] + ), + id="provided", + ), + ), +) +def test_QuantumYieldSandoval(quantum_yield_env, reference_kphio, expected_kphio): + """Test the Sandoval temperature and aridity method. + + The test values here have been calculated using the original R implementation + provided in pyrealm_build_data/sandoval_kphio/calc_phi0.R. A more complete check + across a wider range of values is provided in the regression tests but this also + tests the provisision of alternative reference_kphio. + + > source('calc_phi0.R') + > tc <- c(5, 10, 15, 20, 25, 30) + > ai <- c(0.9, 0.9, 2, 2, 5, 5) + > gdd0 <- c(10, 20, 10, 20, 10, 20) + > round(mapply(calc_phi0, ai, tc, gdd0), 5) + > round(mapply(calc_phi0, ai, tc, gdd0, MoreArgs=list(phi_o_theo=1/8)), 5) + """ + + from pyrealm.pmodel.quantum_yield import QuantumYieldSandoval + + qy = QuantumYieldSandoval( + env=quantum_yield_env, + reference_kphio=reference_kphio, + ) + + assert np.allclose(qy.kphio, expected_kphio) From 8dd18bac81641e5c223dd32d829d9f0edea0b554 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 31 Jul 2024 17:53:10 +0100 Subject: [PATCH 026/241] Added use of QuantumYield registry to tests --- tests/unit/pmodel/test_quantum_yield.py | 51 +++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/tests/unit/pmodel/test_quantum_yield.py b/tests/unit/pmodel/test_quantum_yield.py index ece4682e..165d6d3f 100644 --- a/tests/unit/pmodel/test_quantum_yield.py +++ b/tests/unit/pmodel/test_quantum_yield.py @@ -29,7 +29,10 @@ def quantum_yield_env(): def test_QuantumYieldConstant(quantum_yield_env, reference_kphio, expected_kphio): """Test the constant method.""" - from pyrealm.pmodel.quantum_yield import QuantumYieldConstant + from pyrealm.pmodel.quantum_yield import ( + QUANTUM_YIELD_CLASS_REGISTRY, + QuantumYieldConstant, + ) qy = QuantumYieldConstant( env=quantum_yield_env, @@ -39,6 +42,13 @@ def test_QuantumYieldConstant(quantum_yield_env, reference_kphio, expected_kphio # Should be a scalar assert np.allclose(qy.kphio, np.array([expected_kphio])) + qy2 = QUANTUM_YIELD_CLASS_REGISTRY["constant"]( + env=quantum_yield_env, + reference_kphio=reference_kphio, + ) + + assert np.allclose(qy2.kphio, np.array([expected_kphio])) + @pytest.mark.parametrize( argnames="reference_kphio, expected_kphio_factor", @@ -56,7 +66,10 @@ def test_QuantumYieldBernacchiC3( ): """Test the Bernacchi temperature method for C3 plants.""" - from pyrealm.pmodel.quantum_yield import QuantumYieldBernacchiC3 + from pyrealm.pmodel.quantum_yield import ( + QUANTUM_YIELD_CLASS_REGISTRY, + QuantumYieldBernacchiC3, + ) qy = QuantumYieldBernacchiC3( env=quantum_yield_env, @@ -68,6 +81,13 @@ def test_QuantumYieldBernacchiC3( # multiplying by the reference kphio. assert np.allclose(qy.kphio, qy.reference_kphio * expected_kphio_factor) + qy2 = QUANTUM_YIELD_CLASS_REGISTRY["bernacchi_c3"]( + env=quantum_yield_env, + reference_kphio=reference_kphio, + ) + + assert np.allclose(qy2.kphio, qy2.reference_kphio * expected_kphio_factor) + @pytest.mark.parametrize( argnames="reference_kphio, expected_kphio_factor", @@ -89,7 +109,10 @@ def test_QuantumYieldBernacchiC4( ): """Test the Bernacchi temperature method for C4 plants.""" - from pyrealm.pmodel.quantum_yield import QuantumYieldBernacchiC4 + from pyrealm.pmodel.quantum_yield import ( + QUANTUM_YIELD_CLASS_REGISTRY, + QuantumYieldBernacchiC4, + ) qy = QuantumYieldBernacchiC4( env=quantum_yield_env, @@ -101,6 +124,16 @@ def test_QuantumYieldBernacchiC4( # multiplying by the reference kphio. assert np.allclose(qy.kphio, qy.reference_kphio * expected_kphio_factor) + qy2 = QUANTUM_YIELD_CLASS_REGISTRY["bernacchi_c4"]( + env=quantum_yield_env, + reference_kphio=reference_kphio, + ) + + # The expected_kphio_factor values are the output of the previous implementation + # (calc_ftemp_kphio), which returned the temperature factors that then needed + # multiplying by the reference kphio. + assert np.allclose(qy2.kphio, qy2.reference_kphio * expected_kphio_factor) + @pytest.mark.parametrize( argnames="reference_kphio, expected_kphio", @@ -137,7 +170,10 @@ def test_QuantumYieldSandoval(quantum_yield_env, reference_kphio, expected_kphio > round(mapply(calc_phi0, ai, tc, gdd0, MoreArgs=list(phi_o_theo=1/8)), 5) """ - from pyrealm.pmodel.quantum_yield import QuantumYieldSandoval + from pyrealm.pmodel.quantum_yield import ( + QUANTUM_YIELD_CLASS_REGISTRY, + QuantumYieldSandoval, + ) qy = QuantumYieldSandoval( env=quantum_yield_env, @@ -145,3 +181,10 @@ def test_QuantumYieldSandoval(quantum_yield_env, reference_kphio, expected_kphio ) assert np.allclose(qy.kphio, expected_kphio) + + qy2 = QUANTUM_YIELD_CLASS_REGISTRY["sandoval"]( + env=quantum_yield_env, + reference_kphio=reference_kphio, + ) + + assert np.allclose(qy2.kphio, expected_kphio) From 14a9c86e52d24e3eb15a58ccaec0f1ef4721ce46 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 31 Jul 2024 18:49:33 +0100 Subject: [PATCH 027/241] Use QuantumYieldABC implementation in PModel ! SubdailyPModel not implemented --- pyrealm/pmodel/pmodel.py | 97 ++++++++++---------------- pyrealm/pmodel/quantum_yield.py | 8 ++- tests/regression/pmodel/test_pmodel.py | 43 ++++++++---- 3 files changed, 70 insertions(+), 78 deletions(-) diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index 4498b2c1..2971c4f2 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -20,25 +20,7 @@ from pyrealm.pmodel.jmax_limitation import JmaxLimitation from pyrealm.pmodel.optimal_chi import OPTIMAL_CHI_CLASS_REGISTRY, OptimalChiABC from pyrealm.pmodel.pmodel_environment import PModelEnvironment - -# Design notes on PModel (0.3.1 -> 0.4.0) -# The PModel until 0.3.1 was a single class taking tc etc. as inputs. However -# a common use case would be to look at how the PModel predictions change with -# different options. I (DO) did consider retaining the single class and having -# PModel __init__ create the environment and then have PModel.fit(), but -# having two classes seemed to better separate the physiological model (PModel -# class and attributes) from the environment the model is being fitted to and -# also creates _separate_ PModel objects. - -# Design notes on PModel (0.4.0 -> 0.5.0) -# In separating PPFD and FAPAR into a second step, I had created the IabsScaled -# class to store variables that scale linearly with Iabs. That class held and -# exposed scaled and unscaled versions of several parameteres. For a start, that -# was a bad class name since the values could be unscaled, but also most of the -# unscaled versions are never really used. Really (hat tip, Keith Bloomfield), -# there are two meaningful _efficiency_ variables (LUE, IWUE) and then a set of -# productivity variables. The new structure reflects that, removing the -# un-needed unscaled variables and simplifying the structure. +from pyrealm.pmodel.quantum_yield import QUANTUM_YIELD_CLASS_REGISTRY, QuantumYieldABC class PModel: @@ -141,20 +123,20 @@ class PModel: Args: env: An instance of - :class:`~pyrealm.pmodel.pmodel_environment.PModelEnvironment` - kphio: (Optional) The quantum yield efficiency of photosynthesis - (:math:`\phi_0`, unitless). Note that :math:`\phi_0` is sometimes used to - refer to the quantum yield of electron transfer, which is exactly four times - larger, so check definitions here. + :class:`~pyrealm.pmodel.pmodel_environment.PModelEnvironment` + method_kphio: The method to use for calculating the quantum yield + efficiency of photosynthesis (:math:`\phi_0`, unitless). The method name + must be included in the + :data:`~pyrealm.pmodel.quantum_yield.QUANTUM_YIELD_CLASS_REGISTRY`. method_optchi: (Optional, default=`prentice14`) Selects the method to be used for calculating optimal :math:`chi`. The choice of method also sets the choice of C3 or C4 photosynthetic pathway (see :class:`~pyrealm.pmodel.optimal_chi.OptimalChiABC`). method_jmaxlim: (Optional, default=`wang17`) Method to use for - :math:`J_{max}` limitation - do_ftemp_kphio: (Optional, default=True) Include the temperature- - dependence of quantum yield efficiency (see - :func:`~pyrealm.pmodel.functions.calc_ftemp_kphio`). + :math:`J_{max}` limitation. + reference_kphio: An optional alternative reference value to be passed to the + kphio calculation method. + Examples: >>> import numpy as np @@ -186,10 +168,10 @@ class PModel: def __init__( self, env: PModelEnvironment, - kphio: float | None = None, - do_ftemp_kphio: bool = True, + method_kphio: str = "bernacchi_c3", method_optchi: str = "prentice14", method_jmaxlim: str = "wang17", + reference_kphio: float | None = None, ): self.shape: tuple = env.shape """Records the common numpy array shape of array inputs.""" @@ -204,23 +186,6 @@ def __init__( self.core_const: CoreConst = env.core_const """The CoreConst instance used to create the model environment.""" - # kphio calculation: - self.init_kphio: float - r"""The initial value of :math:`\phi_0` (``kphio``)""" - self.kphio: NDArray - r"""The value of :math:`\phi_0` used with any temperature correction applied.""" - self.do_ftemp_kphio: bool = do_ftemp_kphio - r"""Records if :math:`\phi_0` (``kphio``) is temperature corrected.""" - - # Set context specific defaults for kphio to match Stocker paper - if kphio is None: - if not self.do_ftemp_kphio: - self.init_kphio = 0.049977 - else: - self.init_kphio = 0.081785 - else: - self.init_kphio = kphio - # ----------------------------------------------------------------------- # Optimal ci # The heart of the P-model: calculate ci:ca ratio (chi) and additional terms @@ -243,15 +208,22 @@ def __init__( """Does the OptimalChi method approximate a C3 or C4 pathway.""" # ----------------------------------------------------------------------- - # Temperature dependence of quantum yield efficiency + # Calculate the quantum yield of photosynthesis (kphio) # ----------------------------------------------------------------------- - if self.do_ftemp_kphio: - ftemp_kphio = calc_ftemp_kphio( - env.tc, self.c4, pmodel_const=self.pmodel_const - ) - self.kphio = self.init_kphio * ftemp_kphio - else: - self.kphio = np.array([self.init_kphio]) + self.method_kphio: str = method_kphio + try: + kphio_class = QUANTUM_YIELD_CLASS_REGISTRY[method_kphio] + except KeyError: + raise ValueError(f"Unknown kphio calculation method: {method_kphio}") + + self.kphio: QuantumYieldABC = kphio_class( + env=env, + pmodel_const=self.pmodel_const, + core_const=self.core_const, + reference_kphio=reference_kphio, + ) + """A subclass of QuantumYieldABC, implementing the requested kphio calculation + method.""" # ----------------------------------------------------------------------- # Calculation of Jmax limitation terms @@ -263,6 +235,7 @@ def __init__( self.optchi, method=self.method_jmaxlim, pmodel_const=self.pmodel_const ) """Details of the Jmax limitation calculation for the model""" + # ----------------------------------------------------------------------- # Store the two efficiency predictions # ----------------------------------------------------------------------- @@ -279,7 +252,10 @@ def __init__( # The basic calculation of LUE = phi0 * M_c * m with an added penalty term # for jmax limitation self.lue: NDArray = ( - self.kphio * self.optchi.mj * self.jmaxlim.f_v * self.core_const.k_c_molmass + self.kphio.kphio + * self.optchi.mj + * self.jmaxlim.f_v + * self.core_const.k_c_molmass ) """Light use efficiency (LUE, g C mol-1)""" @@ -401,7 +377,7 @@ def estimate_productivity( self._gpp = self.lue * iabs # V_cmax - self._vcmax = self.kphio * iabs * self.optchi.mjoc * self.jmaxlim.f_v + self._vcmax = self.kphio.kphio * iabs * self.optchi.mjoc * self.jmaxlim.f_v # V_cmax25 (vcmax normalized to const.k_To) ftemp25_inst_vcmax = calc_ftemp_inst_vcmax( @@ -418,10 +394,10 @@ def estimate_productivity( ) # Calculate Jmax - self._jmax = 4 * self.kphio * iabs * self.jmaxlim.f_j + self._jmax = 4 * self.kphio.kphio * iabs * self.jmaxlim.f_j # AJ and AC - a_j = self.kphio * iabs * self.optchi.mj * self.jmaxlim.f_v + a_j = self.kphio.kphio * iabs * self.optchi.mj * self.jmaxlim.f_v a_c = self._vcmax * self.optchi.mc assim = np.minimum(a_j, a_c) @@ -448,11 +424,10 @@ def __repr__(self) -> str: return ( f"PModel(" f"shape={self.shape}, " - f"initial kphio={self.init_kphio}, " - f"ftemp_kphio={self.do_ftemp_kphio}, " f"method_optchi={self.method_optchi}, " f"c4={self.c4}, " f"method_jmaxlim={self.method_jmaxlim}, " + f"method_kphio={self.method_kphio}, " ) def summarize(self, dp: int = 2) -> None: diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index 41895561..6a108209 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -1,7 +1,9 @@ r"""The module :mod:`~pyrealm.pmodel.quantum_yield` provides -the abstract base class :class:`~pyrealm.pmodel.quantum_yield.QuantumYieldABC`, -which is used to support different implementations of the calculation of the intrinsic -quantum yield of photosynthesis. +the abstract base class :class:`~pyrealm.pmodel.quantum_yield.QuantumYieldABC`, which is +used to support different implementations of the calculation of the intrinsic quantum +yield efficiency of photosynthesis (:math:`\phi_0`, unitless). Note that :math:`\phi_0` +is sometimes used to refer to the quantum yield of electron transfer, which is exactly +four times larger, so check definitions here. """ # noqa D210, D415 from __future__ import annotations diff --git a/tests/regression/pmodel/test_pmodel.py b/tests/regression/pmodel/test_pmodel.py index e07db945..e46c1386 100644 --- a/tests/regression/pmodel/test_pmodel.py +++ b/tests/regression/pmodel/test_pmodel.py @@ -602,13 +602,15 @@ def pmodelenv(values): @pytest.mark.parametrize("soilmstress", [False, True], ids=["sm-off", "sm-on"]) -@pytest.mark.parametrize("ftemp_kphio", [True, False], ids=["fkphio-on", "fkphio-off"]) +@pytest.mark.parametrize( + "method_kphio", ["bernacchi_c3", "constant"], ids=["fkphio-on", "fkphio-off"] +) @pytest.mark.parametrize( "luevcmax_method", ["wang17", "smith19", "none"], ids=["wang17", "smith19", "none"] ) @pytest.mark.parametrize("environ", ["sc", "ar"], ids=["sc", "ar"]) def test_pmodel_class_c3( - request, values, pmodelenv, soilmstress, ftemp_kphio, luevcmax_method, environ + request, values, pmodelenv, soilmstress, method_kphio, luevcmax_method, environ ): """Test the PModel class for C3 plants.""" @@ -625,9 +627,9 @@ def test_pmodel_class_c3( ret = PModel( pmodelenv[environ], - kphio=0.05, - do_ftemp_kphio=ftemp_kphio, + method_kphio=method_kphio, method_jmaxlim=luevcmax_method, + reference_kphio=0.05, ) # Estimate productivity @@ -704,12 +706,21 @@ def test_pmodel_class_c3( @pytest.mark.parametrize("soilmstress", [False, True], ids=["sm-off", "sm-on"]) -@pytest.mark.parametrize("ftemp_kphio", [True, False], ids=["fkphio-on", "fkphio-off"]) +@pytest.mark.parametrize( + "method_kphio", ["bernacchi_c4", "constant"], ids=["fkphio-on", "fkphio-off"] +) @pytest.mark.parametrize("environ", ["sc", "ar"], ids=["sc", "ar"]) -def test_pmodel_class_c4(request, values, pmodelenv, soilmstress, ftemp_kphio, environ): +def test_pmodel_class_c4( + request, values, pmodelenv, soilmstress, method_kphio, environ +): """Test the PModel class for C4 plants.""" - from pyrealm.pmodel import PModel, calc_ftemp_kphio, calc_soilmstress_stocker + from pyrealm.pmodel import ( + PModel, + PModelEnvironment, + calc_soilmstress_stocker, + ) + from pyrealm.pmodel.quantum_yield import QuantumYieldBernacchiC4 if soilmstress: soilmstress = calc_soilmstress_stocker( @@ -718,19 +729,23 @@ def test_pmodel_class_c4(request, values, pmodelenv, soilmstress, ftemp_kphio, e else: soilmstress = np.array([1.0]) - # TODO bug in rpmodel 1.2.2 forces an odd downscaling of kphio when - # do_ftemp_kphio is False, so this is scaling back up to match. - if ftemp_kphio: + # TODO bug in rpmodel 1.2.2 forces an odd downscaling of kphio when do_ftemp_kphio + # is False, so the kf factor is calculated to scale the reference kphio back up to + # match. + + if method_kphio == "bernacchi_c4": kf = 1 else: - kf = calc_ftemp_kphio(15, c4=True) + bug_env = PModelEnvironment(tc=15, patm=101325, vpd=800, co2=400) + correction = QuantumYieldBernacchiC4(env=bug_env, reference_kphio=0.05) + kf = correction.kphio / 0.05 ret = PModel( pmodelenv[environ], - kphio=0.05 * kf, # See note above - do_ftemp_kphio=ftemp_kphio, + method_kphio=method_kphio, method_jmaxlim="simple", # enforced in rpmodel. method_optchi="c4", + reference_kphio=0.05 * kf, # See note above ) # Estimate productivity @@ -797,7 +812,7 @@ def test_pmodel_summarise(capsys, values, pmodelenv): from pyrealm.pmodel import PModel - ret = PModel(pmodelenv["sc"], kphio=0.05) + ret = PModel(pmodelenv["sc"], reference_kphio=0.05) # Test what comes back before estimate_productivity ret.summarize() From 39cb8322e1538b10526a940bc93d27862d6d0207 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 31 Jul 2024 18:49:38 +0100 Subject: [PATCH 028/241] Use QuantumYieldABC implementation in PModel ! SubdailyPModel not implemented --- pyrealm/pmodel/pmodel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index 2971c4f2..87d080d6 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -15,7 +15,6 @@ from pyrealm.pmodel.functions import ( calc_ftemp_inst_rd, calc_ftemp_inst_vcmax, - calc_ftemp_kphio, ) from pyrealm.pmodel.jmax_limitation import JmaxLimitation from pyrealm.pmodel.optimal_chi import OPTIMAL_CHI_CLASS_REGISTRY, OptimalChiABC From a81d0fe71c9cedda05b90cdeb1cbf2b6fc2585e4 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 31 Jul 2024 21:16:29 +0100 Subject: [PATCH 029/241] Moving C3/C4 handling within different kphio approaches ! Subdaily still not updated --- pyrealm/pmodel/pmodel.py | 3 +- pyrealm/pmodel/quantum_yield.py | 42 +++++---------- tests/regression/pmodel/test_pmodel.py | 12 +++-- tests/unit/pmodel/test_quantum_yield.py | 72 ++++++++----------------- 4 files changed, 43 insertions(+), 86 deletions(-) diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index 87d080d6..bcbb965d 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -167,7 +167,7 @@ class PModel: def __init__( self, env: PModelEnvironment, - method_kphio: str = "bernacchi_c3", + method_kphio: str = "temperature", method_optchi: str = "prentice14", method_jmaxlim: str = "wang17", reference_kphio: float | None = None, @@ -217,6 +217,7 @@ def __init__( self.kphio: QuantumYieldABC = kphio_class( env=env, + use_c4=self.c4, pmodel_const=self.pmodel_const, core_const=self.core_const, reference_kphio=reference_kphio, diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index 6a108209..a18da211 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -68,8 +68,6 @@ class QuantumYieldABC(ABC): """A short method name used to identify the class in :data:`~pyrealm.pmodel.quantum_yield.QUANTUM_YIELD_CLASS_REGISTRY`. """ - is_c4: bool - """A flag indicating if the method captures the C4 photosynthetic pathway.""" requires: list[str] """A list of names of optional attributes of :class:`~pyrealm.pmodel.pmodel_environment.PModelEnvironment` that must be populated @@ -83,6 +81,7 @@ def __init__( self, env: PModelEnvironment, reference_kphio: float | None = None, + use_c4: bool = False, pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), ): @@ -97,6 +96,8 @@ def __init__( """The CoreConst used for calculating quantum yield""" self.reference_kphio: float = reference_kphio or self.default_reference_kphio """The reference value for kphio for the method.""" + self.use_c4: bool = use_c4 + """Use a C4 parameterisation if available.""" # Declare attributes populated by methods. These are typed but not assigned a # default value as they must are populated by the subclass specific @@ -147,14 +148,12 @@ def summarize(self, dp: int = 2) -> None: def __init_subclass__( cls, method: str, - is_c4: bool, requires: list[str], default_reference_kphio: float, ) -> None: """Initialise a subclass deriving from this ABC.""" cls.method = method - cls.is_c4 = is_c4 cls.requires = requires cls.default_reference_kphio = default_reference_kphio QUANTUM_YIELD_CLASS_REGISTRY[cls.method] = cls @@ -163,7 +162,6 @@ def __init_subclass__( class QuantumYieldConstant( QuantumYieldABC, method="constant", - is_c4=False, requires=[], default_reference_kphio=0.049977, ): @@ -175,48 +173,34 @@ def _calculate_kphio(self) -> None: self.kphio = np.array([self.reference_kphio]) -class QuantumYieldBernacchiC3( +class QuantumYieldTemperature( QuantumYieldABC, - method="bernacchi_c3", - is_c4=False, + method="temperature", requires=[], default_reference_kphio=0.081785, ): - """Calculate kphio following Bernacchi for C3 plants.""" + """Calculate temperature modulated kphio. + + This method follows for C3 plants. + """ def _calculate_kphio( self, ) -> None: """Calculate kphio.""" - ftemp = evaluate_horner_polynomial(self.env.tc, self.pmodel_const.kphio_C3) - ftemp = np.clip(ftemp, 0.0, None) - - self.kphio = ftemp * self.reference_kphio - + if self.use_c4: + ftemp = evaluate_horner_polynomial(self.env.tc, self.pmodel_const.kphio_C4) + else: + ftemp = evaluate_horner_polynomial(self.env.tc, self.pmodel_const.kphio_C3) -class QuantumYieldBernacchiC4( - QuantumYieldABC, - method="bernacchi_c4", - is_c4=True, - requires=[], - default_reference_kphio=0.081785, -): - """Calculate kphio following Bernacchi.""" - - def _calculate_kphio(self) -> None: - """Calculate kphio.""" - - ftemp = evaluate_horner_polynomial(self.env.tc, self.pmodel_const.kphio_C4) ftemp = np.clip(ftemp, 0.0, None) - self.kphio = ftemp * self.reference_kphio class QuantumYieldSandoval( QuantumYieldABC, method="sandoval", - is_c4=False, requires=["aridity_index", "mean_growth_temperature"], default_reference_kphio=1.0 / 9.0, ): diff --git a/tests/regression/pmodel/test_pmodel.py b/tests/regression/pmodel/test_pmodel.py index e46c1386..3a377c58 100644 --- a/tests/regression/pmodel/test_pmodel.py +++ b/tests/regression/pmodel/test_pmodel.py @@ -603,7 +603,7 @@ def pmodelenv(values): @pytest.mark.parametrize("soilmstress", [False, True], ids=["sm-off", "sm-on"]) @pytest.mark.parametrize( - "method_kphio", ["bernacchi_c3", "constant"], ids=["fkphio-on", "fkphio-off"] + "method_kphio", ["temperature", "constant"], ids=["fkphio-on", "fkphio-off"] ) @pytest.mark.parametrize( "luevcmax_method", ["wang17", "smith19", "none"], ids=["wang17", "smith19", "none"] @@ -707,7 +707,7 @@ def test_pmodel_class_c3( @pytest.mark.parametrize("soilmstress", [False, True], ids=["sm-off", "sm-on"]) @pytest.mark.parametrize( - "method_kphio", ["bernacchi_c4", "constant"], ids=["fkphio-on", "fkphio-off"] + "method_kphio", ["temperature", "constant"], ids=["fkphio-on", "fkphio-off"] ) @pytest.mark.parametrize("environ", ["sc", "ar"], ids=["sc", "ar"]) def test_pmodel_class_c4( @@ -720,7 +720,7 @@ def test_pmodel_class_c4( PModelEnvironment, calc_soilmstress_stocker, ) - from pyrealm.pmodel.quantum_yield import QuantumYieldBernacchiC4 + from pyrealm.pmodel.quantum_yield import QuantumYieldTemperature if soilmstress: soilmstress = calc_soilmstress_stocker( @@ -733,11 +733,13 @@ def test_pmodel_class_c4( # is False, so the kf factor is calculated to scale the reference kphio back up to # match. - if method_kphio == "bernacchi_c4": + if method_kphio == "temperature": kf = 1 else: bug_env = PModelEnvironment(tc=15, patm=101325, vpd=800, co2=400) - correction = QuantumYieldBernacchiC4(env=bug_env, reference_kphio=0.05) + correction = QuantumYieldTemperature( + env=bug_env, reference_kphio=0.05, use_c4=True + ) kf = correction.kphio / 0.05 ret = PModel( diff --git a/tests/unit/pmodel/test_quantum_yield.py b/tests/unit/pmodel/test_quantum_yield.py index 165d6d3f..aaf8e204 100644 --- a/tests/unit/pmodel/test_quantum_yield.py +++ b/tests/unit/pmodel/test_quantum_yield.py @@ -51,72 +51,46 @@ def test_QuantumYieldConstant(quantum_yield_env, reference_kphio, expected_kphio @pytest.mark.parametrize( - argnames="reference_kphio, expected_kphio_factor", + argnames="use_c4, reference_kphio, expected_kphio_factor", argvalues=( pytest.param( - None, np.array([0.4535, 0.538, 0.6055, 0.656, 0.6895, 0.706]), id="default" + False, + None, + np.array([0.4535, 0.538, 0.6055, 0.656, 0.6895, 0.706]), + id="default_c3", ), pytest.param( - 0.1, np.array([0.4535, 0.538, 0.6055, 0.656, 0.6895, 0.706]), id="provided" + False, + 0.1, + np.array([0.4535, 0.538, 0.6055, 0.656, 0.6895, 0.706]), + id="provided_c3", ), - ), -) -def test_QuantumYieldBernacchiC3( - quantum_yield_env, reference_kphio, expected_kphio_factor -): - """Test the Bernacchi temperature method for C3 plants.""" - - from pyrealm.pmodel.quantum_yield import ( - QUANTUM_YIELD_CLASS_REGISTRY, - QuantumYieldBernacchiC3, - ) - - qy = QuantumYieldBernacchiC3( - env=quantum_yield_env, - reference_kphio=reference_kphio, - ) - - # The expected_kphio_factor values are the output of the previous implementation - # (calc_ftemp_kphio), which returned the temperature factors that then needed - # multiplying by the reference kphio. - assert np.allclose(qy.kphio, qy.reference_kphio * expected_kphio_factor) - - qy2 = QUANTUM_YIELD_CLASS_REGISTRY["bernacchi_c3"]( - env=quantum_yield_env, - reference_kphio=reference_kphio, - ) - - assert np.allclose(qy2.kphio, qy2.reference_kphio * expected_kphio_factor) - - -@pytest.mark.parametrize( - argnames="reference_kphio, expected_kphio_factor", - argvalues=( pytest.param( + True, None, np.array([0.0744, 0.1896, 0.2816, 0.3504, 0.396, 0.4184]), - id="default", + id="default_c4", ), pytest.param( + True, 0.1, np.array([0.0744, 0.1896, 0.2816, 0.3504, 0.396, 0.4184]), - id="provided", + id="provided_c4", ), ), ) -def test_QuantumYieldBernacchiC4( - quantum_yield_env, reference_kphio, expected_kphio_factor +def test_QuantumYieldTemperature( + quantum_yield_env, use_c4, reference_kphio, expected_kphio_factor ): - """Test the Bernacchi temperature method for C4 plants.""" + """Test the temperature kphio method.""" from pyrealm.pmodel.quantum_yield import ( QUANTUM_YIELD_CLASS_REGISTRY, - QuantumYieldBernacchiC4, + QuantumYieldTemperature, ) - qy = QuantumYieldBernacchiC4( - env=quantum_yield_env, - reference_kphio=reference_kphio, + qy = QuantumYieldTemperature( + env=quantum_yield_env, reference_kphio=reference_kphio, use_c4=use_c4 ) # The expected_kphio_factor values are the output of the previous implementation @@ -124,14 +98,10 @@ def test_QuantumYieldBernacchiC4( # multiplying by the reference kphio. assert np.allclose(qy.kphio, qy.reference_kphio * expected_kphio_factor) - qy2 = QUANTUM_YIELD_CLASS_REGISTRY["bernacchi_c4"]( - env=quantum_yield_env, - reference_kphio=reference_kphio, + qy2 = QUANTUM_YIELD_CLASS_REGISTRY["temperature"]( + env=quantum_yield_env, reference_kphio=reference_kphio, use_c4=use_c4 ) - # The expected_kphio_factor values are the output of the previous implementation - # (calc_ftemp_kphio), which returned the temperature factors that then needed - # multiplying by the reference kphio. assert np.allclose(qy2.kphio, qy2.reference_kphio * expected_kphio_factor) From 84a1d67d848ae8d10dd10426f8f9a41d947a4e2a Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 1 Aug 2024 11:01:00 +0100 Subject: [PATCH 030/241] QuantumYield should inherit constants from PModelEnvironment, not directlyas an argument ! Subdaily still not updated --- pyrealm/pmodel/pmodel.py | 34 ++++++++++++++++----------------- pyrealm/pmodel/quantum_yield.py | 23 ++++++++++------------ 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index bcbb965d..561efe96 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -133,8 +133,10 @@ class PModel: :class:`~pyrealm.pmodel.optimal_chi.OptimalChiABC`). method_jmaxlim: (Optional, default=`wang17`) Method to use for :math:`J_{max}` limitation. - reference_kphio: An optional alternative reference value to be passed to the - kphio calculation method. + reference_kphio: An optional alternative reference value for the quantum yield + efficiency of photosynthesis (:math:`\phi_0`, -) to be passed to the kphio + calculation method. + Examples: @@ -189,19 +191,18 @@ def __init__( # Optimal ci # The heart of the P-model: calculate ci:ca ratio (chi) and additional terms # ----------------------------------------------------------------------- - self.method_optchi: str = method_optchi - """Records the method used to calculate optimal chi.""" - try: - opt_chi_class = OPTIMAL_CHI_CLASS_REGISTRY[method_optchi] - except KeyError: + if method_optchi not in OPTIMAL_CHI_CLASS_REGISTRY: raise ValueError(f"Unknown optimal chi estimation method: {method_optchi}") - self.optchi: OptimalChiABC = opt_chi_class( + self.method_optchi: str = method_optchi + """The method used to calculate optimal chi.""" + + self.optchi: OptimalChiABC = OPTIMAL_CHI_CLASS_REGISTRY[method_optchi]( env=env, pmodel_const=self.pmodel_const, ) - """An subclass OptimalChi, implementing the requested chi calculation method""" + """A subclass of OptimalChiABC, providing optimal chi calculation.""" self.c4: bool = self.optchi.is_c4 """Does the OptimalChi method approximate a C3 or C4 pathway.""" @@ -209,21 +210,18 @@ def __init__( # ----------------------------------------------------------------------- # Calculate the quantum yield of photosynthesis (kphio) # ----------------------------------------------------------------------- - self.method_kphio: str = method_kphio - try: - kphio_class = QUANTUM_YIELD_CLASS_REGISTRY[method_kphio] - except KeyError: + if method_kphio not in QUANTUM_YIELD_CLASS_REGISTRY: raise ValueError(f"Unknown kphio calculation method: {method_kphio}") - self.kphio: QuantumYieldABC = kphio_class( + self.method_kphio: str = method_kphio + """The method used to calculate kphio.""" + + self.kphio: QuantumYieldABC = QUANTUM_YIELD_CLASS_REGISTRY[method_kphio]( env=env, use_c4=self.c4, - pmodel_const=self.pmodel_const, - core_const=self.core_const, reference_kphio=reference_kphio, ) - """A subclass of QuantumYieldABC, implementing the requested kphio calculation - method.""" + """A subclass of QuantumYieldABC, providing kphio calculation.""" # ----------------------------------------------------------------------- # Calculation of Jmax limitation terms diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index a18da211..0f076d99 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -15,7 +15,6 @@ from numpy.typing import NDArray from pyrealm import ExperimentalFeatureWarning -from pyrealm.constants import CoreConst, PModelConst from pyrealm.core.utilities import ( check_input_shapes, evaluate_horner_polynomial, @@ -82,18 +81,12 @@ def __init__( env: PModelEnvironment, reference_kphio: float | None = None, use_c4: bool = False, - pmodel_const: PModelConst = PModelConst(), - core_const: CoreConst = CoreConst(), ): self.env: PModelEnvironment = env """The PModelEnvironment containing the photosynthetic environment for the model.""" self.shape: tuple[int, ...] = env.shape """The shape of the input environment data.""" - self.pmodel_const: PModelConst = pmodel_const - """The PModelConst used for calculating quantum yield""" - self.core_const: CoreConst = core_const - """The CoreConst used for calculating quantum yield""" self.reference_kphio: float = reference_kphio or self.default_reference_kphio """The reference value for kphio for the method.""" self.use_c4: bool = use_c4 @@ -190,9 +183,13 @@ def _calculate_kphio( """Calculate kphio.""" if self.use_c4: - ftemp = evaluate_horner_polynomial(self.env.tc, self.pmodel_const.kphio_C4) + ftemp = evaluate_horner_polynomial( + self.env.tc, self.env.pmodel_const.kphio_C4 + ) else: - ftemp = evaluate_horner_polynomial(self.env.tc, self.pmodel_const.kphio_C3) + ftemp = evaluate_horner_polynomial( + self.env.tc, self.env.pmodel_const.kphio_C3 + ) ftemp = np.clip(ftemp, 0.0, None) self.kphio = ftemp * self.reference_kphio @@ -221,7 +218,7 @@ def _calculate_kphio(self) -> None: ) # Calculate enzyme kinetics - a_ent, b_ent, Hd_base, Ha = self.pmodel_const.sandoval_kinetics + a_ent, b_ent, Hd_base, Ha = self.env.pmodel_const.sandoval_kinetics # Calculate activation entropy as a linear function of # mean growth temperature, J/mol/K deltaS = a_ent + b_ent * self.env.mean_growth_temperature @@ -230,15 +227,15 @@ def _calculate_kphio(self) -> None: # Calculate the optimal temperature to be used as the reference temperature in # the modified Arrhenius calculation - Topt = Hd / (deltaS - self.core_const.k_R * np.log(Ha / (Hd - Ha))) + Topt = Hd / (deltaS - self.env.core_const.k_R * np.log(Ha / (Hd - Ha))) # Calculate peak kphio given the aridity index - m, n = self.pmodel_const.sandoval_peak_phio + m, n = self.env.pmodel_const.sandoval_peak_phio kphio_peak = self.reference_kphio / (1 + (self.env.aridity_index) ** m) ** n # Calculate the modified Arrhenius factor using the f_kphio = calc_modified_arrhenius_factor( - tk=self.env.tc + self.core_const.k_CtoK, + tk=self.env.tc + self.env.core_const.k_CtoK, Ha=Ha, Hd=Hd, deltaS=deltaS, From 1cadd6b089a434df24fdf64f905c85fa81bb134e Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 1 Aug 2024 12:24:05 +0100 Subject: [PATCH 031/241] Updating subdaily --- pyrealm/pmodel/subdaily.py | 101 +++++++++++++++++++---------- tests/unit/pmodel/test_subdaily.py | 8 ++- 2 files changed, 72 insertions(+), 37 deletions(-) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index b7d15d01..d438fdd4 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -31,9 +31,13 @@ PModelEnvironment, SubdailyScaler, calc_ftemp_arrh, - calc_ftemp_kphio, ) -from pyrealm.pmodel.optimal_chi import OPTIMAL_CHI_CLASS_REGISTRY +from pyrealm.pmodel.optimal_chi import OPTIMAL_CHI_CLASS_REGISTRY, OptimalChiABC +from pyrealm.pmodel.quantum_yield import ( + QUANTUM_YIELD_CLASS_REGISTRY, + QuantumYieldABC, + QuantumYieldTemperature, +) def memory_effect( @@ -210,7 +214,9 @@ class SubdailyPModel: function be allowed to hold over values to fill missing values. allow_partial_data: Should estimates of daily optimal conditions be calculated with missing values in the acclimation window. - kphio: The quantum yield efficiency of photosynthesis (:math:`\phi_0`, -). + reference_kphio: An optional alternative reference value for the quantum yield + efficiency of photosynthesis (:math:`\phi_0`, -) to be passed to the kphio + calculation method. fill_kind: The approach used to fill daily realised values to the subdaily timescale, currently one of 'previous' or 'linear'. """ @@ -221,10 +227,10 @@ def __init__( fs_scaler: SubdailyScaler, fapar: NDArray, ppfd: NDArray, - kphio: float = 1 / 8, - do_ftemp_kphio: bool = True, method_optchi: str = "prentice14", method_jmaxlim: str = "wang17", + method_kphio: str = "temperature", + reference_kphio: float | None = None, alpha: float = 1 / 15, allow_holdover: bool = False, allow_partial_data: bool = False, @@ -252,23 +258,42 @@ def __init__( self.datetimes = fs_scaler.datetimes """The datetimes of the observations used in the subdaily model.""" - # Set up kphio attributes + # Populate PModel attributes and type unpopulated attributes self.env: PModelEnvironment = env - self.init_kphio: float = kphio - self.do_ftemp_kphio = do_ftemp_kphio - self.kphio: NDArray + + # Validate the method choices for kphio and optimal chi + if method_optchi not in OPTIMAL_CHI_CLASS_REGISTRY: + raise ValueError(f"Unknown optimal chi estimation method: {method_optchi}") + + self.method_optchi: str = method_optchi + """The method used to calculate optimal chi.""" + self.c4: bool = OPTIMAL_CHI_CLASS_REGISTRY[method_optchi].is_c4 + """Does the optimal chi method represent a C4 pathway.""" + + if method_kphio not in QUANTUM_YIELD_CLASS_REGISTRY: + raise ValueError(f"Unknown kphio calculation method: {method_kphio}") + + self.method_kphio: str = method_kphio + """The method used to calculate kphio.""" # 1) Generate a PModelEnvironment containing the average conditions within the - # daily acclimation window, including any optional variables required by the - # optimal chi calculations used in the model. - optimal_chi_class = OPTIMAL_CHI_CLASS_REGISTRY[method_optchi] + # daily acclimation window. This daily average environment also needs to also + # pass through any optional variables required by the optimal chi and kphio + # method set for the model, which can be accessed via the class requires + # attribute. + + # Get the list of variables for which to calculate daily acclimation conditions. daily_environment_vars = [ "tc", "co2", "patm", "vpd", - *optimal_chi_class.requires, + *OPTIMAL_CHI_CLASS_REGISTRY[method_optchi].requires, + *QUANTUM_YIELD_CLASS_REGISTRY[method_kphio].requires, ] + + # Construct a dictionary of daily acclimation variables, handling optional + # choices which can be None. daily_environment: dict[str, NDArray] = {} for env_var_name in daily_environment_vars: env_var = getattr(self.env, env_var_name) @@ -277,7 +302,8 @@ def __init__( env_var, allow_partial_data=allow_partial_data ) - pmodel_env_acclim = PModelEnvironment( + # Calculate the acclimation environment passing on the constants definitions. + pmodel_env_acclim: PModelEnvironment = PModelEnvironment( **daily_environment, pmodel_const=self.env.pmodel_const, core_const=self.env.core_const, @@ -286,11 +312,11 @@ def __init__( # 2) Fit a PModel to those environmental conditions, using the supplied settings # for the original model. self.pmodel_acclim: PModel = PModel( - pmodel_env_acclim, - kphio=kphio, - do_ftemp_kphio=do_ftemp_kphio, + env=pmodel_env_acclim, + method_kphio=method_kphio, method_optchi=method_optchi, method_jmaxlim=method_jmaxlim, + reference_kphio=reference_kphio, ) r"""P Model predictions for the daily acclimation conditions. @@ -357,29 +383,28 @@ def __init__( """Estimated subdaily :math:`J_{max}`.""" # 8) Recalculate chi using the OptimalChi class from the provided method. - self.optimal_chi = optimal_chi_class( + self.optimal_chi: OptimalChiABC = OPTIMAL_CHI_CLASS_REGISTRY[method_optchi]( env=self.env, pmodel_const=env.pmodel_const ) self.optimal_chi.estimate_chi(xi_values=self.subdaily_xi) """Estimated subdaily :math:`c_i`.""" - # Calculate Ac, J and Aj at subdaily scale to calculate assimilation - if self.do_ftemp_kphio: - ftemp_kphio = calc_ftemp_kphio( - env.tc, optimal_chi_class.is_c4, pmodel_const=env.pmodel_const - ) - self.kphio = self.init_kphio * ftemp_kphio - else: - self.kphio = np.array([self.init_kphio]) + # Calculate kphio at the subdaily scale. + self.kphio: QuantumYieldABC = QUANTUM_YIELD_CLASS_REGISTRY[method_kphio]( + env=env, + use_c4=self.c4, + reference_kphio=reference_kphio, + ) + # Calculate Ac, J and Aj at subdaily scale to calculate assimilation self.subdaily_Ac: NDArray = self.subdaily_vcmax * self.optimal_chi.mc """Estimated subdaily :math:`A_c`.""" iabs = fapar * ppfd - subdaily_J = (4 * self.kphio * iabs) / np.sqrt( - 1 + ((4 * self.kphio * iabs) / self.subdaily_jmax) ** 2 + subdaily_J = (4 * self.kphio.kphio * iabs) / np.sqrt( + 1 + ((4 * self.kphio.kphio * iabs) / self.subdaily_jmax) ** 2 ) self.subdaily_Aj: NDArray = (subdaily_J / 4) * self.optimal_chi.mj @@ -426,10 +451,10 @@ def convert_pmodel_to_subdaily( fs_scaler=fs_scaler, fapar=pmodel.fapar, ppfd=pmodel.ppfd, - kphio=pmodel.init_kphio, - do_ftemp_kphio=pmodel.do_ftemp_kphio, method_optchi=pmodel.method_optchi, method_jmaxlim=pmodel.method_jmaxlim, + method_kphio=pmodel.method_kphio, + reference_kphio=pmodel.kphio.reference_kphio, alpha=alpha, allow_holdover=allow_holdover, fill_kind=fill_kind, @@ -441,7 +466,7 @@ class SubdailyPModel_JAMES: This is alternative implementation of the P Model incorporating slow responses that duplicates the original implementation of the weighted-average approach of - {cite:t}`mengoli:2022a`. + {cite:t}`mengoli:2022a` for C3 plants. The key difference is that :math:`\xi` does not have a slow response, with :math:`c_i` calculated using the daily optimal values during the acclimation window @@ -541,7 +566,11 @@ def __init__( pmodel_const=self.env.pmodel_const, core_const=self.env.core_const, ) - self.pmodel_acclim: PModel = PModel(pmodel_env_acclim, kphio=kphio) + self.pmodel_acclim: PModel = PModel( + env=pmodel_env_acclim, + reference_kphio=kphio, + method_kphio="temperature", + ) r"""P Model predictions for the daily acclimation conditions. A :class:`~pyrealm.pmodel.pmodel.PModel` instance providing the predictions of @@ -627,11 +656,13 @@ def __init__( ) """Estimated subdaily :math:`A_c`.""" - kphio_tc = kphio * calc_ftemp_kphio(tc=self.env.tc) + self.kphio: QuantumYieldABC = QuantumYieldTemperature( + env=env, reference_kphio=kphio + ) iabs = fapar * ppfd - subdaily_J = (4 * kphio_tc * iabs) / np.sqrt( - 1 + ((4 * kphio_tc * iabs) / self.subdaily_jmax) ** 2 + subdaily_J = (4 * self.kphio.kphio * iabs) / np.sqrt( + 1 + ((4 * self.kphio.kphio * iabs) / self.subdaily_jmax) ** 2 ) self.subdaily_Aj: NDArray = ( diff --git a/tests/unit/pmodel/test_subdaily.py b/tests/unit/pmodel/test_subdaily.py index e6ed5c0e..3d43515b 100644 --- a/tests/unit/pmodel/test_subdaily.py +++ b/tests/unit/pmodel/test_subdaily.py @@ -196,11 +196,12 @@ def test_FSPModel_corr(be_vie_data_components, data_args): half_width=np.timedelta64(30, "m"), ) - # Run as a subdaily model + # Run as a subdaily model using the kphio used in the reference implementation. subdaily_pmodel = SubdailyPModel( env=env, ppfd=ppfd, fapar=fapar, + reference_kphio=1 / 8, fs_scaler=fsscaler, allow_holdover=True, ) @@ -330,7 +331,10 @@ def test_convert_pmodel_to_subdaily(be_vie_data_components, method_optchi): ) # Convert a standard model - standard_model = PModel(env=env, kphio=1 / 8, method_optchi=method_optchi) + standard_model = PModel( + env=env, + method_optchi=method_optchi, + ) standard_model.estimate_productivity(fapar=fapar, ppfd=ppfd) converted = convert_pmodel_to_subdaily( From fce92d9e73d8c02081af21b2466eba26b81c0ea0 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 1 Aug 2024 12:32:04 +0100 Subject: [PATCH 032/241] Better R in sandoval_kphio --- .../sandoval_kphio/create_test_inputs.R | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/pyrealm_build_data/sandoval_kphio/create_test_inputs.R b/pyrealm_build_data/sandoval_kphio/create_test_inputs.R index 79adb1a7..5a3bd0eb 100644 --- a/pyrealm_build_data/sandoval_kphio/create_test_inputs.R +++ b/pyrealm_build_data/sandoval_kphio/create_test_inputs.R @@ -1,24 +1,23 @@ source("calc_phi0.R") +# Generate all combinations of some simple input values aridity_index <- c(0.2, 0.5, 0.8, 1.0, 5.0, 10.0) temp <- seq(0, 50, by = 1) mean_gdd_temp <- seq(5, 30, by = 5) data <- expand.grid( - temp = temp, - aridity_index = aridity_index, - mean_gdd_temp = mean_gdd_temp + temp = temp, + aridity_index = aridity_index, + mean_gdd_temp = mean_gdd_temp ) -# Function is not parallelised so loop over inputs -data$phio <- NA - -for (row_idx in seq_along(data$aridity_index)) { - data$phio[row_idx] <- with( - data[row_idx, ], - calc_phi0(AI = aridity_index, tc = temp, mGDD0 = mean_gdd_temp) - ) -} +# Run the reference implementation, which is not parallelised so need mapply +data$phio <- round( + mapply( + calc_phi0, data$aridity_index, data$temp, data$mean_gdd_temp + ), + digits = 8 +) -data$phio <- round(data$phio, digits = 8) +# Save reference dataset. write.csv(data, "sandoval_kphio.csv", row.names = FALSE) From 2495d841c7b7a4dd9110c5aed23688015ec3c303 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 1 Aug 2024 13:59:23 +0100 Subject: [PATCH 033/241] pytest importlib mode not behaving: https://github.com/pytest-dev/pytest/issues/11475 --- pyproject.toml | 1 - .../{test_quantum_yield.py => test_sandoval_quantum_yield.py} | 0 2 files changed, 1 deletion(-) rename tests/regression/pmodel/{test_quantum_yield.py => test_sandoval_quantum_yield.py} (100%) diff --git a/pyproject.toml b/pyproject.toml index 4e22dcb1..8c28b9aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -106,7 +106,6 @@ addopts = """ --doctest-modules --ignore=pyrealm/__main__.py --ignore=tests/pmodel/generate_test_inputs.py - --import-mode importlib """ python_files = 'test_*.py' testpaths = ['tests', 'pyrealm'] diff --git a/tests/regression/pmodel/test_quantum_yield.py b/tests/regression/pmodel/test_sandoval_quantum_yield.py similarity index 100% rename from tests/regression/pmodel/test_quantum_yield.py rename to tests/regression/pmodel/test_sandoval_quantum_yield.py From dfb23e2278c8e5bb715e4cf4ce2e8530640a8151 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 1 Aug 2024 14:38:02 +0100 Subject: [PATCH 034/241] doctest output format fixes --- pyrealm/core/utilities.py | 12 ++++++------ pyrealm/core/water.py | 10 +++++----- pyrealm/pmodel/functions.py | 10 +++++----- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pyrealm/core/utilities.py b/pyrealm/core/utilities.py index 7d6370f2..9491ebf8 100644 --- a/pyrealm/core/utilities.py +++ b/pyrealm/core/utilities.py @@ -24,10 +24,10 @@ >>> import numpy as np >>> x = np.ma.masked_array([1,2,np.nan, 4], mask=[1,0,0,1]) >>> x.mean() - np.float64(nan) + nan >>> x = np.ma.masked_array([1,2,np.nan, 4], mask=[1,0,1,0]) >>> x.mean() - np.float64(3.0) + 3.0 So the general approach here is now: @@ -282,16 +282,16 @@ def bounds_mask( Examples: >>> vals = np.array([-15, 20, 30, 124], dtype=float) >>> np.nansum(vals) - np.float64(159.0) + 159.0 >>> vals_c = bounds_mask(vals, 0, 100, label='temperature') >>> np.nansum(vals_c) - np.float64(50.0) + 50.0 >>> vals_c = bounds_mask(vals, 0, 124, interval_type='[]', label='temperature') >>> np.nansum(vals_c) - np.float64(174.0) + 174.0 >>> vals_c = bounds_mask(vals, 0, 124, interval_type='[)', label='temperature') >>> np.nansum(vals_c) - np.float64(50.0) + 50.0 """ # Get the interval functions diff --git a/pyrealm/core/water.py b/pyrealm/core/water.py index 72c7568b..1d4a9ecc 100644 --- a/pyrealm/core/water.py +++ b/pyrealm/core/water.py @@ -37,7 +37,7 @@ def calc_density_h2o_chen( Examples: >>> round(calc_density_h2o_chen(20, 101325), 3) - np.float64(998.25) + 998.25 """ # Calculate density at 1 atm (kg/m^3): @@ -93,7 +93,7 @@ def calc_density_h2o_fisher( Examples: >>> round(calc_density_h2o_fisher(20, 101325), 3) - np.float64(998.206) + 998.206 """ # Check input shapes, shape not used @@ -156,7 +156,7 @@ def calc_density_h2o( Examples: >>> round(calc_density_h2o(20, 101325), 3) - np.float64(998.206) + 998.206 """ # Safe guard against instability in functions at low temperature. @@ -201,7 +201,7 @@ def calc_viscosity_h2o( Examples: >>> # Density of water at 20 degrees C and standard atmospheric pressure: >>> round(calc_viscosity_h2o(20, 101325), 7) - np.float64(0.0010016) + 0.0010016 """ # Check inputs, return shape not used @@ -269,7 +269,7 @@ def calc_viscosity_h2o_matrix( Examples: >>> # Density of water at 20 degrees C and standard atmospheric pressure: >>> round(calc_viscosity_h2o(20, 101325), 7) - np.float64(0.0010016) + 0.0010016 """ # Check inputs, return shape not used diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index 84692690..e5a198ab 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -110,7 +110,7 @@ def calc_ftemp_inst_rd( >>> # Relative percentage instantaneous change in Rd going from 10 to 25 degrees >>> val = (calc_ftemp_inst_rd(25) / calc_ftemp_inst_rd(10) - 1) * 100 >>> round(val, 4) - np.float64(250.9593) + 250.9593 """ return np.exp( @@ -306,13 +306,13 @@ def calc_ftemp_kphio( >>> # degrees celsius (percent change): >>> val = (calc_ftemp_kphio(25.0) / calc_ftemp_kphio(5.0) - 1) * 100 >>> round(val, 5) - np.float64(52.03969) + 52.03969 >>> # Relative change in the quantum yield efficiency between 5 and 25 >>> # degrees celsius (percent change) for a C4 plant: >>> val = (calc_ftemp_kphio(25.0, c4=True) / ... calc_ftemp_kphio(5.0, c4=True) - 1) * 100 >>> round(val, 5) - np.float64(432.25806) + 432.25806 """ if c4: @@ -411,7 +411,7 @@ def calc_ns_star( >>> # Relative viscosity at 20 degrees Celsius and standard >>> # atmosphere (in Pa): >>> round(calc_ns_star(20, 101325), 5) - np.float64(1.12536) + 1.12536 """ visc_env = calc_viscosity_h2o(tc, patm, core_const=core_const) @@ -729,7 +729,7 @@ def calc_co2_to_ca(co2: NDArray, patm: NDArray) -> NDArray: Examples: >>> np.round(calc_co2_to_ca(413.03, 101325), 6) - np.float64(41.850265) + 41.850265 """ return 1.0e-6 * co2 * patm # Pa, atms. CO2 From e5c9dd2f2987d9d64b3b0057b7f8f41b663421fb Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 1 Aug 2024 14:43:44 +0100 Subject: [PATCH 035/241] mypy ignore on profiling code --- profiling/run_benchmarking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/profiling/run_benchmarking.py b/profiling/run_benchmarking.py index d392b770..ae72c0bc 100644 --- a/profiling/run_benchmarking.py +++ b/profiling/run_benchmarking.py @@ -60,7 +60,7 @@ def get_function_map(root: Path) -> dict[tuple[str, int, str], str]: for node in ast.walk(parsed_ast): if isinstance(node, ast.FunctionDef): # Find the line number used by profiling, which includes any decorators - lineno = min([d.lineno for d in [*node.decorator_list, node]]) + lineno = min([d.lineno for d in [*node.decorator_list, node]]) # type: ignore [attr-defined] if hasattr(node, "class_name"): ast_map[(str(src_file), lineno, node.name)] = ( From 0e23f5f5756beac8fd6ebc9754cd12da95dd7431 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 2 Aug 2024 08:37:07 +0100 Subject: [PATCH 036/241] =?UTF-8?q?=C2=A0Cleaner=20calculation=20of=20kphi?= =?UTF-8?q?o=20in=20subdaily=20P=20model,=20mypy=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyrealm/pmodel/pmodel.py | 2 +- pyrealm/pmodel/quantum_yield.py | 2 +- pyrealm/pmodel/subdaily.py | 14 +++----------- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index 561efe96..8db8b81e 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -172,7 +172,7 @@ def __init__( method_kphio: str = "temperature", method_optchi: str = "prentice14", method_jmaxlim: str = "wang17", - reference_kphio: float | None = None, + reference_kphio: float | NDArray | None = None, ): self.shape: tuple = env.shape """Records the common numpy array shape of array inputs.""" diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index d5b215f9..78138a78 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -106,7 +106,7 @@ def __init__( ) else: reference_kphio = reference_kphio or self.default_reference_kphio - self.reference_kphio: NDArray = np.array([reference_kphio]) + self.reference_kphio = np.array([reference_kphio]) """The kphio reference value for the method.""" self.use_c4: bool = use_c4 diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 694c2d3c..42a85755 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -236,7 +236,7 @@ def __init__( method_optchi: str = "prentice14", method_jmaxlim: str = "wang17", method_kphio: str = "temperature", - reference_kphio: float | None = None, + reference_kphio: float | NDArray | None = None, alpha: float = 1 / 15, allow_holdover: bool = False, allow_partial_data: bool = False, @@ -318,21 +318,12 @@ def __init__( # 2) Fit a PModel to those environmental conditions, using the supplied settings # for the original model. - # If the kphio is a non-scalar array, use the mean kphio within the window to - # calculate the daily optimal behaviour. - if np.ndim(reference_kphio) > 0: - daily_kphio = fs_scaler.get_daily_means( - reference_kphio, allow_partial_data=allow_partial_data - ) - else: - daily_kphio = reference_kphio - self.pmodel_acclim: PModel = PModel( env=pmodel_env_acclim, method_kphio=method_kphio, method_optchi=method_optchi, method_jmaxlim=method_jmaxlim, - reference_kphio=daily_kphio, + reference_kphio=reference_kphio, ) r"""P Model predictions for the daily acclimation conditions. @@ -412,6 +403,7 @@ def __init__( use_c4=self.c4, reference_kphio=reference_kphio, ) + """Subdaily kphio values.""" # Calculate Ac, J and Aj at subdaily scale to calculate assimilation self.subdaily_Ac: NDArray = self.subdaily_vcmax * self.optimal_chi.mc From 758b70abc86fba8437f7a0bc925e901e3bf540d6 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 2 Aug 2024 10:16:13 +0100 Subject: [PATCH 037/241] Rethink of SubdailyPModel behaviour with array kphio --- pyrealm/core/utilities.py | 2 +- pyrealm/pmodel/quantum_yield.py | 21 +++++++++++--------- pyrealm/pmodel/subdaily.py | 35 +++++++++++++++++++++++---------- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/pyrealm/core/utilities.py b/pyrealm/core/utilities.py index 9491ebf8..03fa90f8 100644 --- a/pyrealm/core/utilities.py +++ b/pyrealm/core/utilities.py @@ -88,7 +88,7 @@ def check_input_shapes(*args: float | int | np.generic | np.ndarray | None) -> t if isinstance(val, np.ndarray): # Note that 0-dim ndarrays (which are scalars) pass through as do # one dimensional arrays with a single value (also a scalar) - if not (val.ndim == 0 or val.shape == (1,)): + if val.size > 1: shapes.add(val.shape) # elif isinstance(val, Series): # # Note that 0-dim ndarrays (which are scalars) pass through diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index 78138a78..357ec350 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -90,24 +90,27 @@ def __init__( model.""" self.shape: tuple[int, ...] = env.shape """The shape of the input environment data.""" - self.reference_kphio: NDArray - """The kphio reference value for the method.""" - # If the reference kphio value is an array check if it is allowed and that it - # matches the shape of the environment. - if isinstance(reference_kphio, np.ndarray): + # Set the reference kphio to the class default value if not provided and convert + # the value to np.array if needed + if reference_kphio is None: + reference_kphio = self.default_reference_kphio + if isinstance(reference_kphio, float | int): + reference_kphio = np.array([reference_kphio]) + + # Now check - if the reference_kphio value is a non-scalar array - that array + # inputs are handled by the kphio method and that the shape matches the shape of + # the environment. + if isinstance(reference_kphio, np.ndarray) and reference_kphio.size > 1: if self.array_reference_kphio_ok: check_input_shapes(self.env.tc, reference_kphio) - self.reference_kphio = reference_kphio else: raise ValueError( f"The {self.method} method for kphio does not support arrays " "of reference kphio values" ) - else: - reference_kphio = reference_kphio or self.default_reference_kphio - self.reference_kphio = np.array([reference_kphio]) + self.reference_kphio: NDArray = reference_kphio """The kphio reference value for the method.""" self.use_c4: bool = use_c4 """Use a C4 parameterisation if available.""" diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 42a85755..0367ce38 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -315,15 +315,38 @@ def __init__( core_const=self.env.core_const, ) + # Handle the kphio settings. First, calculate kphio at the subdaily scale. + self.kphio: QuantumYieldABC = QUANTUM_YIELD_CLASS_REGISTRY[method_kphio]( + env=env, + use_c4=self.c4, + reference_kphio=reference_kphio, + ) + """Subdaily kphio values.""" + + # If the kphio method takes a single reference value then we can simply + # recalculate the kphio using the same method for the daily acclimation + # conditions but if the reference value is an array then the correct behaviour + # is not obvious: currently, use the mean calculated kphio within the window to + # calculate the daily acclimation value behaviour and set the kphio method to be + # fixed to avoid altering the inputs. + if self.kphio.reference_kphio.size > 1: + daily_reference_kphio = fs_scaler.get_daily_means( + self.kphio.kphio, allow_partial_data=allow_partial_data + ) + daily_method_kphio = "fixed" + else: + daily_reference_kphio = self.kphio.reference_kphio + daily_method_kphio = self.method_kphio + # 2) Fit a PModel to those environmental conditions, using the supplied settings # for the original model. self.pmodel_acclim: PModel = PModel( env=pmodel_env_acclim, - method_kphio=method_kphio, + method_kphio=daily_method_kphio, method_optchi=method_optchi, method_jmaxlim=method_jmaxlim, - reference_kphio=reference_kphio, + reference_kphio=daily_reference_kphio, ) r"""P Model predictions for the daily acclimation conditions. @@ -397,14 +420,6 @@ def __init__( """Estimated subdaily :math:`c_i`.""" - # Calculate kphio at the subdaily scale. - self.kphio: QuantumYieldABC = QUANTUM_YIELD_CLASS_REGISTRY[method_kphio]( - env=env, - use_c4=self.c4, - reference_kphio=reference_kphio, - ) - """Subdaily kphio values.""" - # Calculate Ac, J and Aj at subdaily scale to calculate assimilation self.subdaily_Ac: NDArray = self.subdaily_vcmax * self.optimal_chi.mc """Estimated subdaily :math:`A_c`.""" From add9c5c0a2c4adb876fbd002c5bec45aada2e4f6 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 2 Aug 2024 10:48:47 +0100 Subject: [PATCH 038/241] Refixing doctests - local numpy outdated --- poetry.lock | 539 ++++++++++++++++++------------------ pyproject.toml | 6 +- pyrealm/core/utilities.py | 12 +- pyrealm/core/water.py | 10 +- pyrealm/pmodel/functions.py | 10 +- 5 files changed, 291 insertions(+), 286 deletions(-) diff --git a/poetry.lock b/poetry.lock index da069290..f21ca1e6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -575,63 +575,63 @@ test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" -version = "7.5.4" +version = "7.6.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99"}, - {file = "coverage-7.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47"}, - {file = "coverage-7.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e"}, - {file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d"}, - {file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3"}, - {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016"}, - {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136"}, - {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9"}, - {file = "coverage-7.5.4-cp310-cp310-win32.whl", hash = "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8"}, - {file = "coverage-7.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f"}, - {file = "coverage-7.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5"}, - {file = "coverage-7.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba"}, - {file = "coverage-7.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b"}, - {file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080"}, - {file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c"}, - {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da"}, - {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0"}, - {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078"}, - {file = "coverage-7.5.4-cp311-cp311-win32.whl", hash = "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806"}, - {file = "coverage-7.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d"}, - {file = "coverage-7.5.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233"}, - {file = "coverage-7.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747"}, - {file = "coverage-7.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638"}, - {file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e"}, - {file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555"}, - {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f"}, - {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c"}, - {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805"}, - {file = "coverage-7.5.4-cp312-cp312-win32.whl", hash = "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b"}, - {file = "coverage-7.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7"}, - {file = "coverage-7.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882"}, - {file = "coverage-7.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d"}, - {file = "coverage-7.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53"}, - {file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4"}, - {file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4"}, - {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9"}, - {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f"}, - {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f"}, - {file = "coverage-7.5.4-cp38-cp38-win32.whl", hash = "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f"}, - {file = "coverage-7.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633"}, - {file = "coverage-7.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088"}, - {file = "coverage-7.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4"}, - {file = "coverage-7.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7"}, - {file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8"}, - {file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d"}, - {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029"}, - {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c"}, - {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7"}, - {file = "coverage-7.5.4-cp39-cp39-win32.whl", hash = "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace"}, - {file = "coverage-7.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d"}, - {file = "coverage-7.5.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5"}, - {file = "coverage-7.5.4.tar.gz", hash = "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353"}, + {file = "coverage-7.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd"}, + {file = "coverage-7.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb"}, + {file = "coverage-7.6.0-cp310-cp310-win32.whl", hash = "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c"}, + {file = "coverage-7.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169"}, + {file = "coverage-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933"}, + {file = "coverage-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63"}, + {file = "coverage-7.6.0-cp311-cp311-win32.whl", hash = "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713"}, + {file = "coverage-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1"}, + {file = "coverage-7.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"}, + {file = "coverage-7.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605"}, + {file = "coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da"}, + {file = "coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67"}, + {file = "coverage-7.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b"}, + {file = "coverage-7.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b"}, + {file = "coverage-7.6.0-cp38-cp38-win32.whl", hash = "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428"}, + {file = "coverage-7.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8"}, + {file = "coverage-7.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c"}, + {file = "coverage-7.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd"}, + {file = "coverage-7.6.0-cp39-cp39-win32.whl", hash = "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2"}, + {file = "coverage-7.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca"}, + {file = "coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6"}, + {file = "coverage-7.6.0.tar.gz", hash = "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51"}, ] [package.dependencies] @@ -760,13 +760,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.2.1" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -1084,13 +1084,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "8.0.0" +version = "8.2.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"}, - {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"}, + {file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"}, + {file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"}, ] [package.dependencies] @@ -1408,13 +1408,13 @@ jupyter-server = ">=1.1.2" [[package]] name = "jupyter-server" -version = "2.14.1" +version = "2.14.2" description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_server-2.14.1-py3-none-any.whl", hash = "sha256:16f7177c3a4ea8fe37784e2d31271981a812f0b2874af17339031dc3510cc2a5"}, - {file = "jupyter_server-2.14.1.tar.gz", hash = "sha256:12558d158ec7a0653bf96cc272bc7ad79e0127d503b982ed144399346694f726"}, + {file = "jupyter_server-2.14.2-py3-none-any.whl", hash = "sha256:47ff506127c2f7851a17bf4713434208fc490955d0e8632e95014a9a9afbeefd"}, + {file = "jupyter_server-2.14.2.tar.gz", hash = "sha256:66095021aa9638ced276c248b1d81862e4c50f292d575920bbe960de1c56b12b"}, ] [package.dependencies] @@ -1463,13 +1463,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.2.3" +version = "4.2.4" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.2.3-py3-none-any.whl", hash = "sha256:0b59d11808e84bb84105c73364edfa867dd475492429ab34ea388a52f2e2e596"}, - {file = "jupyterlab-4.2.3.tar.gz", hash = "sha256:df6e46969ea51d66815167f23d92f105423b7f1f06fa604d4f44aeb018c82c7b"}, + {file = "jupyterlab-4.2.4-py3-none-any.whl", hash = "sha256:807a7ec73637744f879e112060d4b9d9ebe028033b7a429b2d1f4fc523d00245"}, + {file = "jupyterlab-4.2.4.tar.gz", hash = "sha256:343a979fb9582fd08c8511823e320703281cd072a0049bcdafdc7afeda7f2537"}, ] [package.dependencies] @@ -1493,7 +1493,7 @@ dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<7.3.0)", "sphinx-copybutton"] docs-screenshots = ["altair (==5.3.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.2)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.1.post2)", "matplotlib (==3.8.3)", "nbconvert (>=7.0.0)", "pandas (==2.2.1)", "scipy (==1.12.0)", "vega-datasets (==0.9.0)"] test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] -upgrade-extension = ["copier (>=8,<10)", "jinja2-time (<0.3)", "pydantic (<2.0)", "pyyaml-include (<2.0)", "tomli-w (<2.0)"] +upgrade-extension = ["copier (>=9,<10)", "jinja2-time (<0.3)", "pydantic (<3.0)", "pyyaml-include (<3.0)", "tomli-w (<2.0)"] [[package]] name = "jupyterlab-myst" @@ -1525,13 +1525,13 @@ files = [ [[package]] name = "jupyterlab-server" -version = "2.27.2" +version = "2.27.3" description = "A set of server components for JupyterLab and JupyterLab like applications." optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab_server-2.27.2-py3-none-any.whl", hash = "sha256:54aa2d64fd86383b5438d9f0c032f043c4d8c0264b8af9f60bd061157466ea43"}, - {file = "jupyterlab_server-2.27.2.tar.gz", hash = "sha256:15cbb349dc45e954e09bacf81b9f9bcb10815ff660fb2034ecd7417db3a7ea27"}, + {file = "jupyterlab_server-2.27.3-py3-none-any.whl", hash = "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4"}, + {file = "jupyterlab_server-2.27.3.tar.gz", hash = "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4"}, ] [package.dependencies] @@ -1550,13 +1550,13 @@ test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-v [[package]] name = "jupytext" -version = "1.16.2" +version = "1.16.4" description = "Jupyter notebooks as Markdown documents, Julia, Python or R scripts" optional = false python-versions = ">=3.8" files = [ - {file = "jupytext-1.16.2-py3-none-any.whl", hash = "sha256:197a43fef31dca612b68b311e01b8abd54441c7e637810b16b6cb8f2ab66065e"}, - {file = "jupytext-1.16.2.tar.gz", hash = "sha256:8627dd9becbbebd79cc4a4ed4727d89d78e606b4b464eab72357b3b029023a14"}, + {file = "jupytext-1.16.4-py3-none-any.whl", hash = "sha256:76989d2690e65667ea6fb411d8056abe7cd0437c07bd774660b83d62acf9490a"}, + {file = "jupytext-1.16.4.tar.gz", hash = "sha256:28e33f46f2ce7a41fb9d677a4a2c95327285579b64ca104437c4b9eb1e4174e9"}, ] [package.dependencies] @@ -1568,11 +1568,11 @@ pyyaml = "*" tomli = {version = "*", markers = "python_version < \"3.11\""} [package.extras] -dev = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs (<0.4.0)", "jupyter-server (!=2.11)", "nbconvert", "pre-commit", "pytest", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist", "sphinx-gallery (<0.8)"] +dev = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs (>=1.0)", "jupyter-server (!=2.11)", "nbconvert", "pre-commit", "pytest", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist", "sphinx-gallery (<0.8)"] docs = ["myst-parser", "sphinx", "sphinx-copybutton", "sphinx-rtd-theme"] test = ["pytest", "pytest-randomly", "pytest-xdist"] test-cov = ["ipykernel", "jupyter-server (!=2.11)", "nbconvert", "pytest", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist"] -test-external = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs (<0.4.0)", "jupyter-server (!=2.11)", "nbconvert", "pre-commit", "pytest", "pytest-randomly", "pytest-xdist", "sphinx-gallery (<0.8)"] +test-external = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs (>=1.0)", "jupyter-server (!=2.11)", "nbconvert", "pre-commit", "pytest", "pytest-randomly", "pytest-xdist", "sphinx-gallery (<0.8)"] test-functional = ["pytest", "pytest-randomly", "pytest-xdist"] test-integration = ["ipykernel", "jupyter-server (!=2.11)", "nbconvert", "pytest", "pytest-randomly", "pytest-xdist"] test-ui = ["calysto-bash"] @@ -2203,56 +2203,56 @@ test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync" [[package]] name = "numpy" -version = "2.0.0" +version = "2.0.1" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-2.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:04494f6ec467ccb5369d1808570ae55f6ed9b5809d7f035059000a37b8d7e86f"}, - {file = "numpy-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2635dbd200c2d6faf2ef9a0d04f0ecc6b13b3cad54f7c67c61155138835515d2"}, - {file = "numpy-2.0.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:0a43f0974d501842866cc83471bdb0116ba0dffdbaac33ec05e6afed5b615238"}, - {file = "numpy-2.0.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:8d83bb187fb647643bd56e1ae43f273c7f4dbcdf94550d7938cfc32566756514"}, - {file = "numpy-2.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79e843d186c8fb1b102bef3e2bc35ef81160ffef3194646a7fdd6a73c6b97196"}, - {file = "numpy-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7696c615765091cc5093f76fd1fa069870304beaccfd58b5dcc69e55ef49c1"}, - {file = "numpy-2.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b4c76e3d4c56f145d41b7b6751255feefae92edbc9a61e1758a98204200f30fc"}, - {file = "numpy-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd3a644e4807e73b4e1867b769fbf1ce8c5d80e7caaef0d90dcdc640dfc9787"}, - {file = "numpy-2.0.0-cp310-cp310-win32.whl", hash = "sha256:cee6cc0584f71adefe2c908856ccc98702baf95ff80092e4ca46061538a2ba98"}, - {file = "numpy-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:ed08d2703b5972ec736451b818c2eb9da80d66c3e84aed1deeb0c345fefe461b"}, - {file = "numpy-2.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad0c86f3455fbd0de6c31a3056eb822fc939f81b1618f10ff3406971893b62a5"}, - {file = "numpy-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7f387600d424f91576af20518334df3d97bc76a300a755f9a8d6e4f5cadd289"}, - {file = "numpy-2.0.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:34f003cb88b1ba38cb9a9a4a3161c1604973d7f9d5552c38bc2f04f829536609"}, - {file = "numpy-2.0.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:b6f6a8f45d0313db07d6d1d37bd0b112f887e1369758a5419c0370ba915b3871"}, - {file = "numpy-2.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f64641b42b2429f56ee08b4f427a4d2daf916ec59686061de751a55aafa22e4"}, - {file = "numpy-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7039a136017eaa92c1848152827e1424701532ca8e8967fe480fe1569dae581"}, - {file = "numpy-2.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46e161722e0f619749d1cd892167039015b2c2817296104487cd03ed4a955995"}, - {file = "numpy-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0e50842b2295ba8414c8c1d9d957083d5dfe9e16828b37de883f51fc53c4016f"}, - {file = "numpy-2.0.0-cp311-cp311-win32.whl", hash = "sha256:2ce46fd0b8a0c947ae047d222f7136fc4d55538741373107574271bc00e20e8f"}, - {file = "numpy-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbd6acc766814ea6443628f4e6751d0da6593dae29c08c0b2606164db026970c"}, - {file = "numpy-2.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:354f373279768fa5a584bac997de6a6c9bc535c482592d7a813bb0c09be6c76f"}, - {file = "numpy-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d2f62e55a4cd9c58c1d9a1c9edaedcd857a73cb6fda875bf79093f9d9086f85"}, - {file = "numpy-2.0.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:1e72728e7501a450288fc8e1f9ebc73d90cfd4671ebbd631f3e7857c39bd16f2"}, - {file = "numpy-2.0.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:84554fc53daa8f6abf8e8a66e076aff6ece62de68523d9f665f32d2fc50fd66e"}, - {file = "numpy-2.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c73aafd1afca80afecb22718f8700b40ac7cab927b8abab3c3e337d70e10e5a2"}, - {file = "numpy-2.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49d9f7d256fbc804391a7f72d4a617302b1afac1112fac19b6c6cec63fe7fe8a"}, - {file = "numpy-2.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0ec84b9ba0654f3b962802edc91424331f423dcf5d5f926676e0150789cb3d95"}, - {file = "numpy-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:feff59f27338135776f6d4e2ec7aeeac5d5f7a08a83e80869121ef8164b74af9"}, - {file = "numpy-2.0.0-cp312-cp312-win32.whl", hash = "sha256:c5a59996dc61835133b56a32ebe4ef3740ea5bc19b3983ac60cc32be5a665d54"}, - {file = "numpy-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:a356364941fb0593bb899a1076b92dfa2029f6f5b8ba88a14fd0984aaf76d0df"}, - {file = "numpy-2.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e61155fae27570692ad1d327e81c6cf27d535a5d7ef97648a17d922224b216de"}, - {file = "numpy-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4554eb96f0fd263041baf16cf0881b3f5dafae7a59b1049acb9540c4d57bc8cb"}, - {file = "numpy-2.0.0-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:903703372d46bce88b6920a0cd86c3ad82dae2dbef157b5fc01b70ea1cfc430f"}, - {file = "numpy-2.0.0-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:3e8e01233d57639b2e30966c63d36fcea099d17c53bf424d77f088b0f4babd86"}, - {file = "numpy-2.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cde1753efe513705a0c6d28f5884e22bdc30438bf0085c5c486cdaff40cd67a"}, - {file = "numpy-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821eedb7165ead9eebdb569986968b541f9908979c2da8a4967ecac4439bae3d"}, - {file = "numpy-2.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a1712c015831da583b21c5bfe15e8684137097969c6d22e8316ba66b5baabe4"}, - {file = "numpy-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9c27f0946a3536403efb0e1c28def1ae6730a72cd0d5878db38824855e3afc44"}, - {file = "numpy-2.0.0-cp39-cp39-win32.whl", hash = "sha256:63b92c512d9dbcc37f9d81b123dec99fdb318ba38c8059afc78086fe73820275"}, - {file = "numpy-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:3f6bed7f840d44c08ebdb73b1825282b801799e325bcbdfa6bc5c370e5aecc65"}, - {file = "numpy-2.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9416a5c2e92ace094e9f0082c5fd473502c91651fb896bc17690d6fc475128d6"}, - {file = "numpy-2.0.0-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:17067d097ed036636fa79f6a869ac26df7db1ba22039d962422506640314933a"}, - {file = "numpy-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ecb5b0582cd125f67a629072fed6f83562d9dd04d7e03256c9829bdec027ad"}, - {file = "numpy-2.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cef04d068f5fb0518a77857953193b6bb94809a806bd0a14983a8f12ada060c9"}, - {file = "numpy-2.0.0.tar.gz", hash = "sha256:cf5d1c9e6837f8af9f92b6bd3e86d513cdc11f60fd62185cc49ec7d1aba34864"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fbb536eac80e27a2793ffd787895242b7f18ef792563d742c2d673bfcb75134"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:69ff563d43c69b1baba77af455dd0a839df8d25e8590e79c90fcbe1499ebde42"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:1b902ce0e0a5bb7704556a217c4f63a7974f8f43e090aff03fcf262e0b135e02"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:f1659887361a7151f89e79b276ed8dff3d75877df906328f14d8bb40bb4f5101"}, + {file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4658c398d65d1b25e1760de3157011a80375da861709abd7cef3bad65d6543f9"}, + {file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4127d4303b9ac9f94ca0441138acead39928938660ca58329fe156f84b9f3015"}, + {file = "numpy-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e5eeca8067ad04bc8a2a8731183d51d7cbaac66d86085d5f4766ee6bf19c7f87"}, + {file = "numpy-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9adbd9bb520c866e1bfd7e10e1880a1f7749f1f6e5017686a5fbb9b72cf69f82"}, + {file = "numpy-2.0.1-cp310-cp310-win32.whl", hash = "sha256:7b9853803278db3bdcc6cd5beca37815b133e9e77ff3d4733c247414e78eb8d1"}, + {file = "numpy-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81b0893a39bc5b865b8bf89e9ad7807e16717f19868e9d234bdaf9b1f1393868"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75b4e316c5902d8163ef9d423b1c3f2f6252226d1aa5cd8a0a03a7d01ffc6268"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6e4eeb6eb2fced786e32e6d8df9e755ce5be920d17f7ce00bc38fcde8ccdbf9e"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a1e01dcaab205fbece13c1410253a9eea1b1c9b61d237b6fa59bcc46e8e89343"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8fc2de81ad835d999113ddf87d1ea2b0f4704cbd947c948d2f5513deafe5a7b"}, + {file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3d94942c331dd4e0e1147f7a8699a4aa47dffc11bf8a1523c12af8b2e91bbe"}, + {file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15eb4eca47d36ec3f78cde0a3a2ee24cf05ca7396ef808dda2c0ddad7c2bde67"}, + {file = "numpy-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b83e16a5511d1b1f8a88cbabb1a6f6a499f82c062a4251892d9ad5d609863fb7"}, + {file = "numpy-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f87fec1f9bc1efd23f4227becff04bd0e979e23ca50cc92ec88b38489db3b55"}, + {file = "numpy-2.0.1-cp311-cp311-win32.whl", hash = "sha256:36d3a9405fd7c511804dc56fc32974fa5533bdeb3cd1604d6b8ff1d292b819c4"}, + {file = "numpy-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:08458fbf403bff5e2b45f08eda195d4b0c9b35682311da5a5a0a0925b11b9bd8"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bf4e6f4a2a2e26655717a1983ef6324f2664d7011f6ef7482e8c0b3d51e82ac"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6fddc5fe258d3328cd8e3d7d3e02234c5d70e01ebe377a6ab92adb14039cb4"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5daab361be6ddeb299a918a7c0864fa8618af66019138263247af405018b04e1"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:ea2326a4dca88e4a274ba3a4405eb6c6467d3ffbd8c7d38632502eaae3820587"}, + {file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529af13c5f4b7a932fb0e1911d3a75da204eff023ee5e0e79c1751564221a5c8"}, + {file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6790654cb13eab303d8402354fabd47472b24635700f631f041bd0b65e37298a"}, + {file = "numpy-2.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cbab9fc9c391700e3e1287666dfd82d8666d10e69a6c4a09ab97574c0b7ee0a7"}, + {file = "numpy-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99d0d92a5e3613c33a5f01db206a33f8fdf3d71f2912b0de1739894668b7a93b"}, + {file = "numpy-2.0.1-cp312-cp312-win32.whl", hash = "sha256:173a00b9995f73b79eb0191129f2455f1e34c203f559dd118636858cc452a1bf"}, + {file = "numpy-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:bb2124fdc6e62baae159ebcfa368708867eb56806804d005860b6007388df171"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc085b28d62ff4009364e7ca34b80a9a080cbd97c2c0630bb5f7f770dae9414"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fae4ebbf95a179c1156fab0b142b74e4ba4204c87bde8d3d8b6f9c34c5825ef"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:72dc22e9ec8f6eaa206deb1b1355eb2e253899d7347f5e2fae5f0af613741d06"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:ec87f5f8aca726117a1c9b7083e7656a9d0d606eec7299cc067bb83d26f16e0c"}, + {file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f682ea61a88479d9498bf2091fdcd722b090724b08b31d63e022adc063bad59"}, + {file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8efc84f01c1cd7e34b3fb310183e72fcdf55293ee736d679b6d35b35d80bba26"}, + {file = "numpy-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3fdabe3e2a52bc4eff8dc7a5044342f8bd9f11ef0934fcd3289a788c0eb10018"}, + {file = "numpy-2.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:24a0e1befbfa14615b49ba9659d3d8818a0f4d8a1c5822af8696706fbda7310c"}, + {file = "numpy-2.0.1-cp39-cp39-win32.whl", hash = "sha256:f9cf5ea551aec449206954b075db819f52adc1638d46a6738253a712d553c7b4"}, + {file = "numpy-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:e9e81fa9017eaa416c056e5d9e71be93d05e2c3c2ab308d23307a8bc4443c368"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61728fba1e464f789b11deb78a57805c70b2ed02343560456190d0501ba37b0f"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:12f5d865d60fb9734e60a60f1d5afa6d962d8d4467c120a1c0cda6eb2964437d"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eacf3291e263d5a67d8c1a581a8ebbcfd6447204ef58828caf69a5e3e8c75990"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2c3a346ae20cfd80b6cfd3e60dc179963ef2ea58da5ec074fd3d9e7a1e7ba97f"}, + {file = "numpy-2.0.1.tar.gz", hash = "sha256:485b87235796410c3519a699cfe1faab097e509e90ebb05dcd098db2ae87e7b3"}, ] [[package]] @@ -2538,13 +2538,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.7.1" +version = "3.8.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, - {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, + {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, + {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, ] [package.dependencies] @@ -2624,13 +2624,13 @@ files = [ [[package]] name = "pure-eval" -version = "0.2.2" +version = "0.2.3" description = "Safely evaluate AST nodes without side effects" optional = false python-versions = "*" files = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, + {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, + {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, ] [package.extras] @@ -3099,110 +3099,114 @@ files = [ [[package]] name = "rpds-py" -version = "0.19.0" +version = "0.19.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.19.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:fb37bd599f031f1a6fb9e58ec62864ccf3ad549cf14bac527dbfa97123edcca4"}, - {file = "rpds_py-0.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3384d278df99ec2c6acf701d067147320b864ef6727405d6470838476e44d9e8"}, - {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e54548e0be3ac117595408fd4ca0ac9278fde89829b0b518be92863b17ff67a2"}, - {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8eb488ef928cdbc05a27245e52de73c0d7c72a34240ef4d9893fdf65a8c1a955"}, - {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5da93debdfe27b2bfc69eefb592e1831d957b9535e0943a0ee8b97996de21b5"}, - {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79e205c70afddd41f6ee79a8656aec738492a550247a7af697d5bd1aee14f766"}, - {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:959179efb3e4a27610e8d54d667c02a9feaa86bbabaf63efa7faa4dfa780d4f1"}, - {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a6e605bb9edcf010f54f8b6a590dd23a4b40a8cb141255eec2a03db249bc915b"}, - {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9133d75dc119a61d1a0ded38fb9ba40a00ef41697cc07adb6ae098c875195a3f"}, - {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd36b712d35e757e28bf2f40a71e8f8a2d43c8b026d881aa0c617b450d6865c9"}, - {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:354f3a91718489912f2e0fc331c24eaaf6a4565c080e00fbedb6015857c00582"}, - {file = "rpds_py-0.19.0-cp310-none-win32.whl", hash = "sha256:ebcbf356bf5c51afc3290e491d3722b26aaf5b6af3c1c7f6a1b757828a46e336"}, - {file = "rpds_py-0.19.0-cp310-none-win_amd64.whl", hash = "sha256:75a6076289b2df6c8ecb9d13ff79ae0cad1d5fb40af377a5021016d58cd691ec"}, - {file = "rpds_py-0.19.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6d45080095e585f8c5097897313def60caa2046da202cdb17a01f147fb263b81"}, - {file = "rpds_py-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5c9581019c96f865483d031691a5ff1cc455feb4d84fc6920a5ffc48a794d8a"}, - {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1540d807364c84516417115c38f0119dfec5ea5c0dd9a25332dea60b1d26fc4d"}, - {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e65489222b410f79711dc3d2d5003d2757e30874096b2008d50329ea4d0f88c"}, - {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9da6f400eeb8c36f72ef6646ea530d6d175a4f77ff2ed8dfd6352842274c1d8b"}, - {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37f46bb11858717e0efa7893c0f7055c43b44c103e40e69442db5061cb26ed34"}, - {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:071d4adc734de562bd11d43bd134330fb6249769b2f66b9310dab7460f4bf714"}, - {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9625367c8955e4319049113ea4f8fee0c6c1145192d57946c6ffcd8fe8bf48dd"}, - {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e19509145275d46bc4d1e16af0b57a12d227c8253655a46bbd5ec317e941279d"}, - {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d438e4c020d8c39961deaf58f6913b1bf8832d9b6f62ec35bd93e97807e9cbc"}, - {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90bf55d9d139e5d127193170f38c584ed3c79e16638890d2e36f23aa1630b952"}, - {file = "rpds_py-0.19.0-cp311-none-win32.whl", hash = "sha256:8d6ad132b1bc13d05ffe5b85e7a01a3998bf3a6302ba594b28d61b8c2cf13aaf"}, - {file = "rpds_py-0.19.0-cp311-none-win_amd64.whl", hash = "sha256:7ec72df7354e6b7f6eb2a17fa6901350018c3a9ad78e48d7b2b54d0412539a67"}, - {file = "rpds_py-0.19.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:5095a7c838a8647c32aa37c3a460d2c48debff7fc26e1136aee60100a8cd8f68"}, - {file = "rpds_py-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f2f78ef14077e08856e788fa482107aa602636c16c25bdf59c22ea525a785e9"}, - {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7cc6cb44f8636fbf4a934ca72f3e786ba3c9f9ba4f4d74611e7da80684e48d2"}, - {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf902878b4af334a09de7a45badbff0389e7cf8dc2e4dcf5f07125d0b7c2656d"}, - {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:688aa6b8aa724db1596514751ffb767766e02e5c4a87486ab36b8e1ebc1aedac"}, - {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57dbc9167d48e355e2569346b5aa4077f29bf86389c924df25c0a8b9124461fb"}, - {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4cf5a9497874822341c2ebe0d5850fed392034caadc0bad134ab6822c0925b"}, - {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8a790d235b9d39c70a466200d506bb33a98e2ee374a9b4eec7a8ac64c2c261fa"}, - {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1d16089dfa58719c98a1c06f2daceba6d8e3fb9b5d7931af4a990a3c486241cb"}, - {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bc9128e74fe94650367fe23f37074f121b9f796cabbd2f928f13e9661837296d"}, - {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c8f77e661ffd96ff104bebf7d0f3255b02aa5d5b28326f5408d6284c4a8b3248"}, - {file = "rpds_py-0.19.0-cp312-none-win32.whl", hash = "sha256:5f83689a38e76969327e9b682be5521d87a0c9e5a2e187d2bc6be4765f0d4600"}, - {file = "rpds_py-0.19.0-cp312-none-win_amd64.whl", hash = "sha256:06925c50f86da0596b9c3c64c3837b2481337b83ef3519e5db2701df695453a4"}, - {file = "rpds_py-0.19.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:52e466bea6f8f3a44b1234570244b1cff45150f59a4acae3fcc5fd700c2993ca"}, - {file = "rpds_py-0.19.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e21cc693045fda7f745c790cb687958161ce172ffe3c5719ca1764e752237d16"}, - {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b31f059878eb1f5da8b2fd82480cc18bed8dcd7fb8fe68370e2e6285fa86da6"}, - {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1dd46f309e953927dd018567d6a9e2fb84783963650171f6c5fe7e5c41fd5666"}, - {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34a01a4490e170376cd79258b7f755fa13b1a6c3667e872c8e35051ae857a92b"}, - {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcf426a8c38eb57f7bf28932e68425ba86def6e756a5b8cb4731d8e62e4e0223"}, - {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68eea5df6347d3f1378ce992d86b2af16ad7ff4dcb4a19ccdc23dea901b87fb"}, - {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dab8d921b55a28287733263c0e4c7db11b3ee22aee158a4de09f13c93283c62d"}, - {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6fe87efd7f47266dfc42fe76dae89060038f1d9cb911f89ae7e5084148d1cc08"}, - {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:535d4b52524a961d220875688159277f0e9eeeda0ac45e766092bfb54437543f"}, - {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8b1a94b8afc154fbe36978a511a1f155f9bd97664e4f1f7a374d72e180ceb0ae"}, - {file = "rpds_py-0.19.0-cp38-none-win32.whl", hash = "sha256:7c98298a15d6b90c8f6e3caa6457f4f022423caa5fa1a1ca7a5e9e512bdb77a4"}, - {file = "rpds_py-0.19.0-cp38-none-win_amd64.whl", hash = "sha256:b0da31853ab6e58a11db3205729133ce0df26e6804e93079dee095be3d681dc1"}, - {file = "rpds_py-0.19.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5039e3cef7b3e7a060de468a4a60a60a1f31786da94c6cb054e7a3c75906111c"}, - {file = "rpds_py-0.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab1932ca6cb8c7499a4d87cb21ccc0d3326f172cfb6a64021a889b591bb3045c"}, - {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2afd2164a1e85226fcb6a1da77a5c8896c18bfe08e82e8ceced5181c42d2179"}, - {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1c30841f5040de47a0046c243fc1b44ddc87d1b12435a43b8edff7e7cb1e0d0"}, - {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f757f359f30ec7dcebca662a6bd46d1098f8b9fb1fcd661a9e13f2e8ce343ba1"}, - {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15e65395a59d2e0e96caf8ee5389ffb4604e980479c32742936ddd7ade914b22"}, - {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb0f6eb3a320f24b94d177e62f4074ff438f2ad9d27e75a46221904ef21a7b05"}, - {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b228e693a2559888790936e20f5f88b6e9f8162c681830eda303bad7517b4d5a"}, - {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2575efaa5d949c9f4e2cdbe7d805d02122c16065bfb8d95c129372d65a291a0b"}, - {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5c872814b77a4e84afa293a1bee08c14daed1068b2bb1cc312edbf020bbbca2b"}, - {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850720e1b383df199b8433a20e02b25b72f0fded28bc03c5bd79e2ce7ef050be"}, - {file = "rpds_py-0.19.0-cp39-none-win32.whl", hash = "sha256:ce84a7efa5af9f54c0aa7692c45861c1667080814286cacb9958c07fc50294fb"}, - {file = "rpds_py-0.19.0-cp39-none-win_amd64.whl", hash = "sha256:1c26da90b8d06227d7769f34915913911222d24ce08c0ab2d60b354e2d9c7aff"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:75969cf900d7be665ccb1622a9aba225cf386bbc9c3bcfeeab9f62b5048f4a07"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8445f23f13339da640d1be8e44e5baf4af97e396882ebbf1692aecd67f67c479"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5a7c1062ef8aea3eda149f08120f10795835fc1c8bc6ad948fb9652a113ca55"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:462b0c18fbb48fdbf980914a02ee38c423a25fcc4cf40f66bacc95a2d2d73bc8"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3208f9aea18991ac7f2b39721e947bbd752a1abbe79ad90d9b6a84a74d44409b"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3444fe52b82f122d8a99bf66777aed6b858d392b12f4c317da19f8234db4533"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb4bac7185a9f0168d38c01d7a00addece9822a52870eee26b8d5b61409213"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6b130bd4163c93798a6b9bb96be64a7c43e1cec81126ffa7ffaa106e1fc5cef5"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:a707b158b4410aefb6b054715545bbb21aaa5d5d0080217290131c49c2124a6e"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dc9ac4659456bde7c567107556ab065801622396b435a3ff213daef27b495388"}, - {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:81ea573aa46d3b6b3d890cd3c0ad82105985e6058a4baed03cf92518081eec8c"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f148c3f47f7f29a79c38cc5d020edcb5ca780020fab94dbc21f9af95c463581"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0906357f90784a66e89ae3eadc2654f36c580a7d65cf63e6a616e4aec3a81be"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f629ecc2db6a4736b5ba95a8347b0089240d69ad14ac364f557d52ad68cf94b0"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6feacd1d178c30e5bc37184526e56740342fd2aa6371a28367bad7908d454fc"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b6068ee374fdfab63689be0963333aa83b0815ead5d8648389a8ded593378"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78d57546bad81e0da13263e4c9ce30e96dcbe720dbff5ada08d2600a3502e526"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b6683a37338818646af718c9ca2a07f89787551057fae57c4ec0446dc6224b"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8481b946792415adc07410420d6fc65a352b45d347b78fec45d8f8f0d7496f0"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bec35eb20792ea64c3c57891bc3ca0bedb2884fbac2c8249d9b731447ecde4fa"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:aa5476c3e3a402c37779e95f7b4048db2cb5b0ed0b9d006983965e93f40fe05a"}, - {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:19d02c45f2507b489fd4df7b827940f1420480b3e2e471e952af4d44a1ea8e34"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a3e2fd14c5d49ee1da322672375963f19f32b3d5953f0615b175ff7b9d38daed"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:93a91c2640645303e874eada51f4f33351b84b351a689d470f8108d0e0694210"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b9fc03bf76a94065299d4a2ecd8dfbae4ae8e2e8098bbfa6ab6413ca267709"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a4b07cdf3f84310c08c1de2c12ddadbb7a77568bcb16e95489f9c81074322ed"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba0ed0dc6763d8bd6e5de5cf0d746d28e706a10b615ea382ac0ab17bb7388633"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:474bc83233abdcf2124ed3f66230a1c8435896046caa4b0b5ab6013c640803cc"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329c719d31362355a96b435f4653e3b4b061fcc9eba9f91dd40804ca637d914e"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef9101f3f7b59043a34f1dccbb385ca760467590951952d6701df0da9893ca0c"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:0121803b0f424ee2109d6e1f27db45b166ebaa4b32ff47d6aa225642636cd834"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8344127403dea42f5970adccf6c5957a71a47f522171fafaf4c6ddb41b61703a"}, - {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:443cec402ddd650bb2b885113e1dcedb22b1175c6be223b14246a714b61cd521"}, - {file = "rpds_py-0.19.0.tar.gz", hash = "sha256:4fdc9afadbeb393b4bbbad75481e0ea78e4469f2e1d713a90811700830b553a9"}, + {file = "rpds_py-0.19.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:aaf71f95b21f9dc708123335df22e5a2fef6307e3e6f9ed773b2e0938cc4d491"}, + {file = "rpds_py-0.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca0dda0c5715efe2ab35bb83f813f681ebcd2840d8b1b92bfc6fe3ab382fae4a"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81db2e7282cc0487f500d4db203edc57da81acde9e35f061d69ed983228ffe3b"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1a8dfa125b60ec00c7c9baef945bb04abf8ac772d8ebefd79dae2a5f316d7850"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:271accf41b02687cef26367c775ab220372ee0f4925591c6796e7c148c50cab5"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9bc4161bd3b970cd6a6fcda70583ad4afd10f2750609fb1f3ca9505050d4ef3"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0cf2a0dbb5987da4bd92a7ca727eadb225581dd9681365beba9accbe5308f7d"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b5e28e56143750808c1c79c70a16519e9bc0a68b623197b96292b21b62d6055c"}, + {file = "rpds_py-0.19.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c7af6f7b80f687b33a4cdb0a785a5d4de1fb027a44c9a049d8eb67d5bfe8a687"}, + {file = "rpds_py-0.19.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e429fc517a1c5e2a70d576077231538a98d59a45dfc552d1ac45a132844e6dfb"}, + {file = "rpds_py-0.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d2dbd8f4990d4788cb122f63bf000357533f34860d269c1a8e90ae362090ff3a"}, + {file = "rpds_py-0.19.1-cp310-none-win32.whl", hash = "sha256:e0f9d268b19e8f61bf42a1da48276bcd05f7ab5560311f541d22557f8227b866"}, + {file = "rpds_py-0.19.1-cp310-none-win_amd64.whl", hash = "sha256:df7c841813f6265e636fe548a49664c77af31ddfa0085515326342a751a6ba51"}, + {file = "rpds_py-0.19.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:902cf4739458852fe917104365ec0efbea7d29a15e4276c96a8d33e6ed8ec137"}, + {file = "rpds_py-0.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f3d73022990ab0c8b172cce57c69fd9a89c24fd473a5e79cbce92df87e3d9c48"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3837c63dd6918a24de6c526277910e3766d8c2b1627c500b155f3eecad8fad65"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cdb7eb3cf3deb3dd9e7b8749323b5d970052711f9e1e9f36364163627f96da58"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26ab43b6d65d25b1a333c8d1b1c2f8399385ff683a35ab5e274ba7b8bb7dc61c"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75130df05aae7a7ac171b3b5b24714cffeabd054ad2ebc18870b3aa4526eba23"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c34f751bf67cab69638564eee34023909380ba3e0d8ee7f6fe473079bf93f09b"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f2671cb47e50a97f419a02cd1e0c339b31de017b033186358db92f4d8e2e17d8"}, + {file = "rpds_py-0.19.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c73254c256081704dba0a333457e2fb815364018788f9b501efe7c5e0ada401"}, + {file = "rpds_py-0.19.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4383beb4a29935b8fa28aca8fa84c956bf545cb0c46307b091b8d312a9150e6a"}, + {file = "rpds_py-0.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dbceedcf4a9329cc665452db1aaf0845b85c666e4885b92ee0cddb1dbf7e052a"}, + {file = "rpds_py-0.19.1-cp311-none-win32.whl", hash = "sha256:f0a6d4a93d2a05daec7cb885157c97bbb0be4da739d6f9dfb02e101eb40921cd"}, + {file = "rpds_py-0.19.1-cp311-none-win_amd64.whl", hash = "sha256:c149a652aeac4902ecff2dd93c3b2681c608bd5208c793c4a99404b3e1afc87c"}, + {file = "rpds_py-0.19.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:56313be667a837ff1ea3508cebb1ef6681d418fa2913a0635386cf29cff35165"}, + {file = "rpds_py-0.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d1d7539043b2b31307f2c6c72957a97c839a88b2629a348ebabe5aa8b626d6b"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1dc59a5e7bc7f44bd0c048681f5e05356e479c50be4f2c1a7089103f1621d5"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8f78398e67a7227aefa95f876481485403eb974b29e9dc38b307bb6eb2315ea"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef07a0a1d254eeb16455d839cef6e8c2ed127f47f014bbda64a58b5482b6c836"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8124101e92c56827bebef084ff106e8ea11c743256149a95b9fd860d3a4f331f"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08ce9c95a0b093b7aec75676b356a27879901488abc27e9d029273d280438505"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b02dd77a2de6e49078c8937aadabe933ceac04b41c5dde5eca13a69f3cf144e"}, + {file = "rpds_py-0.19.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4dd02e29c8cbed21a1875330b07246b71121a1c08e29f0ee3db5b4cfe16980c4"}, + {file = "rpds_py-0.19.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9c7042488165f7251dc7894cd533a875d2875af6d3b0e09eda9c4b334627ad1c"}, + {file = "rpds_py-0.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f809a17cc78bd331e137caa25262b507225854073fd319e987bd216bed911b7c"}, + {file = "rpds_py-0.19.1-cp312-none-win32.whl", hash = "sha256:3ddab996807c6b4227967fe1587febade4e48ac47bb0e2d3e7858bc621b1cace"}, + {file = "rpds_py-0.19.1-cp312-none-win_amd64.whl", hash = "sha256:32e0db3d6e4f45601b58e4ac75c6f24afbf99818c647cc2066f3e4b192dabb1f"}, + {file = "rpds_py-0.19.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:747251e428406b05fc86fee3904ee19550c4d2d19258cef274e2151f31ae9d38"}, + {file = "rpds_py-0.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dc733d35f861f8d78abfaf54035461e10423422999b360966bf1c443cbc42705"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbda75f245caecff8faa7e32ee94dfaa8312a3367397975527f29654cd17a6ed"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd04d8cab16cab5b0a9ffc7d10f0779cf1120ab16c3925404428f74a0a43205a"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2d66eb41ffca6cc3c91d8387509d27ba73ad28371ef90255c50cb51f8953301"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdf4890cda3b59170009d012fca3294c00140e7f2abe1910e6a730809d0f3f9b"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1fa67ef839bad3815124f5f57e48cd50ff392f4911a9f3cf449d66fa3df62a5"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b82c9514c6d74b89a370c4060bdb80d2299bc6857e462e4a215b4ef7aa7b090e"}, + {file = "rpds_py-0.19.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c7b07959866a6afb019abb9564d8a55046feb7a84506c74a6f197cbcdf8a208e"}, + {file = "rpds_py-0.19.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4f580ae79d0b861dfd912494ab9d477bea535bfb4756a2269130b6607a21802e"}, + {file = "rpds_py-0.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c6d20c8896c00775e6f62d8373aba32956aa0b850d02b5ec493f486c88e12859"}, + {file = "rpds_py-0.19.1-cp313-none-win32.whl", hash = "sha256:afedc35fe4b9e30ab240b208bb9dc8938cb4afe9187589e8d8d085e1aacb8309"}, + {file = "rpds_py-0.19.1-cp313-none-win_amd64.whl", hash = "sha256:1d4af2eb520d759f48f1073ad3caef997d1bfd910dc34e41261a595d3f038a94"}, + {file = "rpds_py-0.19.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:34bca66e2e3eabc8a19e9afe0d3e77789733c702c7c43cd008e953d5d1463fde"}, + {file = "rpds_py-0.19.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:24f8ae92c7fae7c28d0fae9b52829235df83f34847aa8160a47eb229d9666c7b"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71157f9db7f6bc6599a852852f3389343bea34315b4e6f109e5cbc97c1fb2963"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d494887d40dc4dd0d5a71e9d07324e5c09c4383d93942d391727e7a40ff810b"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b3661e6d4ba63a094138032c1356d557de5b3ea6fd3cca62a195f623e381c76"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97fbb77eaeb97591efdc654b8b5f3ccc066406ccfb3175b41382f221ecc216e8"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cc4bc73e53af8e7a42c8fd7923bbe35babacfa7394ae9240b3430b5dcf16b2a"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:35af5e4d5448fa179fd7fff0bba0fba51f876cd55212f96c8bbcecc5c684ae5c"}, + {file = "rpds_py-0.19.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3511f6baf8438326e351097cecd137eb45c5f019944fe0fd0ae2fea2fd26be39"}, + {file = "rpds_py-0.19.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:57863d16187995c10fe9cf911b897ed443ac68189179541734502353af33e693"}, + {file = "rpds_py-0.19.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9e318e6786b1e750a62f90c6f7fa8b542102bdcf97c7c4de2a48b50b61bd36ec"}, + {file = "rpds_py-0.19.1-cp38-none-win32.whl", hash = "sha256:53dbc35808c6faa2ce3e48571f8f74ef70802218554884787b86a30947842a14"}, + {file = "rpds_py-0.19.1-cp38-none-win_amd64.whl", hash = "sha256:8df1c283e57c9cb4d271fdc1875f4a58a143a2d1698eb0d6b7c0d7d5f49c53a1"}, + {file = "rpds_py-0.19.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e76c902d229a3aa9d5ceb813e1cbcc69bf5bda44c80d574ff1ac1fa3136dea71"}, + {file = "rpds_py-0.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de1f7cd5b6b351e1afd7568bdab94934d656abe273d66cda0ceea43bbc02a0c2"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fc5a84777cb61692d17988989690d6f34f7f95968ac81398d67c0d0994a897"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:74129d5ffc4cde992d89d345f7f7d6758320e5d44a369d74d83493429dad2de5"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e360188b72f8080fefa3adfdcf3618604cc8173651c9754f189fece068d2a45"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13e6d4840897d4e4e6b2aa1443e3a8eca92b0402182aafc5f4ca1f5e24f9270a"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f09529d2332264a902688031a83c19de8fda5eb5881e44233286b9c9ec91856d"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0d4b52811dcbc1aba08fd88d475f75b4f6db0984ba12275d9bed1a04b2cae9b5"}, + {file = "rpds_py-0.19.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd635c2c4043222d80d80ca1ac4530a633102a9f2ad12252183bcf338c1b9474"}, + {file = "rpds_py-0.19.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f35b34a5184d5e0cc360b61664c1c06e866aab077b5a7c538a3e20c8fcdbf90b"}, + {file = "rpds_py-0.19.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d4ec0046facab83012d821b33cead742a35b54575c4edfb7ed7445f63441835f"}, + {file = "rpds_py-0.19.1-cp39-none-win32.whl", hash = "sha256:f5b8353ea1a4d7dfb59a7f45c04df66ecfd363bb5b35f33b11ea579111d4655f"}, + {file = "rpds_py-0.19.1-cp39-none-win_amd64.whl", hash = "sha256:1fb93d3486f793d54a094e2bfd9cd97031f63fcb5bc18faeb3dd4b49a1c06523"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7d5c7e32f3ee42f77d8ff1a10384b5cdcc2d37035e2e3320ded909aa192d32c3"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:89cc8921a4a5028d6dd388c399fcd2eef232e7040345af3d5b16c04b91cf3c7e"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca34e913d27401bda2a6f390d0614049f5a95b3b11cd8eff80fe4ec340a1208"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5953391af1405f968eb5701ebbb577ebc5ced8d0041406f9052638bafe52209d"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:840e18c38098221ea6201f091fc5d4de6128961d2930fbbc96806fb43f69aec1"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d8b735c4d162dc7d86a9cf3d717f14b6c73637a1f9cd57fe7e61002d9cb1972"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce757c7c90d35719b38fa3d4ca55654a76a40716ee299b0865f2de21c146801c"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9421b23c85f361a133aa7c5e8ec757668f70343f4ed8fdb5a4a14abd5437244"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3b823be829407393d84ee56dc849dbe3b31b6a326f388e171555b262e8456cc1"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:5e58b61dcbb483a442c6239c3836696b79f2cd8e7eec11e12155d3f6f2d886d1"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39d67896f7235b2c886fb1ee77b1491b77049dcef6fbf0f401e7b4cbed86bbd4"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8b32cd4ab6db50c875001ba4f5a6b30c0f42151aa1fbf9c2e7e3674893fb1dc4"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1c32e41de995f39b6b315d66c27dea3ef7f7c937c06caab4c6a79a5e09e2c415"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1a129c02b42d46758c87faeea21a9f574e1c858b9f358b6dd0bbd71d17713175"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:346557f5b1d8fd9966059b7a748fd79ac59f5752cd0e9498d6a40e3ac1c1875f"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:31e450840f2f27699d014cfc8865cc747184286b26d945bcea6042bb6aa4d26e"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01227f8b3e6c8961490d869aa65c99653df80d2f0a7fde8c64ebddab2b9b02fd"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69084fd29bfeff14816666c93a466e85414fe6b7d236cfc108a9c11afa6f7301"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d2b88efe65544a7d5121b0c3b003ebba92bfede2ea3577ce548b69c5235185"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ea961a674172ed2235d990d7edf85d15d8dfa23ab8575e48306371c070cda67"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:5beffdbe766cfe4fb04f30644d822a1080b5359df7db3a63d30fa928375b2720"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:720f3108fb1bfa32e51db58b832898372eb5891e8472a8093008010911e324c5"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c2087dbb76a87ec2c619253e021e4fb20d1a72580feeaa6892b0b3d955175a71"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ddd50f18ebc05ec29a0d9271e9dbe93997536da3546677f8ca00b76d477680c"}, + {file = "rpds_py-0.19.1.tar.gz", hash = "sha256:31dd5794837f00b46f4096aa8ccaa5972f73a938982e32ed817bb520c465e520"}, ] [[package]] @@ -3291,18 +3295,19 @@ win32 = ["pywin32"] [[package]] name = "setuptools" -version = "70.2.0" +version = "72.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"}, - {file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"}, + {file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"}, + {file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"}, ] [package.extras] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -3350,26 +3355,26 @@ files = [ [[package]] name = "sphinx" -version = "7.3.7" +version = "7.4.7" description = "Python documentation generator" optional = false python-versions = ">=3.9" files = [ - {file = "sphinx-7.3.7-py3-none-any.whl", hash = "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3"}, - {file = "sphinx-7.3.7.tar.gz", hash = "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc"}, + {file = "sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"}, + {file = "sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe"}, ] [package.dependencies] alabaster = ">=0.7.14,<0.8.0" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18.1,<0.22" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" imagesize = ">=1.3" -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.14" -requests = ">=2.25.0" -snowballstemmer = ">=2.0" +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +snowballstemmer = ">=2.2" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" sphinxcontrib-htmlhelp = ">=2.0.0" @@ -3380,8 +3385,8 @@ tomli = {version = ">=2", markers = "python_version < \"3.11\""} [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "importlib_metadata", "mypy (==1.9.0)", "pytest (>=6.0)", "ruff (==0.3.7)", "sphinx-lint", "tomli", "types-docutils", "types-requests"] -test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=6.0)", "setuptools (>=67.0)"] +lint = ["flake8 (>=6.0)", "importlib-metadata (>=6.0)", "mypy (==1.10.1)", "pytest (>=6.0)", "ruff (==0.5.2)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-docutils (==0.21.0.20240711)", "types-requests (>=2.30.0)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] [[package]] name = "sphinx-external-toc" @@ -3425,17 +3430,17 @@ dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.8" +version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"}, - {file = "sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619"}, + {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, + {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] @@ -3458,33 +3463,33 @@ Sphinx = ">=3.5" [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.6" +version = "2.0.0" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f"}, - {file = "sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"}, + {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, + {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.5" +version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_htmlhelp-2.0.5-py3-none-any.whl", hash = "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04"}, - {file = "sphinxcontrib_htmlhelp-2.0.5.tar.gz", hash = "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015"}, + {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, + {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] @@ -3518,33 +3523,33 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.7" +version = "2.0.0" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_qthelp-1.0.7-py3-none-any.whl", hash = "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182"}, - {file = "sphinxcontrib_qthelp-1.0.7.tar.gz", hash = "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6"}, + {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, + {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] -test = ["pytest"] +test = ["defusedxml (>=0.7.1)", "pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.10" +version = "2.0.0" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7"}, - {file = "sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"}, + {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, + {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] @@ -3914,13 +3919,13 @@ test = ["websockets"] [[package]] name = "xarray" -version = "2024.6.0" +version = "2024.7.0" description = "N-D labeled arrays and datasets in Python" optional = false python-versions = ">=3.9" files = [ - {file = "xarray-2024.6.0-py3-none-any.whl", hash = "sha256:721a7394e8ec3d592b2d8ebe21eed074ac077dc1bb1bd777ce00e41700b4866c"}, - {file = "xarray-2024.6.0.tar.gz", hash = "sha256:0b91e0bc4dc0296947947640fe31ec6e867ce258d2f7cbc10bedf4a6d68340c7"}, + {file = "xarray-2024.7.0-py3-none-any.whl", hash = "sha256:1b0fd51ec408474aa1f4a355d75c00cc1c02bd425d97b2c2e551fd21810e7f64"}, + {file = "xarray-2024.7.0.tar.gz", hash = "sha256:4cae512d121a8522d41e66d942fb06c526bc1fd32c2c181d5fe62fe65b671638"}, ] [package.dependencies] diff --git a/pyproject.toml b/pyproject.toml index 8c28b9aa..772a40c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,10 +100,10 @@ module = "tests.*" addopts = """ -v -p no:warnings - -m "not profiling" - --cov=pyrealm + -m "not profiling" + --cov=pyrealm --cov-report=html:reports/coverage - --doctest-modules + --doctest-modules --ignore=pyrealm/__main__.py --ignore=tests/pmodel/generate_test_inputs.py """ diff --git a/pyrealm/core/utilities.py b/pyrealm/core/utilities.py index 03fa90f8..2e86d367 100644 --- a/pyrealm/core/utilities.py +++ b/pyrealm/core/utilities.py @@ -24,10 +24,10 @@ >>> import numpy as np >>> x = np.ma.masked_array([1,2,np.nan, 4], mask=[1,0,0,1]) >>> x.mean() - nan + np.float64(nan) >>> x = np.ma.masked_array([1,2,np.nan, 4], mask=[1,0,1,0]) >>> x.mean() - 3.0 + np.float64(3.0) So the general approach here is now: @@ -282,16 +282,16 @@ def bounds_mask( Examples: >>> vals = np.array([-15, 20, 30, 124], dtype=float) >>> np.nansum(vals) - 159.0 + np.float64(159.0) >>> vals_c = bounds_mask(vals, 0, 100, label='temperature') >>> np.nansum(vals_c) - 50.0 + np.float64(50.0) >>> vals_c = bounds_mask(vals, 0, 124, interval_type='[]', label='temperature') >>> np.nansum(vals_c) - 174.0 + np.float64(174.0) >>> vals_c = bounds_mask(vals, 0, 124, interval_type='[)', label='temperature') >>> np.nansum(vals_c) - 50.0 + np.float64(50.0) """ # Get the interval functions diff --git a/pyrealm/core/water.py b/pyrealm/core/water.py index 1d4a9ecc..72c7568b 100644 --- a/pyrealm/core/water.py +++ b/pyrealm/core/water.py @@ -37,7 +37,7 @@ def calc_density_h2o_chen( Examples: >>> round(calc_density_h2o_chen(20, 101325), 3) - 998.25 + np.float64(998.25) """ # Calculate density at 1 atm (kg/m^3): @@ -93,7 +93,7 @@ def calc_density_h2o_fisher( Examples: >>> round(calc_density_h2o_fisher(20, 101325), 3) - 998.206 + np.float64(998.206) """ # Check input shapes, shape not used @@ -156,7 +156,7 @@ def calc_density_h2o( Examples: >>> round(calc_density_h2o(20, 101325), 3) - 998.206 + np.float64(998.206) """ # Safe guard against instability in functions at low temperature. @@ -201,7 +201,7 @@ def calc_viscosity_h2o( Examples: >>> # Density of water at 20 degrees C and standard atmospheric pressure: >>> round(calc_viscosity_h2o(20, 101325), 7) - 0.0010016 + np.float64(0.0010016) """ # Check inputs, return shape not used @@ -269,7 +269,7 @@ def calc_viscosity_h2o_matrix( Examples: >>> # Density of water at 20 degrees C and standard atmospheric pressure: >>> round(calc_viscosity_h2o(20, 101325), 7) - 0.0010016 + np.float64(0.0010016) """ # Check inputs, return shape not used diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index e5a198ab..84692690 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -110,7 +110,7 @@ def calc_ftemp_inst_rd( >>> # Relative percentage instantaneous change in Rd going from 10 to 25 degrees >>> val = (calc_ftemp_inst_rd(25) / calc_ftemp_inst_rd(10) - 1) * 100 >>> round(val, 4) - 250.9593 + np.float64(250.9593) """ return np.exp( @@ -306,13 +306,13 @@ def calc_ftemp_kphio( >>> # degrees celsius (percent change): >>> val = (calc_ftemp_kphio(25.0) / calc_ftemp_kphio(5.0) - 1) * 100 >>> round(val, 5) - 52.03969 + np.float64(52.03969) >>> # Relative change in the quantum yield efficiency between 5 and 25 >>> # degrees celsius (percent change) for a C4 plant: >>> val = (calc_ftemp_kphio(25.0, c4=True) / ... calc_ftemp_kphio(5.0, c4=True) - 1) * 100 >>> round(val, 5) - 432.25806 + np.float64(432.25806) """ if c4: @@ -411,7 +411,7 @@ def calc_ns_star( >>> # Relative viscosity at 20 degrees Celsius and standard >>> # atmosphere (in Pa): >>> round(calc_ns_star(20, 101325), 5) - 1.12536 + np.float64(1.12536) """ visc_env = calc_viscosity_h2o(tc, patm, core_const=core_const) @@ -729,7 +729,7 @@ def calc_co2_to_ca(co2: NDArray, patm: NDArray) -> NDArray: Examples: >>> np.round(calc_co2_to_ca(413.03, 101325), 6) - 41.850265 + np.float64(41.850265) """ return 1.0e-6 * co2 * patm # Pa, atms. CO2 From 1f315ba49da72bd76f19c79a025689aac0829aba Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 17:59:51 +0000 Subject: [PATCH 039/241] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.5.5 → v0.5.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.5...v0.5.6) - [github.com/pre-commit/mirrors-mypy: v1.11.0 → v1.11.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.0...v1.11.1) - [github.com/mwouts/jupytext: v1.16.4 → v1.16.4b](https://github.com/mwouts/jupytext/compare/v1.16.4...v1.16.4b) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 278a608b..7feca378 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ repos: - id: debug-statements - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.5.5 + rev: v0.5.6 hooks: # Run the linter. - id: ruff @@ -14,7 +14,7 @@ repos: # Run the formatter. - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.11.0" + rev: "v1.11.1" hooks: - id: mypy additional_dependencies: [numpy, types-tabulate, pandas-stubs] @@ -25,7 +25,7 @@ repos: hooks: - id: markdownlint - repo: https://github.com/mwouts/jupytext - rev: v1.16.4 + rev: v1.16.4b hooks: - id: jupytext args: [--pipe, black] From e758592b2c0131dff12d4790680237936f4bb912 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 6 Aug 2024 14:30:31 +0100 Subject: [PATCH 040/241] Doc updates --- docs/source/conf.py | 2 +- docs/source/refs.bib | 1566 +++++++++-------- .../pmodel/pmodel_details/lue_limitation.md | 257 ++- .../pmodel/pmodel_details/pmodel_overview.md | 33 +- pyrealm/pmodel/quantum_yield.py | 14 +- 5 files changed, 995 insertions(+), 877 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index a9905789..73f896ad 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -82,7 +82,7 @@ class MyReferenceStyle(AuthorYearReferenceStyle): ) bibtex_reference_style = "author_year_round" - +bibtex_default_style = "plain" # Cross-reference checking # TODO - find some better solution than this to all of these bizarre cross reference diff --git a/docs/source/refs.bib b/docs/source/refs.bib index 4a8b91e0..75945668 100644 --- a/docs/source/refs.bib +++ b/docs/source/refs.bib @@ -1,860 +1,886 @@ - -@article{Wang:2020ik, - title = {Acclimation of leaf respiration consistent with optimal photosynthetic capacity}, - volume = {26}, - url = {https://onlinelibrary.wiley.com/doi/10.1111/gcb.14980}, - doi = {10.1111/gcb.14980}, - language = {english}, - number = {4}, - journal = {Global Change Biology}, - author = {Wang, Han and Atkin, Owen K and Keenan, Trevor F and Smith, Nicholas G and Wright, Ian J. and Bloomfield, Keith J and Kattge, Jens and Reich, Peter B and Prentice, I. Colin}, - month = feb, - year = {2020}, - note = {tex.date-added: 2020-11-30T12:23:58GMT - tex.date-modified: 2021-01-22T13:54:24GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Wang/Global\%20Change\%20Biol\%202020\%20Wang.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1111/gcb.14980}, - pages = {2573--2583}, - file = {gcb15314-sup-0004-Supinfo.pdf:/Users/dorme/Zotero/storage/NSCU7SWY/gcb15314-sup-0004-Supinfo.pdf:application/pdf;Global Change Biol 2020 Wang.pdf:/Users/dorme/Zotero/storage/4C9SVQUB/Global Change Biol 2020 Wang.pdf:application/pdf} +@techreport{allen:1998a, + title = {Crop Evapotranspiration - {{Guidelines}} for Computing Crop Water Requirements}, + author = {Allen, Richard G. and Pereira, Luis S and Raes, Dirk and Smith, Martin}, + year = {1998}, + number = {56}, + address = {Rome}, + institution = {FAO}, + file = {/Users/dorme/Zotero/storage/UW9UBHX2/Allen et al. - 1998 - Crop evapotranspiration - Guidelines for computing.pdf} } -@article{Wang:2017go, - title = {Towards a universal model for carbon dioxide uptake by plants}, - url = {http://dx.doi.org/10.1038/s41477-017-0006-8}, - doi = {10.1038/s41477-017-0006-8}, - abstract = {Nature Plants, doi:10.1038/s41477-017-0006-8}, - journal = {Nature Plants}, - author = {Wang, Han and Prentice, I. Colin and Keenan, Trevor F and Davis, Tyler W and Wright, Ian J. and Cornwell, William K and Evans, Bradley J and Peng, Changhui}, - month = sep, - year = {2017}, - note = {Publisher: Springer US - tex.date-added: 2020-11-30T12:27:00GMT - tex.date-modified: 2021-01-28T09:14:19GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2017/Wang/Nature\%20Plants\%202017\%20Wang.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1038/s41477-017-0006-8}, - pages = {1--8}, - file = {Nature Plants 2017 Wang.pdf:/Users/dorme/Zotero/storage/XIP7696Y/Nature Plants 2017 Wang.pdf:application/pdf} +@article{Argles:2020cy, + title = {Robust {{Ecosystem Demography}} ({{RED}} Version 1.0): A Parsimonious Approach to Modelling Vegetation Dynamics in {{Earth}} System Models}, + author = {Argles, Arthur P K and Moore, Jonathan R and Huntingford, Chris and Wiltshire, Andrew J and Harper, Anna B and Jones, Chris D and Cox, Peter M}, + year = {2020}, + journal = {Geoscientific Model Development}, + volume = {13}, + number = {9}, + pages = {4067--4089}, + doi = {10.5194/gmd-13-4067-2020}, + date-added = {2020-12-01T16:58:12GMT}, + date-modified = {2021-07-22T14:23:35GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Argles/Geoscientific\%20Model\%20Development\%202020\%20Argles.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.5194/gmd-13-4067-2020}, + file = {/Users/dorme/Zotero/storage/WKQGYNRT/Geoscientific Model Development 2020 Argles.pdf} } -@article{Huber:2009fy, - title = {New international formulation for the viscosity of {H2O}}, - volume = {38}, - url = {http://aip.scitation.org/doi/10.1063/1.3088050}, - doi = {10.1063/1.3088050}, - language = {english}, - number = {2}, - journal = {Journal of Physical and Chemical Reference Data}, - author = {Huber, M L and Perkins, R A and Laesecke, A and Friend, D G and Sengers, J V and Assael, M J and Metaxa, I N and Vogel, E and Mareš, R and Miyagawa, K}, - month = jun, - year = {2009}, - note = {tex.date-added: 2020-12-02T09:52:51GMT - tex.date-modified: 2020-12-17T08:58:40GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2009/Huber/Journal\%20of\%20Physical\%20and\%20Chemical\%20Reference\%20Data\%202009\%20Huber.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1063/1.3088050}, - pages = {101--125}, - file = {Journal of Physical and Chemical Reference Data 2009 Huber.pdf:/Users/dorme/Zotero/storage/D2W4H4S4/Journal of Physical and Chemical Reference Data 2009 Huber.pdf:application/pdf} +@article{Atkin:2015hk, + title = {Global Variability in Leaf Respiration in Relation to Climate, Plant Functional Types and Leaf Traits.}, + author = {Atkin, Owen K and Bloomfield, Keith J and Reich, Peter B and Tjoelker, Mark G and Asner, Gregory P. and Bonal, Damien and B{\"o}nisch, Gerhard and Bradford, Matt G and Cernusak, Lucas A and Cosio, Eric G and Creek, Danielle and Crous, Kristine Y and Domingues, Tomas F and Dukes, Jeffrey S and Egerton, John J G and Evans, John R and Farquhar, Graham D and Fyllas, Nikolaos M and Gauthier, Paul P G and Gloor, Emanuel and Gimeno, Teresa E and Griffin, Kevin L and Guerrieri, Rossella and Heskel, Mary A and Huntingford, Chris and Ishida, Fran{\c c}oise Yoko and Kattge, Jens and Lambers, Hans and Liddell, Michael J and Lloyd, Jon and Lusk, Christopher H and Martin, Roberta E and Maksimov, Ayal P and Maximov, Trofim C and Malhi, Yadvinder and Medlyn, Belinda E and Meir, Patrick and Mercado, Lina M and Mirotchnick, Nicholas and Ng, Desmond and Niinemets, {\"U}lo and O'Sullivan, Odhran S and Phillips, Oliver L and Poorter, Lourens and Poot, Pieter and Prentice, I. Colin and Salinas, Norma and Rowland, Lucy M and Ryan, Michael G and Sitch, Stephen and Slot, Martijn and Smith, Nicholas G and Turnbull, Matthew H and VanderWel, Mark C and Valladares, Fernando and Veneklaas, Erik J and Weerasinghe, Lasantha K and Wirth, Christian and Wright, Ian J. and Wythers, Kirk R and Xiang, Jen and Xiang, Shuang and {Zaragoza-Castells}, Joana}, + year = {2015}, + month = apr, + journal = {New Phytologist}, + volume = {206}, + number = {2}, + pages = {614--636}, + doi = {10.1111/nph.13253}, + abstract = {Leaf dark respiration (Rdark ) is an important yet poorly quantified component of the global carbon cycle. Given this, we analyzed a new global database of Rdark and associated leaf traits. Data for 899 species were compiled from 100 sites (from the Arctic to the tropics). Several woody and nonwoody plant functional types (PFTs) were represented. Mixed-effects models were used to disentangle sources of variation in Rdark . Area-based Rdark at the prevailing average daily growth temperature (T) of each site increased only twofold from the Arctic to the tropics, despite a 20{$^\circ$}C increase in growing T (8-28{$^\circ$}C). By contrast, Rdark at a standard T (25{$^\circ$}C, Rdark (25) ) was threefold higher in the Arctic than in the tropics, and twofold higher at arid than at mesic sites. Species and PFTs at cold sites exhibited higher Rdark (25) at a given photosynthetic capacity (Vcmax (25) ) or leaf nitrogen concentration ([N]) than species at warmer sites. Rdark (25) values at any given Vcmax (25) or [N] were higher in herbs than in woody plants. The results highlight variation in Rdark among species and across global gradients in T and aridity. In addition to their ecological significance, the results provide a framework for improving representation of Rdark in terrestrial biosphere models (TBMs) and associated land-surface components of Earth system models (ESMs).}, + affiliation = {ARC Centre of Excellence in Plant Energy Biology, Research School of Biology, The Australian National University, Building 134, Canberra, ACT, 0200, Australia; Division of Plant Sciences, Research School of Biology, The Australian National University, Building 46, Canberra, ACT, 0200, Australia.}, + date-added = {2021-01-28T11:56:12GMT}, + date-modified = {2021-01-28T15:58:45GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2015/Atkin/New\%20Phytol.\%202015\%20Atkin.pdf}, + pmid = {25581061}, + rating = {0}, + uri = {papers3://publication/doi/10.1111/nph.13253}, + file = {/Users/dorme/Zotero/storage/JCS7TM7H/New Phytol. 2015 Atkin.pdf} } -@article{Argles:2020cy, - title = {Robust {Ecosystem} {Demography} ({RED} version 1.0): a parsimonious approach to modelling vegetation dynamics in {Earth} system models}, - volume = {13}, - url = {https://gmd.copernicus.org/articles/13/4067/2020/}, - doi = {10.5194/gmd-13-4067-2020}, - language = {english}, - number = {9}, - journal = {Geoscientific Model Development}, - author = {Argles, Arthur P K and Moore, Jonathan R and Huntingford, Chris and Wiltshire, Andrew J and Harper, Anna B and Jones, Chris D and Cox, Peter M}, - year = {2020}, - note = {tex.date-added: 2020-12-01T16:58:12GMT - tex.date-modified: 2021-07-22T14:23:35GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Argles/Geoscientific\%20Model\%20Development\%202020\%20Argles.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.5194/gmd-13-4067-2020}, - pages = {4067--4089}, - file = {Geoscientific Model Development 2020 Argles.pdf:/Users/dorme/Zotero/storage/6WTVNVIZ/Geoscientific Model Development 2020 Argles.pdf:application/pdf} +@article{badeck:2005a, + title = {Post-Photosynthetic Fractionation of Stable Carbon Isotopes between Plant Organs---a Widespread Phenomenon}, + author = {Badeck, Franz-W. and Tcherkez, Guillaume and Nogu{\'e}s, Salvador and Piel, Cl{\'e}ment and Ghashghaie, Jaleh}, + year = {2005}, + journal = {Rapid Communications in Mass Spectrometry}, + volume = {19}, + number = {11}, + eprint = {https://analyticalsciencejournals.onlinelibrary.wiley.com/doi/pdf/10.1002/rcm.1912}, + pages = {1381--1391}, + doi = {10.1002/rcm.1912}, + abstract = {Abstract Discrimination against 13C during photosynthesis is a well-characterised phenomenon. It leaves behind distinct signatures in organic matter of plants and in the atmosphere. The former is depleted in 13C, the latter is enriched during periods of preponderant photosynthetic activity of terrestrial ecosystems. The intra-annual cycle and latitudinal gradient in atmospheric 13C resulting from photosynthetic and respiratory activities of terrestrial plants have been exploited for the reconstruction of sources and sinks through deconvolution by inverse modelling. Here, we compile evidence for widespread post-photosynthetic fractionation that further modifies the isotopic signatures of individual plant organs and consequently leads to consistent differences in {$\delta$}13C between plant organs. Leaves were on average 0.96‰ and 1.91‰ more depleted than roots and woody stems, respectively. This phenomenon is relevant if the isotopic signature of CO2-exchange fluxes at the ecosystem level is used for the reconstruction of individual sources and sinks. It may also modify the parameterisation of inverse modelling approaches if it leads to different isotopic signatures of organic matter with different residence times within the ecosystems and to a respiratory contribution to the average difference between the isotopic composition of plant organic matter and the atmosphere. We discuss the main hypotheses that can explain the observed inter-organ differences in {$\delta$}13C. Copyright {\copyright} 2005 John Wiley \& Sons, Ltd.}, + file = {/Users/dorme/Zotero/storage/2NXLVXHK/Badeck et al. - 2005 - Post-photosynthetic fractionation of stable carbon.pdf} } -@article{Atkin:2015hk, - title = {Global variability in leaf respiration in relation to climate, plant functional types and leaf traits.}, - volume = {206}, - url = {http://doi.wiley.com/10.1111/nph.13253}, - doi = {10.1111/nph.13253}, - abstract = {Leaf dark respiration (Rdark ) is an important yet poorly quantified component of the global carbon cycle. Given this, we analyzed a new global database of Rdark and associated leaf traits. Data for 899 species were compiled from 100 sites (from the Arctic to the tropics). Several woody and nonwoody plant functional types (PFTs) were represented. Mixed-effects models were used to disentangle sources of variation in Rdark . Area-based Rdark at the prevailing average daily growth temperature (T) of each site increased only twofold from the Arctic to the tropics, despite a 20°C increase in growing T (8-28°C). By contrast, Rdark at a standard T (25°C, Rdark (25) ) was threefold higher in the Arctic than in the tropics, and twofold higher at arid than at mesic sites. Species and PFTs at cold sites exhibited higher Rdark (25) at a given photosynthetic capacity (Vcmax (25) ) or leaf nitrogen concentration ([N]) than species at warmer sites. Rdark (25) values at any given Vcmax (25) or [N] were higher in herbs than in woody plants. The results highlight variation in Rdark among species and across global gradients in T and aridity. In addition to their ecological significance, the results provide a framework for improving representation of Rdark in terrestrial biosphere models (TBMs) and associated land-surface components of Earth system models (ESMs).}, - language = {english}, - number = {2}, - journal = {New Phytologist}, - author = {Atkin, Owen K and Bloomfield, Keith J and Reich, Peter B and Tjoelker, Mark G and Asner, Gregory P. and Bonal, Damien and Bönisch, Gerhard and Bradford, Matt G and Cernusak, Lucas A and Cosio, Eric G and Creek, Danielle and Crous, Kristine Y and Domingues, Tomas F and Dukes, Jeffrey S and Egerton, John J G and Evans, John R and Farquhar, Graham D and Fyllas, Nikolaos M and Gauthier, Paul P G and Gloor, Emanuel and Gimeno, Teresa E and Griffin, Kevin L and Guerrieri, Rossella and Heskel, Mary A and Huntingford, Chris and Ishida, Françoise Yoko and Kattge, Jens and Lambers, Hans and Liddell, Michael J and Lloyd, Jon and Lusk, Christopher H and Martin, Roberta E and Maksimov, Ayal P and Maximov, Trofim C and Malhi, Yadvinder and Medlyn, Belinda E and Meir, Patrick and Mercado, Lina M and Mirotchnick, Nicholas and Ng, Desmond and Niinemets, Ülo and O’Sullivan, Odhran S and Phillips, Oliver L and Poorter, Lourens and Poot, Pieter and Prentice, I. Colin and Salinas, Norma and Rowland, Lucy M and Ryan, Michael G and Sitch, Stephen and Slot, Martijn and Smith, Nicholas G and Turnbull, Matthew H and VanderWel, Mark C and Valladares, Fernando and Veneklaas, Erik J and Weerasinghe, Lasantha K and Wirth, Christian and Wright, Ian J. and Wythers, Kirk R and Xiang, Jen and Xiang, Shuang and Zaragoza-Castells, Joana}, - month = apr, - year = {2015}, - pmid = {25581061}, - note = {tex.affiliation: ARC Centre of Excellence in Plant Energy Biology, Research School of Biology, The Australian National University, Building 134, Canberra, ACT, 0200, Australia; Division of Plant Sciences, Research School of Biology, The Australian National University, Building 46, Canberra, ACT, 0200, Australia. - tex.date-added: 2021-01-28T11:56:12GMT - tex.date-modified: 2021-01-28T15:58:45GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2015/Atkin/New\%20Phytol.\%202015\%20Atkin.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1111/nph.13253}, - pages = {614--636}, - file = {New Phytol. 2015 Atkin.pdf:/Users/dorme/Zotero/storage/JEF8GCAD/New Phytol. 2015 Atkin.pdf:application/pdf} +@article{BerberanSantos:2009bk, + title = {On the Barometric Formula inside the {{Earth}}}, + author = {{Berberan-Santos}, Mario N and Bodunov, Evgeny N and Pogliani, Lionello}, + year = {2009}, + month = oct, + journal = {Journal of Mathematical Chemistry}, + volume = {47}, + number = {3}, + pages = {990--1004}, + doi = {10.1007/s10910-009-9620-7}, + date-added = {2020-11-30T16:18:45GMT}, + date-modified = {2020-11-30T16:19:02GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2009/Berberan-Santos/J\%20Math\%20Chem\%202009\%20Berberan-Santos.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1007/s10910-009-9620-7}, + file = {/Users/dorme/Zotero/storage/EN33QA2H/J Math Chem 2009 Berberan-Santos.pdf} } -@article{Stocker:2020dh, - title = {P-model v1.0: an optimality-based light use efficiency model for simulating ecosystem gross primary production}, - volume = {13}, - url = {https://gmd.copernicus.org/articles/13/1545/2020/}, - doi = {10.5194/gmd-13-1545-2020}, - language = {english}, - number = {3}, - journal = {Geoscientific Model Development}, - author = {Stocker, Benjamin D and Wang, Han and Smith, Nicholas G and Harrison, Sandy P and Keenan, Trevor F and Sandoval, David and Davis, Tyler and Prentice, I. Colin}, - year = {2020}, - note = {tex.date-added: 2020-11-30T12:24:06GMT - tex.date-modified: 2021-01-28T11:55:51GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Stocker/Geoscientific\%20Model\%20Development\%202020\%20Stocker.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.5194/gmd-13-1545-2020}, - pages = {1545--1581}, - file = {Geoscientific Model Development 2020 Stocker.pdf:/Users/dorme/Zotero/storage/87D3WF3G/Geoscientific Model Development 2020 Stocker.pdf:application/pdf} +@article{berger:1978a, + title = {Long-{{Term Variations}} of {{Daily Insolation}} and {{Quaternary Climatic Changes}}}, + author = {Berger, Andr{\'e}L}, + year = {1978}, + month = dec, + journal = {Journal of the Atmospheric Sciences}, + volume = {35}, + number = {12}, + pages = {2362--2367}, + publisher = {American Meteorological Society}, + issn = {0022-4928, 1520-0469}, + doi = {10.1175/1520-0469(1978)035<2362:LTVODI>2.0.CO;2}, + urldate = {2023-07-13}, + abstract = {Abstract The first part of this note provides all trigonometrical formulas which allow the direct spectral analysis and the computation of those long-term variations of the earth's orbital elements which are of primary interest for the computation of the insolation. The elements are the eccentricity, the longitude of the perihelion, the processional parameter and the obliquity. This new formulary is much more simple to use than the ones previously designed and still provides excellent accuracy, mainly because it takes into account the influence of the most important higher order terms in the series expansions. The second part is devoted to the computation of the daily insolation both for calendar and solar dates.}, + chapter = {Journal of the Atmospheric Sciences}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/DPM5WN32/Berger - 1978 - Long-Term Variations of Daily Insolation and Quate.pdf} +} + +@article{berger:1993a, + title = {Insolation and {{Earth}}'s Orbital Periods}, + author = {Berger, Andr{\'e} and Loutre, Marie-France and Tricot, Christian}, + year = {1993}, + journal = {Journal of Geophysical Research: Atmospheres}, + volume = {98}, + number = {D6}, + pages = {10341--10362}, + issn = {2156-2202}, + doi = {10.1029/93JD00222}, + urldate = {2024-08-02}, + abstract = {Solar irradiance received on a horizontal surface depends on the solar output, the semimajor axis of the elliptical orbit of the Earth around the sun (a), the distance from the Earth to the sun (r), and the zenith distance (z). The spectrum of the distance, r, for a given value of the true longitude, {$\lambda$}, displays mainly the precessional periods and, with much less power, half precession periods, eccentricity periods, and some combination tones. The zenith distance or its equivalent, the elevation angle (E), is only a function of obliquity ({$\epsilon$}) for a given latitude, {$\phi$}, true longitude, and hour angle, H. Therefore the insolation at a given constant value of z is only a function of precession and eccentricity. On the other hand, the value of the hour angle, H, corresponding to this fixed value of z varies with {$\varepsilon$}, except for the equinoxes, where H corresponding to a constant z also remains constant through time. Three kinds of insolation have been computed both analytically and numerically: the instantaneous insolation (irradiance) at noon, the daily irradiation, and the irradiations received during particular time intervals of the day defined by two constant values of the zenith distance (diurnal irradiations). Mean irradiances (irradiations divided by the length of the time interval over which they are calculated) are also computed for different time intervals, like the interval between sunrise and sunset, in particular. Examples of these insolations are given in this paper for the equinoxes and the solstices. At the equinoxes, for each latitude, all insolations are only a function of precession (this invalidates the results obtained by Cerveny [1991]). At the solstices, both precession and obliquity are present, although precession dominates for most of the latitudes. Because the lengths of the astronomical seasons are secularly variable (in terms of precession only), a particular calendar day does not always correspond to the same position relative to the sun through geological time. Similarly, a given longitude of the Sun on its orbit does not correspond to the same calendar day. For example, 103 kyr ago, assuming arbitrarily that the spring equinox is always on March 21, autumn began on September 13, and 114 kyr ago, it began on September 27, the length of the summer season being 85 and 98 calendar days, respectively, at these remote times in the past.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/ALTXDVSM/Berger et al. - 1993 - Insolation and Earth's orbital periods.pdf;/Users/dorme/Zotero/storage/HWQ4XSZN/93JD00222.html} } -@article{BerberanSantos:2009bk, - title = {On the barometric formula inside the {Earth}}, - volume = {47}, - url = {http://link.springer.com/10.1007/s10910-009-9620-7}, - doi = {10.1007/s10910-009-9620-7}, - language = {english}, - number = {3}, - journal = {Journal of Mathematical Chemistry}, - author = {Berberan-Santos, Mario N and Bodunov, Evgeny N and Pogliani, Lionello}, - month = oct, - year = {2009}, - note = {tex.date-added: 2020-11-30T16:18:45GMT - tex.date-modified: 2020-11-30T16:19:02GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2009/Berberan-Santos/J\%20Math\%20Chem\%202009\%20Berberan-Santos.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1007/s10910-009-9620-7}, - pages = {990--1004}, - file = {J Math Chem 2009 Berberan-Santos.pdf:/Users/dorme/Zotero/storage/7WD7PHD7/J Math Chem 2009 Berberan-Santos.pdf:application/pdf} +@article{Bernacchi:2001kg, + title = {Improved Temperature Response Functions for Models of {{Rubisco-limited}} Photosynthesis}, + author = {Bernacchi, C J and Singsaas, E L and Pimentel, C and Portis Jr, A R and Long, S P}, + year = {2001}, + journal = {Plant, Cell \& Environment}, + volume = {24}, + number = {2}, + pages = {253--259}, + doi = {10.1111/j.1365-3040.2001.00668.x}, + date-added = {2020-11-30T12:24:10GMT}, + date-modified = {2020-11-30T14:42:53GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2001/Bernacchi/Plant\%20Cell\%20\&\%20Environment\%202001\%20Bernacchi.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1111/j.1365-3040.2001.00668.x}, + file = {/Users/dorme/Zotero/storage/FI9562Z3/Plant Cell & Environment 2001 Bernacchi.pdf} } -@book{Fisher:1975tm, - title = {Equation of state of pure water and sea water}, - url = {https://apps.dtic.mil/dtic/tr/fulltext/u2/a017775.pdf}, - publisher = {Scripps Institution of Oceanography}, - author = {Fisher, F H and Dial Jr, O E}, - year = {1975}, - note = {tex.date-added: 2020-11-30T12:27:10GMT - tex.date-modified: 2021-01-21T15:04:43GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Books/1975/Fisher/1975\%20Fisher.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/uuid/5D2C2C96-7975-4AB9-8314-A988EFA489FF}, - file = {1975 Fisher.pdf:/Users/dorme/Zotero/storage/MNQYGV9P/1975 Fisher.pdf:application/pdf} +@article{Bernacchi:2003dc, + title = {In Vivo Temperature Response Functions of Parameters Required to Model {{RuBP-limited}} Photosynthesis}, + author = {Bernacchi, C J and Pimentel, C and Long, S P}, + year = {2003}, + month = sep, + journal = {Plant, Cell \& Environment}, + volume = {26}, + number = {9}, + pages = {1419--1430}, + publisher = {John Wiley \& Sons, Ltd}, + doi = {10.1046/j.0016-8025.2003.01050.x}, + abstract = {The leaf model of C3 photosynthesis of Farquhar, von Caemmerer \& Berry (Planta 149, 78--90, 1980) provides the basis for scaling carbon exchange from leaf to canopy and Earth-System models, and is wid...}, + date-added = {2020-11-30T14:15:56GMT}, + date-modified = {2020-11-30T14:42:52GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2003/Bernacchi/Plant\%20Cell\%20\&\%20Environment\%202003\%20Bernacchi.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1046/j.0016-8025.2003.01050.x}, + file = {/Users/dorme/Zotero/storage/7J2I98DM/Plant Cell & Environment 2003 Bernacchi.pdf} } -@article{DeKauwe:2015im, - title = {A test of an optimal stomatal conductance scheme within the {CABLE} land surface model}, - volume = {8}, - url = {https://gmd.copernicus.org/articles/8/431/2015/gmd-8-431-2015.pdf}, - doi = {10.5194/gmd-8-431-2015}, - abstract = {¡p¿¡strong class="journal-contentHeaderColor"¿Abstract.¡/strong¿ Stomatal conductance (¡i¿g¡/i¿¡sub¿s¡/sub¿) affects the fluxes of carbon, energy and water between the vegetated land surface and the atmosphere. We test an implementation of an optimal stomatal conductance model within the Community Atmosphere Biosphere Land Exchange (CABLE) land surface model (LSM). In common with many LSMs, CABLE does not differentiate between ¡i¿g¡/i¿¡sub¿s¡/sub¿ model parameters in relation to plant functional type (PFT), but instead only in relation to photosynthetic pathway. We constrained the key model parameter "¡i¿g¡/i¿¡sub¿1¡/sub¿", which represents plant water use strategy, by PFT, based on a global synthesis of stomatal behaviour. As proof of concept, we also demonstrate that the ¡i¿g¡/i¿¡sub¿1¡/sub¿ parameter can be estimated using two long-term average (1960–1990) bioclimatic variables: (i) temperature and (ii) an indirect estimate of annual plant water availability. The new stomatal model, in conjunction with PFT parameterisations, resulted in a large reduction in annual fluxes of transpiration ({\textasciitilde} 30\% compared to the standard CABLE simulations) across evergreen needleleaf, tundra and C4 grass regions. Differences in other regions of the globe were typically small. Model performance against upscaled data products was not degraded, but did not noticeably reduce existing model–data biases. We identified assumptions relating to the coupling of the vegetation to the atmosphere and the parameterisation of the minimum stomatal conductance as areas requiring further investigation in both CABLE and potentially other LSMs. We conclude that optimisation theory can yield a simple and tractable approach to predicting stomatal conductance in LSMs.¡/p¿}, - language = {english}, - number = {2}, - journal = {Geoscientific Model Development}, - author = {De Kauwe, M G and Kala, J and Lin, Y S and Pitman, A J and Medlyn, B E and Duursma, R A and Abramowitz, G and Wang, Y P and Miralles, D G}, - month = feb, - year = {2015}, - note = {Publisher: Copernicus GmbH - tex.date-added: 2021-11-11T14:04:21GMT - tex.date-modified: 2021-11-11T14:13:27GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2015/De\%20Kauwe/Geoscientific\%20Model\%20Development\%202015\%20De\%20Kauwe.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.5194/gmd-8-431-2015}, - pages = {431--452}, - file = {Geoscientific Model Development 2015 De Kauwe.pdf:/Users/dorme/Zotero/storage/2SQR2JU6/Geoscientific Model Development 2015 De Kauwe.pdf:application/pdf;Geoscientific Model Development 2015 De Kauwe.pdf:/Users/dorme/Zotero/storage/Y65YLM8W/Geoscientific Model Development 2015 De Kauwe.pdf:application/pdf} +@article{boyd:2015a, + title = {Temperature Response of {{C4}} Photosynthesis: {{Biochemical}} Analysis of {{Rubisco}}, {{Phosphoenolpyruvate Carboxylase}} and {{Carbonic Anhydrase}} in {{Setaria}} Viridis.}, + shorttitle = {Temperature Response of {{C4}} Photosynthesis}, + author = {Boyd, Ryan Allen and Gandin, Anthony and Cousins, Asaph B}, + year = {2015}, + month = sep, + journal = {Plant Physiology}, + pages = {pp.00586.2015}, + issn = {0032-0889, 1532-2548}, + doi = {10.1104/pp.15.00586}, + urldate = {2022-05-20}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/P866H95S/Boyd et al. - 2015 - Temperature response of C4 photosynthesis Biochem.pdf} } -@article{Moore:2018dv, - title = {Equilibrium forest demography explains the distribution of tree sizes across {North} {America}}, - volume = {13}, - url = {https://iopscience.iop.org/article/10.1088/1748-9326/aad6d1}, - doi = {10.1088/1748-9326/aad6d1}, - abstract = {Environmental Research Letters, 13(2018) 084019. doi:10.1088/1748-9326/aad6d1}, - number = {8}, - journal = {Environmental Research Letters}, - author = {Moore, Jonathan R and Zhu, Kai and Huntingford, Chris and Cox, Peter M}, - month = aug, - year = {2018}, - note = {Publisher: IOP Publishing - tex.date-added: 2020-12-01T16:56:53GMT - tex.date-modified: 2020-12-17T08:58:39GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Moore/Environ\%20Res\%20Lett\%202018\%20Moore.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1088/1748-9326/aad6d1}, - pages = {084019--10}, - file = {Environ Res Lett 2018 Moore.pdf:/Users/dorme/Zotero/storage/XT8SWLIA/Environ Res Lett 2018 Moore.pdf:application/pdf} +@article{cai:2020a, + title = {Recent Trends in Gross Primary Production and Their Drivers: Analysis and Modelling at Flux-Site and Global Scales}, + shorttitle = {Recent Trends in Gross Primary Production and Their Drivers}, + author = {Cai, Wenjia and Prentice, Iain Colin}, + year = {2020}, + month = dec, + journal = {Environmental Research Letters}, + volume = {15}, + number = {12}, + pages = {124050}, + issn = {1748-9326}, + doi = {10.1088/1748-9326/abc64e}, + urldate = {2022-05-16}, + abstract = {Abstract Gross primary production (GPP) by terrestrial ecosystems is the largest flux in the global carbon cycle, and its continuing increase in response to environmental changes is key to land ecosystems' capacity to offset anthropogenic CO 2 emissions. However, the CO 2 - and climate-sensitivities of GPP vary among models. We applied the `P model'---a parameter-sparse and extensively tested light use efficiency (LUE) model, driven by CO 2 , climate and remotely sensed greenness data---at 29 sites with multi-year eddy-covariance flux measurements. Observed (both positive and negative) GPP trends at these sites were predicted, albeit with some bias. Increasing LUE (due to rising atmospheric CO 2 concentration) and green vegetation cover were the primary controls of modelled GPP trends across sites. Global GPP simulated by the same model increased by 0.46 {\textpm} 0.09 Pg C yr --2 during 1982--2016. This increase falls in the mid-range rate of simulated increase by the TRENDY v8 ensemble of state-of-the-art ecosystem models. The modelled LUE increase during 1900--2013 was 15\%, similar to a published estimate based on deuterium isotopomers. Rising CO 2 was the largest contributor to the modelled GPP increase. Greening, which may in part be caused by rising CO 2 , ranked second but dominated the modelled GPP change over large areas, including semi-arid vegetation on all continents. Warming caused a small net reduction in modelled global GPP, but dominated the modelled GPP increase in high northern latitudes. These findings strengthen the evidence that rising LUE due to rising CO 2 level and increased green vegetation cover (fAPAR) are the main causes of increasing GPP, and thereby, the terrestrial carbon sink.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/9YJ8TV4Y/Cai and Prentice - 2020 - Recent trends in gross primary production and thei.pdf} } -@article{Smith:2019dv, - title = {Global photosynthetic capacity is optimized to the environment}, - volume = {22}, - url = {https://onlinelibrary.wiley.com/doi/10.1111/ele.13210}, - doi = {10.1111/ele.13210}, - language = {english}, - number = {3}, - journal = {Ecology Letters}, - author = {Smith, Nicholas G and Keenan, Trevor F and Colin Prentice, I and Wang, Han and Wright, Ian J. and Niinemets, Ülo and Crous, Kristine Y and Domingues, Tomas F and Guerrieri, Rossella and Yoko Ishida, F and Kattge, Jens and Kruger, Eric L and Maire, Vincent and Rogers, Alistair and Serbin, Shawn P and Tarvainen, Lasse and Togashi, Henrique F and Townsend, Philip A and Wang, Meng and Weerasinghe, Lasantha K and Zhou, Shuang Xi}, - month = jan, - year = {2019}, - note = {tex.date-added: 2020-12-02T15:16:49GMT - tex.date-modified: 2021-01-25T10:03:32GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2019/Smith/Ecol\%20Lett\%202019\%20Smith.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1111/ele.13210}, - pages = {506--517}, - file = {Ecol Lett 2019 Smith.pdf:/Users/dorme/Zotero/storage/3YQVDBCU/Ecol Lett 2019 Smith.pdf:application/pdf} +@article{chen:2008a, + title = {The Equation of State of Pure Water Determined from Sound Speeds}, + author = {Chen, Chen-Tung and Fine, Rana A. and Millero, Frank J.}, + year = {2008}, + month = aug, + journal = {The Journal of Chemical Physics}, + volume = {66}, + number = {5}, + pages = {2142--2144}, + issn = {0021-9606}, + doi = {10.1063/1.434179}, + urldate = {2023-07-04}, + abstract = {The equation of state of water valid over the range 0--100\,{$^\circ$}C and 0--1000 bar has been determined from the high pressure sound velocities of Wilson, which were reanalyzed by Chen and Millero. The equation of state has a maximum error of {\textpm}0.01 bar-1 in isothermal compressibility and is in the form of a secant bulk modulus: K=V0P/(V0-V) =K0+AP+BP2, where K, K0, and V, V0 are the secant bulk moduli and specific volumes at applied pressures P and 0 (1 atm), respectively; A and B are temperature dependent parameters. The good agreement (to within 20{\texttimes}10-6 cm3\,g-1) of specific volumes calculated using the above equation with those obtained from other modifications of the Wilson sound velocity data demonstrates the reliability of the sound velocity method for determining equations of state.}, + file = {/Users/dorme/Zotero/storage/HHYLGDG4/Chen et al. - 2008 - The equation of state of pure water determined fro.pdf;/Users/dorme/Zotero/storage/M6MBWTPL/The-equation-of-state-of-pure-water-determined.html} } -@phdthesis{Lancelot:2020tm, - title = {A novel computational model to predict forest dynamics}, - url = {https://imperialcollegelondon.app.box.com/}, - author = {Lancelot, Maxime}, - month = aug, - year = {2020}, - note = {tex.affiliation: Imperial College London - tex.date-added: 2020-11-30T12:25:21GMT - tex.date-modified: 2020-11-30T14:42:52GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Books/2020/Lancelot/2020\%20Lancelot.pdf - tex.rating: 0 - tex.uri: papers3://publication/uuid/D73D9C6F-36C9-461D-A90C-784809C52BCB}, - file = {2020 Lancelot.pdf:/Users/dorme/Zotero/storage/YGXR7FCI/2020 Lancelot.pdf:application/pdf} +@article{davis:2017a, + title = {Simple Process-Led Algorithms for Simulating Habitats ({{SPLASH}} v.1.0): Robust Indices of Radiation, Evapotranspiration and Plant-Available Moisture}, + shorttitle = {Simple Process-Led Algorithms for Simulating Habitats ({{SPLASH}} v.1.0)}, + author = {Davis, Tyler W. and Prentice, I. Colin and Stocker, Benjamin D. and Thomas, Rebecca T. and Whitley, Rhys J. and Wang, Han and Evans, Bradley J. and {Gallego-Sala}, Angela V. and Sykes, Martin T. and Cramer, Wolfgang}, + year = {2017}, + month = feb, + journal = {Geoscientific Model Development}, + volume = {10}, + number = {2}, + pages = {689--708}, + publisher = {Copernicus GmbH}, + issn = {1991-959X}, + doi = {10.5194/gmd-10-689-2017}, + urldate = {2023-07-05}, + abstract = {Bioclimatic indices for use in studies of ecosystem function, species distribution, and vegetation dynamics under changing climate scenarios depend on estimates of surface fluxes and other quantities, such as radiation, evapotranspiration and soil moisture, for which direct observations are sparse. These quantities can be derived indirectly from meteorological variables, such as near-surface air temperature, precipitation and cloudiness. Here we present a consolidated set of simple process-led algorithms for simulating habitats (SPLASH) allowing robust approximations of key quantities at ecologically relevant timescales. We specify equations, derivations, simplifications, and assumptions for the estimation of daily and monthly quantities of top-of-the-atmosphere solar radiation, net surface radiation, photosynthetic photon flux density, evapotranspiration (potential, equilibrium, and actual), condensation, soil moisture, and runoff, based on analysis of their relationship to fundamental climatic drivers. The climatic drivers include a minimum of three meteorological inputs: precipitation, air temperature, and fraction of bright sunshine hours. Indices, such as the moisture index, the climatic water deficit, and the Priestley--Taylor coefficient, are also defined. The SPLASH code is transcribed in C++, FORTRAN, Python, and R. A total of 1 year of results are presented at the local and global scales to exemplify the spatiotemporal patterns of daily and monthly model outputs along with comparisons to other model results.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/CDUHE8TA/Davis et al. - 2017 - Simple process-led algorithms for simulating habit.pdf} } -@article{Kattge:2007db, - title = {Temperature acclimation in a biochemical model of photosynthesis: a reanalysis of data from 36 species}, - volume = {30}, - url = {http://doi.wiley.com/10.1111/j.1365-3040.2007.01690.x}, - doi = {10.1111/j.1365-3040.2007.01690.x}, - abstract = {The Farquhar et al. model of C3 photosynthesis is frequently used to study the effect of global changes on the biosphere. Its two main parameters representing photosynthetic capacity, Vcmax and Jmax, have been observed to acclimate to plant growth temperature for single species, but a general formulation has never been derived. Here, we present a reanalysis of data from 36 plant species to quantify the temperature dependence of Vcmax and Jmax with a focus on plant growth temperature, ie the plants' average ambient …}, - language = {english}, - number = {9}, - journal = {Plant, Cell \& Environment}, - author = {Kattge, Jens and Knorr, Wolfgang}, - month = sep, - year = {2007}, - note = {tex.date-added: 2020-11-30T14:04:07GMT - tex.date-modified: 2020-12-02T16:14:05GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2007/Kattge/Plant\%20Cell\%20\&\%20Environment\%202007\%20Kattge.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1111/j.1365-3040.2007.01690.x}, - pages = {1176--1190}, - file = {Plant Cell & Environment 2007 Kattge.pdf:/Users/dorme/Zotero/storage/UTXF2JRP/Plant Cell & Environment 2007 Kattge.pdf:application/pdf} +@article{DeKauwe:2015im, + title = {A Test of an Optimal Stomatal Conductance Scheme within the {{CABLE}} Land Surface Model}, + author = {De Kauwe, M G and Kala, J and Lin, Y S and Pitman, A J and Medlyn, B E and Duursma, R A and Abramowitz, G and Wang, Y P and Miralles, D G}, + year = {2015}, + month = feb, + journal = {Geoscientific Model Development}, + volume = {8}, + number = {2}, + pages = {431--452}, + publisher = {Copernicus GmbH}, + doi = {10.5194/gmd-8-431-2015}, + abstract = {{\textexclamdown}p{\textquestiondown}{\textexclamdown}strong class="journal-contentHeaderColor"{\textquestiondown}Abstract.{\textexclamdown}/strong{\textquestiondown} Stomatal conductance ({\textexclamdown}i{\textquestiondown}g{\textexclamdown}/i{\textquestiondown}{\textexclamdown}sub{\textquestiondown}s{\textexclamdown}/sub{\textquestiondown}) affects the fluxes of carbon, energy and water between the vegetated land surface and the atmosphere. We test an implementation of an optimal stomatal conductance model within the Community Atmosphere Biosphere Land Exchange (CABLE) land surface model (LSM). In common with many LSMs, CABLE does not differentiate between {\textexclamdown}i{\textquestiondown}g{\textexclamdown}/i{\textquestiondown}{\textexclamdown}sub{\textquestiondown}s{\textexclamdown}/sub{\textquestiondown} model parameters in relation to plant functional type (PFT), but instead only in relation to photosynthetic pathway. We constrained the key model parameter "{\textexclamdown}i{\textquestiondown}g{\textexclamdown}/i{\textquestiondown}{\textexclamdown}sub{\textquestiondown}1{\textexclamdown}/sub{\textquestiondown}", which represents plant water use strategy, by PFT, based on a global synthesis of stomatal behaviour. As proof of concept, we also demonstrate that the {\textexclamdown}i{\textquestiondown}g{\textexclamdown}/i{\textquestiondown}{\textexclamdown}sub{\textquestiondown}1{\textexclamdown}/sub{\textquestiondown} parameter can be estimated using two long-term average (1960--1990) bioclimatic variables: (i) temperature and (ii) an indirect estimate of annual plant water availability. The new stomatal model, in conjunction with PFT parameterisations, resulted in a large reduction in annual fluxes of transpiration ({\textasciitilde} 30\% compared to the standard CABLE simulations) across evergreen needleleaf, tundra and C4 grass regions. Differences in other regions of the globe were typically small. Model performance against upscaled data products was not degraded, but did not noticeably reduce existing model--data biases. We identified assumptions relating to the coupling of the vegetation to the atmosphere and the parameterisation of the minimum stomatal conductance as areas requiring further investigation in both CABLE and potentially other LSMs. We conclude that optimisation theory can yield a simple and tractable approach to predicting stomatal conductance in LSMs.{\textexclamdown}/p{\textquestiondown}}, + date-added = {2021-11-11T14:04:21GMT}, + date-modified = {2021-11-11T14:13:27GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2015/De\%20Kauwe/Geoscientific\%20Model\%20Development\%202015\%20De\%20Kauwe.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.5194/gmd-8-431-2015}, + file = {/Users/dorme/Zotero/storage/8WDYDVKQ/Geoscientific Model Development 2015 De Kauwe.pdf;/Users/dorme/Zotero/storage/WXI7ASHC/Geoscientific Model Development 2015 De Kauwe.pdf} } -@article{Heskel:2016fg, - title = {Convergence in the temperature response of leaf respiration across biomes and plant functional types}, - volume = {113}, - url = {http://www.pnas.org/lookup/doi/10.1073/pnas.1520282113}, - doi = {10.1073/pnas.1520282113}, - language = {english}, - number = {14}, - journal = {Proceedings of the National Academy of Sciences of the United States of America}, - author = {Heskel, Mary A and O’Sullivan, Odhran S and Reich, Peter B and Tjoelker, Mark G and Weerasinghe, Lasantha K and Penillard, Aurore and Egerton, John J G and Creek, Danielle and Bloomfield, Keith J and Xiang, Jen and Sinca, Felipe and Stangl, Zsofia R and Martinez-de la Torre, Alberto and Griffin, Kevin L and Huntingford, Chris and Hurry, Vaughan and Meir, Patrick and Turnbull, Matthew H and Atkin, Owen K}, - month = apr, - year = {2016}, - note = {tex.date-added: 2020-11-30T13:55:54GMT - tex.date-modified: 2020-11-30T14:42:52GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2016/Heskel/PNAS\%202016\%20Heskel.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1073/pnas.1520282113}, - pages = {3832--3837}, - file = {PNAS 2016 Heskel.pdf:/Users/dorme/Zotero/storage/YR5JESPC/PNAS 2016 Heskel.pdf:application/pdf;PNAS 2016 Heskel.pdf:/Users/dorme/Zotero/storage/ZTIEDG3M/PNAS 2016 Heskel.pdf:application/pdf} +@article{Diaz:2016by, + title = {The Global Spectrum of Plant Form and Function}, + author = {D{\'i}az, Sandra and Kattge, Jens and Cornelissen, Johannes H C and Wright, Ian J. and Lavorel, Sandra and Dray, St{\'e}phane and Reu, Bj{\"o}rn and Kleyer, Michael and Wirth, Christian and Prentice, I. Colin and Garnier, Eric and B{\"o}nisch, Gerhard and Westoby, Mark and Poorter, Hendrik and Reich, Peter B and Moles, Angela T and Dickie, John and Gillison, Andrew N and Zanne, Amy E and Chave, J{\'e}r{\^o}me and Wright, S Joseph and Sheremet'ev, Serge N and Jactel, Herv{\'e} and Baraloto, Christopher and Cerabolini, Bruno and Pierce, Simon and Shipley, Bill and Kirkup, Donald and Casanoves, Fernando and Joswig, Julia S and G{\"u}nther, Angela and Falczuk, Valeria and R{\"u}ger, Nadja and Mahecha, Miguel D and Gorn{\'e}, Lucas D}, + year = {2016}, + month = jan, + journal = {Nature}, + volume = {529}, + number = {7585}, + pages = {167--171}, + publisher = {Nature Publishing Group}, + doi = {10.1038/nature16489}, + abstract = {Nature 529, 167 (2016). doi:10.1038/nature16489}, + date-added = {2021-06-14T12:23:21GMT}, + date-modified = {2021-11-11T14:13:27GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2016/D\%C3\%ADaz/Nature\%202016\%20D\%C3\%ADaz.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1038/nature16489}, + file = {/Users/dorme/Zotero/storage/RGG46LIG/Nature 2016 Díaz.pdf} +} + +@book{duffie:2013a, + title = {Solar {{Engineering}} of {{Thermal Processes}}}, + author = {Duffie, John A. and Beckman, William A.}, + year = {2013}, + month = apr, + publisher = {John Wiley \& Sons}, + abstract = {The updated fourth edition of the "bible" of solar energy theory and applications Over several editions, Solar Engineering of Thermal Processes has become a classic solar engineering text and reference. This revised Fourth Edition offers current coverage of solar energy theory, systems design, and applications in different market sectors along with an emphasis on solar system design and analysis using simulations to help readers translate theory into practice. An important resource for students of solar engineering, solar energy, and alternative energy as well as professionals working in the power and energy industry or related fields, Solar Engineering of Thermal Processes, Fourth Edition features: Increased coverage of leading-edge topics such as photovoltaics and the design of solar cells and heaters A brand-new chapter on applying CombiSys (a readymade TRNSYS simulation program available for free download) to simulate a solar heated house with solar- heated domestic hot water Additional simulation problems available through a companion website An extensive array of homework problems and exercises}, + googlebooks = {5uDdUfMgXYQC}, + isbn = {978-1-118-41541-2}, + langid = {english}, + keywords = {Technology & Engineering / Electronics / General,Technology & Engineering / Mechanical,Technology & Engineering / Power Resources / General} } -@article{Prentice:2014bc, - title = {Balancing the costs of carbon gain and water transport: testing a new theoretical framework for plant functional ecology}, - volume = {17}, - url = {http://doi.wiley.com/10.1111/ele.12211}, - doi = {10.1111/ele.12211}, - language = {english}, - number = {1}, - journal = {Ecology Letters}, - author = {Prentice, I. Colin and Dong, Ning and Gleason, Sean M and Maire, Vincent and Wright, Ian J.}, - year = {2014}, - note = {tex.date-added: 2020-12-01T13:22:48GMT - tex.date-modified: 2021-01-21T15:04:43GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Prentice/Ecol\%20Lett\%202014\%20Prentice.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1111/ele.12211}, - pages = {82--91}, - file = {Ecol Lett 2014 Prentice.pdf:/Users/dorme/Zotero/storage/SZVZVTJS/Ecol Lett 2014 Prentice.pdf:application/pdf} +@article{Farquhar:1980ft, + title = {A Biochemical Model of Photosynthetic {{CO2}} Assimilation in Leaves of {{C3}} Species.}, + author = {Farquhar, G D and {von Caemmerer}, S and Berry, J A}, + year = {1980}, + month = jun, + journal = {Planta}, + volume = {149}, + number = {1}, + pages = {78--90}, + doi = {10.1007/BF00386231}, + abstract = {Various aspects of the biochemistry of photosynthetic carbon assimilation in C3 plants are integrated into a form compatible with studies of gas exchange in leaves. These aspects include the kinetic properties of ribulose bisphosphate carboxylase-oxygenase; the requirements of the photosynthetic carbon reduction and photorespiratory carbon oxidation cycles for reduced pyridine nucleotides; the dependence of electron transport on photon flux and the presence of a temperature dependent upper limit to electron transport. The measurements of gas exchange with which the model outputs may be compared include those of the temperature and partial pressure of CO2(p(CO2)) dependencies of quantum yield, the variation of compensation point with temperature and partial pressure of O2(p(O2)), the dependence of net CO2 assimilation rate on p(CO2) and irradiance, and the influence of p(CO2) and irradiance on the temperature dependence of assimilation rate.}, + affiliation = {Department of Environmental Biology, Research School of Biological Sciences, Australian National University, P.O. Box 475, 2601, Canberra City, ACT, Australia.}, + date-added = {2020-12-17T09:47:58GMT}, + date-modified = {2020-12-17T09:49:44GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/1980/Farquhar/Planta\%201980\%20Farquhar.pdf}, + pmid = {24306196}, + rating = {0}, + uri = {papers3://publication/doi/10.1007/BF00386231}, + file = {/Users/dorme/Zotero/storage/PGDMWNFK/Planta 1980 Farquhar.pdf;/Users/dorme/Zotero/storage/YNCRDMLJ/Planta 1980 Farquhar.pdf} } -@article{Stocker:2018be, - title = {Quantifying soil moisture impacts on light use efficiency across biomes}, - volume = {218}, - url = {http://doi.wiley.com/10.1111/nph.15123}, - doi = {10.1111/nph.15123}, - abstract = {Terrestrial primary productivity and carbon cycle impacts of droughts are commonly quantified using vapour pressure deficit (VPD) data and remotely sensed greenness, without accounting for soil moisture. However, soil moisture limitation is known to strongly affect plant physiology. Here, we investigate light use efficiency, the ratio of gross primary productivity (GPP) to absorbed light. We derive its fractional reduction due to soil moisture (fLUE), separated from VPD and greenness changes, using artificial neural networks trained …}, - language = {english}, - number = {4}, - journal = {New Phytologist}, - author = {Stocker, Benjamin D and Zscheischler, Jakob and Keenan, Trevor F and Prentice, I. Colin and Penuelas, Josep and Seneviratne, Sonia I}, - month = mar, - year = {2018}, - note = {tex.date-added: 2021-01-25T09:23:00GMT - tex.date-modified: 2021-01-28T15:58:46GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Stocker/New\%20Phytol.\%202018\%20Stocker.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1111/nph.15123}, - pages = {1430--1449}, - file = {New Phytol. 2018 Stocker.pdf:/Users/dorme/Zotero/storage/5AZW6ZK9/New Phytol. 2018 Stocker.pdf:application/pdf} +@article{farquhar:1982a, + title = {On the Relationship between Carbon Isotope Discrimination and the Intercellular Carbon Dioxide Concentration in Leaves}, + author = {Farquhar, Graham D and O'Leary, Marion H and Berry, Joseph A}, + year = {1982}, + journal = {Australian Journal of Plant Physiology}, + volume = {9}, + number = {2}, + pages = {121}, + issn = {1445-4408}, + doi = {10.1071/PP9820121}, + urldate = {2022-05-20}, + abstract = {Theory is developed to explain the carbon isotopic composition of plants. It is shown how diffusion of gaseous COz can significantly affect carbon isotopic discrimination. The effects on discrimination by diffusion and carboxylation are integrated, yielding a simple relationship between discrimination and the ratio of the intercellular and atmospheric partial pressures of COZ. The effects of dark respiration and photorespiration are also considered, and it is suggested that they have relatively little effect on discrimination other than cia their effects on intercellular p(COz). It is also suggested that various environmental factors such as light, temperature, salinity and drought will also have effects via changes in intercellular p(C0,). A simple method is suggested for assessing water use efficiencies in the field.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/8ACJPME5/Farquhar et al. - 1982 - On the Relationship Between Carbon Isotope Discrim.pdf} } -@book{HEllenbergBerlinGeobotanicalInstituteETH:fe, - title = {A key to {Raunkiaer} plant life forms with revised subdivision.}, - url = {https://ci.nii.ac.jp/naid/10004142697/}, - abstract = {CiNii 国立情報学研究所 学術情報ナビゲータ[サイニィ]. メニュー 検索 …}, - author = {{H Ellenberg - Berlin Geobotanical Institute ETH} and {Stiftung} and {1967}}, - doi = {10.5169/seals-377651}, - note = {tex.date-added: 2020-12-07T11:13:07GMT - tex.date-modified: 2020-12-17T08:58:40GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Books/Unknown/H\%20Ellenberg\%C2\%A0-\%20Berlin\%20Geobotanical\%20Institute\%20ETH/H\%20Ellenberg\%C2\%A0-\%20Berlin\%20Geobotanical\%20Institute\%20ETH.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.5169/seals-377651} +@book{Fisher:1975tm, + title = {Equation of State of Pure Water and Sea Water}, + author = {Fisher, F H and Dial Jr, O E}, + year = {1975}, + publisher = {Scripps Institution of Oceanography}, + date-added = {2020-11-30T12:27:10GMT}, + date-modified = {2021-01-21T15:04:43GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Books/1975/Fisher/1975\%20Fisher.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/uuid/5D2C2C96-7975-4AB9-8314-A988EFA489FF}, + file = {/Users/dorme/Zotero/storage/3K2X7BU7/1975 Fisher.pdf} } -@article{Walker:2014ce, - title = {The relationship of leaf photosynthetic traits - {Vcmaxand} {Jmax}- to leaf nitrogen, leaf phosphorus, and specific leaf area: a meta-analysis and modeling study}, - volume = {4}, - url = {http://doi.wiley.com/10.1002/ece3.1173}, - doi = {10.1002/ece3.1173}, - language = {english}, - number = {16}, - journal = {Ecology and Evolution}, - author = {Walker, Anthony P and Beckerman, Andrew P and Gu, Lianhong and Kattge, Jens and Cernusak, Lucas A and Domingues, Tomas F and Scales, Joanna C and Wohlfahrt, Georg and Wullschleger, Stan D and Woodward, F Ian}, - month = jul, - year = {2014}, - note = {tex.date-added: 2020-12-07T11:43:53GMT - tex.date-modified: 2020-12-17T08:58:39GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Walker/Ecology\%20and\%20Evolution\%202014\%20Walker.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1002/ece3.1173}, - pages = {3218--3235}, - file = {Ecology and Evolution 2014 Walker.pdf:/Users/dorme/Zotero/storage/WVL2ZGGZ/Ecology and Evolution 2014 Walker.pdf:application/pdf} +@article{frank:2015a, + title = {Water-Use Efficiency and Transpiration across {{European}} Forests during the {{Anthropocene}}}, + author = {Frank, D. C. and Poulter, B. and Saurer, M. and Esper, J. and Huntingford, C. and Helle, G. and Treydte, K. and Zimmermann, N. E. and Schleser, G.~H. and Ahlstr{\"o}m, A. and Ciais, P. and Friedlingstein, P. and Levis, S. and Lomas, M. and Sitch, S. and Viovy, N. and {Andreu-Hayles}, L. and Bednarz, Z. and Berninger, F. and Boettger, T. and D`Alessandro, C. M. and Daux, V. and Filot, M. and Grabner, M. and Gutierrez, E. and Haupt, M. and Hilasvuori, E. and Jungner, H. and {Kalela-Brundin}, M. and Krapiec, M. and Leuenberger, M. and Loader, N. J. and Marah, H. and {Masson-Delmotte}, V. and Pazdur, A. and Pawelczyk, S. and Pierre, M. and Planells, O. and Pukiene, R. and {Reynolds-Henne}, C. E. and Rinne, K. T. and Saracino, A. and Sonninen, E. and Stievenard, M. and Switsur, V. R. and Szczepanek, M. and {Szychowska-Krapiec}, E. and Todaro, L. and Waterhouse, J.~S. and Weigl, M.}, + year = {2015}, + month = jun, + journal = {Nature Climate Change}, + volume = {5}, + number = {6}, + pages = {579--583}, + issn = {1758-6798}, + doi = {10.1038/nclimate2614}, + abstract = {Considering the combined effects of CO2 fertilization and climate change drivers on plant physiology leads to a modest increase in simulated European forest transpiration in spite of the effects of CO2-induced stomatal closure.}, + file = {/Users/dorme/Zotero/storage/CNDFZFBW/Frank et al. - 2015 - Water-use efficiency and transpiration across Euro.pdf} } -@article{Peng:2021ky, - title = {Global climate and nutrient controls of photosynthetic capacity}, - url = {http://dx.doi.org/10.1038/s42003-021-01985-7}, - doi = {10.1038/s42003-021-01985-7}, - abstract = {Communications Biology, doi:10.1038/s42003-021-01985-7}, - journal = {Communications Biology}, - author = {Peng, Yunke and Bloomfield, Keith J and Cernusak, Lucas A and Domingues, Tomas F and Prentice, I. Colin}, - month = apr, - year = {2021}, - note = {Publisher: Springer US - tex.date-added: 2021-06-14T08:31:31GMT - tex.date-modified: 2021-11-11T14:13:27GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2021/Peng/Communications\%20Biology\%202021\%20Peng.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1038/s42003-021-01985-7}, - pages = {1--9}, - file = {Communications Biology 2021 Peng.pdf:/Users/dorme/Zotero/storage/U8Q5LA52/Communications Biology 2021 Peng.pdf:application/pdf} +@article{graven:2020a, + title = {Changes to {{Carbon Isotopes}} in {{Atmospheric CO}} {\textsubscript{2}} {{Over}} the {{Industrial Era}} and {{Into}} the {{Future}}}, + author = {Graven, Heather and Keeling, Ralph F. and Rogelj, Joeri}, + year = {2020}, + month = nov, + journal = {Global Biogeochemical Cycles}, + volume = {34}, + number = {11}, + issn = {0886-6236, 1944-9224}, + doi = {10.1029/2019GB006170}, + urldate = {2022-05-23}, + abstract = {In this ``Grand Challenges'' paper, we review how the carbon isotopic composition of atmospheric CO2 has changed since the Industrial Revolution due to human activities and their influence on the natural carbon cycle, and we provide new estimates of possible future changes for a range of scenarios. Emissions of CO2 from fossil fuel combustion and land use change reduce the ratio of 13C/12C in atmospheric CO2 ({$\delta$}13CO2). This is because 12C is preferentially assimilated during photosynthesis and {$\delta$}13C in plant-derived carbon in terrestrial ecosystems and fossil fuels is lower than atmospheric {$\delta$}13CO2. Emissions of CO2 from fossil fuel combustion also reduce the ratio of 14C/C in atmospheric CO2 ({$\Delta$}14CO2) because 14C is absent in million-year-old fossil fuels, which have been stored for much longer than the radioactive decay time of 14C. Atmospheric {$\Delta$}14CO2 rapidly increased in the 1950s to 1960s because of 14C produced during nuclear bomb testing. The resulting trends in {$\delta$}13C and {$\Delta$}14C in atmospheric CO2 are influenced not only by these human emissions but also by natural carbon exchanges that mix carbon between the atmosphere and ocean and terrestrial ecosystems. This mixing caused {$\Delta$}14CO2 to return toward preindustrial levels in the first few decades after the spike from nuclear testing. More recently, as the bomb 14C excess is now mostly well mixed with the decadally overturning carbon reservoirs, fossil fuel emissions have become the main factor driving further decreases in atmospheric {$\Delta$}14CO2. For {$\delta$}13CO2, in addition to exchanges between reservoirs, the extent to which 12C is preferentially assimilated during photosynthesis appears to have increased, slowing down the recent {$\delta$}13CO2 trend slightly. A new compilation of ice core and flask {$\delta$}13CO2 observations indicates that the decline in {$\delta$}13CO2 since the preindustrial period is less than some prior estimates, which may have incorporated artifacts owing to offsets from different laboratories' measurements. Atmospheric observations of {$\delta$}13CO2 have been used to investigate carbon fluxes and the functioning of plants, and they are used for comparison with {$\delta$}13C in other materials such as tree rings. Atmospheric observations of {$\Delta$}14CO2 have been used to quantify the rate of air-sea gas exchange and ocean circulation, and the rate of net primary production and the turnover time of carbon in plant material and soils. Atmospheric observations of {$\Delta$}14CO2 are also used for comparison with {$\Delta$}14C in other materials in many fields such as archaeology, forensics, and physiology. Another major application is the assessment of regional emissions of CO2 from fossil fuel combustion using {$\Delta$}14CO2 observations and models. In the future, {$\delta$}13CO2 and {$\Delta$}14CO2 will continue to change. The sign and magnitude of the changes are mainly determined by global fossil fuel emissions. We present here simulations of future {$\delta$}13CO2 and {$\Delta$}14CO2 for six scenarios based on the shared socioeconomic pathways (SSPs) from the 6th Coupled Model Intercomparison Project (CMIP6). Applications using atmospheric {$\delta$}13CO2 and {$\Delta$}14CO2 observations in carbon cycle science and many other fields will be affected by these future changes. We recommend an increased effort toward making coordinated measurements of {$\delta$}13C and {$\Delta$}14C across the Earth System and for further development of isotopic modeling and model-data analysis tools.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/BFT23X8N/Graven et al. - 2020 - Changes to Carbon Isotopes in Atmospheric CO .pdf} } -@article{Bernacchi:2001kg, - title = {Improved temperature response functions for models of {Rubisco}-limited photosynthesis}, - volume = {24}, - url = {http://doi.wiley.com/10.1111/j.1365-3040.2001.00668.x}, - doi = {10.1111/j.1365-3040.2001.00668.x}, - language = {english}, - number = {2}, - journal = {Plant, Cell \& Environment}, - author = {Bernacchi, C J and Singsaas, E L and Pimentel, C and Portis Jr, A R and Long, S P}, - year = {2001}, - note = {tex.date-added: 2020-11-30T12:24:10GMT - tex.date-modified: 2020-11-30T14:42:53GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2001/Bernacchi/Plant\%20Cell\%20\&\%20Environment\%202001\%20Bernacchi.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1111/j.1365-3040.2001.00668.x}, - pages = {253--259}, - file = {Plant Cell & Environment 2001 Bernacchi.pdf:/Users/dorme/Zotero/storage/NQZRL4RI/Plant Cell & Environment 2001 Bernacchi.pdf:application/pdf} +@book{HEllenbergBerlinGeobotanicalInstituteETH:fe, + title = {A Key to {{Raunkiaer}} Plant Life Forms with Revised Subdivision.}, + author = {{H Ellenberg - Berlin Geobotanical Institute ETH} and {Stiftung} and {1967}}, + doi = {10.5169/seals-377651}, + abstract = {CiNii 国立情報学研究所 学術情報ナビゲータ[サイニィ]. メニュー 検索 {\dots}}, + date-added = {2020-12-07T11:13:07GMT}, + date-modified = {2020-12-17T08:58:40GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Books/Unknown/H\%20Ellenberg\%C2\%A0-\%20Berlin\%20Geobotanical\%20Institute\%20ETH/H\%20Ellenberg\%C2\%A0-\%20Berlin\%20Geobotanical\%20Institute\%20ETH.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.5169/seals-377651} } -@article{Li:2014bc, - title = {Simulation of tree-ring widths with a model for primary production, carbon allocation, and growth}, - volume = {11}, - url = {https://bg.copernicus.org/articles/11/6711/2014/}, - doi = {10.5194/bg-11-6711-2014}, - language = {english}, - number = {23}, - journal = {Biogeosciences (Online)}, - author = {Li, G and Harrison, S P and Prentice, I. C. and Falster, D}, - year = {2014}, - note = {tex.date-added: 2020-12-01T16:59:12GMT - tex.date-modified: 2021-11-11T13:59:21GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Li/Biogeosciences\%202014\%20Li.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.5194/bg-11-6711-2014}, - pages = {6711--6724}, - file = {Biogeosciences 2014 Li.pdf:/Users/dorme/Zotero/storage/346S9AQK/Biogeosciences 2014 Li.pdf:application/pdf} +@article{henderson-sellers:1984a, + title = {A New Formula for Latent Heat of Vaporization of Water as a Function of Temperature}, + author = {{Henderson-Sellers}, B.}, + year = {1984}, + journal = {Quarterly Journal of the Royal Meteorological Society}, + volume = {110}, + number = {466}, + pages = {1186--1190}, + issn = {1477-870X}, + doi = {10.1002/qj.49711046626}, + urldate = {2023-07-04}, + abstract = {Existing formulae and approximations for the latent heat of vaporization of water, Lv, are reviewed. Using an analytical approximation to the saturated vapour pressure as a function of temperature, a new, temperature-dependent function for Lv is derived.}, + copyright = {Copyright {\copyright} 1984 Royal Meteorological Society}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/RHK394FU/qj.html} } -@article{Bernacchi:2003dc, - title = {In vivo temperature response functions of parameters required to model {RuBP}-limited photosynthesis}, - volume = {26}, - url = {https://onlinelibrary-wiley-com.iclibezp1.cc.ic.ac.uk/doi/full/10.1046/j.0016-8025.2003.01050.x}, - doi = {10.1046/j.0016-8025.2003.01050.x}, - abstract = {The leaf model of C3 photosynthesis of Farquhar, von Caemmerer \& Berry (Planta 149, 78–90, 1980) provides the basis for scaling carbon exchange from leaf to canopy and Earth-System models, and is wid...}, - language = {english}, - number = {9}, - journal = {Plant, Cell \& Environment}, - author = {Bernacchi, C J and Pimentel, C and Long, S P}, - month = sep, - year = {2003}, - note = {Publisher: John Wiley \& Sons, Ltd - tex.date-added: 2020-11-30T14:15:56GMT - tex.date-modified: 2020-11-30T14:42:52GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2003/Bernacchi/Plant\%20Cell\%20\&\%20Environment\%202003\%20Bernacchi.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1046/j.0016-8025.2003.01050.x}, - pages = {1419--1430}, - file = {Plant Cell & Environment 2003 Bernacchi.pdf:/Users/dorme/Zotero/storage/K2EX6ZIL/Plant Cell & Environment 2003 Bernacchi.pdf:application/pdf} +@article{hengl:2017a, + title = {{{SoilGrids250m}}: {{Global}} Gridded Soil Information Based on Machine Learning}, + shorttitle = {{{SoilGrids250m}}}, + author = {Hengl, Tomislav and de Jesus, Jorge Mendes and Heuvelink, Gerard B. M. and Gonzalez, Maria Ruiperez and Kilibarda, Milan and Blagoti{\'c}, Aleksandar and Shangguan, Wei and Wright, Marvin N. and Geng, Xiaoyuan and {Bauer-Marschallinger}, Bernhard and Guevara, Mario Antonio and Vargas, Rodrigo and MacMillan, Robert A. and Batjes, Niels H. and Leenaars, Johan G. B. and Ribeiro, Eloi and Wheeler, Ichsani and Mantel, Stephan and Kempen, Bas}, + year = {2017}, + month = feb, + journal = {PLOS ONE}, + volume = {12}, + number = {2}, + pages = {e0169748}, + publisher = {Public Library of Science}, + issn = {1932-6203}, + doi = {10.1371/journal.pone.0169748}, + urldate = {2023-07-05}, + abstract = {This paper describes the technical development and accuracy assessment of the most recent and improved version of the SoilGrids system at 250m resolution (June 2016 update). SoilGrids provides global predictions for standard numeric soil properties (organic carbon, bulk density, Cation Exchange Capacity (CEC), pH, soil texture fractions and coarse fragments) at seven standard depths (0, 5, 15, 30, 60, 100 and 200 cm), in addition to predictions of depth to bedrock and distribution of soil classes based on the World Reference Base (WRB) and USDA classification systems (ca. 280 raster layers in total). Predictions were based on ca. 150,000 soil profiles used for training and a stack of 158 remote sensing-based soil covariates (primarily derived from MODIS land products, SRTM DEM derivatives, climatic images and global landform and lithology maps), which were used to fit an ensemble of machine learning methods---random forest and gradient boosting and/or multinomial logistic regression---as implemented in the R packages ranger, xgboost, nnet and caret. The results of 10--fold cross-validation show that the ensemble models explain between 56\% (coarse fragments) and 83\% (pH) of variation with an overall average of 61\%. Improvements in the relative accuracy considering the amount of variation explained, in comparison to the previous version of SoilGrids at 1 km spatial resolution, range from 60 to 230\%. Improvements can be attributed to: (1) the use of machine learning instead of linear regression, (2) to considerable investments in preparing finer resolution covariate layers and (3) to insertion of additional soil profiles. Further development of SoilGrids could include refinement of methods to incorporate input uncertainties and derivation of posterior probability distributions (per pixel), and further automation of spatial modeling so that soil maps can be generated for potentially hundreds of soil variables. Another area of future research is the development of methods for multiscale merging of SoilGrids predictions with local and/or national gridded soil products (e.g. up to 50 m spatial resolution) so that increasingly more accurate, complete and consistent global soil information can be produced. SoilGrids are available under the Open Data Base License.}, + langid = {english}, + keywords = {Agricultural soil science,Forecasting,Glaciers,Machine learning,Remote sensing,Shannon index,Soil pH,Trees}, + file = {/Users/dorme/Zotero/storage/2YL6J66K/Hengl et al. - 2017 - SoilGrids250m Global gridded soil information bas.pdf} } -@article{Diaz:2016by, - title = {The global spectrum of plant form and function}, - volume = {529}, - url = {http://dx.doi.org/10.1038/nature16489}, - doi = {10.1038/nature16489}, - abstract = {Nature 529, 167 (2016). doi:10.1038/nature16489}, - number = {7585}, - journal = {Nature}, - author = {Díaz, Sandra and Kattge, Jens and Cornelissen, Johannes H C and Wright, Ian J. and Lavorel, Sandra and Dray, Stéphane and Reu, Björn and Kleyer, Michael and Wirth, Christian and Prentice, I. Colin and Garnier, Eric and Bönisch, Gerhard and Westoby, Mark and Poorter, Hendrik and Reich, Peter B and Moles, Angela T and Dickie, John and Gillison, Andrew N and Zanne, Amy E and Chave, Jérôme and Wright, S Joseph and Sheremet’ev, Serge N and Jactel, Hervé and Baraloto, Christopher and Cerabolini, Bruno and Pierce, Simon and Shipley, Bill and Kirkup, Donald and Casanoves, Fernando and Joswig, Julia S and Günther, Angela and Falczuk, Valeria and Rüger, Nadja and Mahecha, Miguel D and Gorné, Lucas D}, - month = jan, - year = {2016}, - note = {Publisher: Nature Publishing Group - tex.date-added: 2021-06-14T12:23:21GMT - tex.date-modified: 2021-11-11T14:13:27GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2016/D\%C3\%ADaz/Nature\%202016\%20D\%C3\%ADaz.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1038/nature16489}, - pages = {167--171}, - file = {Nature 2016 Díaz.pdf:/Users/dorme/Zotero/storage/5DWC9AW2/Nature 2016 Díaz.pdf:application/pdf} +@article{Heskel:2016fg, + title = {Convergence in the Temperature Response of Leaf Respiration across Biomes and Plant Functional Types}, + author = {Heskel, Mary A and O'Sullivan, Odhran S and Reich, Peter B and Tjoelker, Mark G and Weerasinghe, Lasantha K and Penillard, Aurore and Egerton, John J G and Creek, Danielle and Bloomfield, Keith J and Xiang, Jen and Sinca, Felipe and Stangl, Zsofia R and {Martinez-de la Torre}, Alberto and Griffin, Kevin L and Huntingford, Chris and Hurry, Vaughan and Meir, Patrick and Turnbull, Matthew H and Atkin, Owen K}, + year = {2016}, + month = apr, + journal = {Proceedings of the National Academy of Sciences of the United States of America}, + volume = {113}, + number = {14}, + pages = {3832--3837}, + doi = {10.1073/pnas.1520282113}, + date-added = {2020-11-30T13:55:54GMT}, + date-modified = {2020-11-30T14:42:52GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2016/Heskel/PNAS\%202016\%20Heskel.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1073/pnas.1520282113}, + file = {/Users/dorme/Zotero/storage/22X4KLAX/PNAS 2016 Heskel.pdf;/Users/dorme/Zotero/storage/LC3HMVT7/PNAS 2016 Heskel.pdf} } -@article{Lin:2015wh, - title = {Optimal stomatal behaviour around the world}, - volume = {5}, - url = {https://doi.org/10.1038/nclimate2550}, - abstract = {Stomatal conductance is a land-surface attribute that links the water and carbon cycles. Analysis of a global database covering a wide range of plant functional types and biomes now provides a framework for predicting the behaviour of stomatal conductance that can be applied to model ecosystem productivity, energy balance and ecohydrological processes in a changing climate.}, - number = {5}, - journal = {Nature Climate Change}, - author = {Lin, Yan-Shih and Medlyn, Belinda E and Duursma, Remko A and Prentice, I. Colin and Wang, Han and Baig, Sofia and Eamus, Derek and de Dios, Victor Resco and Mitchell, Patrick and Ellsworth, David S and de Beeck, Maarten Op and Wallin, Goran and Uddling, Johan and Tarvainen, Lasse and Linderson, Maj-Lena and Cernusak, Lucas A and Nippert, Jesse B and Ocheltree, Troy W and Tissue, David T and Martin-StPaul, Nicolas K and Rogers, Alistair and Warren, Jeff M and De Angelis, Paolo and Hikosaka, Kouki and Han, Qingmin and Onoda, Yusuke and Gimeno, Teresa E and Barton, Craig V M and Bennie, Jonathan and Bonal, Damien and Bosc, Alexandre and Low, Markus and Macinins-Ng, Cate and Rey, Ana and Rowland, Lucy and Setterfield, Samantha A and Tausz-Posch, Sabine and Zaragoza-Castells, Joana and Broadmeadow, Mark S J and Drake, John E and Freeman, Michael and Ghannoum, Oula and Hutley, Lindsay B and Kelly, Jeff W and Kikuzawa, Kihachiro and Kolari, Pasi and Koyama, Kohei and Limousin, Jean-Marc and Meir, Patrick and Lola da Costa, Antonio C and Mikkelsen, Teis N and Salinas, Norma and Sun, Wei and Wingate, Lisa}, - year = {2015}, - note = {tex.date-added: 2021-11-11T14:12:05GMT - tex.date-modified: 2021-11-11T14:13:27GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2015/Lin/2015\%20Lin-2.pdf - tex.rating: 0 - tex.uri: papers3://publication/uuid/61D6E8CB-F257-4021-AC24-2DF4D72C298E}, - pages = {459--464}, - file = {2015 Lin-2.pdf:/Users/dorme/Zotero/storage/WV3XV4SD/2015 Lin-2.pdf:application/pdf} +@article{Huber:2009fy, + title = {New International Formulation for the Viscosity of {{H2O}}}, + author = {Huber, M L and Perkins, R A and Laesecke, A and Friend, D G and Sengers, J V and Assael, M J and Metaxa, I N and Vogel, E and Mare{\v s}, R and Miyagawa, K}, + year = {2009}, + month = jun, + journal = {Journal of Physical and Chemical Reference Data}, + volume = {38}, + number = {2}, + pages = {101--125}, + doi = {10.1063/1.3088050}, + date-added = {2020-12-02T09:52:51GMT}, + date-modified = {2020-12-17T08:58:40GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2009/Huber/Journal\%20of\%20Physical\%20and\%20Chemical\%20Reference\%20Data\%202009\%20Huber.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1063/1.3088050}, + file = {/Users/dorme/Zotero/storage/HREIVFC4/Journal of Physical and Chemical Reference Data 2009 Huber.pdf} } -@article{Farquhar:1980ft, - title = {A biochemical model of photosynthetic {CO2} assimilation in leaves of {C3} species.}, - volume = {149}, - url = {http://link.springer.com/10.1007/BF00386231}, - doi = {10.1007/BF00386231}, - abstract = {Various aspects of the biochemistry of photosynthetic carbon assimilation in C3 plants are integrated into a form compatible with studies of gas exchange in leaves. These aspects include the kinetic properties of ribulose bisphosphate carboxylase-oxygenase; the requirements of the photosynthetic carbon reduction and photorespiratory carbon oxidation cycles for reduced pyridine nucleotides; the dependence of electron transport on photon flux and the presence of a temperature dependent upper limit to electron transport. The measurements of gas exchange with which the model outputs may be compared include those of the temperature and partial pressure of CO2(p(CO2)) dependencies of quantum yield, the variation of compensation point with temperature and partial pressure of O2(p(O2)), the dependence of net CO2 assimilation rate on p(CO2) and irradiance, and the influence of p(CO2) and irradiance on the temperature dependence of assimilation rate.}, - language = {english}, - number = {1}, - journal = {Planta}, - author = {Farquhar, G D and von Caemmerer, S and Berry, J A}, - month = jun, - year = {1980}, - pmid = {24306196}, - note = {tex.affiliation: Department of Environmental Biology, Research School of Biological Sciences, Australian National University, P.O. Box 475, 2601, Canberra City, ACT, Australia. - tex.date-added: 2020-12-17T09:47:58GMT - tex.date-modified: 2020-12-17T09:49:44GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/1980/Farquhar/Planta\%201980\%20Farquhar.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1007/BF00386231}, - pages = {78--90}, - file = {Planta 1980 Farquhar.pdf:/Users/dorme/Zotero/storage/WFTRGJRB/Planta 1980 Farquhar.pdf:application/pdf;Planta 1980 Farquhar.pdf:/Users/dorme/Zotero/storage/FP3457LT/Planta 1980 Farquhar.pdf:application/pdf} +@article{Kattge:2007db, + title = {Temperature Acclimation in a Biochemical Model of Photosynthesis: A Reanalysis of Data from 36 Species}, + author = {Kattge, Jens and Knorr, Wolfgang}, + year = {2007}, + month = sep, + journal = {Plant, Cell \& Environment}, + volume = {30}, + number = {9}, + pages = {1176--1190}, + doi = {10.1111/j.1365-3040.2007.01690.x}, + abstract = {The Farquhar et al. model of C3 photosynthesis is frequently used to study the effect of global changes on the biosphere. Its two main parameters representing photosynthetic capacity, Vcmax and Jmax, have been observed to acclimate to plant growth temperature for single species, but a general formulation has never been derived. Here, we present a reanalysis of data from 36 plant species to quantify the temperature dependence of Vcmax and Jmax with a focus on plant growth temperature, ie the plants' average ambient {\dots}}, + date-added = {2020-11-30T14:04:07GMT}, + date-modified = {2020-12-02T16:14:05GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2007/Kattge/Plant\%20Cell\%20\&\%20Environment\%202007\%20Kattge.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1111/j.1365-3040.2007.01690.x}, + file = {/Users/dorme/Zotero/storage/WCL92RHJ/Plant Cell & Environment 2007 Kattge.pdf} } -@article{Togashi:2018es, - title = {Functional trait variation related to gap dynamics in tropical moist forests$_{\textrm{{A}}}$ vegetation modelling perspective}, - volume = {35}, - url = {https://doi.org/10.1016/j.ppees.2018.10.004}, - doi = {10.1016/j.ppees.2018.10.004}, - abstract = {Perspectives in Plant Ecology, Evolution and Systematics, 35 (2018) 52-64. doi:10.1016/j.ppees.2018.10.004}, - journal = {Perspectives in Plant Ecology, Evolution and Systematics}, - author = {Togashi, Henrique Fürstenau and Atkin, Owen K and Bloomfield, Keith J and Bradford, Matt and Cao, Kunfang and Dong, Ning and Evans, Bradley J and Fan, Zexin and Harrison, Sandy P and Hua, Zhu and Liddell, Michael J and Lloyd, Jon and Ni, Jian and Wang, Han and Weerasinghe, Lasantha K and Prentice, Iain Colin}, - month = dec, - year = {2018}, - note = {Publisher: Elsevier - tex.date-added: 2020-12-01T17:02:03GMT - tex.date-modified: 2020-12-17T08:58:40GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Togashi/Perspectives\%20in\%20Plant\%20Ecology\%20Evolution\%20and\%20Systematics\%202018\%20Togashi.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1016/j.ppees.2018.10.004}, - pages = {52--64}, - file = {Perspectives in Plant Ecology Evolution and Systematics 2018 Togashi.pdf:/Users/dorme/Zotero/storage/7T29HQCL/Perspectives in Plant Ecology Evolution and Systematics 2018 Togashi.pdf:application/pdf} +@article{kennedy:2019a, + title = {Implementing {{Plant Hydraulics}} in the {{Community Land Model}}, {{Version}} 5}, + author = {Kennedy, Daniel and Swenson, Sean and Oleson, Keith W. and Lawrence, David M. and Fisher, Rosie and {Lola da Costa}, Antonio Carlos and Gentine, Pierre}, + year = {2019}, + month = feb, + journal = {Journal of Advances in Modeling Earth Systems}, + volume = {11}, + number = {2}, + pages = {485--513}, + issn = {19422466}, + doi = {10.1029/2018MS001500}, + urldate = {2022-07-21}, + abstract = {Version 5 of the Community Land Model (CLM5) introduces the plant hydraulic stress (PHS) configuration of vegetation water use, which is described and compared with the corresponding parameterization from CLM4.5. PHS updates vegetation water stress and root water uptake to better reflect plant hydraulic theory, advancing the physical basis of the model. The new configuration introduces prognostic vegetation water potential, modeled at the root, stem, and leaf levels. Leaf water potential replaces soil potential as the basis for stomatal conductance water stress, and root water potential is used to implement hydraulic root water uptake, replacing a transpiration partitioning function. Point simulations of a tropical forest site (Caxiuan{\~a}, Brazil) under ambient conditions and partial precipitation exclusion highlight the differences between PHS and the previous CLM implementation. Model description and simulation results are contextualized with a list of benefits and limitations of the new model formulation, including hypotheses that were not testable in previous versions of the model. Key results include reductions in transpiration and soil moisture biases relative to a control model under both ambient and exclusion conditions, correcting excessive dry season soil moisture stress in the control model. PHS implements hydraulic gradient root water uptake, which allows hydraulic redistribution and compensatory root water uptake and results in PHS utilizing a larger portion of the soil column to buffer shortfalls in precipitation. The new model structure, which bases water stress on leaf water potential, could have significant implications for vegetation-climate feedbacks, including increased sensitivity of photosynthesis to atmospheric vapor pressure deficit.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/X6XIHAEF/Kennedy et al. - 2019 - Implementing Plant Hydraulics in the Community Lan.pdf} } -@article{cai:2020a, - title = {Recent trends in gross primary production and their drivers: analysis and modelling at flux-site and global scales}, - volume = {15}, - issn = {1748-9326}, - shorttitle = {Recent trends in gross primary production and their drivers}, - url = {https://iopscience.iop.org/article/10.1088/1748-9326/abc64e}, - doi = {10.1088/1748-9326/abc64e}, - abstract = {Abstract - - Gross primary production (GPP) by terrestrial ecosystems is the largest flux in the global carbon cycle, and its continuing increase in response to environmental changes is key to land ecosystems’ capacity to offset anthropogenic CO - 2 - emissions. However, the CO - 2 - - and climate-sensitivities of GPP vary among models. We applied the ‘P model’—a parameter-sparse and extensively tested light use efficiency (LUE) model, driven by CO - 2 - , climate and remotely sensed greenness data—at 29 sites with multi-year eddy-covariance flux measurements. Observed (both positive and negative) GPP trends at these sites were predicted, albeit with some bias. Increasing LUE (due to rising atmospheric CO - 2 - concentration) and green vegetation cover were the primary controls of modelled GPP trends across sites. Global GPP simulated by the same model increased by 0.46 ± 0.09 Pg C yr - –2 - during 1982–2016. This increase falls in the mid-range rate of simulated increase by the TRENDY v8 ensemble of state-of-the-art ecosystem models. The modelled LUE increase during 1900–2013 was 15\%, similar to a published estimate based on deuterium isotopomers. Rising CO - 2 - was the largest contributor to the modelled GPP increase. Greening, which may in part be caused by rising CO - 2 - , ranked second but dominated the modelled GPP change over large areas, including semi-arid vegetation on all continents. Warming caused a small net reduction in modelled global GPP, but dominated the modelled GPP increase in high northern latitudes. These findings strengthen the evidence that rising LUE due to rising CO - 2 - level and increased green vegetation cover (fAPAR) are the main causes of increasing GPP, and thereby, the terrestrial carbon sink.}, - language = {en}, - number = {12}, - urldate = {2022-05-16}, - journal = {Environmental Research Letters}, - author = {Cai, Wenjia and Prentice, Iain Colin}, - month = dec, - year = {2020}, - pages = {124050}, - file = {Cai and Prentice - 2020 - Recent trends in gross primary production and thei.pdf:/Users/dorme/Zotero/storage/NGHELDVI/Cai and Prentice - 2020 - Recent trends in gross primary production and thei.pdf:application/pdf} +@phdthesis{Lancelot:2020tm, + title = {A Novel Computational Model to Predict Forest Dynamics}, + author = {Lancelot, Maxime}, + year = {2020}, + month = aug, + affiliation = {Imperial College London}, + date-added = {2020-11-30T12:25:21GMT}, + date-modified = {2020-11-30T14:42:52GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Books/2020/Lancelot/2020\%20Lancelot.pdf}, + rating = {0}, + uri = {papers3://publication/uuid/D73D9C6F-36C9-461D-A90C-784809C52BCB}, + file = {/Users/dorme/Zotero/storage/86NBGKCA/2020 Lancelot.pdf} } @article{lavergne:2020a, - title = {Impacts of soil water stress on the acclimated stomatal limitation of photosynthesis: {Insights} from stable carbon isotope data}, - volume = {26}, - issn = {1354-1013, 1365-2486}, - shorttitle = {Impacts of soil water stress on the acclimated stomatal limitation of photosynthesis}, - url = {https://onlinelibrary.wiley.com/doi/10.1111/gcb.15364}, - doi = {10.1111/gcb.15364}, - abstract = {Atmospheric aridity and drought both influence physiological function in plant leaves, but their relative contributions to changes in the ratio of leaf internal to ambient partial pressure of CO2 (χ) – an index of adjustments in both stomatal conductance and photosynthetic rate to environmental conditions – are difficult to disentangle. Many stomatal models predicting χ include the influence of only one of these drivers. In particular, the least-cost optimality hypothesis considers the effect of atmospheric demand for water on χ but does not predict how soils with reduced water further influence χ, potentially leading to an overestimation of χ under dry conditions. Here, we use a large network of stable carbon isotope measurements in C3 woody plants to examine the acclimated response of χ to soil water stress. We estimate the ratio of cost factors for carboxylation and transpiration (β) expected from the theory to explain the variance in the data, and investigate the responses of β (and thus χ) to soil water content and suction across seed plant groups, leaf phenological types and regions. Overall, β decreases linearly with soil drying, implying that the cost of water transport along the soil–plant–atmosphere continuum increases as water available in the soil decreases. However, despite contrasting hydraulic strategies, the stomatal responses of angiosperms and gymnosperms to soil water tend to converge, consistent with the optimality theory. The prediction of β as a simple, empirical function of soil water significantly improves χ predictions by up to 6.3 ± 2.3\% (mean ± SD of adjusted-R2) over 1980–2018 and results in a reduction of around 2\% of mean χ values across the globe. Our results highlight the importance of soil water status on stomatal functions and plant water-use efficiency, and suggest the implementation of trait-based hydraulic functions into the model to account for soil water stress.}, - language = {en}, - number = {12}, - urldate = {2022-05-19}, - journal = {Global Change Biology}, - author = {Lavergne, Aliénor and Sandoval, David and Hare, Vincent J. and Graven, Heather and Prentice, Iain Colin}, - month = dec, - year = {2020}, - pages = {7158--7172}, - file = {Lavergne et al. - 2020 - Impacts of soil water stress on the acclimated sto.pdf:/Users/dorme/Zotero/storage/ULV9VU2Y/Lavergne et al. - 2020 - Impacts of soil water stress on the acclimated sto.pdf:application/pdf} + title = {Impacts of Soil Water Stress on the Acclimated Stomatal Limitation of Photosynthesis: {{Insights}} from Stable Carbon Isotope Data}, + shorttitle = {Impacts of Soil Water Stress on the Acclimated Stomatal Limitation of Photosynthesis}, + author = {Lavergne, Ali{\'e}nor and Sandoval, David and Hare, Vincent J. and Graven, Heather and Prentice, Iain Colin}, + year = {2020}, + month = dec, + journal = {Global Change Biology}, + volume = {26}, + number = {12}, + pages = {7158--7172}, + issn = {1354-1013, 1365-2486}, + doi = {10.1111/gcb.15364}, + urldate = {2022-05-19}, + abstract = {Atmospheric aridity and drought both influence physiological function in plant leaves, but their relative contributions to changes in the ratio of leaf internal to ambient partial pressure of CO2 ({$\chi$}) -- an index of adjustments in both stomatal conductance and photosynthetic rate to environmental conditions -- are difficult to disentangle. Many stomatal models predicting {$\chi$} include the influence of only one of these drivers. In particular, the least-cost optimality hypothesis considers the effect of atmospheric demand for water on {$\chi$} but does not predict how soils with reduced water further influence {$\chi$}, potentially leading to an overestimation of {$\chi$} under dry conditions. Here, we use a large network of stable carbon isotope measurements in C3 woody plants to examine the acclimated response of {$\chi$} to soil water stress. We estimate the ratio of cost factors for carboxylation and transpiration ({$\beta$}) expected from the theory to explain the variance in the data, and investigate the responses of {$\beta$} (and thus {$\chi$}) to soil water content and suction across seed plant groups, leaf phenological types and regions. Overall, {$\beta$} decreases linearly with soil drying, implying that the cost of water transport along the soil--plant--atmosphere continuum increases as water available in the soil decreases. However, despite contrasting hydraulic strategies, the stomatal responses of angiosperms and gymnosperms to soil water tend to converge, consistent with the optimality theory. The prediction of {$\beta$} as a simple, empirical function of soil water significantly improves {$\chi$} predictions by up to 6.3 {\textpm} 2.3\% (mean {\textpm} SD of adjusted-R2) over 1980--2018 and results in a reduction of around 2\% of mean {$\chi$} values across the globe. Our results highlight the importance of soil water status on stomatal functions and plant water-use efficiency, and suggest the implementation of trait-based hydraulic functions into the model to account for soil water stress.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/ECFRUWX5/Lavergne et al. - 2020 - Impacts of soil water stress on the acclimated sto.pdf} } -@article{farquhar:1982a, - title = {On the relationship between carbon isotope discrimination and the intercellular carbon dioxide concentration in leaves}, - volume = {9}, - issn = {1445-4408}, - url = {http://www.publish.csiro.au/?paper=PP9820121}, - doi = {10.1071/PP9820121}, - abstract = {Theory is developed to explain the carbon isotopic composition of plants. It is shown how diffusion of gaseous COz can significantly affect carbon isotopic discrimination. The effects on discrimination by diffusion and carboxylation are integrated, yielding a simple relationship between discrimination and the ratio of the intercellular and atmospheric partial pressures of COZ. The effects of dark respiration and photorespiration are also considered, and it is suggested that they have relatively little effect on discrimination other than cia their effects on intercellular p(COz). It is also suggested that various environmental factors such as light, temperature, salinity and drought will also have effects via changes in intercellular p(C0,). A simple method is suggested for assessing water use efficiencies in the field.}, - language = {en}, - number = {2}, - urldate = {2022-05-20}, - journal = {Australian Journal of Plant Physiology}, - author = {Farquhar, Graham D and O'Leary, Marion H and Berry, Joseph A}, - year = {1982}, - pages = {121}, - file = {Farquhar et al. - 1982 - On the Relationship Between Carbon Isotope Discrim.pdf:/Users/dorme/Zotero/storage/QMMIYWRA/Farquhar et al. - 1982 - On the Relationship Between Carbon Isotope Discrim.pdf:application/pdf} +@article{lavergne:2022a, + title = {A Semi-Empirical Model for Primary Production, Isotopic Discrimination and Competition of {{C3}} and {{C4}} Plants}, + author = {Lavergne, Ali{\'e}nor and Harrison, Sandy P. and Atsawawaranunt, Kamolphat and Dong, Ning and Prentice, Iain Colin}, + year = {2022}, + journal = {Global Ecology and Biogeography (submitted)}, + file = {/Users/dorme/Zotero/storage/I797PRT2/Lavergneetal_GEB.docx} } -@article{voncaemmerer:2014a, - title = {Carbon isotope discrimination as a tool to explore {C4} photosynthesis}, - volume = {65}, - issn = {1460-2431, 0022-0957}, - url = {https://academic.oup.com/jxb/article-lookup/doi/10.1093/jxb/eru127}, - doi = {10.1093/jxb/eru127}, - abstract = {Photosynthetic carbon isotope discrimination is a non-destructive tool for investigating C4 metabolism. Tuneable diode laser absorption spectroscopy provides new opportunities for making rapid, concurrent measurements of carbon isotope discrimination and CO2 assimilation over a range of environmental conditions, and this has facilitated the use of carbon isotope discrimination as a probe of C4 metabolism. In spite of the significant progress made in recent years, understanding how photosynthetic carbon isotope discrimination measured concurrently with gas exchange relates to carbon isotope composition of leaf and plant dry matter remains a challenge that requires resolution if this technique is to be successfully applied as a screening tool in crop breeding and phylogenetic research. In this review, we update our understanding of the factors and assumptions that underlie variations in photosynthetic carbon isotope discrimination in C4 leaves. Closing the main gaps in our understanding of carbon isotope discrimination during C4 photosynthesis may help advance research aimed at developing higher productivity and efficiency in key C4 food, feed, and biofuel crops.}, - language = {en}, - number = {13}, - urldate = {2022-05-20}, - journal = {Journal of Experimental Botany}, - author = {von Caemmerer, Susanne and Ghannoum, Oula and Pengelly, Jasper J. L. and Cousins, Asaph B.}, - month = jul, - year = {2014}, - pages = {3459--3470}, - file = {Caemmerer et al. - 2014 - Carbon isotope discrimination as a tool to explore.pdf:/Users/dorme/Zotero/storage/EVAEICEV/Caemmerer et al. - 2014 - Carbon isotope discrimination as a tool to explore.pdf:application/pdf} +@article{Li:2014bc, + title = {Simulation of Tree-Ring Widths with a Model for Primary Production, Carbon Allocation, and Growth}, + author = {Li, G and Harrison, S P and Prentice, I. C. and Falster, D}, + year = {2014}, + journal = {Biogeosciences (Online)}, + volume = {11}, + number = {23}, + pages = {6711--6724}, + doi = {10.5194/bg-11-6711-2014}, + date-added = {2020-12-01T16:59:12GMT}, + date-modified = {2021-11-11T13:59:21GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Li/Biogeosciences\%202014\%20Li.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.5194/bg-11-6711-2014}, + file = {/Users/dorme/Zotero/storage/HAR4D2NE/Biogeosciences 2014 Li.pdf} } -@article{boyd:2015a, - title = {Temperature response of {C4} photosynthesis: {Biochemical} analysis of {Rubisco}, {Phosphoenolpyruvate} {Carboxylase} and {Carbonic} {Anhydrase} in {Setaria} viridis.}, - issn = {0032-0889, 1532-2548}, - shorttitle = {Temperature response of {C4} photosynthesis}, - url = {https://academic.oup.com/plphys/article/169/3/1850-1861/6114196}, - doi = {10.1104/pp.15.00586}, - language = {en}, - urldate = {2022-05-20}, - journal = {Plant Physiology}, - author = {Boyd, Ryan Allen and Gandin, Anthony and Cousins, Asaph B}, - month = sep, - year = {2015}, - pages = {pp.00586.2015}, - file = {Boyd et al. - 2015 - Temperature response of C4 photosynthesis Biochem.pdf:/Users/dorme/Zotero/storage/RHH98FWY/Boyd et al. - 2015 - Temperature response of C4 photosynthesis Biochem.pdf:application/pdf} +@article{Lin:2015wh, + title = {Optimal Stomatal Behaviour around the World}, + author = {Lin, Yan-Shih and Medlyn, Belinda E and Duursma, Remko A and Prentice, I. Colin and Wang, Han and Baig, Sofia and Eamus, Derek and {de Dios}, Victor Resco and Mitchell, Patrick and Ellsworth, David S and {de Beeck}, Maarten Op and Wallin, Goran and Uddling, Johan and Tarvainen, Lasse and Linderson, Maj-Lena and Cernusak, Lucas A and Nippert, Jesse B and Ocheltree, Troy W and Tissue, David T and {Martin-StPaul}, Nicolas K and Rogers, Alistair and Warren, Jeff M and De Angelis, Paolo and Hikosaka, Kouki and Han, Qingmin and Onoda, Yusuke and Gimeno, Teresa E and Barton, Craig V M and Bennie, Jonathan and Bonal, Damien and Bosc, Alexandre and Low, Markus and {Macinins-Ng}, Cate and Rey, Ana and Rowland, Lucy and Setterfield, Samantha A and {Tausz-Posch}, Sabine and {Zaragoza-Castells}, Joana and Broadmeadow, Mark S J and Drake, John E and Freeman, Michael and Ghannoum, Oula and Hutley, Lindsay B and Kelly, Jeff W and Kikuzawa, Kihachiro and Kolari, Pasi and Koyama, Kohei and Limousin, Jean-Marc and Meir, Patrick and {Lola da Costa}, Antonio C and Mikkelsen, Teis N and Salinas, Norma and Sun, Wei and Wingate, Lisa}, + year = {2015}, + journal = {Nature Climate Change}, + volume = {5}, + number = {5}, + pages = {459--464}, + abstract = {Stomatal conductance is a land-surface attribute that links the water and carbon cycles. Analysis of a global database covering a wide range of plant functional types and biomes now provides a framework for predicting the behaviour of stomatal conductance that can be applied to model ecosystem productivity, energy balance and ecohydrological processes in a changing climate.}, + date-added = {2021-11-11T14:12:05GMT}, + date-modified = {2021-11-11T14:13:27GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2015/Lin/2015\%20Lin-2.pdf}, + rating = {0}, + uri = {papers3://publication/uuid/61D6E8CB-F257-4021-AC24-2DF4D72C298E}, + file = {/Users/dorme/Zotero/storage/J7WANJNI/2015 Lin-2.pdf} +} + +@article{linacre:1968a, + title = {Estimating the Net-Radiation Flux}, + author = {Linacre, E. T.}, + year = {1968}, + month = jan, + journal = {Agricultural Meteorology}, + volume = {5}, + number = {1}, + pages = {49--63}, + issn = {0002-1571}, + doi = {10.1016/0002-1571(68)90022-8}, + urldate = {2024-08-02}, + abstract = {A major influence controlling the water loss from irrigated crops is the net-radiation intensity Qn, but measurements of this are not normally available, and so attempts are often made to deduce it from other climatic data, such as the solar-radiation. Here it is shown that the relationship between net and solar-radiation intensities depends on the degree of cloudiness and the ambient temperature. By making appropriate assumptions, a series of expressions for Qn is derived, with decreasing accuracy but increasing simplicity of estimation. It appears that clouds lower the net-radiation intensity when it exceeds a critical value in the region of 0.02 cal./cm2 min, but increase it when the intensity is lower.}, + file = {/Users/dorme/Zotero/storage/UY4NRV4W/0002157168900228.html} +} + +@article{long:1993a, + title = {Quantum Yields for Uptake of Carbon Dioxide in {{C3}} Vascular Plants of Contrasting Habitats and Taxonomic Groupings}, + author = {Long, S. P. and Postl, W. F. and {Bolh{\'a}r-Nordenkampf}, H. R.}, + year = {1993}, + month = feb, + journal = {Planta}, + volume = {189}, + number = {2}, + pages = {226--234}, + issn = {1432-2048}, + doi = {10.1007/BF00195081}, + urldate = {2024-07-19}, + abstract = {The maximum quantum yields ({$\phi$}a,c) for CO2 uptake in low-oxygen atmospheres were determined for 11 species of C3 vascular plants of diverse taxa, habitat and life form using an Ulbricht-sphere leaf chamber. Comparisons were also made between tissues of varied age within species. The species examined were Psilotum nudum (L.) P. Beauv., Davallia bullata Wall. ex Hook., Cycas revoluta Thunb., Araucaria heterophylla (Salisb.) Franco, Picea abies (L.) Karst., Nerium oleander L., Ruellia humilis Nutt., Pilea microphylla (L.) Karst., Beaucarnea stricta Lem., Oplismenus hirtellus (L.) P. Beauv. and Poa annua L. Quantum yields were calculated from the initial slopes of the response of CO2 uptake to the quantity of photons absorbed in conditions of diffuse lighting. Regression analysis of variance of the initial slopes of the response of CO2 uptake to photon absorption failed to show any statistically significant differences between age classes within species or between the mature photosynthetic organs of different species. The constancy of {$\phi$}a,c was apparent despite marked variation in the light-saturated rates of CO2 uptake within and between species. The mean {$\phi$}a,c was 0.093{\textpm}0.003 for 11 species. By contrast, surface absorptance varied markedly between species from 0.90 to 0.60, producing proportional variation in the quantum yield calculated on an incidentlight basis. The ratio of variable to maximum fluorescence emission at 695 nm for the same tissues also failed to show any statistically significant variation between species, with a mean of 0.838{\textpm}0.008. Mean values of {$\phi$}a,c reported here for C3 species, in the absence of photorespiration, are higher than reported in previous surveys of vascular plants, but consistent with recent estimates of the quantum yields of O2 evolution.}, + langid = {english}, + keywords = {C3 plant,Photosynthesis,Quantum yield (O2 CO2 uptake)}, + file = {/Users/dorme/Zotero/storage/88PTVDYD/Long et al. - 1993 - Quantum yields for uptake of carbon dioxide in C3 .pdf} } -@article{graven:2020a, - title = {Changes to {Carbon} {Isotopes} in {Atmospheric} {CO} $_{\textrm{2}}$ {Over} the {Industrial} {Era} and {Into} the {Future}}, - volume = {34}, - issn = {0886-6236, 1944-9224}, - url = {https://onlinelibrary.wiley.com/doi/10.1029/2019GB006170}, - doi = {10.1029/2019GB006170}, - abstract = {In this “Grand Challenges” paper, we review how the carbon isotopic composition of atmospheric CO2 has changed since the Industrial Revolution due to human activities and their influence on the natural carbon cycle, and we provide new estimates of possible future changes for a range of scenarios. Emissions of CO2 from fossil fuel combustion and land use change reduce the ratio of 13C/12C in atmospheric CO2 (δ13CO2). This is because 12C is preferentially assimilated during photosynthesis and δ13C in plant‐derived carbon in terrestrial ecosystems and fossil fuels is lower than atmospheric δ13CO2. Emissions of CO2 from fossil fuel combustion also reduce the ratio of 14C/C in atmospheric CO2 (Δ14CO2) because 14C is absent in million‐year‐old fossil fuels, which have been stored for much longer than the radioactive decay time of 14C. Atmospheric Δ14CO2 rapidly increased in the 1950s to 1960s because of 14C produced during nuclear bomb testing. The resulting trends in δ13C and Δ14C in atmospheric CO2 are influenced not only by these human emissions but also by natural carbon exchanges that mix carbon between the atmosphere and ocean and terrestrial ecosystems. This mixing caused Δ14CO2 to return toward preindustrial levels in the first few decades after the spike from nuclear testing. More recently, as the bomb 14C excess is now mostly well mixed with the decadally overturning carbon reservoirs, fossil fuel emissions have become the main factor driving further decreases in atmospheric Δ14CO2. For δ13CO2, in addition to exchanges between reservoirs, the extent to which 12C is preferentially assimilated during photosynthesis appears to have increased, slowing down the recent δ13CO2 trend slightly. A new compilation of ice core and flask δ13CO2 observations indicates that the decline in δ13CO2 since the preindustrial period is less than some prior estimates, which may have incorporated artifacts owing to offsets from different laboratories' measurements. Atmospheric observations of δ13CO2 have been used to investigate carbon fluxes and the functioning of plants, and they are used for comparison with δ13C in other materials such as tree rings. Atmospheric observations of Δ14CO2 have been used to quantify the rate of air‐sea gas exchange and ocean circulation, and the rate of net primary production and the turnover time of carbon in plant material and soils. Atmospheric observations of Δ14CO2 are also used for comparison with Δ14C in other materials in many fields such as archaeology, forensics, and physiology. Another major application is the assessment of regional emissions of CO2 from fossil fuel combustion using Δ14CO2 observations and models. In the future, δ13CO2 and Δ14CO2 will continue to change. The sign and magnitude of the changes are mainly determined by global fossil fuel emissions. We present here simulations of future δ13CO2 and Δ14CO2 for six scenarios based on the shared socioeconomic pathways (SSPs) from the 6th Coupled Model Intercomparison Project (CMIP6). Applications using atmospheric δ13CO2 and Δ14CO2 observations in carbon cycle science and many other fields will be affected by these future changes. We recommend an increased effort toward making coordinated measurements of δ13C and Δ14C across the Earth System and for further development of isotopic modeling and model‐data analysis tools.}, - language = {en}, - number = {11}, - urldate = {2022-05-23}, - journal = {Global Biogeochemical Cycles}, - author = {Graven, Heather and Keeling, Ralph F. and Rogelj, Joeri}, - month = nov, - year = {2020}, - file = {Graven et al. - 2020 - Changes to Carbon Isotopes in Atmospheric CO .pdf:/Users/dorme/Zotero/storage/XUCC46IU/Graven et al. - 2020 - Changes to Carbon Isotopes in Atmospheric CO .pdf:application/pdf} +@article{mengoli:2022a, + title = {Ecosystem {{Photosynthesis}} in {{Land}}-{{Surface Models}}: {{A First}}-{{Principles Approach Incorporating Acclimation}}}, + shorttitle = {Ecosystem {{Photosynthesis}} in {{Land}}-{{Surface Models}}}, + author = {Mengoli, Giulia and Agust{\'i}-Panareda, Anna and Boussetta, Souhail and Harrison, Sandy P. and Trotta, Carlo and Prentice, I. Colin}, + year = {2022}, + month = jan, + journal = {Journal of Advances in Modeling Earth Systems}, + volume = {14}, + number = {1}, + issn = {1942-2466, 1942-2466}, + doi = {10.1029/2021MS002767}, + urldate = {2022-05-26}, + abstract = {Vegetation regulates land-atmosphere, water, and energy exchanges and is an essential component of land-surface models (LSMs). However, LSMs have been handicapped by assumptions that equate acclimated photosynthetic responses to the environment with the fast responses observable in the laboratory. The effects of acclimation can be taken into account by including PFT-specific values of photosynthetic parameters, but at the cost of increasing parameter requirements. Here, we develop an alternative approach for including acclimation in LSMs by adopting the P model, an existing light-use efficiency model for gross primary production (GPP) that implicitly predicts the acclimation of photosynthetic parameters on a weekly to monthly timescale via optimality principles. We demonstrate that it is possible to explicitly separate the fast and slow photosynthetic responses to environmental conditions, allowing the simulation of GPP at the sub-daily timesteps required for coupling in an LSM. The resulting model reproduces the diurnal cycles of GPP recorded by eddy-covariance flux towers in a temperate grassland and boreal, temperate and tropical forests. The best performance is achieved when biochemical capacities are adjusted to match recent midday conditions. Comparison between this model and the operational LSM in the European Centre for Medium-range Weather Forecasts climate model shows that the new model has better predictive power in most of the sites and years analyzed, particularly in summer and autumn. Our analyses suggest a simple and parameter-sparse method to include both instantaneous and acclimated responses within an LSM framework, with potential applications in weather, climate, and carbon-cycle modeling.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/KAFPVD6H/2021ms002767-sup-0002-supporting information si-s02.pdf;/Users/dorme/Zotero/storage/VU8B6HP8/Mengoli et al. - 2022 - Ecosystem Photosynthesis in Land‐Surface Models A.pdf;/Users/dorme/Zotero/storage/ZQBUWXEK/2021ms002767-sup-0001-supporting information si-s01.pdf} } -@article{mengoli:2022a, - title = {Ecosystem {Photosynthesis} in {Land}‐{Surface} {Models}: {A} {First}‐{Principles} {Approach} {Incorporating} {Acclimation}}, - volume = {14}, - issn = {1942-2466, 1942-2466}, - shorttitle = {Ecosystem {Photosynthesis} in {Land}‐{Surface} {Models}}, - url = {https://onlinelibrary.wiley.com/doi/10.1029/2021MS002767}, - doi = {10.1029/2021MS002767}, - abstract = {Vegetation regulates land-atmosphere, water, and energy exchanges and is an essential component of land-surface models (LSMs). However, LSMs have been handicapped by assumptions that equate acclimated photosynthetic responses to the environment with the fast responses observable in the laboratory. The effects of acclimation can be taken into account by including PFT-specific values of photosynthetic parameters, but at the cost of increasing parameter requirements. Here, we develop an alternative approach for including acclimation in LSMs by adopting the P model, an existing light-use efficiency model for gross primary production (GPP) that implicitly predicts the acclimation of photosynthetic parameters on a weekly to monthly timescale via optimality principles. We demonstrate that it is possible to explicitly separate the fast and slow photosynthetic responses to environmental conditions, allowing the simulation of GPP at the sub-daily timesteps required for coupling in an LSM. The resulting model reproduces the diurnal cycles of GPP recorded by eddy-covariance flux towers in a temperate grassland and boreal, temperate and tropical forests. The best performance is achieved when biochemical capacities are adjusted to match recent midday conditions. Comparison between this model and the operational LSM in the European Centre for Medium-range Weather Forecasts climate model shows that the new model has better predictive power in most of the sites and years analyzed, particularly in summer and autumn. Our analyses suggest a simple and parameter-sparse method to include both instantaneous and acclimated responses within an LSM framework, with potential applications in weather, climate, and carbon-cycle modeling.}, - language = {en}, - number = {1}, - urldate = {2022-05-26}, - journal = {Journal of Advances in Modeling Earth Systems}, - author = {Mengoli, Giulia and Agustí‐Panareda, Anna and Boussetta, Souhail and Harrison, Sandy P. and Trotta, Carlo and Prentice, I. Colin}, - month = jan, - year = {2022}, - file = {2021ms002767-sup-0001-supporting information si-s01.pdf:/Users/dorme/Zotero/storage/YC3IEKUM/2021ms002767-sup-0001-supporting information si-s01.pdf:application/pdf;2021ms002767-sup-0002-supporting information si-s02.pdf:/Users/dorme/Zotero/storage/TP5WW2YH/2021ms002767-sup-0002-supporting information si-s02.pdf:application/pdf;Mengoli et al. - 2022 - Ecosystem Photosynthesis in Land‐Surface Models A.pdf:/Users/dorme/Zotero/storage/JU7AZTI4/Mengoli et al. - 2022 - Ecosystem Photosynthesis in Land‐Surface Models A.pdf:application/pdf} +@article{mengoli:2023a, + title = {A Global Function of Climatic Aridity Accounts for Soil Moisture Stress on Carbon Assimilation}, + author = {Mengoli, Giulia and Harrison, Sandy P. and Prentice, I. Colin}, + year = {2023}, + month = jun, + journal = {EGUsphere}, + pages = {1--19}, + publisher = {Copernicus GmbH}, + doi = {10.5194/egusphere-2023-1261}, + urldate = {2023-07-03}, + abstract = {{$<$}p{$><$}strong class="journal-contentHeaderColor"{$>$}Abstract.{$<$}/strong{$>$} The coupling between carbon uptake and water loss through stomata implies that gross primary production (GPP) can be limited by soil water availability through reduced leaf area and/or reduced stomatal conductance. Vegetation and land-surface models typically assume that GPP is highest under well-watered conditions and apply a stress function to reduce GPP with declining soil moisture below a critical threshold, which may be universal or prescribed by vegetation type. It is unclear how well current schemes represent the water conservation strategies of plants in different climates. Here eddy-covariance flux data are used to investigate empirically how soil moisture influences the light-use efficiency (LUE) of GPP. Well-watered GPP is estimated using the P model, a first-principles LUE model driven by atmospheric data and remotely sensed green vegetation cover. Breakpoint regression is used to relate the daily value of the ratio \β(\θ) (flux-derived GPP/modelled well-watered GPP) to soil moisture, which is estimated using a generic water-balance model. Maximum LUE, even during wetter periods, is shown to decline with increasing climatic aridity index (AI). The critical soil-moisture threshold also declines with AI. Moreover, for any AI, there is a value of soil moisture at which \β(\θ) is maximized, and this value declines with increasing AI. Thus, ecosystems adapted to seasonally dry conditions use water more conservatively (relative to well-watered ecosystems) when soil moisture is high, but maintain higher GPP when soil moisture is low. An empirical non-linear function of AI expressing these relationships is derived by non-linear regression, and used to generate a \β(\θ) function that provides a multiplier for well-watered GPP as simulated by the P model. Substantially improved GPP simulation is shown during both unstressed and water-stressed conditions, compared to the reference model version that ignores soil-moisture stress, and to an earlier formulation in which maximum LUE was not reduced. This scheme may provide a step towards better-founded representations of carbon-water cycle coupling in vegetation and land-surface models.{$<$}/p{$>$}}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/GMFKIMVQ/Mengoli et al. - 2023 - A global function of climatic aridity accounts for.pdf} } -@article{lavergne:2022a, - title = {A semi-empirical model for primary production, isotopic discrimination and competition of {C3} and {C4} plants}, - journal = {Global Ecology and Biogeography (submitted)}, - author = {Lavergne, Aliénor and Harrison, Sandy P. and Atsawawaranunt, Kamolphat and Dong, Ning and Prentice, Iain Colin}, - year = {2022}, - file = {Lavergneetal_GEB.docx:/Users/dorme/Zotero/storage/C4HSADV3/Lavergneetal_GEB.docx:application/vnd.openxmlformats-officedocument.wordprocessingml.document} +@article{Moore:2018dv, + title = {Equilibrium Forest Demography Explains the Distribution of Tree Sizes across {{North America}}}, + author = {Moore, Jonathan R and Zhu, Kai and Huntingford, Chris and Cox, Peter M}, + year = {2018}, + month = aug, + journal = {Environmental Research Letters}, + volume = {13}, + number = {8}, + pages = {084019--10}, + publisher = {IOP Publishing}, + doi = {10.1088/1748-9326/aad6d1}, + abstract = {Environmental Research Letters, 13(2018) 084019. doi:10.1088/1748-9326/aad6d1}, + date-added = {2020-12-01T16:56:53GMT}, + date-modified = {2020-12-17T08:58:39GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Moore/Environ\%20Res\%20Lett\%202018\%20Moore.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1088/1748-9326/aad6d1}, + file = {/Users/dorme/Zotero/storage/9Z93DUPX/Environ Res Lett 2018 Moore.pdf} +} + +@article{murphy:2021a, + title = {A Derivation Error That Affects Carbon Balance Models Exists in the Current Implementation of the Modified {{Arrhenius}} Function}, + author = {Murphy, Bridget K. and Stinziano, Joseph R.}, + year = {2021}, + journal = {New Phytologist}, + volume = {231}, + number = {6}, + pages = {2371--2381}, + issn = {1469-8137}, + doi = {10.1111/nph.16883}, + urldate = {2024-07-25}, + abstract = {Understanding biological temperature responses is crucial to predicting global carbon fluxes. The current approach to modelling temperature responses of photosynthetic capacity in large scale modelling efforts uses a modified Arrhenius equation. We rederived the modified Arrhenius equation from the source publication from 1942 and uncovered a missing term that was dropped by 2002. We compare fitted temperature response parameters between the correct and incorrect derivation of the modified Arrhenius equation. We find that most parameters are minimally affected, though activation energy is impacted quite substantially. We then scaled the impact of these small errors to whole plant carbon balance and found that the impact of the rederivation of the modified Arrhenius equation on modelled daily carbon gain causes a meaningful deviation of c. 18\% day-1. This suggests that the error in the derivation of the modified Arrhenius equation has impacted the accuracy of predictions of carbon fluxes at larger scales since {$>$} 40\% of Earth System Models contain the erroneous derivation. We recommend that the derivation error be corrected in modelling efforts moving forward.}, + copyright = {{\copyright} 2020 The Authors New Phytologist {\copyright} 2020 New Phytologist Trust}, + langid = {english}, + keywords = {Arrhenius,carbon balance,gas exchange,modelling,photosynthesis,temperature}, + file = {/Users/dorme/Zotero/storage/NZTU5A6H/Murphy and Stinziano - 2021 - A derivation error that affects carbon balance mod.pdf;/Users/dorme/Zotero/storage/5Y2669L6/nph.html} } -@article{kennedy:2019a, - title = {Implementing {Plant} {Hydraulics} in the {Community} {Land} {Model}, {Version} 5}, - volume = {11}, - issn = {19422466}, - url = {http://doi.wiley.com/10.1029/2018MS001500}, - doi = {10.1029/2018MS001500}, - abstract = {Version 5 of the Community Land Model (CLM5) introduces the plant hydraulic stress (PHS) configuration of vegetation water use, which is described and compared with the corresponding parameterization from CLM4.5. PHS updates vegetation water stress and root water uptake to better reflect plant hydraulic theory, advancing the physical basis of the model. The new configuration introduces prognostic vegetation water potential, modeled at the root, stem, and leaf levels. Leaf water potential replaces soil potential as the basis for stomatal conductance water stress, and root water potential is used to implement hydraulic root water uptake, replacing a transpiration partitioning function. Point simulations of a tropical forest site (Caxiuanã, Brazil) under ambient conditions and partial precipitation exclusion highlight the differences between PHS and the previous CLM implementation. Model description and simulation results are contextualized with a list of benefits and limitations of the new model formulation, including hypotheses that were not testable in previous versions of the model. Key results include reductions in transpiration and soil moisture biases relative to a control model under both ambient and exclusion conditions, correcting excessive dry season soil moisture stress in the control model. PHS implements hydraulic gradient root water uptake, which allows hydraulic redistribution and compensatory root water uptake and results in PHS utilizing a larger portion of the soil column to buffer shortfalls in precipitation. The new model structure, which bases water stress on leaf water potential, could have significant implications for vegetation-climate feedbacks, including increased sensitivity of photosynthesis to atmospheric vapor pressure deficit.}, - language = {en}, - number = {2}, - urldate = {2022-07-21}, - journal = {Journal of Advances in Modeling Earth Systems}, - author = {Kennedy, Daniel and Swenson, Sean and Oleson, Keith W. and Lawrence, David M. and Fisher, Rosie and Lola da Costa, Antonio Carlos and Gentine, Pierre}, - month = feb, - year = {2019}, - pages = {485--513}, - file = {Kennedy et al. - 2019 - Implementing Plant Hydraulics in the Community Lan.pdf:/Users/dorme/Zotero/storage/DK2KUV85/Kennedy et al. - 2019 - Implementing Plant Hydraulics in the Community Lan.pdf:application/pdf} +@article{Peng:2021ky, + title = {Global Climate and Nutrient Controls of Photosynthetic Capacity}, + author = {Peng, Yunke and Bloomfield, Keith J and Cernusak, Lucas A and Domingues, Tomas F and Prentice, I. Colin}, + year = {2021}, + month = apr, + journal = {Communications Biology}, + pages = {1--9}, + publisher = {Springer US}, + doi = {10.1038/s42003-021-01985-7}, + abstract = {Communications Biology, doi:10.1038/s42003-021-01985-7}, + date-added = {2021-06-14T08:31:31GMT}, + date-modified = {2021-11-11T14:13:27GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2021/Peng/Communications\%20Biology\%202021\%20Peng.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1038/s42003-021-01985-7}, + file = {/Users/dorme/Zotero/storage/ZPIDVNUB/Communications Biology 2021 Peng.pdf} } -@article{badeck:2005a, - title = {Post-photosynthetic fractionation of stable carbon isotopes between plant organs—a widespread phenomenon}, - volume = {19}, - url = {https://analyticalsciencejournals.onlinelibrary.wiley.com/doi/abs/10.1002/rcm.1912}, - doi = {https://doi.org/10.1002/rcm.1912}, - abstract = {Abstract Discrimination against 13C during photosynthesis is a well-characterised phenomenon. It leaves behind distinct signatures in organic matter of plants and in the atmosphere. The former is depleted in 13C, the latter is enriched during periods of preponderant photosynthetic activity of terrestrial ecosystems. The intra-annual cycle and latitudinal gradient in atmospheric 13C resulting from photosynthetic and respiratory activities of terrestrial plants have been exploited for the reconstruction of sources and sinks through deconvolution by inverse modelling. Here, we compile evidence for widespread post-photosynthetic fractionation that further modifies the isotopic signatures of individual plant organs and consequently leads to consistent differences in δ13C between plant organs. Leaves were on average 0.96‰ and 1.91‰ more depleted than roots and woody stems, respectively. This phenomenon is relevant if the isotopic signature of CO2-exchange fluxes at the ecosystem level is used for the reconstruction of individual sources and sinks. It may also modify the parameterisation of inverse modelling approaches if it leads to different isotopic signatures of organic matter with different residence times within the ecosystems and to a respiratory contribution to the average difference between the isotopic composition of plant organic matter and the atmosphere. We discuss the main hypotheses that can explain the observed inter-organ differences in δ13C. Copyright © 2005 John Wiley \& Sons, Ltd.}, - number = {11}, - journal = {Rapid Communications in Mass Spectrometry}, - author = {Badeck, Franz-W. and Tcherkez, Guillaume and Nogués, Salvador and Piel, Clément and Ghashghaie, Jaleh}, - year = {2005}, - note = {tex.eprint: https://analyticalsciencejournals.onlinelibrary.wiley.com/doi/pdf/10.1002/rcm.1912}, - pages = {1381--1391}, - file = {Badeck et al. - 2005 - Post-photosynthetic fractionation of stable carbon.pdf:/Users/dorme/Zotero/storage/A8TG832F/Badeck et al. - 2005 - Post-photosynthetic fractionation of stable carbon.pdf:application/pdf} +@article{Prentice:2014bc, + title = {Balancing the Costs of Carbon Gain and Water Transport: Testing a New Theoretical Framework for Plant Functional Ecology}, + author = {Prentice, I. Colin and Dong, Ning and Gleason, Sean M and Maire, Vincent and Wright, Ian J.}, + year = {2014}, + journal = {Ecology Letters}, + volume = {17}, + number = {1}, + pages = {82--91}, + doi = {10.1111/ele.12211}, + date-added = {2020-12-01T13:22:48GMT}, + date-modified = {2021-01-21T15:04:43GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Prentice/Ecol\%20Lett\%202014\%20Prentice.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1111/ele.12211}, + file = {/Users/dorme/Zotero/storage/MDRBDVTF/Ecol Lett 2014 Prentice.pdf} } -@article{frank:2015a, - title = {Water-use efficiency and transpiration across {European} forests during the {Anthropocene}}, - volume = {5}, - issn = {1758-6798}, - url = {https://doi.org/10.1038/nclimate2614}, - doi = {10.1038/nclimate2614}, - abstract = {Considering the combined effects of CO2 fertilization and climate change drivers on plant physiology leads to a modest increase in simulated European forest transpiration in spite of the effects of CO2-induced stomatal closure.}, - number = {6}, - journal = {Nature Climate Change}, - author = {Frank, D. C. and Poulter, B. and Saurer, M. and Esper, J. and Huntingford, C. and Helle, G. and Treydte, K. and Zimmermann, N. E. and Schleser, G. H. and Ahlström, A. and Ciais, P. and Friedlingstein, P. and Levis, S. and Lomas, M. and Sitch, S. and Viovy, N. and Andreu-Hayles, L. and Bednarz, Z. and Berninger, F. and Boettger, T. and D‘Alessandro, C. M. and Daux, V. and Filot, M. and Grabner, M. and Gutierrez, E. and Haupt, M. and Hilasvuori, E. and Jungner, H. and Kalela-Brundin, M. and Krapiec, M. and Leuenberger, M. and Loader, N. J. and Marah, H. and Masson-Delmotte, V. and Pazdur, A. and Pawelczyk, S. and Pierre, M. and Planells, O. and Pukiene, R. and Reynolds-Henne, C. E. and Rinne, K. T. and Saracino, A. and Sonninen, E. and Stievenard, M. and Switsur, V. R. and Szczepanek, M. and Szychowska-Krapiec, E. and Todaro, L. and Waterhouse, J. S. and Weigl, M.}, - month = jun, - year = {2015}, - pages = {579--583}, - file = {Frank et al. - 2015 - Water-use efficiency and transpiration across Euro.pdf:/Users/dorme/Zotero/storage/DQE7I4U4/Frank et al. - 2015 - Water-use efficiency and transpiration across Euro.pdf:application/pdf} +@article{Smith:2019dv, + title = {Global Photosynthetic Capacity Is Optimized to the Environment}, + author = {Smith, Nicholas G and Keenan, Trevor F and Colin Prentice, I and Wang, Han and Wright, Ian J. and Niinemets, {\"U}lo and Crous, Kristine Y and Domingues, Tomas F and Guerrieri, Rossella and Yoko Ishida, F and Kattge, Jens and Kruger, Eric L and Maire, Vincent and Rogers, Alistair and Serbin, Shawn P and Tarvainen, Lasse and Togashi, Henrique F and Townsend, Philip A and Wang, Meng and Weerasinghe, Lasantha K and Zhou, Shuang Xi}, + year = {2019}, + month = jan, + journal = {Ecology Letters}, + volume = {22}, + number = {3}, + pages = {506--517}, + doi = {10.1111/ele.13210}, + date-added = {2020-12-02T15:16:49GMT}, + date-modified = {2021-01-25T10:03:32GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2019/Smith/Ecol\%20Lett\%202019\%20Smith.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1111/ele.13210}, + file = {/Users/dorme/Zotero/storage/EIWDBL6T/Ecol Lett 2019 Smith.pdf} } -@article{mengoli:2023a, - title = {A global function of climatic aridity accounts for soil moisture stress on carbon assimilation}, - url = {https://egusphere.copernicus.org/preprints/2023/egusphere-2023-1261/}, - doi = {10.5194/egusphere-2023-1261}, - abstract = {{\textless}p{\textgreater}{\textless}strong class="journal-contentHeaderColor"{\textgreater}Abstract.{\textless}/strong{\textgreater} The coupling between carbon uptake and water loss through stomata implies that gross primary production (GPP) can be limited by soil water availability through reduced leaf area and/or reduced stomatal conductance. Vegetation and land-surface models typically assume that GPP is highest under well-watered conditions and apply a stress function to reduce GPP with declining soil moisture below a critical threshold, which may be universal or prescribed by vegetation type. It is unclear how well current schemes represent the water conservation strategies of plants in different climates. Here eddy-covariance flux data are used to investigate empirically how soil moisture influences the light-use efficiency (LUE) of GPP. Well-watered GPP is estimated using the P model, a first-principles LUE model driven by atmospheric data and remotely sensed green vegetation cover. Breakpoint regression is used to relate the daily value of the ratio \β(\θ) (flux-derived GPP/modelled well-watered GPP) to soil moisture, which is estimated using a generic water-balance model. Maximum LUE, even during wetter periods, is shown to decline with increasing climatic aridity index (AI). The critical soil-moisture threshold also declines with AI. Moreover, for any AI, there is a value of soil moisture at which \β(\θ) is maximized, and this value declines with increasing AI. Thus, ecosystems adapted to seasonally dry conditions use water more conservatively (relative to well-watered ecosystems) when soil moisture is high, but maintain higher GPP when soil moisture is low. An empirical non-linear function of AI expressing these relationships is derived by non-linear regression, and used to generate a \β(\θ) function that provides a multiplier for well-watered GPP as simulated by the P model. Substantially improved GPP simulation is shown during both unstressed and water-stressed conditions, compared to the reference model version that ignores soil-moisture stress, and to an earlier formulation in which maximum LUE was not reduced. This scheme may provide a step towards better-founded representations of carbon-water cycle coupling in vegetation and land-surface models.{\textless}/p{\textgreater}}, - language = {English}, - urldate = {2023-07-03}, - journal = {EGUsphere}, - author = {Mengoli, Giulia and Harrison, Sandy P. and Prentice, I. Colin}, - month = jun, - year = {2023}, - note = {Publisher: Copernicus GmbH}, - pages = {1--19}, - file = {Full Text PDF:/Users/dorme/Zotero/storage/JVIB9NS3/Mengoli et al. - 2023 - A global function of climatic aridity accounts for.pdf:application/pdf} +@article{Stocker:2018be, + title = {Quantifying Soil Moisture Impacts on Light Use Efficiency across Biomes}, + author = {Stocker, Benjamin D and Zscheischler, Jakob and Keenan, Trevor F and Prentice, I. Colin and Penuelas, Josep and Seneviratne, Sonia I}, + year = {2018}, + month = mar, + journal = {New Phytologist}, + volume = {218}, + number = {4}, + pages = {1430--1449}, + doi = {10.1111/nph.15123}, + abstract = {Terrestrial primary productivity and carbon cycle impacts of droughts are commonly quantified using vapour pressure deficit (VPD) data and remotely sensed greenness, without accounting for soil moisture. However, soil moisture limitation is known to strongly affect plant physiology. Here, we investigate light use efficiency, the ratio of gross primary productivity (GPP) to absorbed light. We derive its fractional reduction due to soil moisture (fLUE), separated from VPD and greenness changes, using artificial neural networks trained {\dots}}, + date-added = {2021-01-25T09:23:00GMT}, + date-modified = {2021-01-28T15:58:46GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Stocker/New\%20Phytol.\%202018\%20Stocker.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1111/nph.15123}, + file = {/Users/dorme/Zotero/storage/E6PPD38Z/New Phytol. 2018 Stocker.pdf} } -@techreport{allen:1998a, - address = {Rome}, - title = {Crop evapotranspiration - {Guidelines} for computing crop water requirements}, - number = {56}, - institution = {FAO}, - author = {Allen, Richard G. and Pereira, Luis S and Raes, Dirk and Smith, Martin}, - year = {1998}, - file = {Allen et al. - 1998 - Crop evapotranspiration - Guidelines for computing.pdf:/Users/dorme/Zotero/storage/68AVA64R/Allen et al. - 1998 - Crop evapotranspiration - Guidelines for computing.pdf:application/pdf} +@article{Stocker:2020dh, + title = {P-Model v1.0: An Optimality-Based Light Use Efficiency Model for Simulating Ecosystem Gross Primary Production}, + author = {Stocker, Benjamin D and Wang, Han and Smith, Nicholas G and Harrison, Sandy P and Keenan, Trevor F and Sandoval, David and Davis, Tyler and Prentice, I. Colin}, + year = {2020}, + journal = {Geoscientific Model Development}, + volume = {13}, + number = {3}, + pages = {1545--1581}, + doi = {10.5194/gmd-13-1545-2020}, + date-added = {2020-11-30T12:24:06GMT}, + date-modified = {2021-01-28T11:55:51GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Stocker/Geoscientific\%20Model\%20Development\%202020\%20Stocker.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.5194/gmd-13-1545-2020}, + file = {/Users/dorme/Zotero/storage/J4YM5X2R/Geoscientific Model Development 2020 Stocker.pdf} } -@article{tsilingiris:2008a, - title = {Thermophysical and transport properties of humid air at temperature range between 0 and 100°{C}}, - volume = {49}, - issn = {0196-8904}, - url = {https://www.sciencedirect.com/science/article/pii/S0196890407003329}, - doi = {10.1016/j.enconman.2007.09.015}, - abstract = {The aim of the present investigation is evaluation of the thermophysical and transport properties of moist air as a function of mixture temperature with relative humidity as a parameter, ranging between dry air and saturation conditions. Based on a literature review of the most widely available analytical procedures and methods, a number of developed correlations are presented, which are employed with recent gas mixture component properties as input parameters, to derive the temperature and humidity dependence of mixture density, viscosity, specific heat capacity, thermal conductivity, thermal diffusivity and Prandtl number under conditions corresponding to the total barometric pressure of 101.3kPa. The derived results at an accuracy level suitable for engineering calculations were plotted and compared with adequate accuracy with existing results from previous analytical calculations and measured data from earlier experimental investigations. The saturated mixture properties were also appropriately fitted, and the fitting expressions suitable for computer calculations are also presented.}, - language = {en}, - number = {5}, - urldate = {2023-07-04}, - journal = {Energy Conversion and Management}, - author = {Tsilingiris, P. T.}, - month = may, - year = {2008}, - keywords = {Density, Prandtl number, Specific heat capacity, Thermal conductivity, Thermal diffusivity, Thermophysical properties, Viscosity}, - pages = {1098--1110}, - file = {ScienceDirect Full Text PDF:/Users/dorme/Zotero/storage/EZSDLB2V/Tsilingiris - 2008 - Thermophysical and transport properties of humid a.pdf:application/pdf;ScienceDirect Snapshot:/Users/dorme/Zotero/storage/IZWWYPC8/S0196890407003329.html:text/html} +@article{Togashi:2018es, + title = {Functional Trait Variation Related to Gap Dynamics in Tropical Moist forests{{{\textsubscript{A}}}} Vegetation Modelling Perspective}, + author = {Togashi, Henrique F{\"u}rstenau and Atkin, Owen K and Bloomfield, Keith J and Bradford, Matt and Cao, Kunfang and Dong, Ning and Evans, Bradley J and Fan, Zexin and Harrison, Sandy P and Hua, Zhu and Liddell, Michael J and Lloyd, Jon and Ni, Jian and Wang, Han and Weerasinghe, Lasantha K and Prentice, Iain Colin}, + year = {2018}, + month = dec, + journal = {Perspectives in Plant Ecology, Evolution and Systematics}, + volume = {35}, + pages = {52--64}, + publisher = {Elsevier}, + doi = {10.1016/j.ppees.2018.10.004}, + abstract = {Perspectives in Plant Ecology, Evolution and Systematics, 35 (2018) 52-64. doi:10.1016/j.ppees.2018.10.004}, + date-added = {2020-12-01T17:02:03GMT}, + date-modified = {2020-12-17T08:58:40GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Togashi/Perspectives\%20in\%20Plant\%20Ecology\%20Evolution\%20and\%20Systematics\%202018\%20Togashi.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1016/j.ppees.2018.10.004}, + file = {/Users/dorme/Zotero/storage/L4HJJSBU/Perspectives in Plant Ecology Evolution and Systematics 2018 Togashi.pdf} } -@article{henderson-sellers:1984a, - title = {A new formula for latent heat of vaporization of water as a function of temperature}, - volume = {110}, - copyright = {Copyright © 1984 Royal Meteorological Society}, - issn = {1477-870X}, - url = {https://onlinelibrary.wiley.com/doi/abs/10.1002/qj.49711046626}, - doi = {10.1002/qj.49711046626}, - abstract = {Existing formulae and approximations for the latent heat of vaporization of water, Lv, are reviewed. Using an analytical approximation to the saturated vapour pressure as a function of temperature, a new, temperature-dependent function for Lv is derived.}, - language = {en}, - number = {466}, - urldate = {2023-07-04}, - journal = {Quarterly Journal of the Royal Meteorological Society}, - author = {Henderson-Sellers, B.}, - year = {1984}, - note = {\_eprint: https://onlinelibrary.wiley.com/doi/pdf/10.1002/qj.49711046626}, - pages = {1186--1190}, - file = {Snapshot:/Users/dorme/Zotero/storage/WJAU4R6F/qj.html:text/html} +@article{tsilingiris:2008a, + title = {Thermophysical and Transport Properties of Humid Air at Temperature Range between 0 and 100{$^\circ$}{{C}}}, + author = {Tsilingiris, P. T.}, + year = {2008}, + month = may, + journal = {Energy Conversion and Management}, + volume = {49}, + number = {5}, + pages = {1098--1110}, + issn = {0196-8904}, + doi = {10.1016/j.enconman.2007.09.015}, + urldate = {2023-07-04}, + abstract = {The aim of the present investigation is evaluation of the thermophysical and transport properties of moist air as a function of mixture temperature with relative humidity as a parameter, ranging between dry air and saturation conditions. Based on a literature review of the most widely available analytical procedures and methods, a number of developed correlations are presented, which are employed with recent gas mixture component properties as input parameters, to derive the temperature and humidity dependence of mixture density, viscosity, specific heat capacity, thermal conductivity, thermal diffusivity and Prandtl number under conditions corresponding to the total barometric pressure of 101.3kPa. The derived results at an accuracy level suitable for engineering calculations were plotted and compared with adequate accuracy with existing results from previous analytical calculations and measured data from earlier experimental investigations. The saturated mixture properties were also appropriately fitted, and the fitting expressions suitable for computer calculations are also presented.}, + langid = {english}, + keywords = {Density,Prandtl number,Specific heat capacity,Thermal conductivity,Thermal diffusivity,Thermophysical properties,Viscosity}, + file = {/Users/dorme/Zotero/storage/CUISZDZT/Tsilingiris - 2008 - Thermophysical and transport properties of humid a.pdf;/Users/dorme/Zotero/storage/RFS82MFU/S0196890407003329.html} } -@article{chen:2008a, - title = {The equation of state of pure water determined from sound speeds}, - volume = {66}, - issn = {0021-9606}, - url = {https://doi.org/10.1063/1.434179}, - doi = {10.1063/1.434179}, - abstract = {The equation of state of water valid over the range 0–100 °C and 0–1000 bar has been determined from the high pressure sound velocities of Wilson, which were reanalyzed by Chen and Millero. The equation of state has a maximum error of ±0.01 bar−1 in isothermal compressibility and is in the form of a secant bulk modulus: K=V0P/(V0−V) =K0+AP+BP2, where K, K0, and V, V0 are the secant bulk moduli and specific volumes at applied pressures P and 0 (1 atm), respectively; A and B are temperature dependent parameters. The good agreement (to within 20×10−6 cm3 g−1) of specific volumes calculated using the above equation with those obtained from other modifications of the Wilson sound velocity data demonstrates the reliability of the sound velocity method for determining equations of state.}, - number = {5}, - urldate = {2023-07-04}, - journal = {The Journal of Chemical Physics}, - author = {Chen, Chen‐Tung and Fine, Rana A. and Millero, Frank J.}, - month = aug, - year = {2008}, - pages = {2142--2144}, - file = {Full Text PDF:/Users/dorme/Zotero/storage/2WBI492T/Chen et al. - 2008 - The equation of state of pure water determined fro.pdf:application/pdf;Snapshot:/Users/dorme/Zotero/storage/IRHA5IDN/The-equation-of-state-of-pure-water-determined.html:text/html} +@article{voncaemmerer:2014a, + title = {Carbon Isotope Discrimination as a Tool to Explore {{C4}} Photosynthesis}, + author = {{von Caemmerer}, Susanne and Ghannoum, Oula and Pengelly, Jasper J. L. and Cousins, Asaph B.}, + year = {2014}, + month = jul, + journal = {Journal of Experimental Botany}, + volume = {65}, + number = {13}, + pages = {3459--3470}, + issn = {1460-2431, 0022-0957}, + doi = {10.1093/jxb/eru127}, + urldate = {2022-05-20}, + abstract = {Photosynthetic carbon isotope discrimination is a non-destructive tool for investigating C4 metabolism. Tuneable diode laser absorption spectroscopy provides new opportunities for making rapid, concurrent measurements of carbon isotope discrimination and CO2 assimilation over a range of environmental conditions, and this has facilitated the use of carbon isotope discrimination as a probe of C4 metabolism. In spite of the significant progress made in recent years, understanding how photosynthetic carbon isotope discrimination measured concurrently with gas exchange relates to carbon isotope composition of leaf and plant dry matter remains a challenge that requires resolution if this technique is to be successfully applied as a screening tool in crop breeding and phylogenetic research. In this review, we update our understanding of the factors and assumptions that underlie variations in photosynthetic carbon isotope discrimination in C4 leaves. Closing the main gaps in our understanding of carbon isotope discrimination during C4 photosynthesis may help advance research aimed at developing higher productivity and efficiency in key C4 food, feed, and biofuel crops.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/DBGBCVUB/Caemmerer et al. - 2014 - Carbon isotope discrimination as a tool to explore.pdf} } -@article{hengl:2017a, - title = {{SoilGrids250m}: {Global} gridded soil information based on machine learning}, - volume = {12}, - issn = {1932-6203}, - shorttitle = {{SoilGrids250m}}, - url = {https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0169748}, - doi = {10.1371/journal.pone.0169748}, - abstract = {This paper describes the technical development and accuracy assessment of the most recent and improved version of the SoilGrids system at 250m resolution (June 2016 update). SoilGrids provides global predictions for standard numeric soil properties (organic carbon, bulk density, Cation Exchange Capacity (CEC), pH, soil texture fractions and coarse fragments) at seven standard depths (0, 5, 15, 30, 60, 100 and 200 cm), in addition to predictions of depth to bedrock and distribution of soil classes based on the World Reference Base (WRB) and USDA classification systems (ca. 280 raster layers in total). Predictions were based on ca. 150,000 soil profiles used for training and a stack of 158 remote sensing-based soil covariates (primarily derived from MODIS land products, SRTM DEM derivatives, climatic images and global landform and lithology maps), which were used to fit an ensemble of machine learning methods—random forest and gradient boosting and/or multinomial logistic regression—as implemented in the R packages ranger, xgboost, nnet and caret. The results of 10–fold cross-validation show that the ensemble models explain between 56\% (coarse fragments) and 83\% (pH) of variation with an overall average of 61\%. Improvements in the relative accuracy considering the amount of variation explained, in comparison to the previous version of SoilGrids at 1 km spatial resolution, range from 60 to 230\%. Improvements can be attributed to: (1) the use of machine learning instead of linear regression, (2) to considerable investments in preparing finer resolution covariate layers and (3) to insertion of additional soil profiles. Further development of SoilGrids could include refinement of methods to incorporate input uncertainties and derivation of posterior probability distributions (per pixel), and further automation of spatial modeling so that soil maps can be generated for potentially hundreds of soil variables. Another area of future research is the development of methods for multiscale merging of SoilGrids predictions with local and/or national gridded soil products (e.g. up to 50 m spatial resolution) so that increasingly more accurate, complete and consistent global soil information can be produced. SoilGrids are available under the Open Data Base License.}, - language = {en}, - number = {2}, - urldate = {2023-07-05}, - journal = {PLOS ONE}, - author = {Hengl, Tomislav and Jesus, Jorge Mendes de and Heuvelink, Gerard B. M. and Gonzalez, Maria Ruiperez and Kilibarda, Milan and Blagotić, Aleksandar and Shangguan, Wei and Wright, Marvin N. and Geng, Xiaoyuan and Bauer-Marschallinger, Bernhard and Guevara, Mario Antonio and Vargas, Rodrigo and MacMillan, Robert A. and Batjes, Niels H. and Leenaars, Johan G. B. and Ribeiro, Eloi and Wheeler, Ichsani and Mantel, Stephan and Kempen, Bas}, - month = feb, - year = {2017}, - note = {Publisher: Public Library of Science}, - keywords = {Agricultural soil science, Forecasting, Glaciers, Machine learning, Remote sensing, Shannon index, Soil pH, Trees}, - pages = {e0169748}, - file = {Full Text PDF:/Users/dorme/Zotero/storage/VS5FRVSK/Hengl et al. - 2017 - SoilGrids250m Global gridded soil information bas.pdf:application/pdf} +@article{Walker:2014ce, + title = {The Relationship of Leaf Photosynthetic Traits - {{Vcmaxand Jmax-}} to Leaf Nitrogen, Leaf Phosphorus, and Specific Leaf Area: A Meta-Analysis and Modeling Study}, + author = {Walker, Anthony P and Beckerman, Andrew P and Gu, Lianhong and Kattge, Jens and Cernusak, Lucas A and Domingues, Tomas F and Scales, Joanna C and Wohlfahrt, Georg and Wullschleger, Stan D and Woodward, F Ian}, + year = {2014}, + month = jul, + journal = {Ecology and Evolution}, + volume = {4}, + number = {16}, + pages = {3218--3235}, + doi = {10.1002/ece3.1173}, + date-added = {2020-12-07T11:43:53GMT}, + date-modified = {2020-12-17T08:58:39GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Walker/Ecology\%20and\%20Evolution\%202014\%20Walker.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1002/ece3.1173}, + file = {/Users/dorme/Zotero/storage/N8LKZ4EP/Ecology and Evolution 2014 Walker.pdf} } -@article{davis:2017a, - title = {Simple process-led algorithms for simulating habitats ({SPLASH} v.1.0): robust indices of radiation, evapotranspiration and plant-available moisture}, - volume = {10}, - issn = {1991-959X}, - shorttitle = {Simple process-led algorithms for simulating habitats ({SPLASH} v.1.0)}, - url = {https://gmd.copernicus.org/articles/10/689/2017/}, - doi = {10.5194/gmd-10-689-2017}, - abstract = {Bioclimatic indices for use in studies of ecosystem function, species distribution, and vegetation dynamics under changing climate scenarios depend on estimates of surface fluxes and other quantities, such as radiation, evapotranspiration and soil moisture, for which direct observations are sparse. These quantities can be derived indirectly from meteorological variables, such as near-surface air temperature, precipitation and cloudiness. Here we present a consolidated set of simple process-led algorithms for simulating habitats (SPLASH) allowing robust approximations of key quantities at ecologically relevant timescales. We specify equations, derivations, simplifications, and assumptions for the estimation of daily and monthly quantities of top-of-the-atmosphere solar radiation, net surface radiation, photosynthetic photon flux density, evapotranspiration (potential, equilibrium, and actual), condensation, soil moisture, and runoff, based on analysis of their relationship to fundamental climatic drivers. The climatic drivers include a minimum of three meteorological inputs: precipitation, air temperature, and fraction of bright sunshine hours. Indices, such as the moisture index, the climatic water deficit, and the Priestley–Taylor coefficient, are also defined. The SPLASH code is transcribed in C++, FORTRAN, Python, and R. A total of 1 year of results are presented at the local and global scales to exemplify the spatiotemporal patterns of daily and monthly model outputs along with comparisons to other model results.}, - language = {English}, - number = {2}, - urldate = {2023-07-05}, - journal = {Geoscientific Model Development}, - author = {Davis, Tyler W. and Prentice, I. Colin and Stocker, Benjamin D. and Thomas, Rebecca T. and Whitley, Rhys J. and Wang, Han and Evans, Bradley J. and Gallego-Sala, Angela V. and Sykes, Martin T. and Cramer, Wolfgang}, - month = feb, - year = {2017}, - note = {Publisher: Copernicus GmbH}, - pages = {689--708}, - file = {Full Text PDF:/Users/dorme/Zotero/storage/RUZWLGHT/Davis et al. - 2017 - Simple process-led algorithms for simulating habit.pdf:application/pdf} +@article{Wang:2017go, + title = {Towards a Universal Model for Carbon Dioxide Uptake by Plants}, + author = {Wang, Han and Prentice, I. Colin and Keenan, Trevor F and Davis, Tyler W and Wright, Ian J. and Cornwell, William K and Evans, Bradley J and Peng, Changhui}, + year = {2017}, + month = sep, + journal = {Nature Plants}, + pages = {1--8}, + publisher = {Springer US}, + doi = {10.1038/s41477-017-0006-8}, + abstract = {Nature Plants, doi:10.1038/s41477-017-0006-8}, + date-added = {2020-11-30T12:27:00GMT}, + date-modified = {2021-01-28T09:14:19GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2017/Wang/Nature\%20Plants\%202017\%20Wang.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1038/s41477-017-0006-8}, + file = {/Users/dorme/Zotero/storage/D4RYI3NP/Nature Plants 2017 Wang.pdf} } -@article{berger:1978a, - title = {Long-{Term} {Variations} of {Daily} {Insolation} and {Quaternary} {Climatic} {Changes}}, - volume = {35}, - issn = {0022-4928, 1520-0469}, - url = {https://journals.ametsoc.org/view/journals/atsc/35/12/1520-0469_1978_035_2362_ltvodi_2_0_co_2.xml}, - doi = {10.1175/1520-0469(1978)035<2362:LTVODI>2.0.CO;2}, - abstract = {Abstract The first part of this note provides all trigonometrical formulas which allow the direct spectral analysis and the computation of those long-term variations of the earth’s orbital elements which are of primary interest for the computation of the insolation. The elements are the eccentricity, the longitude of the perihelion, the processional parameter and the obliquity. This new formulary is much more simple to use than the ones previously designed and still provides excellent accuracy, mainly because it takes into account the influence of the most important higher order terms in the series expansions. The second part is devoted to the computation of the daily insolation both for calendar and solar dates.}, - language = {EN}, - number = {12}, - urldate = {2023-07-13}, - journal = {Journal of the Atmospheric Sciences}, - author = {Berger, AndréL}, - month = dec, - year = {1978}, - note = {Publisher: American Meteorological Society - Section: Journal of the Atmospheric Sciences}, - pages = {2362--2367}, - file = {Full Text PDF:/Users/dorme/Zotero/storage/M9UHD7J8/Berger - 1978 - Long-Term Variations of Daily Insolation and Quate.pdf:application/pdf} +@article{Wang:2020ik, + title = {Acclimation of Leaf Respiration Consistent with Optimal Photosynthetic Capacity}, + author = {Wang, Han and Atkin, Owen K and Keenan, Trevor F and Smith, Nicholas G and Wright, Ian J. and Bloomfield, Keith J and Kattge, Jens and Reich, Peter B and Prentice, I. Colin}, + year = {2020}, + month = feb, + journal = {Global Change Biology}, + volume = {26}, + number = {4}, + pages = {2573--2583}, + doi = {10.1111/gcb.14980}, + date-added = {2020-11-30T12:23:58GMT}, + date-modified = {2021-01-22T13:54:24GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Wang/Global\%20Change\%20Biol\%202020\%20Wang.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1111/gcb.14980}, + file = {/Users/dorme/Zotero/storage/2XYW4BF4/gcb15314-sup-0004-Supinfo.pdf;/Users/dorme/Zotero/storage/RAGU56IZ/Global Change Biol 2020 Wang.pdf} +} + +@book{woolf:1968a, + title = {On the {{Computation}} of {{Solar Elevation Angles}} and the {{Determination}} of {{Sunrise}} and {{Sunset Times}}}, + author = {Woolf, Harold M.}, + year = {1968}, + publisher = {{National Aeronautics and Space Administration}}, + langid = {english} } diff --git a/docs/source/users/pmodel/pmodel_details/lue_limitation.md b/docs/source/users/pmodel/pmodel_details/lue_limitation.md index 86edacac..4a2ee005 100644 --- a/docs/source/users/pmodel/pmodel_details/lue_limitation.md +++ b/docs/source/users/pmodel/pmodel_details/lue_limitation.md @@ -7,7 +7,7 @@ jupytext: format_version: 0.13 jupytext_version: 1.16.4 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -26,7 +26,8 @@ kernelspec: from matplotlib import pyplot import numpy as np -from pyrealm.pmodel import PModel, PModelEnvironment, calc_ftemp_kphio +from pyrealm.pmodel import PModel, PModelEnvironment +from pyrealm.pmodel.quantum_yield import QuantumYieldTemperature, QuantumYieldSandoval %matplotlib inline @@ -44,9 +45,9 @@ meanalpha_2d = np.broadcast_to(meanalpha_1d, (n_pts, n_pts)) co2_2d = np.broadcast_to(co2_1d, (n_pts, n_pts)) ``` -Once key [photosynthetic parameters](photosynthetic_environment) and -[optimal chi](optimal_chi.md) have been calculated, the -{class}`~pyrealm.pmodel.pmodel.PModel` class can report estimates of: +Once key [photosynthetic parameters](photosynthetic_environment) and [optimal +chi](optimal_chi.md) have been calculated, the {class}`~pyrealm.pmodel.pmodel.PModel` +class can report estimates of: * the light use efficiency (LUE), as grams of carbon per mole of photons, and * the intrinsic water use efficiency (IWUE), as micromoles per mole of photons. @@ -59,100 +60,93 @@ $$ \text{LUE} = \phi_0 \cdot M_C \cdot m_j $$ -where $\phi_0$ is the quantum yield efficiency of photosynthesis, $M_C$ is the -molar mass of carbon and $m_j$ is the $\ce{CO2}$ limitation term of light use -efficiency from the calculation of optimal $\chi$. +where $\phi_0$ is the quantum yield efficiency of photosynthesis, $M_C$ is the molar +mass of carbon and $m_j$ is the $\ce{CO2}$ limitation term of light use efficiency from +the calculation of optimal $\chi$. However, the light use efficiency may be adjusted by +different approaches to estimation of $\phi_0$ and limitation of $J_{max}$, adding +terms for: -```{warning} - -Note that $\phi_0$ is sometimes used to refer to the quantum yield of electron -transfer, which is exactly four times larger than the quantum yield of -photosynthesis. - -``` - -However, the {class}`pyrealm.pmodel.pmodel.PModel` class also incorporates two further -factors: - -* temperature (t) dependence of $\phi_0$, -* $J_{max}$ limitation of $m_j$ by a factor $f_v$ and +* method dependent modulation of $\phi_0$ ($\phi_0^{\prime}$), and +* $J_{max}$ limitation of $m_j$ by a factor $f_v$. $$ - \text{LUE} = \phi_0(t) \cdot M_C \cdot m_j \cdot f_v + \text{LUE} = \phi_0^{\prime} \cdot M_C \cdot m_j \cdot f_v $$ -### $\phi_0$ and temperature dependency +### Quantum yield efficiency of photosynthesis -The {class}`~pyrealm.pmodel.pmodel.PModel` uses a single variable to capture the -apparent quantum yield efficiency of photosynthesis (`kphio`, $\phi_0$). The value of -$\phi_0$ shows temperature dependence, which is modelled following -{cite:t}`Bernacchi:2003dc` for C3 plants and {cite:t}`cai:2020a` for C4 plants (see -{func}`~pyrealm.pmodel.functions.calc_ftemp_kphio`). The temperature dependency is -applied by default but can be turned off using the -{class}`~pyrealm.pmodel.pmodel.PModel` argument `do_ftemp_kphio=False`. +:::{warning} -The default values of `kphio` vary with the model options, corresponding -to the empirically fitted values from {cite:t}`Stocker:2020dh`. If the temperature -dependence of $\phi_0$ is applied, $\phi_0 = 0.081785$, otherwise $\phi_0 = 0.049977$. +Note that $\phi_0$ is also sometimes used to refer to the quantum yield of electron +transfer, which is exactly four times larger than the quantum yield of photosynthesis. -The initial value of $\phi_0$ and the values used in calculations are stored in -the `init_kphio` and `kphio` attributes of the {class}`~pyrealm.pmodel.pmodel.PModel` -object. The code examples compare models with and without temperature -dependency of $\phi_0$. +::: -```{code-cell} -env = PModelEnvironment(tc=30, patm=101325, vpd=820, co2=400) -model_fixkphio = PModel(env, kphio=0.08, do_ftemp_kphio=False) -model_fixkphio.init_kphio -``` +The value of $\phi_0$ captures the conversion rate of moles photosynthetically active +photons into moles of $\ce{CO2}$. The theoretical maximum for this value is 1/9, in the +absence of a Q cycle, or 1/8 when a Q cycle is operating {cite}`long:1993a`. These +theoretical maxima are not necessarily directly used in calculating light use +efficiency: -```{code-cell} -model_fixkphio.kphio -``` +* The values of $\phi_0$ are often adjusted to include other components of light +capture. For example, {cite:t}`Stocker:2020dh` include a factor for incomplete leaf +absorptance in their estimation of $\phi_0$ and argue that $\phi_0$ should be treated as +a parameter representing canopy-scale effective quantum yield. -```{code-cell} -model_tempkphio = PModel(env, kphio=0.08, do_ftemp_kphio=True) -model_fixkphio.init_kphio -``` +* The maximum quantum yield can vary with environmental conditions, such as temperature +variation in $\phi_0$ {cite}`Bernacchi:2003dc`. -```{code-cell} -model_fixkphio.kphio -``` +For these reasons, the {class}`~pyrealm.pmodel.pmodel.PModel` provides alternative +approaches to estimating the value of $\phi{0}$, using the `method_kphio` argument. The +currently implemented approaches are described below. Note that each approach has a +specific **reference value for $\phi_{0}$**, which is used as the baseline for further +calculations. This value can be altered via the `reference_kphio` argument. + +### Temperature dependent $\phi_0$ -The scaling of temperature dependence varies for C3 and C4 plants and the function -{func}`~pyrealm.pmodel.functions.calc_ftemp_kphio` is used to calculate a limitation -factor that is applied to $\phi_0$. +The default approach (`method_kphio='temperature'`) applies a temperature dependent +estimate of $\phi_0$, following {cite:t}`Bernacchi:2003dc` for C3 plants and +{cite:t}`cai:2020a` for C4 plants. The default reference value for this approach is +$\phi_0 = 0.081785$, following the BRC parameterisation in Table 1. of +{cite:t}`Stocker:2020dh`. ```{code-cell} :tags: [hide-input] # Calculate temperature dependence of quantum yield efficiency -fkphio_c3 = calc_ftemp_kphio(tc_1d, c4=False) -fkphio_c4 = calc_ftemp_kphio(tc_1d, c4=True) +env = PModelEnvironment(tc=tc_1d, patm=101325, vpd=820, co2=400) + +fkphio_c3 = QuantumYieldTemperature(env=env, use_c4=False) +fkphio_c4 = QuantumYieldTemperature(env=env, use_c4=True) # Create a line plot of ftemp kphio -pyplot.plot(tc_1d, fkphio_c3, label="C3") -pyplot.plot(tc_1d, fkphio_c4, label="C4") +pyplot.plot(tc_1d, fkphio_c3.kphio, label="C3") +pyplot.plot(tc_1d, fkphio_c4.kphio, label="C4") pyplot.title("Temperature dependence of quantum yield efficiency") pyplot.xlabel("Temperature °C") -pyplot.ylabel("Limitation factor") +pyplot.ylabel("Quantum yield efficiency ($\phi_0$)") pyplot.legend() pyplot.show() ``` -### Setting $\phi_0$ directly +#### Fixed $\phi_0$ -In addition to fixed or temperature dependent $\phi_0$, it is also possible to provide -$\phi_0$ values for each observation in the P Model. In this case, you will need to -provide an array of values that has the same shape as the other driver variables and -these values are then used within the calculations for each observation. +This approach (`method_kphio='fixed'`) applies a fixed value of $\phi_0$ in the +calculation of light use efficiency. The default reference value used in this case is +$\phi_0 = 0.049977$, following the ORG settings parameterisation in Table 1. of +{cite:t}`Stocker:2020dh`. -This option is provided to allow users to experiment with alternative per-observation -calculations of $\phi_0$ limitation - for example, modulation of $\phi_0$ by temperature -and aridity - that are not implemented within the `PModel` or `SubdailyPModel` classes. -This approach is used in the plot below to show the simple linear scaling of LUE with -$\phi_0$ for a constant environment. +However, the fixed method will also accept $\phi_0$ values for each observation being +fitted in the PModel. This option is provided to allow users to experiment with +alternative per-observation estimation of $\phi_0$ that are not currently implemented. +You will need to provide an array of values that has the same shape as the other driver +variables and these values are then used within the calculations for each observation. + +In the code and plot below, this approach is used to provide a simple linear series of +$\phi_0$ values to an otherwise constant environment. As you would expect given +$\text{LUE} = \phi_0 \cdot M_C \cdot m_j$, light use efficiency changes linearly along +this gradient of $\phi_0$ values. ```{code-cell} :tags: [hide-input] @@ -167,7 +161,7 @@ env = PModelEnvironment( vpd=np.repeat(820, n_vals), co2=np.repeat(400, n_vals), ) -model_var_kphio = PModel(env, kphio=kphio_values, do_ftemp_kphio=False) +model_var_kphio = PModel(env, method_kphio="fixed", reference_kphio=kphio_values) # Create a line plot of ftemp kphio pyplot.plot(kphio_values, model_var_kphio.lue) @@ -177,6 +171,93 @@ pyplot.ylabel("LUE") pyplot.show() ``` +#### Temperature and aridity effects on $\phi_0$ + +The option `method_kphio='sandoval'` implements an experimental calculation +{cite}`sandoval:in_prep` of $\phi_0$ as a function of a local aridity index (P/PET), the +mean growth temperature and the air temperature {cite}`sandoval:in_prep`. This approach +uses the theoretical maximum value of $\phi_0 = 1/9$ as the reference value. You will +need to provide the aridity index and mean growing temperature for observations when +creating the `PModelEnvironment`. + +First, the aridity index is used to adjust the reference value ($\phi_{0R}$) using a +double exponential function to calculate a new maximum value given the climatological +aridity ($\phi_{0A}$): + +$\phi_{0A} = \dfrac{\phi_{0R}}{(1 + \textrm{AI}^m) ^ n}$ + +This captures a decrease in maximum $\phi_0$ in arid conditions, as shown below. + +```{code-cell} +n_vals = 51 +aridity_index = np.logspace(-2, 1.5, num=n_vals) + +env = PModelEnvironment( + tc=np.repeat(20, n_vals), + patm=np.repeat(101325, n_vals), + vpd=np.repeat(820, n_vals), + co2=np.repeat(400, n_vals), + aridity_index=aridity_index, + mean_growth_temperature=np.repeat(20, n_vals), +) + +sandoval_kphio = QuantumYieldSandoval(env) + +fig, ax = pyplot.subplots(1, 1) +ax.plot(aridity_index, sandoval_kphio.kphio) +ax.set_title("Change in $\phi_0$ with aridity index (P/PET).") +ax.set_ylabel("$\phi_0$") +ax.set_xlabel("Aridity Index") +ax.set_xscale("log") +pyplot.show() +``` + +In addition to capping the peak $\phi_0$ as a function of the aridity index, this +approach also alters the temperature at which $\phi_0$ is maximised as a function of the +mean growth temperature ($T_g$) in a location. The plot below shows how aridity and mean +growth temperature interact to change the location and height of the peak $\phi_0$. + +```{code-cell} +n_vals = 51 +mean_growth_values = np.array([10, 22, 24, 25]) +aridity_values = np.array([1.0, 1.5, 5.0]) +tc_values = np.linspace(0, 40, n_vals) + +shape = (n_vals, len(aridity_values), len(mean_growth_values)) + +ai3, tc3, mg3 = np.meshgrid(aridity_values, tc_values, mean_growth_values) + + +env = PModelEnvironment( + tc=tc3, + patm=np.full(shape, 101325), + vpd=np.full(shape, 820), + co2=np.full(shape, 400), + aridity_index=ai3, + mean_growth_temperature=mg3, +) + +sandoval_kphio = QuantumYieldSandoval(env) + +fig, axes = pyplot.subplots(ncols=3, nrows=1, sharey=True, figsize=(10, 6)) + +for ai_idx, (ax, ai_val) in enumerate(zip(axes, aridity_values)): + + for mg_idx, mg_val in enumerate(mean_growth_values): + ax.plot( + env.tc[:, ai_idx, mg_idx], + sandoval_kphio.kphio[:, ai_idx, mg_idx], + label=f"$T_{{g}}$ = {mg_val}", + ) + ax.set_title(f"AI = {ai_val}") + ax.set_ylabel("$\phi_0$") + ax.set_xlabel("Observed temperature") + + +ax.legend(frameon=False) +pyplot.show() +``` + ### Limitation of electron transfer rate ($J_{max}$) and carboxylation capacity ($V_{cmax}$) The {class}`~pyrealm.pmodel.pmodel.PModel` implements three alternative approaches to @@ -195,33 +276,31 @@ options for this setting are: and $V_{cmax}$ described in {cite:t}`Smith:2019dv`. The calculation details can be seen in the {meth}`~pyrealm.pmodel.jmax_limitation.JmaxLimitation.smith19` method. -```{code-cell} -model_jmax_simple = PModel(env, kphio=0.08, method_jmaxlim="simple") -model_jmax_wang17 = PModel(env, kphio=0.08, method_jmaxlim="wang17") -model_jmax_smith19 = PModel(env, kphio=0.08, method_jmaxlim="smith19") - -# Compare LUE from the three methods -np.array([model_jmax_simple.lue, model_jmax_wang17.lue, model_jmax_smith19.lue]) -``` ++++ The plot below shows the effects of each method on the LUE across a temperature -gradient ($P=101325.0 , \ce{CO2}= 400 \text{ppm}, \text{VPD}=820$) and $\phi_0=0.05$). +gradient ($P=101325.0 , \ce{CO2}= 400 \text{ppm}, \text{VPD}=820$) and fixed $\phi_0=0.08$. ```{code-cell} :tags: [hide-input] # Calculate variation in m_jlim with temperature env = PModelEnvironment(tc=tc_1d, patm=101325, vpd=820, co2=400) -model_tc_wang17 = PModel(env, kphio=0.08, do_ftemp_kphio=False) -model_tc_simple = PModel(env, kphio=0.08, do_ftemp_kphio=False, method_jmaxlim="simple") -model_tc_smith19 = PModel( - env, kphio=0.08, do_ftemp_kphio=False, method_jmaxlim="smith19" + +model_jmax_simple = PModel( + env, method_jmaxlim="simple", method_kphio="fixed", reference_kphio=0.08 +) +model_jmax_wang17 = PModel( + env, method_jmaxlim="wang17", method_kphio="fixed", reference_kphio=0.08 +) +model_jmax_smith19 = PModel( + env, method_jmaxlim="smith19", method_kphio="fixed", reference_kphio=0.08 ) # Create a line plot of the resulting values of m_j -pyplot.plot(tc_1d, model_tc_simple.lue, label="simple") -pyplot.plot(tc_1d, model_tc_wang17.lue, label="wang17") -pyplot.plot(tc_1d, model_tc_smith19.lue, label="smith19") +pyplot.plot(tc_1d, model_jmax_simple.lue, label="simple") +pyplot.plot(tc_1d, model_jmax_wang17.lue, label="wang17") +pyplot.plot(tc_1d, model_jmax_smith19.lue, label="smith19") pyplot.title("Effects of J_max limitation") pyplot.xlabel("Temperature °C") @@ -229,3 +308,7 @@ pyplot.ylabel("Light Use Efficiency (g C mol-1)") pyplot.legend() pyplot.show() ``` + +```{code-cell} + +``` diff --git a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md index ef50e665..6963ef28 100644 --- a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md +++ b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md @@ -26,16 +26,16 @@ reference documentation](../../../api/pmodel_api) ## Overview -The P Model is a model of carbon capture and water use by plants. Four forcing variables -are used to define the environment that the plant experiences: +The P Model is a model of carbon capture and water use by plants. Four core forcing +variables are used to define the environment that the plant experiences: * temperature (`tc`, °C), * vapor pressure deficit (`vpd`, Pa), * atmospheric $\ce{CO2}$ concentration (`co2`, ppm), and * atmospheric pressure (`patm`, Pa). -From these inputs, the model breaks down into four broad stages, each of which is -described in more detail in the link for each stage +From these inputs, the model breaks down into the following broad stages, each of which +is described in more detail in the link for each stage The main steps are: @@ -43,22 +43,21 @@ The main steps are: environmental variables are used to calculate four key variables describing the photosynthetic environment of a plant. -* Calculation of [leaf $\ce{CO2}$ variables](../pmodel_details/optimal_chi). The photosynthetic - environment is then used to calculate the optimal ratio of internal to external CO2 - concentration ($chi$), along with $\ce{CO2}$ partial pressures and limitation factors. - This step also governs the main differences between C3 and C4 photosynthesis. +* Calculation of [leaf $\ce{CO2}$ variables](../pmodel_details/optimal_chi). The + photosynthetic environment is then used to calculate the optimal ratio of internal to + external CO2 concentration ($chi$), along with $\ce{CO2}$ partial pressures and + limitation factors. This step also governs the main differences between C3 and C4 + photosynthesis. -* Constraints on [light use efficiency (LUE)](lue_limitation). The calculation of light - use efficiency can be subjected to a number of constraints: +* Determination of the temperature sensitivity of the [quantum yield + efficiency](quantum_yield) of photosynthesis (`kphio`, $\phi_0$). - * Theoretical limitations to the maximum rates of Rubsico regeneration - ($J_{max}$) and maximum carboxylation capacity ($V_{cmax}$) +* Theoretical limitations to the maximum rates of Rubsico regeneration $J_{max}$) and + maximum carboxylation capacity ($V_{cmax}$) that can act as further constraints on + [light use efficiency (LUE)](lue_limitation). - * Temperature sensitivity of the quantum yield efficiency of photosynthesis - (`kphio`, $\phi_0$). - - * Different approaches to incorporating effects of [soil moisture - stress](soil_moisture) on productivity. +* Different approaches to incorporating effects of [soil moisture stress](soil_moisture) + on productivity. * Estimation of [gross primary productivity](estimating-productivity). Once LUE has been calculated, estimates of absorbed photosynthetically active radiation, can be used to diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index 357ec350..a3f3a6c6 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -235,6 +235,17 @@ class QuantumYieldSandoval( 1/9 in the absence of a Q cycle (Long, 1993). """ + def peak_quantum_yield(self, aridity: NDArray) -> NDArray: + """Calculate the peak quantum yield as a function of the aridity index. + + Args: + aridity: An array of aridity index values. + """ + + # Calculate peak kphio given the aridity index + m, n = self.env.pmodel_const.sandoval_peak_phio + return self.reference_kphio / (1 + (self.env.aridity_index) ** m) ** n + def _calculate_kphio(self) -> None: """Calculate kphio.""" @@ -258,8 +269,7 @@ def _calculate_kphio(self) -> None: Topt = Hd / (deltaS - self.env.core_const.k_R * np.log(Ha / (Hd - Ha))) # Calculate peak kphio given the aridity index - m, n = self.env.pmodel_const.sandoval_peak_phio - kphio_peak = self.reference_kphio / (1 + (self.env.aridity_index) ** m) ** n + kphio_peak = self.peak_quantum_yield(aridity=self.env.aridity_index) # Calculate the modified Arrhenius factor using the f_kphio = calc_modified_arrhenius_factor( From 2246a613781efb62988b3cffe580a98e8616a783 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 7 Aug 2024 11:37:16 +0100 Subject: [PATCH 041/241] P model user docs update --- .../pmodel/pmodel_details/jmax_limitation.md | 79 +++++++++++++ .../pmodel/pmodel_details/pmodel_overview.md | 107 ++++++++++++------ .../{lue_limitation.md => quantum_yield.md} | 98 ++-------------- pyproject.toml | 6 + 4 files changed, 168 insertions(+), 122 deletions(-) create mode 100644 docs/source/users/pmodel/pmodel_details/jmax_limitation.md rename docs/source/users/pmodel/pmodel_details/{lue_limitation.md => quantum_yield.md} (71%) diff --git a/docs/source/users/pmodel/pmodel_details/jmax_limitation.md b/docs/source/users/pmodel/pmodel_details/jmax_limitation.md new file mode 100644 index 00000000..5e07802f --- /dev/null +++ b/docs/source/users/pmodel/pmodel_details/jmax_limitation.md @@ -0,0 +1,79 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# $J_{max}$ limitation + +```{code-cell} +:tags: [hide-input] + +from matplotlib import pyplot +import numpy as np +from pyrealm.pmodel import PModel, PModelEnvironment + +%matplotlib inline + +# Set the resolution of examples +n_pts = 201 + +# Create a range of representative values for key inputs. +tc_1d = np.linspace(-25, 50, n_pts) +``` + +Environmental conditions can also lead to limitation of both the electron transfer rate +and the carboxylation capacity ($V_{cmax}$) of leaves. The +{class}`~pyrealm.pmodel.pmodel.PModel` implements three alternative approaches to the +calculation of $J_{max}$ and $V_{cmax}$, using the argument `method_jmaxlim`. These +options set the calculation of two factor ($f_j$ and $f_v$) which are applied to the +calculation of $J_{max}$ and $V_{cmax}$. The options for this setting are: + +* `simple`: This approach implements the 'simple' formulations of the P Model, with no + limitations and hence $f_j = f_v = 1$. +* `wang17`: This is the default setting for `method_jmaxlim` and applies the + calculations describe in {cite:t}`Wang:2017go`. The calculation details can be + seen in the {meth}`~pyrealm.pmodel.jmax_limitation.JmaxLimitation.wang17` method. + +* `smith19`: This is an alternate calculation for optimal values of $J_{max}$ + and $V_{cmax}$ described in {cite:t}`Smith:2019dv`. The calculation details can be + seen in the {meth}`~pyrealm.pmodel.jmax_limitation.JmaxLimitation.smith19` method. + +The plot below shows the effects of each method on the light use efficienct across a +temperature gradient. The other forcing variables are fixed ($P=101325.0 , \ce{CO2}= 400 +\text{ppm}, \text{VPD}=820$) and $\phi_0$ is also fixed ($\phi_0=0.08$). + +```{code-cell} +:tags: [hide-input] + +# Calculate variation in m_jlim with temperature +env = PModelEnvironment(tc=tc_1d, patm=101325, vpd=820, co2=400) + +model_jmax_simple = PModel( + env, method_jmaxlim="simple", method_kphio="fixed", reference_kphio=0.08 +) +model_jmax_wang17 = PModel( + env, method_jmaxlim="wang17", method_kphio="fixed", reference_kphio=0.08 +) +model_jmax_smith19 = PModel( + env, method_jmaxlim="smith19", method_kphio="fixed", reference_kphio=0.08 +) + +# Create a line plot of the resulting values of m_j +pyplot.plot(tc_1d, model_jmax_simple.lue, label="simple") +pyplot.plot(tc_1d, model_jmax_wang17.lue, label="wang17") +pyplot.plot(tc_1d, model_jmax_smith19.lue, label="smith19") + +pyplot.title("Effects of J_max limitation") +pyplot.xlabel("Temperature °C") +pyplot.ylabel("Light Use Efficiency (g C mol-1)") +pyplot.legend() +pyplot.show() +``` diff --git a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md index 6963ef28..5bf8192f 100644 --- a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md +++ b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md @@ -5,9 +5,8 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -26,42 +25,86 @@ reference documentation](../../../api/pmodel_api) ## Overview -The P Model is a model of carbon capture and water use by plants. Four core forcing -variables are used to define the environment that the plant experiences: +The P Model is a model of carbon capture and water use by plants. There are four core +forcing variables that define the photosynthetic environment of the plant, although +extensions of the basic P model may add other required variables such as aridity or soil +moisture content. The four core variables are: * temperature (`tc`, °C), * vapor pressure deficit (`vpd`, Pa), * atmospheric $\ce{CO2}$ concentration (`co2`, ppm), and * atmospheric pressure (`patm`, Pa). -From these inputs, the model breaks down into the following broad stages, each of which -is described in more detail in the link for each stage - -The main steps are: - -* Calculation of the [photosynthetic environment](photosynthetic_environment). The - environmental variables are used to calculate four key variables describing the - photosynthetic environment of a plant. - -* Calculation of [leaf $\ce{CO2}$ variables](../pmodel_details/optimal_chi). The - photosynthetic environment is then used to calculate the optimal ratio of internal to - external CO2 concentration ($chi$), along with $\ce{CO2}$ partial pressures and - limitation factors. This step also governs the main differences between C3 and C4 - photosynthesis. - -* Determination of the temperature sensitivity of the [quantum yield - efficiency](quantum_yield) of photosynthesis (`kphio`, $\phi_0$). - -* Theoretical limitations to the maximum rates of Rubsico regeneration $J_{max}$) and - maximum carboxylation capacity ($V_{cmax}$) that can act as further constraints on - [light use efficiency (LUE)](lue_limitation). - -* Different approaches to incorporating effects of [soil moisture stress](soil_moisture) - on productivity. - -* Estimation of [gross primary productivity](estimating-productivity). Once LUE has been - calculated, estimates of absorbed photosynthetically active radiation, can be used to - predict gross primary productivity (GPP) and other key rates within the leaf. +Those forcing variables are then used to calculate four further variables that capture +the [photosynthetic environment](photosynthetic_environment) of a leaf. These are the: + +1. photorespiratory compensation point ($\Gamma^*$), +2. Michaelis-Menten coefficient for photosynthesis ($K_{mm}$), +3. relative viscosity of water, given a standard at 25°C ($\eta^*$), and +4. partial pressure of $\ce{CO2}$ in ambient air ($c_a$). + +A P Model can then be fitted to calculate the expected optimal light use efficiency +given the environment. The basic calculation captures how many moles of carbon can be +captured for each mole of photosynthetically active photons captured by the leaf. In its +simplest form, this equation is: + +$$ + \text{LUE} = M_C \cdot \phi_0 \cdot m_j, +$$ + +where $M_C$ is the molar mass of carbon and $\phi_0$ (the quantum yield efficiency of +photosynthesis) captures how many moles of photons are required to capture one mole of +carbon dioxide. + +The term $m_j$ is at the heart of the P model and describes the trade off between +[carbon dioxide capture and water loss in photosynthesis](optimal_chi). Given the +environmental conditions, a leaf will adjust its stomata, setting a ratio of internal to +external carbon dioxide partial pressure ($\chi$) that optimises this trade off. Under +adverse conditions, this limits the partial pressure of carbon dioxide within the leaf +($c_i = c_a \chi$) and gives rise to the limitation term $m_j$ that describes the +resulting loss in light use efficiency. This calculation also allows the P model to +estimate the intrinsic water use efficiency of photosynthesis (IWUE) as micromoles per +mole of photons. + +There are several methods for the calculation of $\chi$ and $m_j$, which are selected +using the `method_optchi` argument when fitting a P model. These methods specify the +choice of C3 and C4 photosynthetic pathways but also environmental modification of +optimal $\chi$. + +The P model can optionally include further limitations to the light use efficiency of +photosynthesis. The extended equation shows two modifications: + +$$ + \text{LUE} = M_C \cdot \phi_0(E) \cdot m_j \cdot f_J +$$ + +* The function $\phi_0(E)$ captures methods that introduce environmental modulation of + the [quantum yield efficiency of photosynthesis](quantum_yield), such as variation in + $\phi_0$ with air temperature. These methods are selected using the `method_kphio` + argument when fitting a P model. + +* The additional term $f_j$ describes further [limitation of the electron transfer + rate](jmax_limitation) of photosynthesis ($J_{max}$ limitation). These methods are + selected using the `method_jmaxlim` argument when fitting a P model. + +:::{warning} + +Several of the approaches implemented within the P model in `pyrealm` may be estimating +the same underlying environmental limitation of light use efficiency via different +pathways. As an example, there are multiple approaches to incorporating effects of [soil +moisture stress](soil_moisture) on productivity, via modulation of $\phi_0$, $m_j$ and +the calculation of GPP penalty factors. + +Some combinations of methods may therefore result in multiple corrections for the same +limitation. At present, `pyrealm` does not automatically detect such over-correction, so +take care when selecting methods for fitting the P model. + +::: + +As a final stage, once the LUE has been calculated, then estimates of the actual +absorbed irradiance for a section of canopy (µmols of photons per m2 per second) can +then be used to estimate [gross primary productivity](estimating-productivity) (GPP) and +other key rates within the leaf. ## Variable graph diff --git a/docs/source/users/pmodel/pmodel_details/lue_limitation.md b/docs/source/users/pmodel/pmodel_details/quantum_yield.md similarity index 71% rename from docs/source/users/pmodel/pmodel_details/lue_limitation.md rename to docs/source/users/pmodel/pmodel_details/quantum_yield.md index 4a2ee005..92a3ae8c 100644 --- a/docs/source/users/pmodel/pmodel_details/lue_limitation.md +++ b/docs/source/users/pmodel/pmodel_details/quantum_yield.md @@ -5,14 +5,13 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 --- -# LUE Limitation +# Quantum yield efficiency of photosynthesis ```{code-cell} :tags: [hide-input] @@ -45,36 +44,6 @@ meanalpha_2d = np.broadcast_to(meanalpha_1d, (n_pts, n_pts)) co2_2d = np.broadcast_to(co2_1d, (n_pts, n_pts)) ``` -Once key [photosynthetic parameters](photosynthetic_environment) and [optimal -chi](optimal_chi.md) have been calculated, the {class}`~pyrealm.pmodel.pmodel.PModel` -class can report estimates of: - -* the light use efficiency (LUE), as grams of carbon per mole of photons, and -* the intrinsic water use efficiency (IWUE), as micromoles per mole of photons. - -## Light use efficiency - -In its simplest form: - -$$ - \text{LUE} = \phi_0 \cdot M_C \cdot m_j -$$ - -where $\phi_0$ is the quantum yield efficiency of photosynthesis, $M_C$ is the molar -mass of carbon and $m_j$ is the $\ce{CO2}$ limitation term of light use efficiency from -the calculation of optimal $\chi$. However, the light use efficiency may be adjusted by -different approaches to estimation of $\phi_0$ and limitation of $J_{max}$, adding -terms for: - -* method dependent modulation of $\phi_0$ ($\phi_0^{\prime}$), and -* $J_{max}$ limitation of $m_j$ by a factor $f_v$. - -$$ - \text{LUE} = \phi_0^{\prime} \cdot M_C \cdot m_j \cdot f_v -$$ - -### Quantum yield efficiency of photosynthesis - :::{warning} Note that $\phi_0$ is also sometimes used to refer to the quantum yield of electron @@ -102,7 +71,7 @@ currently implemented approaches are described below. Note that each approach ha specific **reference value for $\phi_{0}$**, which is used as the baseline for further calculations. This value can be altered via the `reference_kphio` argument. -### Temperature dependent $\phi_0$ +## Temperature dependent $\phi_0$ The default approach (`method_kphio='temperature'`) applies a temperature dependent estimate of $\phi_0$, following {cite:t}`Bernacchi:2003dc` for C3 plants and @@ -130,7 +99,7 @@ pyplot.legend() pyplot.show() ``` -#### Fixed $\phi_0$ +## Fixed $\phi_0$ This approach (`method_kphio='fixed'`) applies a fixed value of $\phi_0$ in the calculation of light use efficiency. The default reference value used in this case is @@ -171,7 +140,7 @@ pyplot.ylabel("LUE") pyplot.show() ``` -#### Temperature and aridity effects on $\phi_0$ +## Temperature and aridity effects on $\phi_0$ The option `method_kphio='sandoval'` implements an experimental calculation {cite}`sandoval:in_prep` of $\phi_0$ as a function of a local aridity index (P/PET), the @@ -189,6 +158,8 @@ $\phi_{0A} = \dfrac{\phi_{0R}}{(1 + \textrm{AI}^m) ^ n}$ This captures a decrease in maximum $\phi_0$ in arid conditions, as shown below. ```{code-cell} +:tags: [hide-input] + n_vals = 51 aridity_index = np.logspace(-2, 1.5, num=n_vals) @@ -218,6 +189,8 @@ mean growth temperature ($T_g$) in a location. The plot below shows how aridity growth temperature interact to change the location and height of the peak $\phi_0$. ```{code-cell} +:tags: [hide-input] + n_vals = 51 mean_growth_values = np.array([10, 22, 24, 25]) aridity_values = np.array([1.0, 1.5, 5.0]) @@ -257,58 +230,3 @@ for ai_idx, (ax, ai_val) in enumerate(zip(axes, aridity_values)): ax.legend(frameon=False) pyplot.show() ``` - -### Limitation of electron transfer rate ($J_{max}$) and carboxylation capacity ($V_{cmax}$) - -The {class}`~pyrealm.pmodel.pmodel.PModel` implements three alternative approaches to -the calculation of $J_{max}$ and $V_{cmax}$, using the argument -`method_jmaxlim`. These options set the calculation of two factor ($f_j$ and -$f_v$) which are applied to the calculation of $J_{max}$ and $V_{cmax}$. The -options for this setting are: - -* `simple`: These are the 'simple' formulations of the P Model, with $f_j = f_v - = 1$. -* `wang17`: This is the default setting for `method_jmaxlim` and applies the - calculations describe in {cite:t}`Wang:2017go`. The calculation details can be - seen in the {meth}`~pyrealm.pmodel.jmax_limitation.JmaxLimitation.wang17` method. - -* `smith19`: This is an alternate calculation for optimal values of $J_{max}$ - and $V_{cmax}$ described in {cite:t}`Smith:2019dv`. The calculation details can be - seen in the {meth}`~pyrealm.pmodel.jmax_limitation.JmaxLimitation.smith19` method. - -+++ - -The plot below shows the effects of each method on the LUE across a temperature -gradient ($P=101325.0 , \ce{CO2}= 400 \text{ppm}, \text{VPD}=820$) and fixed $\phi_0=0.08$. - -```{code-cell} -:tags: [hide-input] - -# Calculate variation in m_jlim with temperature -env = PModelEnvironment(tc=tc_1d, patm=101325, vpd=820, co2=400) - -model_jmax_simple = PModel( - env, method_jmaxlim="simple", method_kphio="fixed", reference_kphio=0.08 -) -model_jmax_wang17 = PModel( - env, method_jmaxlim="wang17", method_kphio="fixed", reference_kphio=0.08 -) -model_jmax_smith19 = PModel( - env, method_jmaxlim="smith19", method_kphio="fixed", reference_kphio=0.08 -) - -# Create a line plot of the resulting values of m_j -pyplot.plot(tc_1d, model_jmax_simple.lue, label="simple") -pyplot.plot(tc_1d, model_jmax_wang17.lue, label="wang17") -pyplot.plot(tc_1d, model_jmax_smith19.lue, label="smith19") - -pyplot.title("Effects of J_max limitation") -pyplot.xlabel("Temperature °C") -pyplot.ylabel("Light Use Efficiency (g C mol-1)") -pyplot.legend() -pyplot.show() -``` - -```{code-cell} - -``` diff --git a/pyproject.toml b/pyproject.toml index 772a40c7..7110af96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -140,3 +140,9 @@ ignore = [ [tool.ruff.lint.pydocstyle] convention = "google" + +[tool.jupytext] +# Stop jupytext from removing mystnb and other settings in MyST Notebook YAML headers +notebook_metadata_filter = "-jupytext.text_representation.jupytext_version,settings,mystnb" +# Also stop it from stripping cell metadata. +cell_metadata_filter = "all" \ No newline at end of file From 3239cb4a48046363367c34d75bbdf73bb8c86188 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 7 Aug 2024 12:30:13 +0100 Subject: [PATCH 042/241] Fixing issue with typed but not populated attributes in summarise --- pyrealm/pmodel/pmodel_environment.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/pyrealm/pmodel/pmodel_environment.py b/pyrealm/pmodel/pmodel_environment.py index 14ff2f9b..34722c4c 100644 --- a/pyrealm/pmodel/pmodel_environment.py +++ b/pyrealm/pmodel/pmodel_environment.py @@ -211,7 +211,17 @@ def summarize(self, dp: int = 2) -> None: ("ns_star", "-"), ] - if self.theta is not None: - attrs += [("theta", "m3/m3")] + # Add any optional variables - need to check here if these attributes actually + # exist because if they are not provided they are typed but not populated. + optional_vars = [ + ("theta", "m3/m3"), + ("rootzonestress", "-"), + ("aridity_index", "-"), + ("mean_growth_temperature", "°C"), + ] + + for opt_var, unit in optional_vars: + if getattr(self, opt_var, None) is not None: + attrs += [(opt_var, unit)] summarize_attrs(self, attrs, dp=dp) From ed5ad067092144fe5fe6b7db688a5a5436873a04 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 7 Aug 2024 12:46:06 +0100 Subject: [PATCH 043/241] Doc fixing and notebook updates --- docs/source/_toc.yml | 3 +- docs/source/api/pmodel_api.md | 9 ++++- docs/source/refs.bib | 8 ++++ docs/source/users/pmodel/module_overview.md | 8 ++-- .../pmodel/pmodel_details/pmodel_overview.md | 8 ++-- .../pmodel/pmodel_details/worked_examples.md | 27 +++++++++++++- .../subdaily_details/subdaily_calculations.md | 3 +- .../pmodel/subdaily_details/worked_example.md | 37 ++++++++++++++++--- pyrealm/pmodel/pmodel.py | 2 - 9 files changed, 84 insertions(+), 21 deletions(-) diff --git a/docs/source/_toc.yml b/docs/source/_toc.yml index 51ceec9f..1c587e0e 100644 --- a/docs/source/_toc.yml +++ b/docs/source/_toc.yml @@ -12,7 +12,8 @@ subtrees: - file: users/pmodel/pmodel_details/worked_examples.md - file: users/pmodel/pmodel_details/photosynthetic_environment.md - file: users/pmodel/pmodel_details/optimal_chi.md - - file: users/pmodel/pmodel_details/lue_limitation.md + - file: users/pmodel/pmodel_details/quantum_yield.md + - file: users/pmodel/pmodel_details/jmax_limitation.md - file: users/pmodel/pmodel_details/envt_variation_outputs.md - file: users/pmodel/pmodel_details/soil_moisture.md - file: users/pmodel/pmodel_details/extreme_values.md diff --git a/docs/source/api/pmodel_api.md b/docs/source/api/pmodel_api.md index ca593ae4..9bb4f669 100644 --- a/docs/source/api/pmodel_api.md +++ b/docs/source/api/pmodel_api.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python @@ -50,6 +49,14 @@ kernelspec: :members: ``` +## The {mod}`~pyrealm.pmodel.quantum_yield` submodule + +```{eval-rst} +.. automodule:: pyrealm.pmodel.quantum_yield + :autosummary: + :members: +``` + ## The {mod}`~pyrealm.pmodel.functions` submodule ```{eval-rst} diff --git a/docs/source/refs.bib b/docs/source/refs.bib index 75945668..f7dc458b 100644 --- a/docs/source/refs.bib +++ b/docs/source/refs.bib @@ -705,6 +705,14 @@ @article{Prentice:2014bc file = {/Users/dorme/Zotero/storage/MDRBDVTF/Ecol Lett 2014 Prentice.pdf} } +@article{sandoval:in_prep, + title = {Aridity and Growth Temperature Effects on Phio Manuscript}, + author = {Sandoval, David}, + year = {in\_prep}, + volume = {?}, + pages = {??-??} +} + @article{Smith:2019dv, title = {Global Photosynthetic Capacity Is Optimized to the Environment}, author = {Smith, Nicholas G and Keenan, Trevor F and Colin Prentice, I and Wang, Han and Wright, Ian J. and Niinemets, {\"U}lo and Crous, Kristine Y and Domingues, Tomas F and Guerrieri, Rossella and Yoko Ishida, F and Kattge, Jens and Kruger, Eric L and Maire, Vincent and Rogers, Alistair and Serbin, Shawn P and Tarvainen, Lasse and Togashi, Henrique F and Townsend, Philip A and Wang, Meng and Weerasinghe, Lasantha K and Zhou, Shuang Xi}, diff --git a/docs/source/users/pmodel/module_overview.md b/docs/source/users/pmodel/module_overview.md index 5be8782d..04c29687 100644 --- a/docs/source/users/pmodel/module_overview.md +++ b/docs/source/users/pmodel/module_overview.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python @@ -27,8 +26,11 @@ ecophysiological model of optimal carbon dioxide uptake by plants * Details of calculations of: * the [photosynthetic_environment](pmodel_details/photosynthetic_environment), * [optimal chi](pmodel_details/optimal_chi) values, - * limits on [light use efficiency](pmodel_details/lue_limitation), and - * the estimation of [gross primary productivity](pmodel_details/envt_variation_outputs.md#estimating-productivity). + * estimation of quantum yield efficiency (pmodel_details/quantum_yield), + * estimation of [electron transfer rate limitation](pmodel_details/jmax_limitation), + and + * the estimation of [gross primary + productivity](pmodel_details/envt_variation_outputs.md#estimating-productivity). * Approaches to the impacts of [soil moisture stress](pmodel_details/soil_moisture). * The behaviour of P Model equations with [extreme forcing diff --git a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md index 5bf8192f..9626ee98 100644 --- a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md +++ b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md @@ -57,7 +57,7 @@ photosynthesis) captures how many moles of photons are required to capture one m carbon dioxide. The term $m_j$ is at the heart of the P model and describes the trade off between -[carbon dioxide capture and water loss in photosynthesis](optimal_chi). Given the +[carbon dioxide capture and water loss in photosynthesis](./optimal_chi). Given the environmental conditions, a leaf will adjust its stomata, setting a ratio of internal to external carbon dioxide partial pressure ($\chi$) that optimises this trade off. Under adverse conditions, this limits the partial pressure of carbon dioxide within the leaf @@ -79,12 +79,12 @@ $$ $$ * The function $\phi_0(E)$ captures methods that introduce environmental modulation of - the [quantum yield efficiency of photosynthesis](quantum_yield), such as variation in - $\phi_0$ with air temperature. These methods are selected using the `method_kphio` + the [quantum yield efficiency of photosynthesis](./quantum_yield), such as variation + in $\phi_0$ with air temperature. These methods are selected using the `method_kphio` argument when fitting a P model. * The additional term $f_j$ describes further [limitation of the electron transfer - rate](jmax_limitation) of photosynthesis ($J_{max}$ limitation). These methods are + rate](./jmax_limitation) of photosynthesis ($J_{max}$ limitation). These methods are selected using the `method_jmaxlim` argument when fitting a P model. :::{warning} diff --git a/docs/source/users/pmodel/pmodel_details/worked_examples.md b/docs/source/users/pmodel/pmodel_details/worked_examples.md index 4fe2823a..f3db6947 100644 --- a/docs/source/users/pmodel/pmodel_details/worked_examples.md +++ b/docs/source/users/pmodel/pmodel_details/worked_examples.md @@ -5,9 +5,8 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -40,6 +39,8 @@ The example shows the steps required using a single site with: ### Estimate photosynthetic environment ```{code-cell} +:trusted: true + from importlib import resources from matplotlib import pyplot as plt @@ -60,10 +61,14 @@ terse - just the shape of the data - but the more detailed summary of the attributes. ```{code-cell} +:trusted: true + env ``` ```{code-cell} +:trusted: true + env.summarize() ``` @@ -73,6 +78,8 @@ Next, the P Model can be fitted to the photosynthetic environment using the ({class}`~pyrealm.pmodel.pmodel.PModel`) class: ```{code-cell} +:trusted: true + model = PModel(env) ``` @@ -80,6 +87,8 @@ The returned model object holds a lot of information. The representation of the model object shows a terse display of the settings used to run the model: ```{code-cell} +:trusted: true + model ``` @@ -90,6 +99,8 @@ photosynthetic efficiency: the intrinsic water use efficiency (``iwue``) and the use efficiency (``lue``). ```{code-cell} +:trusted: true + model.summarize() ``` @@ -102,6 +113,8 @@ This object also has a {meth}`~pyrealm.pmodel.optimal_chi.OptimalChiABC.summariz method: ```{code-cell} +:trusted: true + model.optchi.summarize() ``` @@ -118,6 +131,8 @@ Here we are using: * a PPFD of 834 µmol m-2 s-1. ```{code-cell} +:trusted: true + model.estimate_productivity(fapar=0.91, ppfd=834) model.summarize() ``` @@ -150,6 +165,8 @@ to be the same size so some of the variables have repeated data across dimension * Elevation is constant across months, so the data for each month is repeated. ```{code-cell} +:trusted: true + # Load an example dataset containing the forcing variables. data_path = resources.files("pyrealm_build_data.rpmodel") / "pmodel_global.nc" ds = xarray.load_dataset(data_path) @@ -169,6 +186,8 @@ data to atmospheric pressure, and then this is used to set the photosynthetic environment for the model: ```{code-cell} +:trusted: true + # Convert elevation to atmospheric pressure patm = calc_patm(elev) @@ -187,6 +206,8 @@ That environment can then be run to calculate the P model predictions for light efficiency: ```{code-cell} +:trusted: true + # Run the P model model = PModel(env) @@ -200,6 +221,8 @@ Finally, the light use efficiency can be used to calculate GPP given the photosynthetic photon flux density and fAPAR. ```{code-cell} +:trusted: true + # Scale the outputs from values per unit iabs to realised values model.estimate_productivity(fapar, ppfd) diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md index 661fd643..21664b8b 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python @@ -78,7 +77,7 @@ subdaily_env = PModelEnvironment( ) # Fit the standard P Model -pmodel_standard = PModel(subdaily_env, kphio=1 / 8) +pmodel_standard = PModel(subdaily_env, method_kphio="fixed", reference_kphio=1 / 8) pmodel_standard.estimate_productivity(ppfd=ppfd_subdaily, fapar=fapar_subdaily) pmodel_standard.summarize() ``` diff --git a/docs/source/users/pmodel/subdaily_details/worked_example.md b/docs/source/users/pmodel/subdaily_details/worked_example.md index e53936e5..fac12b6a 100644 --- a/docs/source/users/pmodel/subdaily_details/worked_example.md +++ b/docs/source/users/pmodel/subdaily_details/worked_example.md @@ -5,9 +5,8 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -15,6 +14,8 @@ kernelspec: # Worked example of the Subdaily P Model ```{code-cell} +:trusted: true + from importlib import resources import xarray @@ -60,6 +61,8 @@ The test data use some UK WFDE data for three sites in order to compare predicti over a time series. ```{code-cell} +:trusted: true + # Loading the example dataset: dpath = ( resources.files("pyrealm_build_data.uk_data") / "UK_WFDE5_FAPAR_2018_JuneJuly.nc" @@ -81,6 +84,8 @@ The WFDE data need some conversion for use in the PModel, along with the definit the atmospheric CO2 concentration. ```{code-cell} +:trusted: true + # Variable set up # Air temperature in °C from Tair in Kelvin tc = (ds["Tair"] - 273.15).to_numpy() @@ -100,6 +105,8 @@ co2 = np.ones_like(tc) * 400 The code below then calculates the photosynthetic environment. ```{code-cell} +:trusted: true + # Generate and check the PModelEnvironment pm_env = PModelEnvironment(tc=tc, patm=patm, vpd=vpd, co2=co2) pm_env.summarize() @@ -111,14 +118,22 @@ The standard implementation of the P Model used below assumes that plants can instantaneously adopt optimal behaviour. ```{code-cell} +:trusted: true + # Standard PModels -pmodC3 = PModel(env=pm_env, kphio=1 / 8, method_optchi="prentice14") +pmodC3 = PModel( + env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="prentice14" +) pmodC3.estimate_productivity(fapar=fapar, ppfd=ppfd) pmodC3.summarize() ``` ```{code-cell} -pmodC4 = PModel(env=pm_env, kphio=1 / 8, method_optchi="c4_no_gamma") +:trusted: true + +pmodC4 = PModel( + env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="c4_no_gamma" +) pmodC4.estimate_productivity(fapar=fapar, ppfd=ppfd) pmodC4.summarize() ``` @@ -132,6 +147,8 @@ calculations: essentially the plant does not acclimate until the optimal values calculated again to update those realised estimates. ```{code-cell} +:trusted: true + # Set the acclimation window to an hour either side of noon fsscaler = SubdailyScaler(datetimes) fsscaler.set_window( @@ -142,7 +159,8 @@ fsscaler.set_window( # Fit C3 and C4 with the new implementation subdailyC3 = SubdailyPModel( env=pm_env, - kphio=1 / 8, + method_kphio="fixed", + reference_kphio=1 / 8, method_optchi="prentice14", fapar=fapar, ppfd=ppfd, @@ -152,7 +170,8 @@ subdailyC3 = SubdailyPModel( ) subdailyC4 = SubdailyPModel( env=pm_env, - kphio=1 / 8, + method_kphio="fixed", + reference_kphio=1 / 8, method_optchi="c4_no_gamma", fapar=fapar, ppfd=ppfd, @@ -169,6 +188,8 @@ shown above and plots the instantaneous predictions against predictions includin photosynthetic responses. ```{code-cell} +:trusted: true + # Store the predictions in the xarray Dataset to use indexing ds["GPP_pmodC3"] = (ds["Tair"].dims, pmodC3.gpp) ds["GPP_subdailyC3"] = (ds["Tair"].dims, subdailyC3.gpp) @@ -226,6 +247,8 @@ The subdaily models can also be obtained directly from the standard models, usin `convert_pmodel_to_subdaily` method: ```{code-cell} +:trusted: true + # Convert standard C3 model converted_C3 = convert_pmodel_to_subdaily( pmodel=pmodC3, @@ -247,6 +270,8 @@ This produces the same outputs as the `SubdailyPModel` class, but is convenient compact when the two models are going to be compared. ```{code-cell} +:trusted: true + # Models have identical GPP - maximum absolute difference is zero. print(np.nanmax(abs(subdailyC3.gpp.flatten() - converted_C3.gpp.flatten()))) print(np.nanmax(abs(subdailyC4.gpp.flatten() - converted_C4.gpp.flatten()))) diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index 8db8b81e..354a4e9f 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -137,8 +137,6 @@ class PModel: efficiency of photosynthesis (:math:`\phi_0`, -) to be passed to the kphio calculation method. - - Examples: >>> import numpy as np >>> from pyrealm.pmodel.pmodel_environment import PModelEnvironment From 40f7f67641caf0d5d3ea6b62654ae05206692a91 Mon Sep 17 00:00:00 2001 From: James Emberton Date: Thu, 20 Jun 2024 10:06:30 +0100 Subject: [PATCH 044/241] updated numpy version to 2.0.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 039f811e..ae3fd475 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ version = "0.10.1" [tool.poetry.dependencies] dacite = "^1.6.0" -numpy = "^1.16.5" +numpy = "^2.0.0" python = ">=3.10" scipy = "^1.7.3" tabulate = "^0.8.10" From 494a9ff010b777d38582fd136c49da1266fed259 Mon Sep 17 00:00:00 2001 From: James Emberton Date: Thu, 20 Jun 2024 10:10:14 +0100 Subject: [PATCH 045/241] added ruff numpy 2.0 upgrade rule --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index ae3fd475..44fafcff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -118,6 +118,7 @@ select = [ "I", # isort "UP", # pyupgrade "RUF", # RUF specific checks + "NPY201" ] # On top of the Google convention, disable: From 67e3cd57c376def45913b8f142f318dfeb93a0d9 Mon Sep 17 00:00:00 2001 From: James Emberton Date: Thu, 20 Jun 2024 10:15:14 +0100 Subject: [PATCH 046/241] fixes for numpy 2.0 compatability --- pyrealm/core/utilities.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyrealm/core/utilities.py b/pyrealm/core/utilities.py index 9fde6fa8..d59fe42d 100644 --- a/pyrealm/core/utilities.py +++ b/pyrealm/core/utilities.py @@ -212,8 +212,8 @@ def _get_interval_functions(interval_type: str = "[]") -> tuple[np.ufunc, np.ufu def bounds_checker( values: NDArray, - lower: float = -np.infty, - upper: float = np.infty, + lower: float = -np.inf, + upper: float = np.inf, interval_type: str = "[]", label: str = "", unit: str = "", @@ -256,8 +256,8 @@ def bounds_checker( def bounds_mask( inputs: NDArray, - lower: float = -np.infty, - upper: float = np.infty, + lower: float = -np.inf, + upper: float = np.inf, interval_type: str = "[]", label: str = "", ) -> NDArray[np.floating]: From 0558bbb7793d3491cd5bd64b1212bc3b943b2845 Mon Sep 17 00:00:00 2001 From: James Emberton Date: Thu, 20 Jun 2024 10:21:29 +0100 Subject: [PATCH 047/241] updated poetry.lock --- poetry.lock | 471 ++++++++++++++++++++++++++++------------------------ 1 file changed, 252 insertions(+), 219 deletions(-) diff --git a/poetry.lock b/poetry.lock index d0bacf12..7c1ca517 100644 --- a/poetry.lock +++ b/poetry.lock @@ -326,32 +326,41 @@ files = [ [[package]] name = "cftime" -version = "1.6.3" +version = "1.6.4" description = "Time-handling functionality from netcdf4-python" optional = false python-versions = ">=3.8" files = [ - {file = "cftime-1.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b62d42546fa5c914dfea5b15a9aaed2087ea1211cc36d08c374502ef95892038"}, - {file = "cftime-1.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb6dd70b2ccabfe1a14b7fbb0bbdce0418e71697094373c0d573c880790fa291"}, - {file = "cftime-1.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9878bfd8c1c3f24184ecbd528f739ba46ebaceaf1c8a24d348d7befb117a285"}, - {file = "cftime-1.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:3cf6e216a4c06f9a628cdf8e9c9d5e8097fb3eb02dd087dd14ab3b18478a7271"}, - {file = "cftime-1.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d2c01456d9d7b46aa710a41d1c711a50d5ea259aff4a987d0e973d1093bc922"}, - {file = "cftime-1.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:80eb1170ce1639016f55760847f4aadd04b0312496c5bac2797e930914bba48d"}, - {file = "cftime-1.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d87dadd0824262bdd7493babd2a44447da0a22175ded8ae9e060a3aebec7c5d7"}, - {file = "cftime-1.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:0a38eb9f5c733a23e1714bd3ef2762ed5acee34f127670f8fb4ad6464946f6b3"}, - {file = "cftime-1.6.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2d113a01ab924445e61d65c26bbd95bc08e4a22878d3b947064bba056c884c4a"}, - {file = "cftime-1.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f11685663a6af97418908060492a07663c16d42519c139ca03c2ffb1377fd25"}, - {file = "cftime-1.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a98abb1d46d118e52b0611ce668a0b714b407be26177ef0581ecf5e95f894725"}, - {file = "cftime-1.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:4d6fbd5f41b322cfa7b0ac3aaadeceb4450100a164b5bccbbb9e7c5048489a88"}, - {file = "cftime-1.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bedb577bc8b8f3f10f5336c0792e5dae88605781890f50f36b45bb46907968e8"}, - {file = "cftime-1.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:022dabf1610cdd04a693e730fa8f71d307059717f29dba921e7486e553412bb4"}, - {file = "cftime-1.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbf782ab4ac0605bdec2b941952c897595613203942b7f8c2fccd17efa5147df"}, - {file = "cftime-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:9eb177a02db7cd84aa6962278e4bd2d3106a545de82e6aacd9404f1e153661db"}, - {file = "cftime-1.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b86be8c2f254147be4ba88f12099466dde457a4a3a21de6c69d52a7224c13ae"}, - {file = "cftime-1.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:523b9a6bf03f5e36407979e248381d0fcab2d225b915bbde77d00c6dde192b90"}, - {file = "cftime-1.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a14d2c7d22fd2a6dfa6ad563283b6d6679f1df95e0ed8d14b8f284dad402887"}, - {file = "cftime-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:d9b00c2844c7a1701d8ede5336b6321dfee256ceab81a34a1aff0483d56891a6"}, - {file = "cftime-1.6.3.tar.gz", hash = "sha256:d0a6b29f72a13f08e008b9becff247cc75c84acb213332ede18879c5b6aa4dfd"}, + {file = "cftime-1.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ee70074df4bae0d9ee98f201cf5f11fd302791cf1cdeb73c34f685d6b632e17d"}, + {file = "cftime-1.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e5456fd58d4cc6b8d7b4932b749617ee142b62a52bc5d8e3c282ce69ce3a20ba"}, + {file = "cftime-1.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1289e08617be350a6b26c6e4352a0cb088625ac33d25e95110df549c26d6ab8e"}, + {file = "cftime-1.6.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b132d9225b4a109929866200846c72302316db9069e2de3ec8d8ec377f567f"}, + {file = "cftime-1.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ca1a264570e68fbb611bba251641b8efd0cf88c0ad2dcab5fa784df264232b75"}, + {file = "cftime-1.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:6fc82928cbf477bebf233f41914e64bff7b9e894c7f0c34170784a48250f8da7"}, + {file = "cftime-1.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1558d9b477bd29626cd8bfc89e736635f72887d1a993e2834ab579bba7abb8c"}, + {file = "cftime-1.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:03494e7b66a2fbb6b04e364ab67185130dee0ced660abac5c1559070571d143d"}, + {file = "cftime-1.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dcb2a01d4e614437582af33b36db4fb441b7666758482864827a1f037d2b639"}, + {file = "cftime-1.6.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b47bf25195fb3889bbae34df0e80957eb69c48f66902f5d538c7a8ec34253f6"}, + {file = "cftime-1.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d4f2cc0d5c6ffba9c5b0fd1ecd0c7c1c426d0be7b8de1480e2a9fb857c1905e9"}, + {file = "cftime-1.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:76b8f1e5d1e424accdf760a43e0a1793a7b640bab83cb067273d5c9dbb336c44"}, + {file = "cftime-1.6.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c349a91fa7ac9ec50118b04a8746bdea967bd2fc525d87c776003040b8d3392"}, + {file = "cftime-1.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:588d073400798adc24ece759cd1cb24ef730f55d1f70e31a898e7686f9d763d8"}, + {file = "cftime-1.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e07b91b488570573bbeb6f815656a8974d13d15b2279c82de2927f4f692bbcd"}, + {file = "cftime-1.6.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f92f2e405eeda47b30ab6231d8b7d136a55f21034d394f93ade322d356948654"}, + {file = "cftime-1.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:567574df94d0de1101bb5da76e7fbc6eabfddeeb2eb8cf83286b3599a136bbf7"}, + {file = "cftime-1.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:5b5ad7559a16bedadb66af8e417b6805f758acb57aa38d2730844dfc63a1e667"}, + {file = "cftime-1.6.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c072fe9e09925af66a9473edf5752ca1890ba752e7c1935d1f0245ad48f0977c"}, + {file = "cftime-1.6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c05a71389f53d6340cb365b60f028c08268c72401660b9ef76108dee9f1cb5b2"}, + {file = "cftime-1.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0edeb1cb019d8155b2513cffb96749c0d7d459370e69bdf03077e0bee214aed8"}, + {file = "cftime-1.6.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8f05d5d6bb4137f9783fa61ad330030fcea8dcc6946dea69a27774edbe480e7"}, + {file = "cftime-1.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:b32ac1278a2a111b066d5a1e6e5ce6f38c4c505993a6a3130873b56f99d7b56f"}, + {file = "cftime-1.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c20f03e12af39534c3450bba376272803bfb850b5ce6433c839bfaa99f8d835a"}, + {file = "cftime-1.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:90609b3c1a31a756a68ecdbc961a4ce0b22c1620f166c8dabfa3a4c337ac8b9e"}, + {file = "cftime-1.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbe11ad73b2a0ddc79995da21459fc2a3fd6b1593ca73f00a60e4d81c3e230f3"}, + {file = "cftime-1.6.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25f043703e785de0bd7cd8222c0a53317e9aeb3dfc062588b05e6f3ebb007468"}, + {file = "cftime-1.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f9acc272df1022f24fe7dbe9de43fa5d8271985161df14549e4d8d28c90dc9ea"}, + {file = "cftime-1.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:e8467b6fbf8dbfe0be8c04d61180765fdd3b9ab0fe51313a0bbf87e63634a3d8"}, + {file = "cftime-1.6.4.tar.gz", hash = "sha256:e325406193758a7ed67308deb52e727782a19e384e183378e7ff62098be0aedc"}, ] [package.dependencies] @@ -779,13 +788,13 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "fastjsonschema" -version = "2.19.1" +version = "2.20.0" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" files = [ - {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, - {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, + {file = "fastjsonschema-2.20.0-py3-none-any.whl", hash = "sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a"}, + {file = "fastjsonschema-2.20.0.tar.gz", hash = "sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23"}, ] [package.extras] @@ -793,18 +802,18 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "filelock" -version = "3.14.0" +version = "3.15.3" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, - {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, + {file = "filelock-3.15.3-py3-none-any.whl", hash = "sha256:0151273e5b5d6cf753a61ec83b3a9b7d8821c39ae9af9d7ecf2f9e2f17404103"}, + {file = "filelock-3.15.3.tar.gz", hash = "sha256:e1199bf5194a2277273dacd50269f0d87d0682088a3c561c15674ea9005d8635"}, ] [package.extras] docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] typing = ["typing-extensions (>=4.8)"] [[package]] @@ -1237,13 +1246,13 @@ files = [ [[package]] name = "jsonpointer" -version = "2.4" +version = "3.0.0" description = "Identify specific nodes in a JSON document (RFC 6901)" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +python-versions = ">=3.7" files = [ - {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, - {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, + {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, + {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, ] [[package]] @@ -1454,13 +1463,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.2.1" +version = "4.2.2" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.2.1-py3-none-any.whl", hash = "sha256:6ac6e3827b3c890e6e549800e8a4f4aaea6a69321e2240007902aa7a0c56a8e4"}, - {file = "jupyterlab-4.2.1.tar.gz", hash = "sha256:a10fb71085a6900820c62d43324005046402ffc8f0fde696103e37238a839507"}, + {file = "jupyterlab-4.2.2-py3-none-any.whl", hash = "sha256:59ee9b839f43308c3dfd55d72d1f1a299ed42a7f91f2d1afe9c12a783f9e525f"}, + {file = "jupyterlab-4.2.2.tar.gz", hash = "sha256:a534b6a25719a92a40d514fb133a9fe8f0d9981b0bbce5d8a5fcaa33344a3038"}, ] [package.dependencies] @@ -1474,6 +1483,7 @@ jupyter-server = ">=2.4.0,<3" jupyterlab-server = ">=2.27.1,<3" notebook-shim = ">=0.2" packaging = "*" +setuptools = ">=40.1.0" tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} tornado = ">=6.2.0" traitlets = "*" @@ -2123,38 +2133,36 @@ files = [ [[package]] name = "netcdf4" -version = "1.6.5" +version = "1.7.1" description = "Provides an object-oriented python interface to the netCDF version 4 library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "netCDF4-1.6.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d23b97cbde2bf413fadc4697c5c255a0436511c02f811e127e0fb12f5b882a4c"}, - {file = "netCDF4-1.6.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e5edfed673005f47f8d2fbea9c72c382b085dd358ac3c20ca743a563ed7b90e"}, - {file = "netCDF4-1.6.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10d2ac9ae1308ca837d86c6dc304ec455a85bdba0f2175e222844a54589168dc"}, - {file = "netCDF4-1.6.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a63a2be2f80977ac23bb0aa736c565011fd4639097ce0922e01b0dc38015df2"}, - {file = "netCDF4-1.6.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aaceea2097d292bad398d9f9b4fe403efa7b1568fcfa6faba9b67b1630027f9"}, - {file = "netCDF4-1.6.5-cp310-cp310-win_amd64.whl", hash = "sha256:111357d9e12eb79e8d58bfd91bc6b230d35b17a0ebd8c546d17416e8ceebea49"}, - {file = "netCDF4-1.6.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c5fede0b34c0a02a1b9e84116bfb3fcd2f80124a651d4836e72b785d10e2f15"}, - {file = "netCDF4-1.6.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3de5512b9270aa6472e4f3aa2bf895a7364c1d4f8667ce3b82e8232197d4fec8"}, - {file = "netCDF4-1.6.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b20971a164431f6eca1d24df8aa153db15c2c1b9630e83ccc5cf004e8ac8151d"}, - {file = "netCDF4-1.6.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad1101d538077152b866782e44458356981526bf2ea9cc07930bf28b589c82a7"}, - {file = "netCDF4-1.6.5-cp311-cp311-win_amd64.whl", hash = "sha256:de4dc973fae9e2bbdf42e094125e423a4c25393172a61958314969b055a38889"}, - {file = "netCDF4-1.6.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:19e16c63cdd7c0dbffe284a4a65f226ba1026f476f35cbedd099b4792b395f69"}, - {file = "netCDF4-1.6.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b994afce2ca4073f6b757385a6c0ffec25ecaae2b8821535b303c7cdbf6de42b"}, - {file = "netCDF4-1.6.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0187646e3348e7a8cd654617dda65517df138042c94c2fcc6682ff7c8c6654dc"}, - {file = "netCDF4-1.6.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1ab5dabac27d25fcc82c52dc29a74a6585e865208cce35f4e285df83d3df0b2"}, - {file = "netCDF4-1.6.5-cp312-cp312-win_amd64.whl", hash = "sha256:081e9043ac6160989f60570928eabe803c88ce7df1d3f79f2345dc48f68ef752"}, - {file = "netCDF4-1.6.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b47b22dda5b25ba6291f97634d7ac67b0a843f8ae5c9d9d5813c15364f66d0a"}, - {file = "netCDF4-1.6.5-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4609dd62d14798c9524327287091875449d68588c128abb768fc0c76c4a28165"}, - {file = "netCDF4-1.6.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2455e9d35fde067e6a6bdc24aa9d44962235a071cec49904d1589e298c23dcd3"}, - {file = "netCDF4-1.6.5-cp38-cp38-win_amd64.whl", hash = "sha256:2c210794d96431d92b5992e46ad8a9f97237bf6d6956f8816978a03dc0fa18c3"}, - {file = "netCDF4-1.6.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:18255b8b283d32d3900092f29c67e53aa25bd8f0dfe7adde59fe782d865a381c"}, - {file = "netCDF4-1.6.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:53050562bac84738bbd121fbbee9593d074579f5d6fdaafcb981abeb5c964225"}, - {file = "netCDF4-1.6.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:938c062382406bca9198b16adddd87c09b00521766b138cdfd11c95546eefeb8"}, - {file = "netCDF4-1.6.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a8300451d7542d3c4ff1dcccf5fb1c7d44bdd1dc08ec77dab04416caf13cb1f"}, - {file = "netCDF4-1.6.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a27db2701feef31201c9b20b04a9579196edc20dfc339ca423c7b81e462d6e14"}, - {file = "netCDF4-1.6.5-cp39-cp39-win_amd64.whl", hash = "sha256:574d7742ab321e5f9f33b5b1296c4ad4e5c469152c17d4fc453d5070e413e596"}, - {file = "netCDF4-1.6.5.tar.gz", hash = "sha256:824881d0aacfde5bd982d6adedd8574259c85553781e7b83e0ce82b890bfa0ef"}, + {file = "netCDF4-1.7.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7503bc1a7b013c7ba5d715a72826f7debf65633eace4a4280c2700b1cc001945"}, + {file = "netCDF4-1.7.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:3b345b68365ecae2c8c9c33e7d41a1a94e80ef987f40928a02e2f210d05d02b2"}, + {file = "netCDF4-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:867466bef3d109d79d35b2bbcb713565f29b2df0cb52cd19691cba65374129ac"}, + {file = "netCDF4-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73f017f4d909cea6ab1065e8199d597a9bf5cf60f91c37ae8a040c35256bc196"}, + {file = "netCDF4-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:48c56e96107ec8e2daf08cb0a9dde2b66e118de397c5f06511b31c37ef35e113"}, + {file = "netCDF4-1.7.1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:dfb92f8db5731b285546b732dfbe5870ed09b16a0453bb213a8dba83d1045935"}, + {file = "netCDF4-1.7.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:9cd8b9ab2508cc4a8d52957f84c1f34d94755c748ef6f285f756044842184852"}, + {file = "netCDF4-1.7.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b43f6569ef09fba75d2bd194fe60d286736b96329e0e50e90df4e236b272db0e"}, + {file = "netCDF4-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56af0fa24a39a14bc68cc1ab97e6d33fbaff934ba0659f740ad54bd80fbf732f"}, + {file = "netCDF4-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ce2207d836e5289f8caa66a540b222f76c242e6be565cefe8478a19bb08c206"}, + {file = "netCDF4-1.7.1-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:5724ba076ea49b63625447cd6e8d936929a2b23d3e63157c16a607e8e7505598"}, + {file = "netCDF4-1.7.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b6917f8ad44722fefb26134b540e97a9eef5ffd0b73e4564666b697f0f43ae5d"}, + {file = "netCDF4-1.7.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d407f5725daf8972ff7a4af48925a75c349158681e3f14f264616a013fe97aca"}, + {file = "netCDF4-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e26fd9a30c26d7757444410fe85d68ce8d3f64119d33feaa4daed374d1779590"}, + {file = "netCDF4-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:7258b98ebfaf7f0a3f362946d0192020d0d0284b131e7ef775e66858d3ff13ae"}, + {file = "netCDF4-1.7.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:b300b6933ab83496914c0f1731075a3a40829b9010c3f1548eece5ccb3ea629a"}, + {file = "netCDF4-1.7.1-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:c4ece6fe318f787b212e6169dee5e2c3326650dd64b1af44e2b815c6b48f2231"}, + {file = "netCDF4-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a9d8906ff7c86e1af176efbd85603088c98271cf844562a482286411289a7ec"}, + {file = "netCDF4-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f858bef2edd5dfccacd4c556eae7db55b185ba6af9b6520d8ae1ea16a72004a6"}, + {file = "netCDF4-1.7.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:225a03e1d216618d14f721c72b47a42f09e68dcc6b1509c93c784c60c630129f"}, + {file = "netCDF4-1.7.1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:85d28a26080b2a05b0786135be7b215ed0629a974895b135bd4ef2eddbb3e1ad"}, + {file = "netCDF4-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec569b56ab8714aded398b1667e1ca01489c71ed51965e9a0bd51d7c217ce352"}, + {file = "netCDF4-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7553e9cd37ef9a2382e3f8088b0f4c00e8078e76e2358c140eb882eefabe6db7"}, + {file = "netCDF4-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:6e343b7e42cd11184c2686e2899915bb1f3f1df7c9c62681590c35c088a9c66b"}, + {file = "netcdf4-1.7.1.tar.gz", hash = "sha256:87d666093870ebbc0153c8eb42a4a70d6a1d33b47fa3d8fd2e01b6d8de52023e"}, ] [package.dependencies] @@ -2195,47 +2203,56 @@ test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync" [[package]] name = "numpy" -version = "1.26.4" +version = "2.0.0" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, - {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, - {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, - {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, - {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, - {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, - {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, - {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, - {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, - {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, - {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, + {file = "numpy-2.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:04494f6ec467ccb5369d1808570ae55f6ed9b5809d7f035059000a37b8d7e86f"}, + {file = "numpy-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2635dbd200c2d6faf2ef9a0d04f0ecc6b13b3cad54f7c67c61155138835515d2"}, + {file = "numpy-2.0.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:0a43f0974d501842866cc83471bdb0116ba0dffdbaac33ec05e6afed5b615238"}, + {file = "numpy-2.0.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:8d83bb187fb647643bd56e1ae43f273c7f4dbcdf94550d7938cfc32566756514"}, + {file = "numpy-2.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79e843d186c8fb1b102bef3e2bc35ef81160ffef3194646a7fdd6a73c6b97196"}, + {file = "numpy-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7696c615765091cc5093f76fd1fa069870304beaccfd58b5dcc69e55ef49c1"}, + {file = "numpy-2.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b4c76e3d4c56f145d41b7b6751255feefae92edbc9a61e1758a98204200f30fc"}, + {file = "numpy-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd3a644e4807e73b4e1867b769fbf1ce8c5d80e7caaef0d90dcdc640dfc9787"}, + {file = "numpy-2.0.0-cp310-cp310-win32.whl", hash = "sha256:cee6cc0584f71adefe2c908856ccc98702baf95ff80092e4ca46061538a2ba98"}, + {file = "numpy-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:ed08d2703b5972ec736451b818c2eb9da80d66c3e84aed1deeb0c345fefe461b"}, + {file = "numpy-2.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad0c86f3455fbd0de6c31a3056eb822fc939f81b1618f10ff3406971893b62a5"}, + {file = "numpy-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7f387600d424f91576af20518334df3d97bc76a300a755f9a8d6e4f5cadd289"}, + {file = "numpy-2.0.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:34f003cb88b1ba38cb9a9a4a3161c1604973d7f9d5552c38bc2f04f829536609"}, + {file = "numpy-2.0.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:b6f6a8f45d0313db07d6d1d37bd0b112f887e1369758a5419c0370ba915b3871"}, + {file = "numpy-2.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f64641b42b2429f56ee08b4f427a4d2daf916ec59686061de751a55aafa22e4"}, + {file = "numpy-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7039a136017eaa92c1848152827e1424701532ca8e8967fe480fe1569dae581"}, + {file = "numpy-2.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46e161722e0f619749d1cd892167039015b2c2817296104487cd03ed4a955995"}, + {file = "numpy-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0e50842b2295ba8414c8c1d9d957083d5dfe9e16828b37de883f51fc53c4016f"}, + {file = "numpy-2.0.0-cp311-cp311-win32.whl", hash = "sha256:2ce46fd0b8a0c947ae047d222f7136fc4d55538741373107574271bc00e20e8f"}, + {file = "numpy-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbd6acc766814ea6443628f4e6751d0da6593dae29c08c0b2606164db026970c"}, + {file = "numpy-2.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:354f373279768fa5a584bac997de6a6c9bc535c482592d7a813bb0c09be6c76f"}, + {file = "numpy-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d2f62e55a4cd9c58c1d9a1c9edaedcd857a73cb6fda875bf79093f9d9086f85"}, + {file = "numpy-2.0.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:1e72728e7501a450288fc8e1f9ebc73d90cfd4671ebbd631f3e7857c39bd16f2"}, + {file = "numpy-2.0.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:84554fc53daa8f6abf8e8a66e076aff6ece62de68523d9f665f32d2fc50fd66e"}, + {file = "numpy-2.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c73aafd1afca80afecb22718f8700b40ac7cab927b8abab3c3e337d70e10e5a2"}, + {file = "numpy-2.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49d9f7d256fbc804391a7f72d4a617302b1afac1112fac19b6c6cec63fe7fe8a"}, + {file = "numpy-2.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0ec84b9ba0654f3b962802edc91424331f423dcf5d5f926676e0150789cb3d95"}, + {file = "numpy-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:feff59f27338135776f6d4e2ec7aeeac5d5f7a08a83e80869121ef8164b74af9"}, + {file = "numpy-2.0.0-cp312-cp312-win32.whl", hash = "sha256:c5a59996dc61835133b56a32ebe4ef3740ea5bc19b3983ac60cc32be5a665d54"}, + {file = "numpy-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:a356364941fb0593bb899a1076b92dfa2029f6f5b8ba88a14fd0984aaf76d0df"}, + {file = "numpy-2.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e61155fae27570692ad1d327e81c6cf27d535a5d7ef97648a17d922224b216de"}, + {file = "numpy-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4554eb96f0fd263041baf16cf0881b3f5dafae7a59b1049acb9540c4d57bc8cb"}, + {file = "numpy-2.0.0-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:903703372d46bce88b6920a0cd86c3ad82dae2dbef157b5fc01b70ea1cfc430f"}, + {file = "numpy-2.0.0-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:3e8e01233d57639b2e30966c63d36fcea099d17c53bf424d77f088b0f4babd86"}, + {file = "numpy-2.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cde1753efe513705a0c6d28f5884e22bdc30438bf0085c5c486cdaff40cd67a"}, + {file = "numpy-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821eedb7165ead9eebdb569986968b541f9908979c2da8a4967ecac4439bae3d"}, + {file = "numpy-2.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a1712c015831da583b21c5bfe15e8684137097969c6d22e8316ba66b5baabe4"}, + {file = "numpy-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9c27f0946a3536403efb0e1c28def1ae6730a72cd0d5878db38824855e3afc44"}, + {file = "numpy-2.0.0-cp39-cp39-win32.whl", hash = "sha256:63b92c512d9dbcc37f9d81b123dec99fdb318ba38c8059afc78086fe73820275"}, + {file = "numpy-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:3f6bed7f840d44c08ebdb73b1825282b801799e325bcbdfa6bc5c370e5aecc65"}, + {file = "numpy-2.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9416a5c2e92ace094e9f0082c5fd473502c91651fb896bc17690d6fc475128d6"}, + {file = "numpy-2.0.0-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:17067d097ed036636fa79f6a869ac26df7db1ba22039d962422506640314933a"}, + {file = "numpy-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ecb5b0582cd125f67a629072fed6f83562d9dd04d7e03256c9829bdec027ad"}, + {file = "numpy-2.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cef04d068f5fb0518a77857953193b6bb94809a806bd0a14983a8f12ada060c9"}, + {file = "numpy-2.0.0.tar.gz", hash = "sha256:cf5d1c9e6837f8af9f92b6bd3e86d513cdc11f60fd62185cc49ec7d1aba34864"}, ] [[package]] @@ -2251,13 +2268,13 @@ files = [ [[package]] name = "packaging" -version = "24.0" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -2542,13 +2559,13 @@ twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.46" +version = "3.0.47" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.46-py3-none-any.whl", hash = "sha256:45abe60a8300f3c618b23c16c4bb98c6fc80af8ce8b17c7ae92db48db3ee63c1"}, - {file = "prompt_toolkit-3.0.46.tar.gz", hash = "sha256:869c50d682152336e23c4db7f74667639b5047494202ffe7670817053fd57795"}, + {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, + {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, ] [package.dependencies] @@ -2556,27 +2573,28 @@ wcwidth = "*" [[package]] name = "psutil" -version = "5.9.8" +version = "6.0.0" description = "Cross-platform lib for process and system monitoring in Python." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, - {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, - {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, - {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, - {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, - {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, - {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, - {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, - {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, - {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, - {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, - {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, - {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, - {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, - {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, - {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, + {file = "psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6"}, + {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0"}, + {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c"}, + {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3"}, + {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c"}, + {file = "psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35"}, + {file = "psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1"}, + {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"}, + {file = "psutil-6.0.0-cp36-cp36m-win32.whl", hash = "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14"}, + {file = "psutil-6.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c"}, + {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"}, + {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"}, + {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"}, + {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"}, ] [package.extras] @@ -3178,28 +3196,28 @@ files = [ [[package]] name = "ruff" -version = "0.4.8" +version = "0.4.9" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066"}, - {file = "ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913"}, - {file = "ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3"}, - {file = "ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb"}, - {file = "ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764"}, - {file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883"}, - {file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199"}, - {file = "ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b"}, - {file = "ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45"}, - {file = "ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a"}, - {file = "ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc"}, - {file = "ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed"}, - {file = "ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa"}, - {file = "ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9"}, - {file = "ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d"}, - {file = "ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780"}, - {file = "ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268"}, + {file = "ruff-0.4.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b262ed08d036ebe162123170b35703aaf9daffecb698cd367a8d585157732991"}, + {file = "ruff-0.4.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:98ec2775fd2d856dc405635e5ee4ff177920f2141b8e2d9eb5bd6efd50e80317"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4555056049d46d8a381f746680db1c46e67ac3b00d714606304077682832998e"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e91175fbe48f8a2174c9aad70438fe9cb0a5732c4159b2a10a3565fea2d94cde"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8e7b95673f22e0efd3571fb5b0cf71a5eaaa3cc8a776584f3b2cc878e46bff"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2d45ddc6d82e1190ea737341326ecbc9a61447ba331b0a8962869fcada758505"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78de3fdb95c4af084087628132336772b1c5044f6e710739d440fc0bccf4d321"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06b60f91bfa5514bb689b500a25ba48e897d18fea14dce14b48a0c40d1635893"}, + {file = "ruff-0.4.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88bffe9c6a454bf8529f9ab9091c99490578a593cc9f9822b7fc065ee0712a06"}, + {file = "ruff-0.4.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:673bddb893f21ab47a8334c8e0ea7fd6598ecc8e698da75bcd12a7b9d0a3206e"}, + {file = "ruff-0.4.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8c1aff58c31948cc66d0b22951aa19edb5af0a3af40c936340cd32a8b1ab7438"}, + {file = "ruff-0.4.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:784d3ec9bd6493c3b720a0b76f741e6c2d7d44f6b2be87f5eef1ae8cc1d54c84"}, + {file = "ruff-0.4.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:732dd550bfa5d85af8c3c6cbc47ba5b67c6aed8a89e2f011b908fc88f87649db"}, + {file = "ruff-0.4.9-py3-none-win32.whl", hash = "sha256:8064590fd1a50dcf4909c268b0e7c2498253273309ad3d97e4a752bb9df4f521"}, + {file = "ruff-0.4.9-py3-none-win_amd64.whl", hash = "sha256:e0a22c4157e53d006530c902107c7f550b9233e9706313ab57b892d7197d8e52"}, + {file = "ruff-0.4.9-py3-none-win_arm64.whl", hash = "sha256:5d5460f789ccf4efd43f265a58538a2c24dbce15dbf560676e430375f20a8198"}, + {file = "ruff-0.4.9.tar.gz", hash = "sha256:f1cb0828ac9533ba0135d148d214e284711ede33640465e706772645483427e3"}, ] [[package]] @@ -3260,6 +3278,21 @@ nativelib = ["pyobjc-framework-Cocoa", "pywin32"] objc = ["pyobjc-framework-Cocoa"] win32 = ["pywin32"] +[[package]] +name = "setuptools" +version = "70.1.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-70.1.0-py3-none-any.whl", hash = "sha256:d9b8b771455a97c8a9f3ab3448ebe0b29b5e105f1228bba41028be116985a267"}, + {file = "setuptools-70.1.0.tar.gz", hash = "sha256:01a1e793faa5bd89abc851fa15d0a0db26f160890c7102cd8dce643e886b47f5"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "six" version = "1.16.0" @@ -3506,64 +3539,64 @@ test = ["pytest"] [[package]] name = "sqlalchemy" -version = "2.0.30" +version = "2.0.31" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.30-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b48154678e76445c7ded1896715ce05319f74b1e73cf82d4f8b59b46e9c0ddc"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2753743c2afd061bb95a61a51bbb6a1a11ac1c44292fad898f10c9839a7f75b2"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7bfc726d167f425d4c16269a9a10fe8630ff6d14b683d588044dcef2d0f6be7"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4f61ada6979223013d9ab83a3ed003ded6959eae37d0d685db2c147e9143797"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a365eda439b7a00732638f11072907c1bc8e351c7665e7e5da91b169af794af"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bba002a9447b291548e8d66fd8c96a6a7ed4f2def0bb155f4f0a1309fd2735d5"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-win32.whl", hash = "sha256:0138c5c16be3600923fa2169532205d18891b28afa817cb49b50e08f62198bb8"}, - {file = "SQLAlchemy-2.0.30-cp310-cp310-win_amd64.whl", hash = "sha256:99650e9f4cf3ad0d409fed3eec4f071fadd032e9a5edc7270cd646a26446feeb"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:955991a09f0992c68a499791a753523f50f71a6885531568404fa0f231832aa0"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f69e4c756ee2686767eb80f94c0125c8b0a0b87ede03eacc5c8ae3b54b99dc46"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69c9db1ce00e59e8dd09d7bae852a9add716efdc070a3e2068377e6ff0d6fdaa"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1429a4b0f709f19ff3b0cf13675b2b9bfa8a7e79990003207a011c0db880a13"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:efedba7e13aa9a6c8407c48facfdfa108a5a4128e35f4c68f20c3407e4376aa9"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:16863e2b132b761891d6c49f0a0f70030e0bcac4fd208117f6b7e053e68668d0"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-win32.whl", hash = "sha256:2ecabd9ccaa6e914e3dbb2aa46b76dede7eadc8cbf1b8083c94d936bcd5ffb49"}, - {file = "SQLAlchemy-2.0.30-cp311-cp311-win_amd64.whl", hash = "sha256:0b3f4c438e37d22b83e640f825ef0f37b95db9aa2d68203f2c9549375d0b2260"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5a79d65395ac5e6b0c2890935bad892eabb911c4aa8e8015067ddb37eea3d56c"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9a5baf9267b752390252889f0c802ea13b52dfee5e369527da229189b8bd592e"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cb5a646930c5123f8461f6468901573f334c2c63c795b9af350063a736d0134"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:296230899df0b77dec4eb799bcea6fbe39a43707ce7bb166519c97b583cfcab3"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c62d401223f468eb4da32627bffc0c78ed516b03bb8a34a58be54d618b74d472"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3b69e934f0f2b677ec111b4d83f92dc1a3210a779f69bf905273192cf4ed433e"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-win32.whl", hash = "sha256:77d2edb1f54aff37e3318f611637171e8ec71472f1fdc7348b41dcb226f93d90"}, - {file = "SQLAlchemy-2.0.30-cp312-cp312-win_amd64.whl", hash = "sha256:b6c7ec2b1f4969fc19b65b7059ed00497e25f54069407a8701091beb69e591a5"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5a8e3b0a7e09e94be7510d1661339d6b52daf202ed2f5b1f9f48ea34ee6f2d57"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b60203c63e8f984df92035610c5fb76d941254cf5d19751faab7d33b21e5ddc0"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1dc3eabd8c0232ee8387fbe03e0a62220a6f089e278b1f0aaf5e2d6210741ad"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:40ad017c672c00b9b663fcfcd5f0864a0a97828e2ee7ab0c140dc84058d194cf"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e42203d8d20dc704604862977b1470a122e4892791fe3ed165f041e4bf447a1b"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-win32.whl", hash = "sha256:2a4f4da89c74435f2bc61878cd08f3646b699e7d2eba97144030d1be44e27584"}, - {file = "SQLAlchemy-2.0.30-cp37-cp37m-win_amd64.whl", hash = "sha256:b6bf767d14b77f6a18b6982cbbf29d71bede087edae495d11ab358280f304d8e"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc0c53579650a891f9b83fa3cecd4e00218e071d0ba00c4890f5be0c34887ed3"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:311710f9a2ee235f1403537b10c7687214bb1f2b9ebb52702c5aa4a77f0b3af7"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:408f8b0e2c04677e9c93f40eef3ab22f550fecb3011b187f66a096395ff3d9fd"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37a4b4fb0dd4d2669070fb05b8b8824afd0af57587393015baee1cf9890242d9"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a943d297126c9230719c27fcbbeab57ecd5d15b0bd6bfd26e91bfcfe64220621"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0a089e218654e740a41388893e090d2e2c22c29028c9d1353feb38638820bbeb"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-win32.whl", hash = "sha256:fa561138a64f949f3e889eb9ab8c58e1504ab351d6cf55259dc4c248eaa19da6"}, - {file = "SQLAlchemy-2.0.30-cp38-cp38-win_amd64.whl", hash = "sha256:7d74336c65705b986d12a7e337ba27ab2b9d819993851b140efdf029248e818e"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ae8c62fe2480dd61c532ccafdbce9b29dacc126fe8be0d9a927ca3e699b9491a"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2383146973a15435e4717f94c7509982770e3e54974c71f76500a0136f22810b"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8409de825f2c3b62ab15788635ccaec0c881c3f12a8af2b12ae4910a0a9aeef6"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0094c5dc698a5f78d3d1539853e8ecec02516b62b8223c970c86d44e7a80f6c7"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:edc16a50f5e1b7a06a2dcc1f2205b0b961074c123ed17ebda726f376a5ab0953"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f7703c2010355dd28f53deb644a05fc30f796bd8598b43f0ba678878780b6e4c"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-win32.whl", hash = "sha256:1f9a727312ff6ad5248a4367358e2cf7e625e98b1028b1d7ab7b806b7d757513"}, - {file = "SQLAlchemy-2.0.30-cp39-cp39-win_amd64.whl", hash = "sha256:a0ef36b28534f2a5771191be6edb44cc2673c7b2edf6deac6562400288664221"}, - {file = "SQLAlchemy-2.0.30-py3-none-any.whl", hash = "sha256:7108d569d3990c71e26a42f60474b4c02c8586c4681af5fd67e51a044fdea86a"}, - {file = "SQLAlchemy-2.0.30.tar.gz", hash = "sha256:2b1708916730f4830bc69d6f49d37f7698b5bd7530aca7f04f785f8849e95255"}, -] - -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} + {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2a213c1b699d3f5768a7272de720387ae0122f1becf0901ed6eaa1abd1baf6c"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9fea3d0884e82d1e33226935dac990b967bef21315cbcc894605db3441347443"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ad7f221d8a69d32d197e5968d798217a4feebe30144986af71ada8c548e9fa"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2bee229715b6366f86a95d497c347c22ddffa2c7c96143b59a2aa5cc9eebbc"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cd5b94d4819c0c89280b7c6109c7b788a576084bf0a480ae17c227b0bc41e109"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:750900a471d39a7eeba57580b11983030517a1f512c2cb287d5ad0fcf3aebd58"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-win32.whl", hash = "sha256:7bd112be780928c7f493c1a192cd8c5fc2a2a7b52b790bc5a84203fb4381c6be"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-win_amd64.whl", hash = "sha256:5a48ac4d359f058474fadc2115f78a5cdac9988d4f99eae44917f36aa1476327"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f68470edd70c3ac3b6cd5c2a22a8daf18415203ca1b036aaeb9b0fb6f54e8298"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e2c38c2a4c5c634fe6c3c58a789712719fa1bf9b9d6ff5ebfce9a9e5b89c1ca"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd15026f77420eb2b324dcb93551ad9c5f22fab2c150c286ef1dc1160f110203"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2196208432deebdfe3b22185d46b08f00ac9d7b01284e168c212919891289396"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:352b2770097f41bff6029b280c0e03b217c2dcaddc40726f8f53ed58d8a85da4"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56d51ae825d20d604583f82c9527d285e9e6d14f9a5516463d9705dab20c3740"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-win32.whl", hash = "sha256:6e2622844551945db81c26a02f27d94145b561f9d4b0c39ce7bfd2fda5776dac"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-win_amd64.whl", hash = "sha256:ccaf1b0c90435b6e430f5dd30a5aede4764942a695552eb3a4ab74ed63c5b8d3"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3b74570d99126992d4b0f91fb87c586a574a5872651185de8297c6f90055ae42"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f77c4f042ad493cb8595e2f503c7a4fe44cd7bd59c7582fd6d78d7e7b8ec52c"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd1591329333daf94467e699e11015d9c944f44c94d2091f4ac493ced0119449"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74afabeeff415e35525bf7a4ecdab015f00e06456166a2eba7590e49f8db940e"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b9c01990d9015df2c6f818aa8f4297d42ee71c9502026bb074e713d496e26b67"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66f63278db425838b3c2b1c596654b31939427016ba030e951b292e32b99553e"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-win32.whl", hash = "sha256:0b0f658414ee4e4b8cbcd4a9bb0fd743c5eeb81fc858ca517217a8013d282c96"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-win_amd64.whl", hash = "sha256:fa4b1af3e619b5b0b435e333f3967612db06351217c58bfb50cee5f003db2a5a"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f43e93057cf52a227eda401251c72b6fbe4756f35fa6bfebb5d73b86881e59b0"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d337bf94052856d1b330d5fcad44582a30c532a2463776e1651bd3294ee7e58b"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c06fb43a51ccdff3b4006aafee9fcf15f63f23c580675f7734245ceb6b6a9e05"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:b6e22630e89f0e8c12332b2b4c282cb01cf4da0d26795b7eae16702a608e7ca1"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:79a40771363c5e9f3a77f0e28b3302801db08040928146e6808b5b7a40749c88"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-win32.whl", hash = "sha256:501ff052229cb79dd4c49c402f6cb03b5a40ae4771efc8bb2bfac9f6c3d3508f"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-win_amd64.whl", hash = "sha256:597fec37c382a5442ffd471f66ce12d07d91b281fd474289356b1a0041bdf31d"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dc6d69f8829712a4fd799d2ac8d79bdeff651c2301b081fd5d3fe697bd5b4ab9"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:23b9fbb2f5dd9e630db70fbe47d963c7779e9c81830869bd7d137c2dc1ad05fb"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21c97efcbb9f255d5c12a96ae14da873233597dfd00a3a0c4ce5b3e5e79704"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a6a9837589c42b16693cf7bf836f5d42218f44d198f9343dd71d3164ceeeac"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc251477eae03c20fae8db9c1c23ea2ebc47331bcd73927cdcaecd02af98d3c3"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2fd17e3bb8058359fa61248c52c7b09a97cf3c820e54207a50af529876451808"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-win32.whl", hash = "sha256:c76c81c52e1e08f12f4b6a07af2b96b9b15ea67ccdd40ae17019f1c373faa227"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-win_amd64.whl", hash = "sha256:4b600e9a212ed59355813becbcf282cfda5c93678e15c25a0ef896b354423238"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b6cf796d9fcc9b37011d3f9936189b3c8074a02a4ed0c0fbbc126772c31a6d4"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:78fe11dbe37d92667c2c6e74379f75746dc947ee505555a0197cfba9a6d4f1a4"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc47dc6185a83c8100b37acda27658fe4dbd33b7d5e7324111f6521008ab4fe"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a41514c1a779e2aa9a19f67aaadeb5cbddf0b2b508843fcd7bafdf4c6864005"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:afb6dde6c11ea4525318e279cd93c8734b795ac8bb5dda0eedd9ebaca7fa23f1"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3f9faef422cfbb8fd53716cd14ba95e2ef655400235c3dfad1b5f467ba179c8c"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-win32.whl", hash = "sha256:fc6b14e8602f59c6ba893980bea96571dd0ed83d8ebb9c4479d9ed5425d562e9"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-win_amd64.whl", hash = "sha256:3cb8a66b167b033ec72c3812ffc8441d4e9f5f78f5e31e54dcd4c90a4ca5bebc"}, + {file = "SQLAlchemy-2.0.31-py3-none-any.whl", hash = "sha256:69f3e3c08867a8e4856e92d7afb618b95cdee18e0bc1647b77599722c9a28911"}, + {file = "SQLAlchemy-2.0.31.tar.gz", hash = "sha256:b607489dd4a54de56984a0c7656247504bd5523d9d0ba799aef59d4add009484"}, +] + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} typing-extensions = ">=4.6.0" [package.extras] @@ -3676,22 +3709,22 @@ files = [ [[package]] name = "tornado" -version = "6.4" +version = "6.4.1" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false -python-versions = ">= 3.8" +python-versions = ">=3.8" files = [ - {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, - {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, - {file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"}, - {file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"}, - {file = "tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212"}, - {file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"}, - {file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"}, - {file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"}, - {file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"}, - {file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"}, - {file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"}, + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"}, + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"}, + {file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"}, + {file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"}, + {file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"}, ] [[package]] @@ -3744,13 +3777,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.12.1" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, - {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -3780,13 +3813,13 @@ dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake [[package]] name = "urllib3" -version = "2.2.1" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, - {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] @@ -3909,4 +3942,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = ">=3.10" -content-hash = "5ae3bb0a9ec2508b26129ea9b67b263479ec0e502c153d99b9f72e38e56a628b" +content-hash = "60c570ef4d977a74de54a3703da5282cd59e10c89ea5b8ad2e8573d305b30499" From 2ad29470d22189459525ee6dac96ea560ed03b71 Mon Sep 17 00:00:00 2001 From: James Emberton Date: Thu, 20 Jun 2024 10:34:49 +0100 Subject: [PATCH 048/241] type corrections --- pyrealm/core/utilities.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrealm/core/utilities.py b/pyrealm/core/utilities.py index d59fe42d..d82aadc6 100644 --- a/pyrealm/core/utilities.py +++ b/pyrealm/core/utilities.py @@ -24,7 +24,7 @@ >>> import numpy as np >>> x = np.ma.masked_array([1,2,np.nan, 4], mask=[1,0,0,1]) >>> x.mean() - nan + np.float64(nan) >>> x = np.ma.masked_array([1,2,np.nan, 4], mask=[1,0,1,0]) >>> x.mean() 3.0 @@ -282,7 +282,7 @@ def bounds_mask( Examples: >>> vals = np.array([-15, 20, 30, 124], dtype=float) >>> np.nansum(vals) - 159.0 + np.float64(159.0) >>> vals_c = bounds_mask(vals, 0, 100, label='temperature') >>> np.nansum(vals_c) 50.0 From 25b9c957e23bc2d8c334ca9789d9aab439a8677c Mon Sep 17 00:00:00 2001 From: James Emberton Date: Thu, 20 Jun 2024 10:44:26 +0100 Subject: [PATCH 049/241] further decstring test return value type fixes --- pyrealm/core/utilities.py | 8 ++++---- pyrealm/core/water.py | 10 +++++----- pyrealm/pmodel/functions.py | 14 +++++++------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pyrealm/core/utilities.py b/pyrealm/core/utilities.py index d82aadc6..76207b6a 100644 --- a/pyrealm/core/utilities.py +++ b/pyrealm/core/utilities.py @@ -27,7 +27,7 @@ np.float64(nan) >>> x = np.ma.masked_array([1,2,np.nan, 4], mask=[1,0,1,0]) >>> x.mean() - 3.0 + np.float64(3.0) So the general approach here is now: @@ -285,13 +285,13 @@ def bounds_mask( np.float64(159.0) >>> vals_c = bounds_mask(vals, 0, 100, label='temperature') >>> np.nansum(vals_c) - 50.0 + np.float64(50.0) >>> vals_c = bounds_mask(vals, 0, 124, interval_type='[]', label='temperature') >>> np.nansum(vals_c) - 174.0 + np.float64(174.0) >>> vals_c = bounds_mask(vals, 0, 124, interval_type='[)', label='temperature') >>> np.nansum(vals_c) - 50.0 + np.float64(50.0) """ # Get the interval functions diff --git a/pyrealm/core/water.py b/pyrealm/core/water.py index 1d4a9ecc..72c7568b 100644 --- a/pyrealm/core/water.py +++ b/pyrealm/core/water.py @@ -37,7 +37,7 @@ def calc_density_h2o_chen( Examples: >>> round(calc_density_h2o_chen(20, 101325), 3) - 998.25 + np.float64(998.25) """ # Calculate density at 1 atm (kg/m^3): @@ -93,7 +93,7 @@ def calc_density_h2o_fisher( Examples: >>> round(calc_density_h2o_fisher(20, 101325), 3) - 998.206 + np.float64(998.206) """ # Check input shapes, shape not used @@ -156,7 +156,7 @@ def calc_density_h2o( Examples: >>> round(calc_density_h2o(20, 101325), 3) - 998.206 + np.float64(998.206) """ # Safe guard against instability in functions at low temperature. @@ -201,7 +201,7 @@ def calc_viscosity_h2o( Examples: >>> # Density of water at 20 degrees C and standard atmospheric pressure: >>> round(calc_viscosity_h2o(20, 101325), 7) - 0.0010016 + np.float64(0.0010016) """ # Check inputs, return shape not used @@ -269,7 +269,7 @@ def calc_viscosity_h2o_matrix( Examples: >>> # Density of water at 20 degrees C and standard atmospheric pressure: >>> round(calc_viscosity_h2o(20, 101325), 7) - 0.0010016 + np.float64(0.0010016) """ # Check inputs, return shape not used diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index 17283ef4..8486a752 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -61,7 +61,7 @@ def calc_ftemp_arrh( Examples: >>> # Relative rate change from 25 to 10 degrees Celsius (percent change) >>> round((1.0-calc_ftemp_arrh( 283.15, 100000)) * 100, 4) - 88.1991 + np.float64(88.1991) """ # Note that the following forms are equivalent: @@ -107,7 +107,7 @@ def calc_ftemp_inst_rd( >>> # Relative percentage instantaneous change in Rd going from 10 to 25 degrees >>> val = (calc_ftemp_inst_rd(25) / calc_ftemp_inst_rd(10) - 1) * 100 >>> round(val, 4) - 250.9593 + np.float64(250.9593) """ return np.exp( @@ -172,7 +172,7 @@ def calc_ftemp_inst_vcmax( >>> # not acclimatedly) from 10 to 25 degrees (percent change): >>> val = ((calc_ftemp_inst_vcmax(25)/calc_ftemp_inst_vcmax(10)-1) * 100) >>> round(val, 4) - 283.1775 + np.float64(283.1775) """ # Convert temperatures to Kelvin @@ -233,13 +233,13 @@ def calc_ftemp_kphio( >>> # degrees celsius (percent change): >>> val = (calc_ftemp_kphio(25.0) / calc_ftemp_kphio(5.0) - 1) * 100 >>> round(val, 5) - 52.03969 + np.float64(52.03969) >>> # Relative change in the quantum yield efficiency between 5 and 25 >>> # degrees celsius (percent change) for a C4 plant: >>> val = (calc_ftemp_kphio(25.0, c4=True) / ... calc_ftemp_kphio(5.0, c4=True) - 1) * 100 >>> round(val, 5) - 432.25806 + np.float64(432.25806) """ if c4: @@ -338,7 +338,7 @@ def calc_ns_star( >>> # Relative viscosity at 20 degrees Celsius and standard >>> # atmosphere (in Pa): >>> round(calc_ns_star(20, 101325), 5) - 1.12536 + np.float64(1.12536) """ visc_env = calc_viscosity_h2o(tc, patm, core_const=core_const) @@ -405,7 +405,7 @@ def calc_kmm( >>> # Michaelis-Menten coefficient at 20 degrees Celsius and standard >>> # atmosphere (in Pa): >>> round(calc_kmm(20, 101325), 5) - 46.09928 + np.float64(46.09928) """ # Check inputs, return shape not used From 415b01b46c5b1af6b6039a286093402d0ae57827 Mon Sep 17 00:00:00 2001 From: James Emberton Date: Thu, 20 Jun 2024 10:47:37 +0100 Subject: [PATCH 050/241] one more type fix --- pyrealm/pmodel/functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index 8486a752..91d921d3 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -656,7 +656,7 @@ def calc_co2_to_ca(co2: NDArray, patm: NDArray) -> NDArray: Examples: >>> np.round(calc_co2_to_ca(413.03, 101325), 6) - 41.850265 + np.float64(41.850265) """ return 1.0e-6 * co2 * patm # Pa, atms. CO2 From 2ec3d79ad6943ade7605c1970ae3a12c987fcdf7 Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Wed, 7 Aug 2024 12:44:27 +0100 Subject: [PATCH 051/241] Added docstring for newly added init_realised variable --- pyrealm/pmodel/subdaily.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 27ccadfe..d8745522 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -213,6 +213,8 @@ class SubdailyPModel: kphio: The quantum yield efficiency of photosynthesis (:math:`\phi_0`, -). fill_kind: The approach used to fill daily realised values to the subdaily timescale, currently one of 'previous' or 'linear'. + init_realised: A tuple of three NumPy arrays (xi_real, vcmax25_real, + jmax25_real). """ def __init__( From 387d3c959ae832cdf5cf42d98c2103b3184cfd4b Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 7 Aug 2024 13:56:45 +0100 Subject: [PATCH 052/241] Docstring update for quantum yield --- pyrealm/pmodel/quantum_yield.py | 97 +++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 16 deletions(-) diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index a3f3a6c6..2ed797f6 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -1,9 +1,11 @@ -r"""The module :mod:`~pyrealm.pmodel.quantum_yield` provides -the abstract base class :class:`~pyrealm.pmodel.quantum_yield.QuantumYieldABC`, which is -used to support different implementations of the calculation of the intrinsic quantum -yield efficiency of photosynthesis (:math:`\phi_0`, unitless). Note that :math:`\phi_0` -is sometimes used to refer to the quantum yield of electron transfer, which is exactly -four times larger, so check definitions here. +r"""The module :mod:`~pyrealm.pmodel.quantum_yield` provides the abstract base class +:class:`~pyrealm.pmodel.quantum_yield.QuantumYieldABC`, which is used to support +different implementations of the calculation of the intrinsic quantum yield efficiency +of photosynthesis (:math:`\phi_0`, unitless). The module then provides subclasses of the +ABC implementing different approaches. + +Note that :math:`\phi_0` is sometimes used to refer to the quantum yield of electron +transfer, which is exactly four times larger, so check definitions here. """ # noqa D210, D415 from __future__ import annotations @@ -34,7 +36,7 @@ .. code:: python - bianchi_phi_0 = QUANTUM_YIELD_CLASS_REGISTRY['bianchi'] + temperature_phio = QUANTUM_YIELD_CLASS_REGISTRY['temperature'] """ @@ -51,12 +53,46 @@ class QuantumYieldABC(ABC): ``kphio`` and is automatically called by the ``__init__`` method when a subclass instance is created. + Subclasses must define several class attributes when created: + + .. code:: python + + class QuantumYieldFixed( + QuantumYieldABC, + method="method_name", + requires=["an_environment_variable"], + default_reference_kphio=0.049977, + array_reference_kphio_ok=True, + ): + + * The ``method`` argument sets the name of the method, which can then be used to + select the implemented class from the + :data:`~pyrealm.pmodel.quantum_yield.QUANTUM_YIELD_CLASS_REGISTRY`. + * The `requires` argument sets a list of variables that must be present in the + :class:`~pyrealm.pmodel.pmodel_environment.PModelEnvironment` to use this + approach. The core ``tc``, ``vpd``, ``patm`` and ``co2`` variables do not need to + be included in this list. + * The ``default_reference_kphio`` argument sets the default value for :math:`\phi_0` + that will be used by the implementation. The ``__init__`` method will then check + whether array values are accepted and that the shape of an array is congruent with + the other data. + * The ``array_reference_kphio_ok`` argument sets whether the method can accept an + array of :math:`\phi_0` values or whether a single global reference value should + be used. + + The definition of the ``_calculate_kphio`` method for subclasses can also provide C3 + and C4 implementations for calculate :math:`\phi_0` - or possibly raise an error for + one pathway - using the ``use_c4`` attribute. + Args: env: An instance of :class:`~pyrealm.pmodel.pmodel_environment.PModelEnvironment` providing the photosynthetic environment for the model. - pmodel_const: An instance of - :class:`~pyrealm.constants.pmodel_const.PModelConst`. + reference_kphio: An optional value to be used instead of the default reference + kphio for the subclass. This is typically a single float but some approaches + may support an array of values here. + use_c4: Should the calculation use parameterisation for C4 photosynthesis rather + than C3 photosynthesis. Returns: Instances of the abstract base class should not be created - use instances of @@ -184,10 +220,18 @@ class QuantumYieldFixed( default_reference_kphio=0.049977, array_reference_kphio_ok=True, ): - """Constant kphio.""" + r"""Apply a fixed value for :math:`\phi_0`. + + This implementation applies a fixed value for the quantum yield without any + environmental variation. The default value used is :math:`\phi_0 = 0.049977`, + following the ORG settings parameterisation in Table 1. of {cite:t}`Stocker:2020dh`. + + This implementation will accept an array of values to allow externally estimated + values to be passed to a P model. + """ def _calculate_kphio(self) -> None: - """Constant kphio.""" + """Set fixed kphio.""" self.kphio = self.reference_kphio @@ -199,9 +243,23 @@ class QuantumYieldTemperature( default_reference_kphio=0.081785, array_reference_kphio_ok=False, ): - """Calculate temperature modulated kphio. + r"""Calculate temperature dependent of quantum yield efficiency. + + This implementation calculates temperature dependent quantum yield efficiency, as a + quadratic function of temperature (:math:`T`). - This method follows for C3 plants. + .. math:: + + \phi(T) = a + b T - c T^2 + + The values of :math:`a, b, c` are dependent on whether :math:`\phi_0` is being + estimated for C3 or C4 photosynthesis. For C3 photosynthesis, the default values use + the temperature dependence of the maximum quantum yield of photosystem II in + light-adapted tobacco leaves determined by :cite:t:`Bernacchi:2003dc`. For C4 + photosynthesis, the default values are taken from :cite:t:`cai:2020a`. + + The default reference value for this approach is :math:`\phi_0 = 0.081785` following + the BRC parameterisation in Table 1. of {cite:t}`Stocker:2020dh`. """ def _calculate_kphio( @@ -229,10 +287,17 @@ class QuantumYieldSandoval( default_reference_kphio=1.0 / 9.0, array_reference_kphio_ok=False, ): - """Calculate kphio following Sandoval. + r"""Calculate aridity and mean growth temperature effects on quantum yield. + + This experimental approach implements the method of :cite:t:`sandoval:in_prep`. This + approach modifies the maximum possible :math:`\phi_0` as a function of the + climatological aridity index. It then also adjusts the temperature at which the + highest :math:`\phi_0` can be attained as a function of the mean growth temperature + for an observation. It then calculates the expected :math:`\phi_0` as a function of + temperature via a modified Arrhenius relationship. - Reference kphio is the theoretical maximum quantum yield, defaulting to the ratio of - 1/9 in the absence of a Q cycle (Long, 1993). + The reference kphio for this approach is the theoretical maximum quantum yield, + defaulting to the ratio of 1/9 in the absence of a Q cycle :cite:`long:1993a`. """ def peak_quantum_yield(self, aridity: NDArray) -> NDArray: From 67b1e04784f24acbf1731159bacc39a2ed934126 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 8 Aug 2024 10:38:36 +0100 Subject: [PATCH 053/241] Replacing and removing the calc_ftemp_kphio and calc_ftemp_inst_vcmax functions --- pyrealm/constants/pmodel_const.py | 40 +++++----- pyrealm/pmodel/__init__.py | 2 - pyrealm/pmodel/functions.py | 101 ++++-------------------- pyrealm/pmodel/pmodel.py | 26 +++--- tests/regression/pmodel/test_pmodel.py | 65 +++++++++++---- tests/unit/pmodel/test_functions_new.py | 22 ------ 6 files changed, 100 insertions(+), 156 deletions(-) diff --git a/pyrealm/constants/pmodel_const.py b/pyrealm/constants/pmodel_const.py index 817636e0..ea95ca16 100644 --- a/pyrealm/constants/pmodel_const.py +++ b/pyrealm/constants/pmodel_const.py @@ -22,12 +22,8 @@ class PModelConst(ConstantsClass): (:attr:`~pyrealm.constants.pmodel_const.PModelConst.heskel_b`, :attr:`~pyrealm.constants.pmodel_const.PModelConst.heskel_c`) - * **Temperature and entropy of VCMax**. Values taken from Table 3 of - :cite:t:`Kattge:2007db` - (:attr:`~pyrealm.constants.pmodel_const.PModelConst.kattge_knorr_a_ent`, - :attr:`~pyrealm.constants.pmodel_const.PModelConst.kattge_knorr_b_ent`, - :attr:`~pyrealm.constants.pmodel_const.PModelConst.kattge_knorr_Ha`, - :attr:`~pyrealm.constants.pmodel_const.PModelConst.kattge_knorr_Hd`) + * **Enzyme kinetics for VCMax**. Values taken from Table 3 of + :cite:t:`Kattge:2007db`. * **Scaling of Kphio with temperature**. The parameters of quadratic functions for the temperature dependence of Kphio are: @@ -99,11 +95,11 @@ class PModelConst(ConstantsClass): 294.804, 75000.0, ) - """Enzyme kinetics parameters for estimation of kphion from mean growth temperature - in the Sandoval method for estimation of quantum yield efficiency. Values are: the - intercept and slope of activation entropy as a function of the mean growth - temperature (J/mol/K), the deactivation energy constant (J/mol) and the activation - energy (J/mol). """ + """Enzyme kinetics parameters for estimation of kphio from mean growth temperature + in the Sandoval method :cite:t:`Sandoval:in_prep` for estimation of quantum yield + efficiency. Values are: the intercept and slope of activation entropy as a function + of the mean growth temperature (J/mol/K), the deactivation energy constant (J/mol) + and the activation energy (J/mol). """ plant_T_ref: float = 25.0 """Standard baseline reference temperature of photosynthetic processes (Prentice, @@ -115,17 +111,17 @@ class PModelConst(ConstantsClass): heskel_c: float = 0.0005 """Quadratic coefficient of scaling of dark respiration (:math:`c`, 0.0005)""" - # KattgeKnorr - kattge_knorr_a_ent: float = 668.39 - """Offset of entropy vs. temperature relationship (:math:`a_{ent}`, 668.39, - J/mol/K)""" - kattge_knorr_b_ent: float = -1.07 - """Slope of entropy vs. temperature relationship (:math:`b_{ent}`, -1.07, - J/mol/K^2)""" - kattge_knorr_Ha: float = 71513 - """Activation energy (:math:`H_a`, 71513, J/mol)""" - kattge_knorr_Hd: float = 200000 - """Deactivation energy (:math:`H_d`, 200000, J/mol)""" + # KattgeKnorr vcmax + kattge_knorr_kinetics: tuple[float, float, float, float] = ( + 668.39, + -1.07, + 71513, + 200000, + ) + """Enzyme kinetics parameters for estimation of V_cmax25 from Table 3 + of :cite:t:`Kattge:2007db`. Values are: the intercept and slope of activation + entropy as a function of the mean growth temperature (J/mol/K), the deactivation + energy constant (J/mol) and the activation energy (J/mol). """ # Subdaily activatation energy subdaily_vcmax25_ha: float = 65330 diff --git a/pyrealm/pmodel/__init__.py b/pyrealm/pmodel/__init__.py index 96264b43..6ebdfe50 100644 --- a/pyrealm/pmodel/__init__.py +++ b/pyrealm/pmodel/__init__.py @@ -37,8 +37,6 @@ calc_co2_to_ca, calc_ftemp_arrh, calc_ftemp_inst_rd, - calc_ftemp_inst_vcmax, - calc_ftemp_kphio, calc_gammastar, calc_kmm, calc_ns_star, diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index 84692690..64fdb566 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -46,9 +46,9 @@ def calc_ftemp_arrh( \] Args: - tk: Temperature (in Kelvin) + tk: Temperature (K) ha: Activation energy (in :math:`J \text{mol}^{-1}`) - tk_ref: The reference temperature for the reaction. + tk_ref: The reference temperature for the reaction (K). pmodel_const: Instance of :class:`~pyrealm.constants.pmodel_const.PModelConst`. core_const: Instance of :class:`~pyrealm.constants.core_const.CoreConst`. @@ -92,7 +92,7 @@ def calc_ftemp_inst_rd( fr = \exp( b (T_o - T) - c ( T_o^2 - T^2 )) Args: - tc: Temperature (degrees Celsius) + tc: Temperature (°C) pmodel_const: Instance of :class:`~pyrealm.constants.pmodel_const.PModelConst`. PModel Parameters: @@ -119,84 +119,6 @@ def calc_ftemp_inst_rd( ) -def calc_ftemp_inst_vcmax( - tc: NDArray, - pmodel_const: PModelConst = PModelConst(), - core_const: CoreConst = CoreConst(), -) -> NDArray: - r"""Calculate temperature scaling of :math:`V_{cmax}`. - - This function calculates the temperature-scaling factor :math:`f` of the - instantaneous temperature response of :math:`V_{cmax}`, given the temperature - (:math:`T`) relative to the standard reference temperature (:math:`T_0`), following - modified Arrhenius kinetics. - - .. math:: - - V = f V_{ref} - - The value of :math:`f` is given by :cite:t:`Kattge:2007db` (Eqn 1) as: - - .. math:: - - f = g(T, H_a) \cdot - \frac{1 + \exp( (T_0 \Delta S - H_d) / (T_0 R))} - {1 + \exp( (T \Delta S - H_d) / (T R))} - - where :math:`g(T, H_a)` is a regular Arrhenius-type temperature response function - (see :func:`~pyrealm.pmodel.functions.calc_ftemp_arrh`). The term :math:`\Delta S` - is the entropy factor, calculated as a linear function of :math:`T` in °C following - :cite:t:`Kattge:2007db` (Table 3, Eqn 4): - - .. math:: - - \Delta S = a + b T - - Args: - tc: temperature, or in general the temperature relevant for - photosynthesis (°C) - pmodel_const: Instance of :class:`~pyrealm.constants.pmodel_const.PModelConst`. - core_const: Instance of :class:`~pyrealm.constants.core_const.CoreConst`. - - PModel Parameters: - Ha: activation energy (:math:`H_a`, ``kattge_knorr_Ha``) - Hd: deactivation energy (:math:`H_d`, ``kattge_knorr_Hd``) - To: standard reference temperature expressed - in Kelvin (`T_0`, ``k_To``) - R: the universal gas constant (:math:`R`, ``k_R``) - a: intercept of the entropy factor (:math:`a`, ``kattge_knorr_a_ent``) - b: slope of the entropy factor (:math:`b`, ``kattge_knorr_b_ent``) - - Returns: - Values for :math:`f` - - Examples: - >>> # Relative change in Vcmax going (instantaneously, i.e. not - >>> # not acclimatedly) from 10 to 25 degrees (percent change): - >>> val = ((calc_ftemp_inst_vcmax(25)/calc_ftemp_inst_vcmax(10)-1) * 100) - >>> np.round(val, 4) - array([283.1775]) - """ - - # Convert temperatures to Kelvin - tkref = pmodel_const.plant_T_ref + core_const.k_CtoK - tk = tc + core_const.k_CtoK - - # Calculate entropy following Kattge & Knorr (2007): slope and intercept - # are defined using temperature in °C, not K!!! 'tcgrowth' corresponds - # to 'tmean' in Nicks, 'tc25' is 'to' in Nick's - dent = pmodel_const.kattge_knorr_a_ent + pmodel_const.kattge_knorr_b_ent * tc - fva = calc_ftemp_arrh(tk, pmodel_const.kattge_knorr_Ha) - fvb = ( - 1 - + np.exp( - (tkref * dent - pmodel_const.kattge_knorr_Hd) / (core_const.k_R * tkref) - ) - ) / (1 + np.exp((tk * dent - pmodel_const.kattge_knorr_Hd) / (core_const.k_R * tk))) - - return fva * fvb - - def calc_modified_arrhenius_factor( tk: NDArray, Ha: float | NDArray, @@ -236,11 +158,20 @@ def calc_modified_arrhenius_factor( Values for :math:`f` Examples: - >>> # Relative change in Vcmax going (instantaneously, i.e. not - >>> # not acclimatedly) from 10 to 25 degrees (percent change): - >>> val = ((calc_ftemp_inst_vcmax(25)/calc_ftemp_inst_vcmax(10)-1) * 100) + >>> # Calculate the factor for the relative rate of V_cmax at 10 degrees + >>> # compared to the rate at the reference temperature of 25°C. + >>> from pyrealm.constants import PModelConst + >>> pmodel_const = PModelConst() + >>> # Get enzyme kinetics parameters + >>> a, b, ha, hd = pmodel_const.kattge_knorr_kinetics + >>> # Calculate entropy as a function of temperature _in °C_ + >>> deltaS = a + b * 10 + >>> # Calculate the arrhenius factor + >>> val = calc_modified_arrhenius_factor( + ... tk= 283.15, Ha=ha, Hd=hd, deltaS=deltaS + ... ) >>> np.round(val, 4) - array([283.1775]) + array([0.261]) """ if mode not in ["M2002", "J1942"]: diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index 354a4e9f..ccfbd20a 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -12,10 +12,7 @@ from pyrealm.constants import CoreConst, PModelConst from pyrealm.core.utilities import check_input_shapes, summarize_attrs -from pyrealm.pmodel.functions import ( - calc_ftemp_inst_rd, - calc_ftemp_inst_vcmax, -) +from pyrealm.pmodel.functions import calc_ftemp_inst_rd, calc_modified_arrhenius_factor from pyrealm.pmodel.jmax_limitation import JmaxLimitation from pyrealm.pmodel.optimal_chi import OPTIMAL_CHI_CLASS_REGISTRY, OptimalChiABC from pyrealm.pmodel.pmodel_environment import PModelEnvironment @@ -84,8 +81,9 @@ class PModel: * The maximum carboxylation capacity (mol C m-2) normalised to the standard temperature as: :math:`V_{cmax25} = V_{cmax} / fv(t)`, where :math:`fv(t)` is the - instantaneous temperature response of :math:`V_{cmax}` implemented in - :func:`~pyrealm.pmodel.functions.calc_ftemp_inst_vcmax` + instantaneous temperature response of :math:`V_{cmax}` calculated using a modified + Arrhenius equation + :func:`~pyrealm.pmodel.functions.calc_modified_arrhenius_factor`. * Dark respiration, calculated as: @@ -375,9 +373,19 @@ def estimate_productivity( # V_cmax self._vcmax = self.kphio.kphio * iabs * self.optchi.mjoc * self.jmaxlim.f_v - # V_cmax25 (vcmax normalized to const.k_To) - ftemp25_inst_vcmax = calc_ftemp_inst_vcmax( - self.env.tc, core_const=self.core_const, pmodel_const=self.pmodel_const + # Calculate the modified arrhenius factor to normalise V_cmax to V_cmax25 + # - Get parameters + kk_a, kk_b, kk_ha, kk_hd = self.pmodel_const.kattge_knorr_kinetics + # Calculate entropy as a function of temperature _in °C_ + kk_deltaS = kk_a + kk_b * self.env.tc + # Calculate the arrhenius factor + ftemp25_inst_vcmax = calc_modified_arrhenius_factor( + tk=self.env.tc + self.core_const.k_CtoK, + Ha=kk_ha, + Hd=kk_hd, + deltaS=kk_deltaS, + pmodel_const=self.pmodel_const, + core_const=self.core_const, ) self._vcmax25 = self._vcmax / ftemp25_inst_vcmax diff --git a/tests/regression/pmodel/test_pmodel.py b/tests/regression/pmodel/test_pmodel.py index ea1e7c10..282eb5ad 100644 --- a/tests/regression/pmodel/test_pmodel.py +++ b/tests/regression/pmodel/test_pmodel.py @@ -124,15 +124,37 @@ def test_calc_ftemp_arrh(values, tk, expvars): ], ) def test_calc_ftemp_inst_vcmax(values, tc, expvars): - """Test the calc_ftemp_inst_vcmax function.""" - from pyrealm.pmodel import calc_ftemp_inst_vcmax + """Test the calculation of values returned by calc_ftemp_inst_vcmax in rpmodel. + + This specific function was retired in favour of a more general modified arrhenius + function, but check the predictions match to the rpmodel outputs for this component. + """ + from pyrealm.constants import CoreConst, PModelConst + from pyrealm.pmodel.functions import calc_modified_arrhenius_factor + + pmodel_const = PModelConst() + core_const = CoreConst() + + kk_a, kk_b, kk_ha, kk_hd = pmodel_const.kattge_knorr_kinetics + + # Calculate entropy as a function of temperature _in °C_ + kk_deltaS = kk_a + kk_b * values[tc] + + # Calculate the arrhenius factor + ret = calc_modified_arrhenius_factor( + tk=values[tc] + core_const.k_CtoK, + Ha=kk_ha, + Hd=kk_hd, + deltaS=kk_deltaS, + pmodel_const=pmodel_const, + core_const=core_const, + ) - ret = calc_ftemp_inst_vcmax(values[tc]) assert np.allclose(ret, values[expvars]) # ------------------------------------------ -# Testing calc_ftemp_inst_vcmax - temp only +# Testing calc_ftemp_kphio - temp only # ------------------------------------------ # TODO - submit pull request to rpmodel with fix for this @@ -148,11 +170,22 @@ def test_calc_ftemp_inst_vcmax(values, tc, expvars): ], ) def test_calc_ftemp_kphio(values, tc, c4, expvars): - """Test the calc_ftemp_kphio function.""" - from pyrealm.pmodel import calc_ftemp_kphio + """Test the calc_ftemp_kphio values. - ret = calc_ftemp_kphio(tc=values[tc], c4=c4) - assert np.allclose(ret, values[expvars]) + This function in rpmodel has been replaced by the wider QuantumYield ABC framework + but make sure the outputs still align. + """ + from pyrealm.pmodel.pmodel_environment import PModelEnvironment + from pyrealm.pmodel.quantum_yield import QuantumYieldTemperature + + # Only tc is used from this environment + env = PModelEnvironment(tc=values[tc], patm=101325, vpd=820, co2=400) + + ret = QuantumYieldTemperature(env=env, use_c4=c4) + + # The QuantumYield class returns the actual kphio, not the correction factor, so + # scale back to the correction factor + assert np.allclose(ret.kphio / ret.reference_kphio, values[expvars]) # ------------------------------------------ @@ -445,23 +478,23 @@ def test_jmax_limitation( # - these have all been synchronised so that anything with type 'mx' or 'ar' # used the tc_ar input - from pyrealm.pmodel import JmaxLimitation, PModelEnvironment, calc_ftemp_kphio + from pyrealm.pmodel import JmaxLimitation, PModelEnvironment from pyrealm.pmodel.optimal_chi import OPTIMAL_CHI_CLASS_REGISTRY + from pyrealm.pmodel.quantum_yield import QuantumYieldTemperature oc_method = "c4" if c4 else "prentice14" - if not ftemp_kphio: - ftemp_kphio = 1.0 - elif tc == "tc_sc": - ftemp_kphio = calc_ftemp_kphio(tc=values[tc], c4=c4) - else: - ftemp_kphio = calc_ftemp_kphio(tc=values[tc], c4=c4) - # Optimal Chi env = PModelEnvironment( tc=values[tc], patm=values[patm], vpd=values[vpd], co2=values[co2] ) + if not ftemp_kphio: + ftemp_kphio = 1.0 + else: + kphio = QuantumYieldTemperature(env=env, use_c4=c4) + ftemp_kphio = kphio.kphio / kphio.reference_kphio + OptChiClass = OPTIMAL_CHI_CLASS_REGISTRY[oc_method] optchi = OptChiClass(env) diff --git a/tests/unit/pmodel/test_functions_new.py b/tests/unit/pmodel/test_functions_new.py index e38dbb4e..59f59a09 100644 --- a/tests/unit/pmodel/test_functions_new.py +++ b/tests/unit/pmodel/test_functions_new.py @@ -5,7 +5,6 @@ """ # D210, D415 import numpy as np -import pytest def test_calc_ftemp_arrh(tk=np.array([300]), ha=40000): @@ -22,27 +21,6 @@ def test_calc_ftemp_inst_rd(tc=np.array([30.0])): assert np.allclose(calc_ftemp_inst_rd(tc), 1.4455646406287255) -def test_calc_ftemp_inst_vcmax(tc=np.array([30.0])): - """Test calc_ftemp_inst_rd.""" - from pyrealm.pmodel.functions import calc_ftemp_inst_vcmax - - assert np.allclose(calc_ftemp_inst_vcmax(tc), 1.5427221126407435) - - -@pytest.mark.parametrize( - argnames="tc,c4,expected", - argvalues=[ - (np.array([30]), False, 0.706), - (np.array([30]), True, 0.4183999999999998), - ], -) -def test_calc_ftemp_kphio(tc, c4, expected): - """Test calc_ftemp_inst_rd.""" - from pyrealm.pmodel.functions import calc_ftemp_kphio - - assert np.allclose(calc_ftemp_kphio(tc, c4), expected) - - def test_calc_gammastar(tc=np.array([30.0]), patm=np.array([123456])): """Test calc_ftemp_inst_rd.""" from pyrealm.pmodel.functions import calc_gammastar From 2467eb362b0669d0da4295abe07c3d850f4d0ecb Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 8 Aug 2024 11:02:36 +0100 Subject: [PATCH 054/241] Working out how to pass around arrhenius mode cleanly --- pyrealm/constants/pmodel_const.py | 6 ++++++ pyrealm/pmodel/functions.py | 14 +++++--------- pyrealm/pmodel/pmodel.py | 3 ++- pyrealm/pmodel/quantum_yield.py | 3 ++- tests/regression/pmodel/test_pmodel.py | 5 +++-- .../pmodel/test_sandoval_quantum_yield.py | 4 ++++ 6 files changed, 22 insertions(+), 13 deletions(-) diff --git a/pyrealm/constants/pmodel_const.py b/pyrealm/constants/pmodel_const.py index ea95ca16..932c97b1 100644 --- a/pyrealm/constants/pmodel_const.py +++ b/pyrealm/constants/pmodel_const.py @@ -101,6 +101,12 @@ class PModelConst(ConstantsClass): of the mean growth temperature (J/mol/K), the deactivation energy constant (J/mol) and the activation energy (J/mol). """ + modified_arrhenius_mode: str = "M2002" + """The calculation mode to use with the modified Arrhenius equation in + :func:`~pyrealm.pmodel.functions.calc_modified_arrhenius_factor`. This mode should + be consistently within an analysis, so forms part of the model constants. The two + options are ``M2002`` and ``J1942``, see :cite:t:`murphy:2021a` for details.""" + plant_T_ref: float = 25.0 """Standard baseline reference temperature of photosynthetic processes (Prentice, unpublished) (:math:`T_o` , 25.0, °C)""" diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index 64fdb566..24b88390 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -14,7 +14,7 @@ def calc_ftemp_arrh( tk: NDArray, ha: float | NDArray, - tk_ref: NDArray | None = None, + tk_ref: float | NDArray | None = None, pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), ) -> NDArray: @@ -124,9 +124,8 @@ def calc_modified_arrhenius_factor( Ha: float | NDArray, Hd: float | NDArray, deltaS: float | NDArray, + tk_ref: float | NDArray, mode: str = "M2002", - tk_ref: NDArray | None = None, - pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), ) -> NDArray: r"""Calculate the modified Arrhenius factor with temperature for an enzyme. @@ -136,9 +135,10 @@ def calc_modified_arrhenius_factor( used in the calculation of :math:`V_{cmax}` but also other temperature dependent enzymatic processes. - The function can operate in one of two modes ("M2002" or "J1942") using the two + The function can operate in one of two modes (``M2002`` or ``J1942``) using alternative derivations of the modified Arrhenius relationship presented in - :cite:`murphy:2021a`. + :cite:t:`murphy:2021a`. The ``J1942`` includes an additional factor (tk/tk_ref) that + is ommitted from the simpler ``M2002`` derivation. Args: tk: The temperature at which to calculate the factor (K) @@ -179,10 +179,6 @@ def calc_modified_arrhenius_factor( f"Unknown mode option for calc_modified_arrhenius_factor: {mode}" ) - # Convert temperatures to Kelvin - if tk_ref is None: - tk_ref = np.array([pmodel_const.plant_T_ref + core_const.k_CtoK]) - # Calculate Arrhenius components fva = calc_ftemp_arrh(tk=tk, ha=Ha, tk_ref=tk_ref) diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index ccfbd20a..aa62d631 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -383,8 +383,9 @@ def estimate_productivity( tk=self.env.tc + self.core_const.k_CtoK, Ha=kk_ha, Hd=kk_hd, + tk_ref=self.pmodel_const.plant_T_ref + self.core_const.k_CtoK, + mode=self.pmodel_const.modified_arrhenius_mode, deltaS=kk_deltaS, - pmodel_const=self.pmodel_const, core_const=self.core_const, ) self._vcmax25 = self._vcmax / ftemp25_inst_vcmax diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index 2ed797f6..63ece4be 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -342,8 +342,9 @@ def _calculate_kphio(self) -> None: Ha=Ha, Hd=Hd, deltaS=deltaS, - mode="J1942", tk_ref=Topt, + mode=self.env.pmodel_const.modified_arrhenius_mode, + core_const=self.env.core_const, ) # Apply the factor and store it. diff --git a/tests/regression/pmodel/test_pmodel.py b/tests/regression/pmodel/test_pmodel.py index 282eb5ad..0045424c 100644 --- a/tests/regression/pmodel/test_pmodel.py +++ b/tests/regression/pmodel/test_pmodel.py @@ -132,7 +132,7 @@ def test_calc_ftemp_inst_vcmax(values, tc, expvars): from pyrealm.constants import CoreConst, PModelConst from pyrealm.pmodel.functions import calc_modified_arrhenius_factor - pmodel_const = PModelConst() + pmodel_const = PModelConst(modified_arrhenius_mode="M2002") core_const = CoreConst() kk_a, kk_b, kk_ha, kk_hd = pmodel_const.kattge_knorr_kinetics @@ -145,8 +145,9 @@ def test_calc_ftemp_inst_vcmax(values, tc, expvars): tk=values[tc] + core_const.k_CtoK, Ha=kk_ha, Hd=kk_hd, + tk_ref=pmodel_const.plant_T_ref + core_const.k_CtoK, + mode=pmodel_const.modified_arrhenius_mode, deltaS=kk_deltaS, - pmodel_const=pmodel_const, core_const=core_const, ) diff --git a/tests/regression/pmodel/test_sandoval_quantum_yield.py b/tests/regression/pmodel/test_sandoval_quantum_yield.py index 231567b2..981c3f22 100644 --- a/tests/regression/pmodel/test_sandoval_quantum_yield.py +++ b/tests/regression/pmodel/test_sandoval_quantum_yield.py @@ -23,9 +23,12 @@ def values(): def test_QuantumYieldSandoval(values): """Check implementation against values from original R code.""" + from pyrealm.constants import PModelConst from pyrealm.pmodel import PModelEnvironment from pyrealm.pmodel.quantum_yield import QuantumYieldSandoval + # The reference implementation uses the J1942 derivation for the modified arrhenius + # equation. env = PModelEnvironment( tc=values["temp"].to_numpy(), patm=101325, @@ -33,6 +36,7 @@ def test_QuantumYieldSandoval(values): co2=400, mean_growth_temperature=values["mean_gdd_temp"].to_numpy(), aridity_index=values["aridity_index"].to_numpy(), + pmodel_const=PModelConst(modified_arrhenius_mode="J1942"), ) # Calculate kphio for that environment From 22daf340faa996d70630d592fb82106c30f72200 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 8 Aug 2024 11:59:25 +0100 Subject: [PATCH 055/241] Fixes from @j-emberton and then test and doctest snagging --- docs/source/refs.bib | 1 + .../pmodel/pmodel_details/extreme_values.md | 48 +++++++++++-------- .../subdaily_details/subdaily_calculations.md | 31 +++++++++++- pyrealm/constants/pmodel_const.py | 2 +- pyrealm/pmodel/functions.py | 11 +++-- pyrealm/pmodel/pmodel.py | 2 +- tests/unit/pmodel/test_quantum_yield.py | 6 +++ 7 files changed, 73 insertions(+), 28 deletions(-) diff --git a/docs/source/refs.bib b/docs/source/refs.bib index f7dc458b..700ff609 100644 --- a/docs/source/refs.bib +++ b/docs/source/refs.bib @@ -709,6 +709,7 @@ @article{sandoval:in_prep title = {Aridity and Growth Temperature Effects on Phio Manuscript}, author = {Sandoval, David}, year = {in\_prep}, + journal = {Placeholder}, volume = {?}, pages = {??-??} } diff --git a/docs/source/users/pmodel/pmodel_details/extreme_values.md b/docs/source/users/pmodel/pmodel_details/extreme_values.md index de08db01..7119ac7f 100644 --- a/docs/source/users/pmodel/pmodel_details/extreme_values.md +++ b/docs/source/users/pmodel/pmodel_details/extreme_values.md @@ -5,9 +5,8 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -54,26 +53,29 @@ Note that the default values for C3 photosynthesis give **non-zero values below ```{code-cell} :tags: [hide-input] +:trusted: true from matplotlib import pyplot import numpy as np -from pyrealm.pmodel import calc_ftemp_kphio, calc_gammastar, calc_kmm from pyrealm.core.water import calc_density_h2o +from pyrealm.pmodel import calc_gammastar, calc_kmm, PModelEnvironment +from pyrealm.pmodel.quantum_yield import QuantumYieldTemperature %matplotlib inline # Set the resolution of examples n_pts = 101 -# Create a range of representative values for temperature -tc_1d = np.linspace(-80, 100, n_pts) + +# Create environment containing a range of representative values for temperature +env = PModelEnvironment(tc=np.linspace(-25, 100, n_pts), patm=101325, vpd=820, co2=400) # Calculate temperature dependence of quantum yield efficiency -fkphio_c3 = calc_ftemp_kphio(tc_1d, c4=False) -fkphio_c4 = calc_ftemp_kphio(tc_1d, c4=True) +fkphio_c3 = QuantumYieldTemperature(env, use_c4=False) +fkphio_c4 = QuantumYieldTemperature(env, use_c4=True) # Create a line plot of ftemp kphio -pyplot.plot(tc_1d, fkphio_c3, label="C3") -pyplot.plot(tc_1d, fkphio_c4, label="C4") +pyplot.plot(env.tc, fkphio_c3.kphio, label="C3") +pyplot.plot(env.tc, fkphio_c4.kphio, label="C4") pyplot.title("Temperature dependence of quantum yield efficiency") pyplot.xlabel("Temperature °C") @@ -91,16 +93,22 @@ that again, $\Gamma^_$ has non-zero values for sub-zero temperatures. ```{code-cell} :tags: [hide-input] +:trusted: true # Calculate gammastar at different pressures +tc_1d = np.linspace(-80, 100, n_pts) + +# Create a contour plot of gamma +fig, ax = pyplot.subplots(1, 1) + for patm in [3, 7, 9, 11, 13]: pyplot.plot(tc_1d, calc_gammastar(tc_1d, patm * 1000), label=f"{patm} kPa") -# Create a contour plot of gamma -pyplot.title("Temperature and pressure dependence of $\Gamma^*$") -pyplot.xlabel("Temperature °C") -pyplot.ylabel("$\Gamma^*$") -pyplot.legend() +ax.set_title("Temperature and pressure dependence of $\Gamma^*$") +ax.set_xlabel("Temperature °C") +ax.set_ylabel("$\Gamma^*$") +ax.set_yscale("log") +ax.legend(frameon=False) pyplot.show() ``` @@ -111,9 +119,9 @@ temperature and atmospheric pressure and again behaves smoothly with extreme val ```{code-cell} :tags: [hide-input] +:trusted: true -fig = pyplot.figure() -ax = pyplot.gca() +fig, ax = pyplot.subplots(1, 1) # Calculate K_mm for patm in [3, 7, 9, 11, 13]: @@ -136,9 +144,9 @@ issue with low temperatures arising from the equations for the density of water. ```{code-cell} :tags: [hide-input] +:trusted: true -fig = pyplot.figure() -ax = pyplot.gca() +fig, ax = pyplot.subplots(1, 1) # Calculate rho for patm in [3, 7, 9, 11, 13]: @@ -161,9 +169,9 @@ predictions below about -30 °C. ```{code-cell} :tags: [hide-input] +:trusted: true -fig = pyplot.figure() -ax = pyplot.gca() +fig, ax = pyplot.subplots(1, 1) tc_1d = np.linspace(-40, 20, n_pts) diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md index 21664b8b..1a134c84 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md @@ -6,7 +6,7 @@ jupytext: format_name: myst format_version: 0.13 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -21,6 +21,7 @@ are handled internally by the model fitting in `pyrealm`. ```{code-cell} :tags: [hide-input] +:trusted: true from importlib import resources @@ -47,6 +48,8 @@ site](https://fluxnet.org/doi/FLUXNET2015/BE-Vie), which was also used as a demonstration in {cite:t}`mengoli:2022a`. ```{code-cell} +:trusted: true + data_path = resources.files("pyrealm_build_data.subdaily") / "subdaily_BE_Vie_2014.csv" data = pandas.read_csv(str(data_path)) @@ -68,6 +71,8 @@ subdaily timescale. The code below also estimates GPP under the standard P Model slow responses for comparison. ```{code-cell} +:trusted: true + # Calculate the photosynthetic environment subdaily_env = PModelEnvironment( tc=temp_subdaily, @@ -94,6 +99,8 @@ conditions at the observation closest to noon, or the mean environmental conditi window around noon. ```{code-cell} +:trusted: true + # Create the fast slow scaler fsscaler = SubdailyScaler(datetime_subdaily) @@ -115,6 +122,7 @@ pmodel_subdaily = SubdailyPModel( ```{code-cell} :tags: [hide-input] +:trusted: true idx = np.arange(48 * 120, 48 * 130) plt.figure(figsize=(10, 4)) @@ -138,6 +146,8 @@ inputs to the standard P Model to calculate the optimal behaviour of plants unde conditions. ```{code-cell} +:trusted: true + # Get the daily acclimation conditions for the forcing variables temp_acclim = fsscaler.get_daily_means(temp_subdaily) co2_acclim = fsscaler.get_daily_means(co2_subdaily) @@ -151,7 +161,7 @@ daily_acclim_env = PModelEnvironment( tc=temp_acclim, vpd=vpd_acclim, co2=co2_acclim, patm=patm_acclim ) -pmodel_acclim = PModel(daily_acclim_env, kphio=1 / 8) +pmodel_acclim = PModel(daily_acclim_env, reference_kphio=1 / 8) pmodel_acclim.estimate_productivity(fapar=fapar_acclim, ppfd=ppfd_acclim) ``` @@ -169,6 +179,8 @@ at 25°C. This is acheived by multiplying by the reciprocal of the exponential p the Arrhenius equation ($h^{-1}$ in {cite}`mengoli:2022a`). ```{code-cell} +:trusted: true + # Are these any of the existing values in the constants? ha_vcmax25 = 65330 ha_jmax25 = 43900 @@ -184,6 +196,8 @@ The memory effect can now be applied to the three parameters with slow responses to calculate realised values, here using the default 15 day window. ```{code-cell} +:trusted: true + # Calculation of memory effect in xi, vcmax25 and jmax25 xi_real = memory_effect(pmodel_acclim.optchi.xi, alpha=1 / 15) vcmax25_real = memory_effect(vcmax25_acclim, alpha=1 / 15, allow_holdover=True) @@ -196,6 +210,7 @@ application of the memory effect. ```{code-cell} :tags: [hide-input] +:trusted: true fig, axes = plt.subplots(1, 3, figsize=(16, 5)) @@ -229,6 +244,8 @@ temperature at fast scales: responses of $J_{max}$ and $V_{cmax}$. ```{code-cell} +:trusted: true + tk_subdaily = subdaily_env.tc + pmodel_subdaily.env.core_const.k_CtoK # Fill the realised jmax and vcmax from subdaily to daily @@ -249,6 +266,8 @@ optimal $\chi$, rather than calculating the instantaneously optimal values of $\ as is the case in the standard P Model. ```{code-cell} +:trusted: true + # Interpolate xi to subdaily scale xi_subdaily = fsscaler.fill_daily_to_subdaily(xi_real) @@ -268,6 +287,8 @@ include the slow responses of $V_{cmax25}$ and $J_{max25}$ and fast responses to temperature. ```{code-cell} +:trusted: true + # Calculate Ac Ac_subdaily = ( vcmax_subdaily @@ -296,3 +317,9 @@ GPP_subdaily = ( diff = GPP_subdaily - pmodel_subdaily.gpp print(np.nanmin(diff), np.nanmax(diff)) ``` + +```{code-cell} +:trusted: true + + +``` diff --git a/pyrealm/constants/pmodel_const.py b/pyrealm/constants/pmodel_const.py index 932c97b1..5e3746a6 100644 --- a/pyrealm/constants/pmodel_const.py +++ b/pyrealm/constants/pmodel_const.py @@ -96,7 +96,7 @@ class PModelConst(ConstantsClass): 75000.0, ) """Enzyme kinetics parameters for estimation of kphio from mean growth temperature - in the Sandoval method :cite:t:`Sandoval:in_prep` for estimation of quantum yield + in the Sandoval method :cite:t:`sandoval:in_prep` for estimation of quantum yield efficiency. Values are: the intercept and slope of activation entropy as a function of the mean growth temperature (J/mol/K), the deactivation energy constant (J/mol) and the activation energy (J/mol). """ diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index 24b88390..69f4c98e 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -48,7 +48,10 @@ def calc_ftemp_arrh( Args: tk: Temperature (K) ha: Activation energy (in :math:`J \text{mol}^{-1}`) - tk_ref: The reference temperature for the reaction (K). + tk_ref: The reference temperature for the reaction (K). Optional, defaulting to + the value of + :attr:`PModelConst.plant_T_ref` + expressed in Kelvin. pmodel_const: Instance of :class:`~pyrealm.constants.pmodel_const.PModelConst`. core_const: Instance of :class:`~pyrealm.constants.core_const.CoreConst`. @@ -109,7 +112,7 @@ def calc_ftemp_inst_rd( Examples: >>> # Relative percentage instantaneous change in Rd going from 10 to 25 degrees >>> val = (calc_ftemp_inst_rd(25) / calc_ftemp_inst_rd(10) - 1) * 100 - >>> round(val, 4) + >>> np.round(val, 4) np.float64(250.9593) """ @@ -168,10 +171,10 @@ def calc_modified_arrhenius_factor( >>> deltaS = a + b * 10 >>> # Calculate the arrhenius factor >>> val = calc_modified_arrhenius_factor( - ... tk= 283.15, Ha=ha, Hd=hd, deltaS=deltaS + ... tk= 10 + 273.15, Ha=ha, Hd=hd, deltaS=deltaS, tk_ref=25 +273.15 ... ) >>> np.round(val, 4) - array([0.261]) + np.float64(0.261) """ if mode not in ["M2002", "J1942"]: diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index aa62d631..c3ce20ca 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -184,7 +184,7 @@ def __init__( """The CoreConst instance used to create the model environment.""" # ----------------------------------------------------------------------- - # Optimal ci + # Optimal chi # The heart of the P-model: calculate ci:ca ratio (chi) and additional terms # ----------------------------------------------------------------------- diff --git a/tests/unit/pmodel/test_quantum_yield.py b/tests/unit/pmodel/test_quantum_yield.py index a375a0ca..08dd8577 100644 --- a/tests/unit/pmodel/test_quantum_yield.py +++ b/tests/unit/pmodel/test_quantum_yield.py @@ -7,8 +7,13 @@ @pytest.fixture def quantum_yield_env(): """Simple fixture for providing the quantum yield inputs.""" + from pyrealm.constants import PModelConst from pyrealm.pmodel import PModelEnvironment + # The referene implementation uses the J1942 derivation for the arrhenius + # calculation + pmodel_const = PModelConst(modified_arrhenius_mode="J1942") + return PModelEnvironment( tc=np.array([5, 10, 15, 20, 25, 30]), patm=101325, @@ -16,6 +21,7 @@ def quantum_yield_env(): co2=400, mean_growth_temperature=np.array([10, 20, 10, 20, 10, 20]), aridity_index=np.array([0.9, 0.9, 2, 2, 5, 5]), + pmodel_const=pmodel_const, ) From 1ee9a5be85033a3dffcbc37deb3689584528605a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:00:30 +0000 Subject: [PATCH 056/241] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/source/api/constants_api.md | 1 - docs/source/api/core_api.md | 1 - docs/source/api/splash_api.md | 1 - docs/source/api/tmodel_api.md | 1 - docs/source/conf.py | 19 +++++++++++++++++++ docs/source/development/code_qa_and_typing.md | 1 - docs/source/development/code_testing.md | 1 - docs/source/development/documentation.md | 1 - docs/source/development/github_actions.md | 1 - docs/source/development/overview.md | 1 - .../development/profiling_and_benchmarking.md | 1 - docs/source/development/pyrealm_build_data.md | 1 - docs/source/development/release_process.md | 1 - docs/source/index.md | 1 - docs/source/users/constants.md | 1 - docs/source/users/hygro.md | 1 - docs/source/users/pmodel/c3c4model.md | 1 - .../users/pmodel/isotopic_discrimination.md | 1 - .../pmodel_details/envt_variation_outputs.md | 1 - .../pmodel/pmodel_details/optimal_chi.md | 1 - .../photosynthetic_environment.md | 1 - .../users/pmodel/pmodel_details/rpmodel.md | 1 - .../pmodel/pmodel_details/soil_moisture.md | 1 - .../pmodel/subdaily_details/acclimation.md | 1 - .../subdaily_model_and_missing_data.md | 1 - .../subdaily_details/subdaily_overview.md | 1 - docs/source/users/splash.md | 1 - docs/source/users/tmodel/tmodel.md | 1 - 28 files changed, 19 insertions(+), 27 deletions(-) diff --git a/docs/source/api/constants_api.md b/docs/source/api/constants_api.md index 80bd4ba2..1b992418 100644 --- a/docs/source/api/constants_api.md +++ b/docs/source/api/constants_api.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/core_api.md b/docs/source/api/core_api.md index 89843589..1324720e 100644 --- a/docs/source/api/core_api.md +++ b/docs/source/api/core_api.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/splash_api.md b/docs/source/api/splash_api.md index e8177ab3..fe55c923 100644 --- a/docs/source/api/splash_api.md +++ b/docs/source/api/splash_api.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/tmodel_api.md b/docs/source/api/tmodel_api.md index d74b7989..b7fa9312 100644 --- a/docs/source/api/tmodel_api.md +++ b/docs/source/api/tmodel_api.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/conf.py b/docs/source/conf.py index 73f896ad..f0f487c5 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,3 +1,14 @@ +# --- +# jupyter: +# jupytext: +# cell_metadata_filter: all +# notebook_metadata_filter: -jupytext.text_representation.jupytext_version,settings,mystnb +# text_representation: +# extension: .py +# format_name: light +# format_version: '1.5' +# --- + """Configure the Sphinx documentation builder. -- Path setup -------------------------------------------------------------- @@ -18,7 +29,9 @@ from pyrealm import __version__ as pyrealm_version +# + sys.path.insert(0, os.path.abspath("../")) +# - # -- Project information ----------------------------------------------------- @@ -55,7 +68,9 @@ external_toc_path = "_toc.yml" # optional, default: _toc.yml external_toc_exclude_missing = False # optional, default: False +# + [markdown] # Citation styling +# - def bracket_style() -> BracketStyle: @@ -142,6 +157,7 @@ class MyReferenceStyle(AuthorYearReferenceStyle): ), ] +# + intersphinx_mapping = { "pytest": ("https://docs.pytest.org/en/stable/", None), "numpy": ("https://numpy.org/doc/stable/", None), @@ -149,6 +165,7 @@ class MyReferenceStyle(AuthorYearReferenceStyle): "xarray": ("https://docs.xarray.dev/en/stable/", None), "shapely": ("https://shapely.readthedocs.io/en/stable/", None), } +# - autodoc_default_flags = ["members"] @@ -195,6 +212,7 @@ class MyReferenceStyle(AuthorYearReferenceStyle): # html_theme = 'sphinx_material' html_theme = "sphinx_rtd_theme" +# + html_theme_options = { "logo_only": False, "display_version": True, @@ -208,6 +226,7 @@ class MyReferenceStyle(AuthorYearReferenceStyle): "includehidden": True, "titles_only": False, } +# - # Add any paths that contain custom static files (such as style sheets) here, diff --git a/docs/source/development/code_qa_and_typing.md b/docs/source/development/code_qa_and_typing.md index b951cd8a..848f7a5c 100644 --- a/docs/source/development/code_qa_and_typing.md +++ b/docs/source/development/code_qa_and_typing.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/code_testing.md b/docs/source/development/code_testing.md index 9d126f5a..43829394 100644 --- a/docs/source/development/code_testing.md +++ b/docs/source/development/code_testing.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/documentation.md b/docs/source/development/documentation.md index cbe8cc3f..0ce6b2f8 100644 --- a/docs/source/development/documentation.md +++ b/docs/source/development/documentation.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/github_actions.md b/docs/source/development/github_actions.md index fda8ad3d..d26a7452 100644 --- a/docs/source/development/github_actions.md +++ b/docs/source/development/github_actions.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/overview.md b/docs/source/development/overview.md index 72207d53..837b1efe 100644 --- a/docs/source/development/overview.md +++ b/docs/source/development/overview.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/profiling_and_benchmarking.md b/docs/source/development/profiling_and_benchmarking.md index ccafd4f3..d705d43f 100644 --- a/docs/source/development/profiling_and_benchmarking.md +++ b/docs/source/development/profiling_and_benchmarking.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/pyrealm_build_data.md b/docs/source/development/pyrealm_build_data.md index 0f9dd7c1..b59ec2b2 100644 --- a/docs/source/development/pyrealm_build_data.md +++ b/docs/source/development/pyrealm_build_data.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/release_process.md b/docs/source/development/release_process.md index 9396484c..e9ff6b00 100644 --- a/docs/source/development/release_process.md +++ b/docs/source/development/release_process.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/index.md b/docs/source/index.md index 10234635..43aef59b 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/constants.md b/docs/source/users/constants.md index 7997e3a9..899076b3 100644 --- a/docs/source/users/constants.md +++ b/docs/source/users/constants.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/hygro.md b/docs/source/users/hygro.md index 39322beb..a235875e 100644 --- a/docs/source/users/hygro.md +++ b/docs/source/users/hygro.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/c3c4model.md b/docs/source/users/pmodel/c3c4model.md index 4a400e50..ac4ba204 100644 --- a/docs/source/users/pmodel/c3c4model.md +++ b/docs/source/users/pmodel/c3c4model.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/isotopic_discrimination.md b/docs/source/users/pmodel/isotopic_discrimination.md index 5020de17..574b2f67 100644 --- a/docs/source/users/pmodel/isotopic_discrimination.md +++ b/docs/source/users/pmodel/isotopic_discrimination.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md b/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md index eae62e95..e7364837 100644 --- a/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md +++ b/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/optimal_chi.md b/docs/source/users/pmodel/pmodel_details/optimal_chi.md index 4c794fe0..fb22b49e 100644 --- a/docs/source/users/pmodel/pmodel_details/optimal_chi.md +++ b/docs/source/users/pmodel/pmodel_details/optimal_chi.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md b/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md index adbbca1a..cedd27fe 100644 --- a/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md +++ b/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/rpmodel.md b/docs/source/users/pmodel/pmodel_details/rpmodel.md index f2b4eb93..7e691cc2 100644 --- a/docs/source/users/pmodel/pmodel_details/rpmodel.md +++ b/docs/source/users/pmodel/pmodel_details/rpmodel.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/soil_moisture.md b/docs/source/users/pmodel/pmodel_details/soil_moisture.md index afe55613..2b4b8a53 100644 --- a/docs/source/users/pmodel/pmodel_details/soil_moisture.md +++ b/docs/source/users/pmodel/pmodel_details/soil_moisture.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/acclimation.md b/docs/source/users/pmodel/subdaily_details/acclimation.md index 09512e49..193b38f9 100644 --- a/docs/source/users/pmodel/subdaily_details/acclimation.md +++ b/docs/source/users/pmodel/subdaily_details/acclimation.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md b/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md index 5f1e995b..881f71b8 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_overview.md b/docs/source/users/pmodel/subdaily_details/subdaily_overview.md index 31234000..3278b056 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_overview.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_overview.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/splash.md b/docs/source/users/splash.md index e852f49c..e5c4d283 100644 --- a/docs/source/users/splash.md +++ b/docs/source/users/splash.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/tmodel/tmodel.md b/docs/source/users/tmodel/tmodel.md index ca6c5eec..fda39de0 100644 --- a/docs/source/users/tmodel/tmodel.md +++ b/docs/source/users/tmodel/tmodel.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python From d00331e40d677e8f8a1aa9f8b3ecd48b0caa1ae3 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 8 Aug 2024 12:19:04 +0100 Subject: [PATCH 057/241] Do _not_ jupytext the Sphinx conf.py --- .pre-commit-config.yaml | 3 ++- docs/source/conf.py | 11 ----------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 278a608b..977a7f45 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,7 +29,8 @@ repos: hooks: - id: jupytext args: [--pipe, black] - files: docs/source + files: docs/source + exclude: docs/source/conf.py additional_dependencies: - black==24.4.2 # Matches hook \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index f0f487c5..3921eba7 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,14 +1,3 @@ -# --- -# jupyter: -# jupytext: -# cell_metadata_filter: all -# notebook_metadata_filter: -jupytext.text_representation.jupytext_version,settings,mystnb -# text_representation: -# extension: .py -# format_name: light -# format_version: '1.5' -# --- - """Configure the Sphinx documentation builder. -- Path setup -------------------------------------------------------------- From 9e3d36d326bbcdfdd5aee00218e5b72877f2b8fa Mon Sep 17 00:00:00 2001 From: Surbhi Goel Date: Tue, 20 Aug 2024 12:44:53 +0100 Subject: [PATCH 058/241] Added init_realised in the docstring of SubdailyPModel and Updated poetry.lock --- poetry.lock | 516 +++++++++++++++++++------------------ pyrealm/pmodel/subdaily.py | 4 +- 2 files changed, 268 insertions(+), 252 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1309d393..dbfef49f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -187,13 +187,13 @@ Sphinx = ">=2.2,<9.0" [[package]] name = "babel" -version = "2.15.0" +version = "2.16.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" files = [ - {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, - {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, ] [package.extras] @@ -1119,13 +1119,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "8.2.0" +version = "8.3.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"}, - {file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"}, + {file = "importlib_metadata-8.3.0-py3-none-any.whl", hash = "sha256:42817a4a0be5845d22c6e212db66a94ad261e2318d80b3e0d363894a79df2b67"}, + {file = "importlib_metadata-8.3.0.tar.gz", hash = "sha256:9c8fa6e8ea0f9516ad5c8db9246a731c948193c7754d3babb0114a05b27dd364"}, ] [package.dependencies] @@ -1831,40 +1831,51 @@ files = [ [[package]] name = "matplotlib" -version = "3.9.1.post1" +version = "3.9.2" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.9.1.post1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3779ad3e8b72df22b8a622c5796bbcfabfa0069b835412e3c1dec8ee3de92d0c"}, - {file = "matplotlib-3.9.1.post1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec400340f8628e8e2260d679078d4e9b478699f386e5cc8094e80a1cb0039c7c"}, - {file = "matplotlib-3.9.1.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82c18791b8862ea095081f745b81f896b011c5a5091678fb33204fef641476af"}, - {file = "matplotlib-3.9.1.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:621a628389c09a6b9f609a238af8e66acecece1cfa12febc5fe4195114ba7446"}, - {file = "matplotlib-3.9.1.post1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9a54734ca761ebb27cd4f0b6c2ede696ab6861052d7d7e7b8f7a6782665115f5"}, - {file = "matplotlib-3.9.1.post1-cp310-cp310-win_amd64.whl", hash = "sha256:0721f93db92311bb514e446842e2b21c004541dcca0281afa495053e017c5458"}, - {file = "matplotlib-3.9.1.post1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b08b46058fe2a31ecb81ef6aa3611f41d871f6a8280e9057cb4016cb3d8e894a"}, - {file = "matplotlib-3.9.1.post1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:22b344e84fcc574f561b5731f89a7625db8ef80cdbb0026a8ea855a33e3429d1"}, - {file = "matplotlib-3.9.1.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b49fee26d64aefa9f061b575f0f7b5fc4663e51f87375c7239efa3d30d908fa"}, - {file = "matplotlib-3.9.1.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89eb7e89e2b57856533c5c98f018aa3254fa3789fcd86d5f80077b9034a54c9a"}, - {file = "matplotlib-3.9.1.post1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c06e742bade41fda6176d4c9c78c9ea016e176cd338e62a1686384cb1eb8de41"}, - {file = "matplotlib-3.9.1.post1-cp311-cp311-win_amd64.whl", hash = "sha256:c44edab5b849e0fc1f1c9d6e13eaa35ef65925f7be45be891d9784709ad95561"}, - {file = "matplotlib-3.9.1.post1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:bf28b09986aee06393e808e661c3466be9c21eff443c9bc881bce04bfbb0c500"}, - {file = "matplotlib-3.9.1.post1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:92aeb8c439d4831510d8b9d5e39f31c16c7f37873879767c26b147cef61e54cd"}, - {file = "matplotlib-3.9.1.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f15798b0691b45c80d3320358a88ce5a9d6f518b28575b3ea3ed31b4bd95d009"}, - {file = "matplotlib-3.9.1.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d59fc6096da7b9c1df275f9afc3fef5cbf634c21df9e5f844cba3dd8deb1847d"}, - {file = "matplotlib-3.9.1.post1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ab986817a32a70ce22302438691e7df4c6ee4a844d47289db9d583d873491e0b"}, - {file = "matplotlib-3.9.1.post1-cp312-cp312-win_amd64.whl", hash = "sha256:0d78e7d2d86c4472da105d39aba9b754ed3dfeaeaa4ac7206b82706e0a5362fa"}, - {file = "matplotlib-3.9.1.post1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bd07eba6431b4dc9253cce6374a28c415e1d3a7dc9f8aba028ea7592f06fe172"}, - {file = "matplotlib-3.9.1.post1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ca230cc4482010d646827bd2c6d140c98c361e769ae7d954ebf6fff2a226f5b1"}, - {file = "matplotlib-3.9.1.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ace27c0fdeded399cbc43f22ffa76e0f0752358f5b33106ec7197534df08725a"}, - {file = "matplotlib-3.9.1.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a4f3aeb7ba14c497dc6f021a076c48c2e5fbdf3da1e7264a5d649683e284a2f"}, - {file = "matplotlib-3.9.1.post1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:23f96fbd4ff4cfa9b8a6b685a65e7eb3c2ced724a8d965995ec5c9c2b1f7daf5"}, - {file = "matplotlib-3.9.1.post1-cp39-cp39-win_amd64.whl", hash = "sha256:2808b95452b4ffa14bfb7c7edffc5350743c31bda495f0d63d10fdd9bc69e895"}, - {file = "matplotlib-3.9.1.post1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ffc91239f73b4179dec256b01299d46d0ffa9d27d98494bc1476a651b7821cbe"}, - {file = "matplotlib-3.9.1.post1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f965ebca9fd4feaaca45937c4849d92b70653057497181100fcd1e18161e5f29"}, - {file = "matplotlib-3.9.1.post1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:801ee9323fd7b2da0d405aebbf98d1da77ea430bbbbbec6834c0b3af15e5db44"}, - {file = "matplotlib-3.9.1.post1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:50113e9b43ceb285739f35d43db36aa752fb8154325b35d134ff6e177452f9ec"}, - {file = "matplotlib-3.9.1.post1.tar.gz", hash = "sha256:c91e585c65092c975a44dc9d4239ba8c594ba3c193d7c478b6d178c4ef61f406"}, + {file = "matplotlib-3.9.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9d78bbc0cbc891ad55b4f39a48c22182e9bdaea7fc0e5dbd364f49f729ca1bbb"}, + {file = "matplotlib-3.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c375cc72229614632c87355366bdf2570c2dac01ac66b8ad048d2dabadf2d0d4"}, + {file = "matplotlib-3.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d94ff717eb2bd0b58fe66380bd8b14ac35f48a98e7c6765117fe67fb7684e64"}, + {file = "matplotlib-3.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab68d50c06938ef28681073327795c5db99bb4666214d2d5f880ed11aeaded66"}, + {file = "matplotlib-3.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:65aacf95b62272d568044531e41de26285d54aec8cb859031f511f84bd8b495a"}, + {file = "matplotlib-3.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:3fd595f34aa8a55b7fc8bf9ebea8aa665a84c82d275190a61118d33fbc82ccae"}, + {file = "matplotlib-3.9.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8dd059447824eec055e829258ab092b56bb0579fc3164fa09c64f3acd478772"}, + {file = "matplotlib-3.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c797dac8bb9c7a3fd3382b16fe8f215b4cf0f22adccea36f1545a6d7be310b41"}, + {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d719465db13267bcef19ea8954a971db03b9f48b4647e3860e4bc8e6ed86610f"}, + {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8912ef7c2362f7193b5819d17dae8629b34a95c58603d781329712ada83f9447"}, + {file = "matplotlib-3.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7741f26a58a240f43bee74965c4882b6c93df3e7eb3de160126d8c8f53a6ae6e"}, + {file = "matplotlib-3.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae82a14dab96fbfad7965403c643cafe6515e386de723e498cf3eeb1e0b70cc7"}, + {file = "matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9"}, + {file = "matplotlib-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d"}, + {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7"}, + {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c"}, + {file = "matplotlib-3.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e"}, + {file = "matplotlib-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3"}, + {file = "matplotlib-3.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9"}, + {file = "matplotlib-3.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa"}, + {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b"}, + {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413"}, + {file = "matplotlib-3.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b"}, + {file = "matplotlib-3.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49"}, + {file = "matplotlib-3.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03"}, + {file = "matplotlib-3.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30"}, + {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51"}, + {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c"}, + {file = "matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e"}, + {file = "matplotlib-3.9.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:cef2a73d06601437be399908cf13aee74e86932a5ccc6ccdf173408ebc5f6bb2"}, + {file = "matplotlib-3.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e0830e188029c14e891fadd99702fd90d317df294c3298aad682739c5533721a"}, + {file = "matplotlib-3.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ba9c1299c920964e8d3857ba27173b4dbb51ca4bab47ffc2c2ba0eb5e2cbc5"}, + {file = "matplotlib-3.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cd93b91ab47a3616b4d3c42b52f8363b88ca021e340804c6ab2536344fad9ca"}, + {file = "matplotlib-3.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6d1ce5ed2aefcdce11904fc5bbea7d9c21fff3d5f543841edf3dea84451a09ea"}, + {file = "matplotlib-3.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:b2696efdc08648536efd4e1601b5fd491fd47f4db97a5fbfd175549a7365c1b2"}, + {file = "matplotlib-3.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d52a3b618cb1cbb769ce2ee1dcdb333c3ab6e823944e9a2d36e37253815f9556"}, + {file = "matplotlib-3.9.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:039082812cacd6c6bec8e17a9c1e6baca230d4116d522e81e1f63a74d01d2e21"}, + {file = "matplotlib-3.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6758baae2ed64f2331d4fd19be38b7b4eae3ecec210049a26b6a4f3ae1c85dcc"}, + {file = "matplotlib-3.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:050598c2b29e0b9832cde72bcf97627bf00262adbc4a54e2b856426bb2ef0697"}, + {file = "matplotlib-3.9.2.tar.gz", hash = "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92"}, ] [package.dependencies] @@ -2168,36 +2179,36 @@ files = [ [[package]] name = "netcdf4" -version = "1.7.1.post1" +version = "1.7.1.post2" description = "Provides an object-oriented python interface to the netCDF version 4 library" optional = false python-versions = ">=3.8" files = [ - {file = "netCDF4-1.7.1.post1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5abdc8ab27bcb11325547841311717a0ba8f5b73a5fc5e93b933bc23285d0c03"}, - {file = "netCDF4-1.7.1.post1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:33f5d66ee9cedf43d3932d0e5447eb471f9c53332f93476133b4bfc6b682f790"}, - {file = "netCDF4-1.7.1.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d649fad9d1f63e25a191576c7de158c8c3afa8d4b4001e8683e20da90b49b939"}, - {file = "netCDF4-1.7.1.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:860222bc57bbc714e55705f263162be2c935129dcb700a944bda61aee785ff03"}, - {file = "netCDF4-1.7.1.post1-cp310-cp310-win_amd64.whl", hash = "sha256:d5420155ca6c768c070922d80acd9f4088a913afd25a9fd2f429e7af626374eb"}, - {file = "netCDF4-1.7.1.post1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:a8d3209516aa8c58d70863ab1059af4ec82ef8ecb1c6b8cb4842d7825a6f64da"}, - {file = "netCDF4-1.7.1.post1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:7a10da9b60d3358876d53a0cd691d2c900c2b39903bf25ad5235fd321d59eb2f"}, - {file = "netCDF4-1.7.1.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac99e03d6e28419b206444fd6dc80a5e21d0ae8e53ff37d756fbc16c5d3775"}, - {file = "netCDF4-1.7.1.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e15f3afa4e6910fc158a318ea73fdc6f9e41058c71bf98a99fd63994334d16b0"}, - {file = "netCDF4-1.7.1.post1-cp311-cp311-win_amd64.whl", hash = "sha256:115160fc8e09333754542c33d721d42625a7bd62381a74f2f759297e3e38810b"}, - {file = "netCDF4-1.7.1.post1-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:75bba24ef0354fb6913bc3acdcb3790534e86bf329bbeaaf54122b18e5fd05ea"}, - {file = "netCDF4-1.7.1.post1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ce7f89b98dbb3acd9582db30e6478ce7a7003b2cb70dc20d85fe9506e65ab001"}, - {file = "netCDF4-1.7.1.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac4e30a0d5a8e227d6a890502cfa201388acf606c0c73a5a7594232f3a74e67e"}, - {file = "netCDF4-1.7.1.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:988c45f9122337a12267fb158953c0609e3ea50a557335a3105f104416a4821a"}, - {file = "netCDF4-1.7.1.post1-cp312-cp312-win_amd64.whl", hash = "sha256:8fb3ed3541fa1b5b46e9d92d7e803734a1a3f37d8f5adf5fdf7957c7750cb20e"}, - {file = "netCDF4-1.7.1.post1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:a4d05cc4c3628a7b88d623cb1a02908100a4938335a0289fa79c19016c21d7f9"}, - {file = "netCDF4-1.7.1.post1-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:3a9ba8dc93f3d9019db921e42d40fa6791e7e244f3bb3a874bf2bfb96aea7380"}, - {file = "netCDF4-1.7.1.post1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fbbca82a822ba74b605254f7a267d258f13d67f8a4156a09e26322bfa002a82d"}, - {file = "netCDF4-1.7.1.post1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a09da245f4784421fb4d5740dae0367cdbb270d0a931a33474ec17a9433314d"}, - {file = "netCDF4-1.7.1.post1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:fdcec3a3150f9248e76301ad723f51955efc770edf015dfb61a6480cc7c04a70"}, - {file = "netCDF4-1.7.1.post1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:0fed0eb65a7751a99a0cee08c6df383737d46d17c73cabae81d113f1b4fa3643"}, - {file = "netCDF4-1.7.1.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daa6169fe6617a4612cb75a8ef61ee14011a012633ad1ace1b629a1ff87bf5cf"}, - {file = "netCDF4-1.7.1.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcad21e965978cc5530131bd7e73dcabe7dda1f681f9e4ebf940a65a176d25fe"}, - {file = "netCDF4-1.7.1.post1-cp39-cp39-win_amd64.whl", hash = "sha256:f24027ae19b68cc1274aad8b00d6d81879d506ddca011a080dff2117014398b9"}, - {file = "netcdf4-1.7.1.post1.tar.gz", hash = "sha256:797f0b25d87827fc6821e415d9e15a2068604b18c3be62563e72682bcba76548"}, + {file = "netCDF4-1.7.1.post2-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:a1006ae117a754e3cf41a9e704032bf3837cbf53a695cd71deaad3e02e93d570"}, + {file = "netCDF4-1.7.1.post2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:7530d60cf6450d997ea0607f8b68b9b088f2382c42648cddf5e66e6f1280b692"}, + {file = "netCDF4-1.7.1.post2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:756a54cb212c9fc5d0ea74f7c661621821138ab8f63e818317330330cfd6165c"}, + {file = "netCDF4-1.7.1.post2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:156428fc63e2280e8bcab7f49531cde19fbba192c2ffdfb352c6a3f5e813a80b"}, + {file = "netCDF4-1.7.1.post2-cp310-cp310-win_amd64.whl", hash = "sha256:79d890ade8b8646bb2833c2b9565392cdf5e97e016cf0319693d13bd8c2dd511"}, + {file = "netCDF4-1.7.1.post2-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:b2700bd0a188637b740aa6ad09dbf9d21337fb1e0336f9859c2c6e9525404cc0"}, + {file = "netCDF4-1.7.1.post2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:914e210f76c4ce016aed32ba7dfad57e6316a38502bdcbd071fc74ee8fec73ec"}, + {file = "netCDF4-1.7.1.post2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a98731d88889e41e9a92d67cad8ac9d9c4acba612a999db803bd082384462dea"}, + {file = "netCDF4-1.7.1.post2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6369ed38ffd094fce44e066d0823b6420205d5825a715fe048146052b299754c"}, + {file = "netCDF4-1.7.1.post2-cp311-cp311-win_amd64.whl", hash = "sha256:9fe939ad543371b5ea46864ba6ac88532b2189ce139804b3187c241eb89a02a6"}, + {file = "netCDF4-1.7.1.post2-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:658f38ceb74bb127e293a47fa36f949babba0c872cf3091e2fdafa73caacc7e4"}, + {file = "netCDF4-1.7.1.post2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5f396f150f97831229e47f449fe6acbca8ff9d08b2166560c46790aa6f11b56b"}, + {file = "netCDF4-1.7.1.post2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d5216369a0a4a868dadb5c4137d854810a309b9f9ef1d16786269fbeb244101"}, + {file = "netCDF4-1.7.1.post2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12f8ab560320e879763b7837d6f8f5eb285195271f47fc5c18362e5b097ee67c"}, + {file = "netCDF4-1.7.1.post2-cp312-cp312-win_amd64.whl", hash = "sha256:2cbca7dcd92075aebe7c242e16f51f20bc5073b6f0f1449394dadc3c17e44b29"}, + {file = "netCDF4-1.7.1.post2-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:13dc0d3fa4d46e531f32fa0bb4068bdac35513114b9548ea49f92e85d9702afb"}, + {file = "netCDF4-1.7.1.post2-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:f040aecec09a44388e1469725d471e8f1d491d4b70b27c8b2d45fd47db4e8abc"}, + {file = "netCDF4-1.7.1.post2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0691d20fcc2d41cd0a15ef335a4f038ccaf07c013c4c79ad3e39993cac3c9bbb"}, + {file = "netCDF4-1.7.1.post2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa22721d9860181c03506c6d718b3a9daf8d07dcb35a466b376760f8eddfffe5"}, + {file = "netCDF4-1.7.1.post2-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:d92bd60dc2b4beba293d81912f3094b2854e9f492ce5e9b4a3ad4fbd725a29e8"}, + {file = "netCDF4-1.7.1.post2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:d8c015cd8c8582b351d715aed4c17da2e68493edaa59e91f6cf12756479fbd53"}, + {file = "netCDF4-1.7.1.post2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bc8ca705e39ac9f4d3950c908867d377f789e5bcc6f94e0a2bdadc4c4612f94"}, + {file = "netCDF4-1.7.1.post2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fef5b27a2325a50ec59793c96e5b1e9945061a390c1ea33d403ed91b7a2fb4"}, + {file = "netCDF4-1.7.1.post2-cp39-cp39-win_amd64.whl", hash = "sha256:294b24234fb71ee30640a451ed1428da3569f23383d35f905558093795f3609a"}, + {file = "netcdf4-1.7.1.post2.tar.gz", hash = "sha256:37d557e36654889d7020192bfb56f9d5f93894cb32997eb837ae586c538fd7b6"}, ] [package.dependencies] @@ -2238,56 +2249,63 @@ test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync" [[package]] name = "numpy" -version = "2.0.1" +version = "2.1.0" description = "Fundamental package for array computing in Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "numpy-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fbb536eac80e27a2793ffd787895242b7f18ef792563d742c2d673bfcb75134"}, - {file = "numpy-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:69ff563d43c69b1baba77af455dd0a839df8d25e8590e79c90fcbe1499ebde42"}, - {file = "numpy-2.0.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:1b902ce0e0a5bb7704556a217c4f63a7974f8f43e090aff03fcf262e0b135e02"}, - {file = "numpy-2.0.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:f1659887361a7151f89e79b276ed8dff3d75877df906328f14d8bb40bb4f5101"}, - {file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4658c398d65d1b25e1760de3157011a80375da861709abd7cef3bad65d6543f9"}, - {file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4127d4303b9ac9f94ca0441138acead39928938660ca58329fe156f84b9f3015"}, - {file = "numpy-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e5eeca8067ad04bc8a2a8731183d51d7cbaac66d86085d5f4766ee6bf19c7f87"}, - {file = "numpy-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9adbd9bb520c866e1bfd7e10e1880a1f7749f1f6e5017686a5fbb9b72cf69f82"}, - {file = "numpy-2.0.1-cp310-cp310-win32.whl", hash = "sha256:7b9853803278db3bdcc6cd5beca37815b133e9e77ff3d4733c247414e78eb8d1"}, - {file = "numpy-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81b0893a39bc5b865b8bf89e9ad7807e16717f19868e9d234bdaf9b1f1393868"}, - {file = "numpy-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75b4e316c5902d8163ef9d423b1c3f2f6252226d1aa5cd8a0a03a7d01ffc6268"}, - {file = "numpy-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6e4eeb6eb2fced786e32e6d8df9e755ce5be920d17f7ce00bc38fcde8ccdbf9e"}, - {file = "numpy-2.0.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a1e01dcaab205fbece13c1410253a9eea1b1c9b61d237b6fa59bcc46e8e89343"}, - {file = "numpy-2.0.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8fc2de81ad835d999113ddf87d1ea2b0f4704cbd947c948d2f5513deafe5a7b"}, - {file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3d94942c331dd4e0e1147f7a8699a4aa47dffc11bf8a1523c12af8b2e91bbe"}, - {file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15eb4eca47d36ec3f78cde0a3a2ee24cf05ca7396ef808dda2c0ddad7c2bde67"}, - {file = "numpy-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b83e16a5511d1b1f8a88cbabb1a6f6a499f82c062a4251892d9ad5d609863fb7"}, - {file = "numpy-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f87fec1f9bc1efd23f4227becff04bd0e979e23ca50cc92ec88b38489db3b55"}, - {file = "numpy-2.0.1-cp311-cp311-win32.whl", hash = "sha256:36d3a9405fd7c511804dc56fc32974fa5533bdeb3cd1604d6b8ff1d292b819c4"}, - {file = "numpy-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:08458fbf403bff5e2b45f08eda195d4b0c9b35682311da5a5a0a0925b11b9bd8"}, - {file = "numpy-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bf4e6f4a2a2e26655717a1983ef6324f2664d7011f6ef7482e8c0b3d51e82ac"}, - {file = "numpy-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6fddc5fe258d3328cd8e3d7d3e02234c5d70e01ebe377a6ab92adb14039cb4"}, - {file = "numpy-2.0.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5daab361be6ddeb299a918a7c0864fa8618af66019138263247af405018b04e1"}, - {file = "numpy-2.0.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:ea2326a4dca88e4a274ba3a4405eb6c6467d3ffbd8c7d38632502eaae3820587"}, - {file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529af13c5f4b7a932fb0e1911d3a75da204eff023ee5e0e79c1751564221a5c8"}, - {file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6790654cb13eab303d8402354fabd47472b24635700f631f041bd0b65e37298a"}, - {file = "numpy-2.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cbab9fc9c391700e3e1287666dfd82d8666d10e69a6c4a09ab97574c0b7ee0a7"}, - {file = "numpy-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99d0d92a5e3613c33a5f01db206a33f8fdf3d71f2912b0de1739894668b7a93b"}, - {file = "numpy-2.0.1-cp312-cp312-win32.whl", hash = "sha256:173a00b9995f73b79eb0191129f2455f1e34c203f559dd118636858cc452a1bf"}, - {file = "numpy-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:bb2124fdc6e62baae159ebcfa368708867eb56806804d005860b6007388df171"}, - {file = "numpy-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc085b28d62ff4009364e7ca34b80a9a080cbd97c2c0630bb5f7f770dae9414"}, - {file = "numpy-2.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fae4ebbf95a179c1156fab0b142b74e4ba4204c87bde8d3d8b6f9c34c5825ef"}, - {file = "numpy-2.0.1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:72dc22e9ec8f6eaa206deb1b1355eb2e253899d7347f5e2fae5f0af613741d06"}, - {file = "numpy-2.0.1-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:ec87f5f8aca726117a1c9b7083e7656a9d0d606eec7299cc067bb83d26f16e0c"}, - {file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f682ea61a88479d9498bf2091fdcd722b090724b08b31d63e022adc063bad59"}, - {file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8efc84f01c1cd7e34b3fb310183e72fcdf55293ee736d679b6d35b35d80bba26"}, - {file = "numpy-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3fdabe3e2a52bc4eff8dc7a5044342f8bd9f11ef0934fcd3289a788c0eb10018"}, - {file = "numpy-2.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:24a0e1befbfa14615b49ba9659d3d8818a0f4d8a1c5822af8696706fbda7310c"}, - {file = "numpy-2.0.1-cp39-cp39-win32.whl", hash = "sha256:f9cf5ea551aec449206954b075db819f52adc1638d46a6738253a712d553c7b4"}, - {file = "numpy-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:e9e81fa9017eaa416c056e5d9e71be93d05e2c3c2ab308d23307a8bc4443c368"}, - {file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61728fba1e464f789b11deb78a57805c70b2ed02343560456190d0501ba37b0f"}, - {file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:12f5d865d60fb9734e60a60f1d5afa6d962d8d4467c120a1c0cda6eb2964437d"}, - {file = "numpy-2.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eacf3291e263d5a67d8c1a581a8ebbcfd6447204ef58828caf69a5e3e8c75990"}, - {file = "numpy-2.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2c3a346ae20cfd80b6cfd3e60dc179963ef2ea58da5ec074fd3d9e7a1e7ba97f"}, - {file = "numpy-2.0.1.tar.gz", hash = "sha256:485b87235796410c3519a699cfe1faab097e509e90ebb05dcd098db2ae87e7b3"}, + {file = "numpy-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6326ab99b52fafdcdeccf602d6286191a79fe2fda0ae90573c5814cd2b0bc1b8"}, + {file = "numpy-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0937e54c09f7a9a68da6889362ddd2ff584c02d015ec92672c099b61555f8911"}, + {file = "numpy-2.1.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:30014b234f07b5fec20f4146f69e13cfb1e33ee9a18a1879a0142fbb00d47673"}, + {file = "numpy-2.1.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:899da829b362ade41e1e7eccad2cf274035e1cb36ba73034946fccd4afd8606b"}, + {file = "numpy-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08801848a40aea24ce16c2ecde3b756f9ad756586fb2d13210939eb69b023f5b"}, + {file = "numpy-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:398049e237d1aae53d82a416dade04defed1a47f87d18d5bd615b6e7d7e41d1f"}, + {file = "numpy-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0abb3916a35d9090088a748636b2c06dc9a6542f99cd476979fb156a18192b84"}, + {file = "numpy-2.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10e2350aea18d04832319aac0f887d5fcec1b36abd485d14f173e3e900b83e33"}, + {file = "numpy-2.1.0-cp310-cp310-win32.whl", hash = "sha256:f6b26e6c3b98adb648243670fddc8cab6ae17473f9dc58c51574af3e64d61211"}, + {file = "numpy-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:f505264735ee074250a9c78247ee8618292091d9d1fcc023290e9ac67e8f1afa"}, + {file = "numpy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:76368c788ccb4f4782cf9c842b316140142b4cbf22ff8db82724e82fe1205dce"}, + {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f8e93a01a35be08d31ae33021e5268f157a2d60ebd643cfc15de6ab8e4722eb1"}, + {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9523f8b46485db6939bd069b28b642fec86c30909cea90ef550373787f79530e"}, + {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54139e0eb219f52f60656d163cbe67c31ede51d13236c950145473504fa208cb"}, + {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebbf9fbdabed208d4ecd2e1dfd2c0741af2f876e7ae522c2537d404ca895c3"}, + {file = "numpy-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:378cb4f24c7d93066ee4103204f73ed046eb88f9ad5bb2275bb9fa0f6a02bd36"}, + {file = "numpy-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f699a709120b220dfe173f79c73cb2a2cab2c0b88dd59d7b49407d032b8ebd"}, + {file = "numpy-2.1.0-cp311-cp311-win32.whl", hash = "sha256:ffbd6faeb190aaf2b5e9024bac9622d2ee549b7ec89ef3a9373fa35313d44e0e"}, + {file = "numpy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0af3a5987f59d9c529c022c8c2a64805b339b7ef506509fba7d0556649b9714b"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fe76d75b345dc045acdbc006adcb197cc680754afd6c259de60d358d60c93736"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f358ea9e47eb3c2d6eba121ab512dfff38a88db719c38d1e67349af210bc7529"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:dd94ce596bda40a9618324547cfaaf6650b1a24f5390350142499aa4e34e53d1"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b47c551c6724960479cefd7353656498b86e7232429e3a41ab83be4da1b109e8"}, + {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0756a179afa766ad7cb6f036de622e8a8f16ffdd55aa31f296c870b5679d745"}, + {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24003ba8ff22ea29a8c306e61d316ac74111cebf942afbf692df65509a05f111"}, + {file = "numpy-2.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b34fa5e3b5d6dc7e0a4243fa0f81367027cb6f4a7215a17852979634b5544ee0"}, + {file = "numpy-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4f982715e65036c34897eb598d64aef15150c447be2cfc6643ec7a11af06574"}, + {file = "numpy-2.1.0-cp312-cp312-win32.whl", hash = "sha256:c4cd94dfefbefec3f8b544f61286584292d740e6e9d4677769bc76b8f41deb02"}, + {file = "numpy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0cdef204199278f5c461a0bed6ed2e052998276e6d8ab2963d5b5c39a0500bc"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8ab81ccd753859ab89e67199b9da62c543850f819993761c1e94a75a814ed667"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:442596f01913656d579309edcd179a2a2f9977d9a14ff41d042475280fc7f34e"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:848c6b5cad9898e4b9ef251b6f934fa34630371f2e916261070a4eb9092ffd33"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:54c6a63e9d81efe64bfb7bcb0ec64332a87d0b87575f6009c8ba67ea6374770b"}, + {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652e92fc409e278abdd61e9505649e3938f6d04ce7ef1953f2ec598a50e7c195"}, + {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab32eb9170bf8ffcbb14f11613f4a0b108d3ffee0832457c5d4808233ba8977"}, + {file = "numpy-2.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:8fb49a0ba4d8f41198ae2d52118b050fd34dace4b8f3fb0ee34e23eb4ae775b1"}, + {file = "numpy-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44e44973262dc3ae79e9063a1284a73e09d01b894b534a769732ccd46c28cc62"}, + {file = "numpy-2.1.0-cp313-cp313-win32.whl", hash = "sha256:ab83adc099ec62e044b1fbb3a05499fa1e99f6d53a1dde102b2d85eff66ed324"}, + {file = "numpy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:de844aaa4815b78f6023832590d77da0e3b6805c644c33ce94a1e449f16d6ab5"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:343e3e152bf5a087511cd325e3b7ecfd5b92d369e80e74c12cd87826e263ec06"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f07fa2f15dabe91259828ce7d71b5ca9e2eb7c8c26baa822c825ce43552f4883"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5474dad8c86ee9ba9bb776f4b99ef2d41b3b8f4e0d199d4f7304728ed34d0300"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1f817c71683fd1bb5cff1529a1d085a57f02ccd2ebc5cd2c566f9a01118e3b7d"}, + {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a3336fbfa0d38d3deacd3fe7f3d07e13597f29c13abf4d15c3b6dc2291cbbdd"}, + {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a894c51fd8c4e834f00ac742abad73fc485df1062f1b875661a3c1e1fb1c2f6"}, + {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:9156ca1f79fc4acc226696e95bfcc2b486f165a6a59ebe22b2c1f82ab190384a"}, + {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:624884b572dff8ca8f60fab591413f077471de64e376b17d291b19f56504b2bb"}, + {file = "numpy-2.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:15ef8b2177eeb7e37dd5ef4016f30b7659c57c2c0b57a779f1d537ff33a72c7b"}, + {file = "numpy-2.1.0-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:e5f0642cdf4636198a4990de7a71b693d824c56a757862230454629cf62e323d"}, + {file = "numpy-2.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15976718c004466406342789f31b6673776360f3b1e3c575f25302d7e789575"}, + {file = "numpy-2.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6c1de77ded79fef664d5098a66810d4d27ca0224e9051906e634b3f7ead134c2"}, + {file = "numpy-2.1.0.tar.gz", hash = "sha256:7dc90da0081f7e1da49ec4e398ede6a8e9cc4f5ebe5f9e06b443ed889ee9aaa2"}, ] [[package]] @@ -2387,20 +2405,17 @@ xml = ["lxml (>=4.9.2)"] [[package]] name = "pandas-stubs" -version = "2.2.2.240603" +version = "2.2.2.240807" description = "Type annotations for pandas" optional = false python-versions = ">=3.9" files = [ - {file = "pandas_stubs-2.2.2.240603-py3-none-any.whl", hash = "sha256:e08ce7f602a4da2bff5a67475ba881c39f2a4d4f7fccc1cba57c6f35a379c6c0"}, - {file = "pandas_stubs-2.2.2.240603.tar.gz", hash = "sha256:2dcc86e8fa6ea41535a4561c1f08b3942ba5267b464eff2e99caeee66f9e4cd1"}, + {file = "pandas_stubs-2.2.2.240807-py3-none-any.whl", hash = "sha256:893919ad82be4275f0d07bb47a95d08bae580d3fdea308a7acfcb3f02e76186e"}, + {file = "pandas_stubs-2.2.2.240807.tar.gz", hash = "sha256:64a559725a57a449f46225fbafc422520b7410bff9252b661a225b5559192a93"}, ] [package.dependencies] -numpy = [ - {version = ">=1.23.5", markers = "python_version >= \"3.9\" and python_version < \"3.12\""}, - {version = ">=1.26.0", markers = "python_version >= \"3.12\" and python_version < \"3.13\""}, -] +numpy = ">=1.23.5" types-pytz = ">=2022.1.1" [[package]] @@ -2975,120 +2990,120 @@ files = [ [[package]] name = "pyzmq" -version = "26.1.0" +version = "26.1.1" description = "Python bindings for 0MQ" optional = false python-versions = ">=3.7" files = [ - {file = "pyzmq-26.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:263cf1e36862310bf5becfbc488e18d5d698941858860c5a8c079d1511b3b18e"}, - {file = "pyzmq-26.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d5c8b17f6e8f29138678834cf8518049e740385eb2dbf736e8f07fc6587ec682"}, - {file = "pyzmq-26.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75a95c2358fcfdef3374cb8baf57f1064d73246d55e41683aaffb6cfe6862917"}, - {file = "pyzmq-26.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f99de52b8fbdb2a8f5301ae5fc0f9e6b3ba30d1d5fc0421956967edcc6914242"}, - {file = "pyzmq-26.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bcbfbab4e1895d58ab7da1b5ce9a327764f0366911ba5b95406c9104bceacb0"}, - {file = "pyzmq-26.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:77ce6a332c7e362cb59b63f5edf730e83590d0ab4e59c2aa5bd79419a42e3449"}, - {file = "pyzmq-26.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ba0a31d00e8616149a5ab440d058ec2da621e05d744914774c4dde6837e1f545"}, - {file = "pyzmq-26.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8b88641384e84a258b740801cd4dbc45c75f148ee674bec3149999adda4a8598"}, - {file = "pyzmq-26.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2fa76ebcebe555cce90f16246edc3ad83ab65bb7b3d4ce408cf6bc67740c4f88"}, - {file = "pyzmq-26.1.0-cp310-cp310-win32.whl", hash = "sha256:fbf558551cf415586e91160d69ca6416f3fce0b86175b64e4293644a7416b81b"}, - {file = "pyzmq-26.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:a7b8aab50e5a288c9724d260feae25eda69582be84e97c012c80e1a5e7e03fb2"}, - {file = "pyzmq-26.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:08f74904cb066e1178c1ec706dfdb5c6c680cd7a8ed9efebeac923d84c1f13b1"}, - {file = "pyzmq-26.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:46d6800b45015f96b9d92ece229d92f2aef137d82906577d55fadeb9cf5fcb71"}, - {file = "pyzmq-26.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5bc2431167adc50ba42ea3e5e5f5cd70d93e18ab7b2f95e724dd8e1bd2c38120"}, - {file = "pyzmq-26.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3bb34bebaa1b78e562931a1687ff663d298013f78f972a534f36c523311a84d"}, - {file = "pyzmq-26.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd3f6329340cef1c7ba9611bd038f2d523cea79f09f9c8f6b0553caba59ec562"}, - {file = "pyzmq-26.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:471880c4c14e5a056a96cd224f5e71211997d40b4bf5e9fdded55dafab1f98f2"}, - {file = "pyzmq-26.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ce6f2b66799971cbae5d6547acefa7231458289e0ad481d0be0740535da38d8b"}, - {file = "pyzmq-26.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a1f6ea5b1d6cdbb8cfa0536f0d470f12b4b41ad83625012e575f0e3ecfe97f0"}, - {file = "pyzmq-26.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b45e6445ac95ecb7d728604bae6538f40ccf4449b132b5428c09918523abc96d"}, - {file = "pyzmq-26.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:94c4262626424683feea0f3c34951d39d49d354722db2745c42aa6bb50ecd93b"}, - {file = "pyzmq-26.1.0-cp311-cp311-win32.whl", hash = "sha256:a0f0ab9df66eb34d58205913f4540e2ad17a175b05d81b0b7197bc57d000e829"}, - {file = "pyzmq-26.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:8efb782f5a6c450589dbab4cb0f66f3a9026286333fe8f3a084399149af52f29"}, - {file = "pyzmq-26.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:f133d05aaf623519f45e16ab77526e1e70d4e1308e084c2fb4cedb1a0c764bbb"}, - {file = "pyzmq-26.1.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:3d3146b1c3dcc8a1539e7cc094700b2be1e605a76f7c8f0979b6d3bde5ad4072"}, - {file = "pyzmq-26.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d9270fbf038bf34ffca4855bcda6e082e2c7f906b9eb8d9a8ce82691166060f7"}, - {file = "pyzmq-26.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:995301f6740a421afc863a713fe62c0aaf564708d4aa057dfdf0f0f56525294b"}, - {file = "pyzmq-26.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7eca8b89e56fb8c6c26dd3e09bd41b24789022acf1cf13358e96f1cafd8cae3"}, - {file = "pyzmq-26.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d4feb2e83dfe9ace6374a847e98ee9d1246ebadcc0cb765482e272c34e5820"}, - {file = "pyzmq-26.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d4fafc2eb5d83f4647331267808c7e0c5722c25a729a614dc2b90479cafa78bd"}, - {file = "pyzmq-26.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:58c33dc0e185dd97a9ac0288b3188d1be12b756eda67490e6ed6a75cf9491d79"}, - {file = "pyzmq-26.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:68a0a1d83d33d8367ddddb3e6bb4afbb0f92bd1dac2c72cd5e5ddc86bdafd3eb"}, - {file = "pyzmq-26.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ae7c57e22ad881af78075e0cea10a4c778e67234adc65c404391b417a4dda83"}, - {file = "pyzmq-26.1.0-cp312-cp312-win32.whl", hash = "sha256:347e84fc88cc4cb646597f6d3a7ea0998f887ee8dc31c08587e9c3fd7b5ccef3"}, - {file = "pyzmq-26.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:9f136a6e964830230912f75b5a116a21fe8e34128dcfd82285aa0ef07cb2c7bd"}, - {file = "pyzmq-26.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:a4b7a989c8f5a72ab1b2bbfa58105578753ae77b71ba33e7383a31ff75a504c4"}, - {file = "pyzmq-26.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d416f2088ac8f12daacffbc2e8918ef4d6be8568e9d7155c83b7cebed49d2322"}, - {file = "pyzmq-26.1.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:ecb6c88d7946166d783a635efc89f9a1ff11c33d680a20df9657b6902a1d133b"}, - {file = "pyzmq-26.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:471312a7375571857a089342beccc1a63584315188560c7c0da7e0a23afd8a5c"}, - {file = "pyzmq-26.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e6cea102ffa16b737d11932c426f1dc14b5938cf7bc12e17269559c458ac334"}, - {file = "pyzmq-26.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec7248673ffc7104b54e4957cee38b2f3075a13442348c8d651777bf41aa45ee"}, - {file = "pyzmq-26.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:0614aed6f87d550b5cecb03d795f4ddbb1544b78d02a4bd5eecf644ec98a39f6"}, - {file = "pyzmq-26.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:e8746ce968be22a8a1801bf4a23e565f9687088580c3ed07af5846580dd97f76"}, - {file = "pyzmq-26.1.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:7688653574392d2eaeef75ddcd0b2de5b232d8730af29af56c5adf1df9ef8d6f"}, - {file = "pyzmq-26.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:8d4dac7d97f15c653a5fedcafa82626bd6cee1450ccdaf84ffed7ea14f2b07a4"}, - {file = "pyzmq-26.1.0-cp313-cp313-win32.whl", hash = "sha256:ccb42ca0a4a46232d716779421bbebbcad23c08d37c980f02cc3a6bd115ad277"}, - {file = "pyzmq-26.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e1e5d0a25aea8b691a00d6b54b28ac514c8cc0d8646d05f7ca6cb64b97358250"}, - {file = "pyzmq-26.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:fc82269d24860cfa859b676d18850cbb8e312dcd7eada09e7d5b007e2f3d9eb1"}, - {file = "pyzmq-26.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:416ac51cabd54f587995c2b05421324700b22e98d3d0aa2cfaec985524d16f1d"}, - {file = "pyzmq-26.1.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:ff832cce719edd11266ca32bc74a626b814fff236824aa1aeaad399b69fe6eae"}, - {file = "pyzmq-26.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:393daac1bcf81b2a23e696b7b638eedc965e9e3d2112961a072b6cd8179ad2eb"}, - {file = "pyzmq-26.1.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9869fa984c8670c8ab899a719eb7b516860a29bc26300a84d24d8c1b71eae3ec"}, - {file = "pyzmq-26.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b3b8e36fd4c32c0825b4461372949ecd1585d326802b1321f8b6dc1d7e9318c"}, - {file = "pyzmq-26.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:3ee647d84b83509b7271457bb428cc347037f437ead4b0b6e43b5eba35fec0aa"}, - {file = "pyzmq-26.1.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:45cb1a70eb00405ce3893041099655265fabcd9c4e1e50c330026e82257892c1"}, - {file = "pyzmq-26.1.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:5cca7b4adb86d7470e0fc96037771981d740f0b4cb99776d5cb59cd0e6684a73"}, - {file = "pyzmq-26.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:91d1a20bdaf3b25f3173ff44e54b1cfbc05f94c9e8133314eb2962a89e05d6e3"}, - {file = "pyzmq-26.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c0665d85535192098420428c779361b8823d3d7ec4848c6af3abb93bc5c915bf"}, - {file = "pyzmq-26.1.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:96d7c1d35ee4a495df56c50c83df7af1c9688cce2e9e0edffdbf50889c167595"}, - {file = "pyzmq-26.1.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b281b5ff5fcc9dcbfe941ac5c7fcd4b6c065adad12d850f95c9d6f23c2652384"}, - {file = "pyzmq-26.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5384c527a9a004445c5074f1e20db83086c8ff1682a626676229aafd9cf9f7d1"}, - {file = "pyzmq-26.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:754c99a9840839375ee251b38ac5964c0f369306eddb56804a073b6efdc0cd88"}, - {file = "pyzmq-26.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9bdfcb74b469b592972ed881bad57d22e2c0acc89f5e8c146782d0d90fb9f4bf"}, - {file = "pyzmq-26.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bd13f0231f4788db619347b971ca5f319c5b7ebee151afc7c14632068c6261d3"}, - {file = "pyzmq-26.1.0-cp37-cp37m-win32.whl", hash = "sha256:c5668dac86a869349828db5fc928ee3f58d450dce2c85607067d581f745e4fb1"}, - {file = "pyzmq-26.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad875277844cfaeca7fe299ddf8c8d8bfe271c3dc1caf14d454faa5cdbf2fa7a"}, - {file = "pyzmq-26.1.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:65c6e03cc0222eaf6aad57ff4ecc0a070451e23232bb48db4322cc45602cede0"}, - {file = "pyzmq-26.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:038ae4ffb63e3991f386e7fda85a9baab7d6617fe85b74a8f9cab190d73adb2b"}, - {file = "pyzmq-26.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bdeb2c61611293f64ac1073f4bf6723b67d291905308a7de9bb2ca87464e3273"}, - {file = "pyzmq-26.1.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:61dfa5ee9d7df297c859ac82b1226d8fefaf9c5113dc25c2c00ecad6feeeb04f"}, - {file = "pyzmq-26.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3292d384537b9918010769b82ab3e79fca8b23d74f56fc69a679106a3e2c2cf"}, - {file = "pyzmq-26.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f9499c70c19ff0fbe1007043acb5ad15c1dec7d8e84ab429bca8c87138e8f85c"}, - {file = "pyzmq-26.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d3dd5523ed258ad58fed7e364c92a9360d1af8a9371e0822bd0146bdf017ef4c"}, - {file = "pyzmq-26.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baba2fd199b098c5544ef2536b2499d2e2155392973ad32687024bd8572a7d1c"}, - {file = "pyzmq-26.1.0-cp38-cp38-win32.whl", hash = "sha256:ddbb2b386128d8eca92bd9ca74e80f73fe263bcca7aa419f5b4cbc1661e19741"}, - {file = "pyzmq-26.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:79e45a4096ec8388cdeb04a9fa5e9371583bcb826964d55b8b66cbffe7b33c86"}, - {file = "pyzmq-26.1.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:add52c78a12196bc0fda2de087ba6c876ea677cbda2e3eba63546b26e8bf177b"}, - {file = "pyzmq-26.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c03bd7f3339ff47de7ea9ac94a2b34580a8d4df69b50128bb6669e1191a895"}, - {file = "pyzmq-26.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dcc37d9d708784726fafc9c5e1232de655a009dbf97946f117aefa38d5985a0f"}, - {file = "pyzmq-26.1.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5a6ed52f0b9bf8dcc64cc82cce0607a3dfed1dbb7e8c6f282adfccc7be9781de"}, - {file = "pyzmq-26.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451e16ae8bea3d95649317b463c9f95cd9022641ec884e3d63fc67841ae86dfe"}, - {file = "pyzmq-26.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:906e532c814e1d579138177a00ae835cd6becbf104d45ed9093a3aaf658f6a6a"}, - {file = "pyzmq-26.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:05bacc4f94af468cc82808ae3293390278d5f3375bb20fef21e2034bb9a505b6"}, - {file = "pyzmq-26.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:57bb2acba798dc3740e913ffadd56b1fcef96f111e66f09e2a8db3050f1f12c8"}, - {file = "pyzmq-26.1.0-cp39-cp39-win32.whl", hash = "sha256:f774841bb0e8588505002962c02da420bcfb4c5056e87a139c6e45e745c0e2e2"}, - {file = "pyzmq-26.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:359c533bedc62c56415a1f5fcfd8279bc93453afdb0803307375ecf81c962402"}, - {file = "pyzmq-26.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:7907419d150b19962138ecec81a17d4892ea440c184949dc29b358bc730caf69"}, - {file = "pyzmq-26.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b24079a14c9596846bf7516fe75d1e2188d4a528364494859106a33d8b48be38"}, - {file = "pyzmq-26.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59d0acd2976e1064f1b398a00e2c3e77ed0a157529779e23087d4c2fb8aaa416"}, - {file = "pyzmq-26.1.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:911c43a4117915203c4cc8755e0f888e16c4676a82f61caee2f21b0c00e5b894"}, - {file = "pyzmq-26.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b10163e586cc609f5f85c9b233195554d77b1e9a0801388907441aaeb22841c5"}, - {file = "pyzmq-26.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:28a8b2abb76042f5fd7bd720f7fea48c0fd3e82e9de0a1bf2c0de3812ce44a42"}, - {file = "pyzmq-26.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bef24d3e4ae2c985034439f449e3f9e06bf579974ce0e53d8a507a1577d5b2ab"}, - {file = "pyzmq-26.1.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2cd0f4d314f4a2518e8970b6f299ae18cff7c44d4a1fc06fc713f791c3a9e3ea"}, - {file = "pyzmq-26.1.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fa25a620eed2a419acc2cf10135b995f8f0ce78ad00534d729aa761e4adcef8a"}, - {file = "pyzmq-26.1.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef3b048822dca6d231d8a8ba21069844ae38f5d83889b9b690bf17d2acc7d099"}, - {file = "pyzmq-26.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:9a6847c92d9851b59b9f33f968c68e9e441f9a0f8fc972c5580c5cd7cbc6ee24"}, - {file = "pyzmq-26.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c9b9305004d7e4e6a824f4f19b6d8f32b3578aad6f19fc1122aaf320cbe3dc83"}, - {file = "pyzmq-26.1.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:63c1d3a65acb2f9c92dce03c4e1758cc552f1ae5c78d79a44e3bb88d2fa71f3a"}, - {file = "pyzmq-26.1.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d36b8fffe8b248a1b961c86fbdfa0129dfce878731d169ede7fa2631447331be"}, - {file = "pyzmq-26.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67976d12ebfd61a3bc7d77b71a9589b4d61d0422282596cf58c62c3866916544"}, - {file = "pyzmq-26.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:998444debc8816b5d8d15f966e42751032d0f4c55300c48cc337f2b3e4f17d03"}, - {file = "pyzmq-26.1.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e5c88b2f13bcf55fee78ea83567b9fe079ba1a4bef8b35c376043440040f7edb"}, - {file = "pyzmq-26.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d906d43e1592be4b25a587b7d96527cb67277542a5611e8ea9e996182fae410"}, - {file = "pyzmq-26.1.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80b0c9942430d731c786545da6be96d824a41a51742e3e374fedd9018ea43106"}, - {file = "pyzmq-26.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:314d11564c00b77f6224d12eb3ddebe926c301e86b648a1835c5b28176c83eab"}, - {file = "pyzmq-26.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:093a1a3cae2496233f14b57f4b485da01b4ff764582c854c0f42c6dd2be37f3d"}, - {file = "pyzmq-26.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3c397b1b450f749a7e974d74c06d69bd22dd362142f370ef2bd32a684d6b480c"}, - {file = "pyzmq-26.1.0.tar.gz", hash = "sha256:6c5aeea71f018ebd3b9115c7cb13863dd850e98ca6b9258509de1246461a7e7f"}, + {file = "pyzmq-26.1.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:b1bb952d1e407463c9333ea7e0c0600001e54e08ce836d4f0aff1fb3f902cf63"}, + {file = "pyzmq-26.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:65e2a18e845c6ea7ab849c70db932eaeadee5edede9e379eb21c0a44cf523b2e"}, + {file = "pyzmq-26.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:def7ae3006924b8a0c146a89ab4008310913fa903beedb95e25dea749642528e"}, + {file = "pyzmq-26.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8234571df7816f99dde89c3403cb396d70c6554120b795853a8ea56fcc26cd3"}, + {file = "pyzmq-26.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18da8e84dbc30688fd2baefd41df7190607511f916be34f9a24b0e007551822e"}, + {file = "pyzmq-26.1.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c70dab93d98b2bf3f0ac1265edbf6e7f83acbf71dabcc4611889bb0dea45bed7"}, + {file = "pyzmq-26.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fcb90592c5d5c562e1b1a1ceccf6f00036d73c51db0271bf4d352b8d6b31d468"}, + {file = "pyzmq-26.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cf4be7460a0c1bc71e9b0e64ecdd75a86386ca6afaa36641686f5542d0314e9d"}, + {file = "pyzmq-26.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4cbecda4ddbfc1e309c3be04d333f9be3fc6178b8b6592b309676f929767a15"}, + {file = "pyzmq-26.1.1-cp310-cp310-win32.whl", hash = "sha256:583f73b113b8165713b6ce028d221402b1b69483055b5aa3f991937e34dd1ead"}, + {file = "pyzmq-26.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5e6f39ecb8eb7bfcb976c49262e8cf83ff76e082b77ca23ba90c9b6691a345be"}, + {file = "pyzmq-26.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:8d042d6446cab3a1388b38596f5acabb9926b0b95c3894c519356b577a549458"}, + {file = "pyzmq-26.1.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:362cac2423e36966d336d79d3ec3eafeabc153ee3e7a5cf580d7e74a34b3d912"}, + {file = "pyzmq-26.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0841633446cb1539a832a19bb24c03a20c00887d0cedd1d891b495b07e5c5cb5"}, + {file = "pyzmq-26.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e1fcdc333afbf9918d0a614a6e10858aede7da49a60f6705a77e343fe86a317"}, + {file = "pyzmq-26.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc8d655627d775475eafdcf0e49e74bcc1e5e90afd9ab813b4da98f092ed7b93"}, + {file = "pyzmq-26.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32de51744820857a6f7c3077e620ab3f607d0e4388dfead885d5124ab9bcdc5e"}, + {file = "pyzmq-26.1.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a880240597010914ffb1d6edd04d3deb7ce6a2abf79a0012751438d13630a671"}, + {file = "pyzmq-26.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:26131b1cec02f941ed2d2b4b8cc051662b1c248b044eff5069df1f500bbced56"}, + {file = "pyzmq-26.1.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ce05841322b58510607f9508a573138d995a46c7928887bc433de9cb760fd2ad"}, + {file = "pyzmq-26.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:32123ff0a6db521aadf2b95201e967a4e0d11fb89f73663a99d2f54881c07214"}, + {file = "pyzmq-26.1.1-cp311-cp311-win32.whl", hash = "sha256:e790602d7ea1d6c7d8713d571226d67de7ffe47b1e22ae2c043ebd537de1bccb"}, + {file = "pyzmq-26.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:717960855f2d6fdc2dba9df49dff31c414187bb11c76af36343a57d1f7083d9a"}, + {file = "pyzmq-26.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:08956c26dbcd4fd8835cb777a16e21958ed2412317630e19f0018d49dbeeb470"}, + {file = "pyzmq-26.1.1-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:e80345900ae241c2c51bead7c9fa247bba6d4b2a83423e9791bae8b0a7f12c52"}, + {file = "pyzmq-26.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ec8fe214fcc45dfb0c32e4a7ad1db20244ba2d2fecbf0cbf9d5242d81ca0a375"}, + {file = "pyzmq-26.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf4e283f97688d993cb7a8acbc22889effbbb7cbaa19ee9709751f44be928f5d"}, + {file = "pyzmq-26.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2508bdc8ab246e5ed7c92023d4352aaad63020ca3b098a4e3f1822db202f703d"}, + {file = "pyzmq-26.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:741bdb4d96efe8192616abdc3671931d51a8bcd38c71da2d53fb3127149265d1"}, + {file = "pyzmq-26.1.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:76154943e4c4054b2591792eb3484ef1dd23d59805759f9cebd2f010aa30ee8c"}, + {file = "pyzmq-26.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9498ac427d20d0e0ef0e4bbd6200841e91640dfdf619f544ceec7f464cfb6070"}, + {file = "pyzmq-26.1.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f34453ef3496ca3462f30435bf85f535f9550392987341f9ccc92c102825a79"}, + {file = "pyzmq-26.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:50f0669324e27cc2091ef6ab76ca7112f364b6249691790b4cffce31e73fda28"}, + {file = "pyzmq-26.1.1-cp312-cp312-win32.whl", hash = "sha256:3ee5cbf2625b94de21c68d0cefd35327c8dfdbd6a98fcc41682b4e8bb00d841f"}, + {file = "pyzmq-26.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:75bd448a28b1001b6928679015bc95dd5f172703ed30135bb9e34fc9cda0a3e7"}, + {file = "pyzmq-26.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:4350233569b4bbef88595c5e77ee38995a6f1f1790fae148b578941bfffd1c24"}, + {file = "pyzmq-26.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8087a3281c20b1d11042d372ed5a47734af05975d78e4d1d6e7bd1018535f3"}, + {file = "pyzmq-26.1.1-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:ebef7d3fe11fe4c688f08bc0211a976c3318c097057f258428200737b9fff4da"}, + {file = "pyzmq-26.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a5342110510045a47de1e87f5f1dcc1d9d90109522316dc9830cfc6157c800f"}, + {file = "pyzmq-26.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af690ea4be6ca92a67c2b44a779a023bf0838e92d48497a2268175dc4a505691"}, + {file = "pyzmq-26.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc994e220c1403ae087d7f0fa45129d583e46668a019e389060da811a5a9320e"}, + {file = "pyzmq-26.1.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:b8e153f5dffb0310af71fc6fc9cd8174f4c8ea312c415adcb815d786fee78179"}, + {file = "pyzmq-26.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0065026e624052a51033857e5cd45a94b52946b44533f965f0bdf182460e965d"}, + {file = "pyzmq-26.1.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:63351392f948b5d50b9f55161994bc4feedbfb3f3cfe393d2f503dea2c3ec445"}, + {file = "pyzmq-26.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ffecc43b3c18e36b62fcec995761829b6ac325d8dd74a4f2c5c1653afbb4495a"}, + {file = "pyzmq-26.1.1-cp313-cp313-win32.whl", hash = "sha256:6ff14c2fae6c0c2c1c02590c5c5d75aa1db35b859971b3ca2fcd28f983d9f2b6"}, + {file = "pyzmq-26.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:85f2d2ee5ea9a8f1de86a300e1062fbab044f45b5ce34d20580c0198a8196db0"}, + {file = "pyzmq-26.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:cc09b1de8b985ca5a0ca343dd7fb007267c6b329347a74e200f4654268084239"}, + {file = "pyzmq-26.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:bc904e86de98f8fc5bd41597da5d61232d2d6d60c4397f26efffabb961b2b245"}, + {file = "pyzmq-26.1.1-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:00f39c367bbd6aa8e4bc36af6510561944c619b58eb36199fa334b594a18f615"}, + {file = "pyzmq-26.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de6f384864a959866b782e6a3896538d1424d183f2d3c7ef079f71dcecde7284"}, + {file = "pyzmq-26.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3abb15df0c763339edb27a644c19381b2425ddd1aea3dbd77c1601a3b31867b8"}, + {file = "pyzmq-26.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40908ec2dd3b29bbadc0916a0d3c87f8dbeebbd8fead8e618539f09e0506dec4"}, + {file = "pyzmq-26.1.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:c11a95d3f6fc7e714ccd1066f68f9c1abd764a8b3596158be92f46dd49f41e03"}, + {file = "pyzmq-26.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:4437af9fee7a58302dbd511cc49f0cc2b35c112a33a1111fb123cf0be45205ca"}, + {file = "pyzmq-26.1.1-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:76390d3d66406cb01b9681c382874400e9dfd77f30ecdea4bd1bf5226dd4aff0"}, + {file = "pyzmq-26.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:4d4c7fe5e50e269f9c63a260638488fec194a73993008618a59b54c47ef6ae72"}, + {file = "pyzmq-26.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:25d128524207f53f7aae7c5abdc2b63f8957a060b00521af5ffcd20986b5d8f4"}, + {file = "pyzmq-26.1.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d74b925d997e4f92b042bdd7085cd0a309ee0fd7cb4dc376059bbff6b32ff34f"}, + {file = "pyzmq-26.1.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:732f957441e5b1c65a7509395e6b6cafee9e12df9aa5f4bf92ed266fe0ba70ee"}, + {file = "pyzmq-26.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0a45102ad7ed9f9ddf2bd699cc5df37742cf7301111cba06001b927efecb120"}, + {file = "pyzmq-26.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9f380d5333fc7cd17423f486125dcc073918676e33db70a6a8172b19fc78d23d"}, + {file = "pyzmq-26.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8eaffcd6bf6a9d00b66a2052a33fa7e6a6575427e9644395f13c3d070f2918dc"}, + {file = "pyzmq-26.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f1483d4975ae1b387b39bb8e23d1ff32fe5621aa9e4ed3055d05e9c5613fea53"}, + {file = "pyzmq-26.1.1-cp37-cp37m-win32.whl", hash = "sha256:a83653c6bbe5887caea55e49fbd2909c14b73acf43bcc051eb60b2d514bbd46e"}, + {file = "pyzmq-26.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9763a8d3f5f74ef679989b373c37cc22e8d07e56d26439205cb83edb7722357f"}, + {file = "pyzmq-26.1.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2b045647caf620ce0ed6c8fd9fb6a73116f99aceed966b152a5ba1b416d25311"}, + {file = "pyzmq-26.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f66dcb6625c002f209cdc12cae1a1fec926493cd2262efe37dc6b25a30cea863"}, + {file = "pyzmq-26.1.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0cf1d980c969fb9e538f52abd2227f09e015096bc5c3ef7aa26e0d64051c1db8"}, + {file = "pyzmq-26.1.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:443ebf5e261a95ee9725693f2a5a71401f89b89df0e0ea58844b074067aac2f1"}, + {file = "pyzmq-26.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29de77ba1b1877fe7defc1b9140e65cbd35f72a63bc501e56c2eae55bde5fff4"}, + {file = "pyzmq-26.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f6071ec95af145d7b659dae6786871cd85f0acc599286b6f8ba0c74592d83dd"}, + {file = "pyzmq-26.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f0512fc87629ad968889176bf2165d721cd817401a281504329e2a2ed0ca6a3"}, + {file = "pyzmq-26.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5ccfcf13e80719f6a2d9c0a021d9e47d4550907a29253554be2c09582f6d7963"}, + {file = "pyzmq-26.1.1-cp38-cp38-win32.whl", hash = "sha256:809673947e95752e407aaaaf03f205ee86ebfff9ca51db6d4003dfd87b8428d1"}, + {file = "pyzmq-26.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:62b5180e23e6f581600459cd983473cd723fdc64350f606d21407c99832aaf5f"}, + {file = "pyzmq-26.1.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:fe73d7c89d6f803bed122135ff5783364e8cdb479cf6fe2d764a44b6349e7e0f"}, + {file = "pyzmq-26.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db1b7e2b50ef21f398036786da4c153db63203a402396d9f21e08ea61f3f8dba"}, + {file = "pyzmq-26.1.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7c506a51cb01bb997a3f6440db0d121e5e7a32396e9948b1fdb6a7bfa67243f4"}, + {file = "pyzmq-26.1.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:92eca4f80e8a748d880e55d3cf57ef487692e439f12d5c5a2e1cce84aaa7f6cb"}, + {file = "pyzmq-26.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14bdbae02f72f4716b0ffe7500e9da303d719ddde1f3dcfb4c4f6cc1cf73bb02"}, + {file = "pyzmq-26.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e03be7ed17836c9434cce0668ac1e2cc9143d7169f90f46a0167f6155e176e32"}, + {file = "pyzmq-26.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc5df31e36e4fddd4c8b5c42daee8d54d7b529e898ac984be97bf5517de166a7"}, + {file = "pyzmq-26.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f218179c90a12d660906e04b25a340dd63e9743000ba16232ddaf46888f269da"}, + {file = "pyzmq-26.1.1-cp39-cp39-win32.whl", hash = "sha256:7dfabc180a4da422a4b349c63077347392463a75fa07aa3be96712ed6d42c547"}, + {file = "pyzmq-26.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c5248e6e0fcbbbc912982e99cdd51c342601f495b0fa5bd667f3bdbdbf3e170f"}, + {file = "pyzmq-26.1.1-cp39-cp39-win_arm64.whl", hash = "sha256:2ae7aa1408778dc74582a1226052b930f9083b54b64d7e6ef6ec0466cfdcdec2"}, + {file = "pyzmq-26.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:be3fc2b11c0c384949cf1f01f9a48555039408b0f3e877863b1754225635953e"}, + {file = "pyzmq-26.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48dee75c2a9fa4f4a583d4028d564a0453447ee1277a29b07acc3743c092e259"}, + {file = "pyzmq-26.1.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23f2fe4fb567e8098ebaa7204819658195b10ddd86958a97a6058eed2901eed3"}, + {file = "pyzmq-26.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:472cacd16f627c06d3c8b2d374345ab74446bae913584a6245e2aa935336d929"}, + {file = "pyzmq-26.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8285b25aa20fcc46f1ca4afbc39fd3d5f2fe4c4bbf7f2c7f907a214e87a70024"}, + {file = "pyzmq-26.1.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2067e63fd9d5c13cfe12624dab0366053e523b37a7a01678ce4321f839398939"}, + {file = "pyzmq-26.1.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cc109be2ee3638035d276e18eaf66a1e1f44201c0c4bea4ee0c692766bbd3570"}, + {file = "pyzmq-26.1.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0da97e65ee73261dba70469cc8f63d8da3a8a825337a2e3d246b9e95141cdd0"}, + {file = "pyzmq-26.1.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa79c528706561306938b275f89bb2c6985ce08469c27e5de05bc680df5e826f"}, + {file = "pyzmq-26.1.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3ddbd851a3a2651fdc5065a2804d50cf2f4b13b1bcd66de8e9e855d0217d4fcd"}, + {file = "pyzmq-26.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d3df226ab7464684ae6706e20a5cbab717c3735a7e409b3fa598b754d49f1946"}, + {file = "pyzmq-26.1.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abad7b897e960d577eb4a0f3f789c1780bc3ffe2e7c27cf317e7c90ad26acf12"}, + {file = "pyzmq-26.1.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c513d829a548c2d5c88983167be2b3aa537f6d1191edcdc6fcd8999e18bdd994"}, + {file = "pyzmq-26.1.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70af4c9c991714ef1c65957605a8de42ef0d0620dd5f125953c8e682281bdb80"}, + {file = "pyzmq-26.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8d4234f335b0d0842f7d661d8cd50cbad0729be58f1c4deb85cd96b38fe95025"}, + {file = "pyzmq-26.1.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2c0fdb7b758e0e1605157e480b00b3a599073068a37091a1c75ec65bf7498645"}, + {file = "pyzmq-26.1.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc657577f057d60dd3642c9f95f28b432889b73143140061f7c1331d02f03df6"}, + {file = "pyzmq-26.1.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e3b66fe6131b4f33d239f7d4c3bfb2f8532d8644bae3b3da4f3987073edac55"}, + {file = "pyzmq-26.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59b57e912feef6951aec8bb03fe0faa5ad5f36962883c72a30a9c965e6d988fd"}, + {file = "pyzmq-26.1.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:146956aec7d947c5afc5e7da0841423d7a53f84fd160fff25e682361dcfb32cb"}, + {file = "pyzmq-26.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9521b874fd489495865172f344e46e0159095d1f161858e3fc6e28e43ca15160"}, + {file = "pyzmq-26.1.1.tar.gz", hash = "sha256:a7db05d8b7cd1a8c6610e9e9aa55d525baae7a44a43e18bc3260eb3f92de96c6"}, ] [package.dependencies] @@ -3353,19 +3368,19 @@ win32 = ["pywin32"] [[package]] name = "setuptools" -version = "72.1.0" +version = "73.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"}, - {file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"}, + {file = "setuptools-73.0.0-py3-none-any.whl", hash = "sha256:f2bfcce7ae1784d90b04c57c2802e8649e1976530bb25dc72c2b078d3ecf4864"}, + {file = "setuptools-73.0.0.tar.gz", hash = "sha256:3c08705fadfc8c7c445cf4d98078f0fafb9225775b2b4e8447e40348f82597c0"}, ] [package.extras] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] [[package]] name = "six" @@ -3402,13 +3417,13 @@ files = [ [[package]] name = "soupsieve" -version = "2.5" +version = "2.6" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" files = [ - {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, - {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, + {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, + {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, ] [[package]] @@ -3935,13 +3950,13 @@ files = [ [[package]] name = "webcolors" -version = "24.6.0" +version = "24.8.0" description = "A library for working with the color formats defined by HTML and CSS." optional = false python-versions = ">=3.8" files = [ - {file = "webcolors-24.6.0-py3-none-any.whl", hash = "sha256:8cf5bc7e28defd1d48b9e83d5fc30741328305a8195c29a8e668fa45586568a1"}, - {file = "webcolors-24.6.0.tar.gz", hash = "sha256:1d160d1de46b3e81e58d0a280d0c78b467dc80f47294b91b1ad8029d2cedb55b"}, + {file = "webcolors-24.8.0-py3-none-any.whl", hash = "sha256:fc4c3b59358ada164552084a8ebee637c221e4059267d0f8325b3b560f6c7f0a"}, + {file = "webcolors-24.8.0.tar.gz", hash = "sha256:08b07af286a01bcd30d583a7acadf629583d1f79bfef27dd2c2c5c263817277d"}, ] [package.extras] @@ -3977,36 +3992,37 @@ test = ["websockets"] [[package]] name = "xarray" -version = "2023.12.0" +version = "2024.7.0" description = "N-D labeled arrays and datasets in Python" optional = false python-versions = ">=3.9" files = [ - {file = "xarray-2023.12.0-py3-none-any.whl", hash = "sha256:3c22b6824681762b6c3fcad86dfd18960a617bccbc7f456ce21b43a20e455fb9"}, - {file = "xarray-2023.12.0.tar.gz", hash = "sha256:4565dbc890de47e278346c44d6b33bb07d3427383e077a7ca8ab6606196fd433"}, + {file = "xarray-2024.7.0-py3-none-any.whl", hash = "sha256:1b0fd51ec408474aa1f4a355d75c00cc1c02bd425d97b2c2e551fd21810e7f64"}, + {file = "xarray-2024.7.0.tar.gz", hash = "sha256:4cae512d121a8522d41e66d942fb06c526bc1fd32c2c181d5fe62fe65b671638"}, ] [package.dependencies] -numpy = ">=1.22" -packaging = ">=21.3" -pandas = ">=1.4" +numpy = ">=1.23" +packaging = ">=23.1" +pandas = ">=2.0" [package.extras] accel = ["bottleneck", "flox", "numbagg", "opt-einsum", "scipy"] -complete = ["xarray[accel,io,parallel,viz]"] +complete = ["xarray[accel,dev,io,parallel,viz]"] +dev = ["hypothesis", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-env", "pytest-timeout", "pytest-xdist", "ruff", "xarray[complete]"] io = ["cftime", "fsspec", "h5netcdf", "netCDF4", "pooch", "pydap", "scipy", "zarr"] parallel = ["dask[complete]"] viz = ["matplotlib", "nc-time-axis", "seaborn"] [[package]] name = "zipp" -version = "3.19.2" +version = "3.20.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, - {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, + {file = "zipp-3.20.0-py3-none-any.whl", hash = "sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d"}, + {file = "zipp-3.20.0.tar.gz", hash = "sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31"}, ] [package.extras] @@ -4016,4 +4032,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = ">=3.10" -content-hash = "60c570ef4d977a74de54a3703da5282cd59e10c89ea5b8ad2e8573d305b30499" +content-hash = "47bf9006da7dea679c3ebd0892d08041d477bbcc3d898326280382a6e48777c8" diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 8e9f0cbc..fd3b2447 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -224,8 +224,8 @@ class SubdailyPModel: externally calculated per-observation estimates of kphio. fill_kind: The approach used to fill daily realised values to the subdaily timescale, currently one of 'previous' or 'linear'. - init_realised: A tuple of three NumPy arrays (xi_real, vcmax25_real, - jmax25_real). + init_realised: A tuple of initial realised values of three NumPy arrays + (xi_real, vcmax25_real, jmax25_real). """ def __init__( From 2ad424f51791fad1fe06f06dfe1cd817916b8419 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 17:52:04 +0000 Subject: [PATCH 059/241] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.5.6 → v0.6.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.6...v0.6.2) - [github.com/pre-commit/mirrors-mypy: v1.11.1 → v1.11.2](https://github.com/pre-commit/mirrors-mypy/compare/v1.11.1...v1.11.2) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7feca378..6ec0a712 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ repos: - id: debug-statements - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.5.6 + rev: v0.6.2 hooks: # Run the linter. - id: ruff @@ -14,7 +14,7 @@ repos: # Run the formatter. - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.11.1" + rev: "v1.11.2" hooks: - id: mypy additional_dependencies: [numpy, types-tabulate, pandas-stubs] From 4fd72231db186912024bf002faa7cd69162a5d75 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 17:46:09 +0000 Subject: [PATCH 060/241] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.2 → v0.6.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.2...v0.6.3) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6ec0a712..a6c6ab87 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ repos: - id: debug-statements - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.2 + rev: v0.6.3 hooks: # Run the linter. - id: ruff From e598bac896cd3ebe79c3b2bd491f5dc8afdfbc9b Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 5 Sep 2024 14:56:07 +0100 Subject: [PATCH 061/241] Revised implementation of Flora and PlantFunctionalType --- docs/source/users/tmodel/canopy.md | 662 ++++++++++++++++++ pyrealm/canopy_model/model/flora.py | 230 ++++++ pyrealm_build_data/community/pfts.csv | 3 + pyrealm_build_data/community/pfts.json | 41 ++ pyrealm_build_data/community/pfts.toml | 37 + pyrealm_build_data/community/pfts_invalid.csv | 3 + .../community/pfts_invalid.json | 41 ++ .../community/pfts_invalid.toml | 37 + pyrealm_build_data/community/pfts_partial.csv | 3 + .../community/pfts_partial.json | 40 ++ .../community/pfts_partial.toml | 35 + tests/unit/demography/test_flora.py | 227 ++++++ 12 files changed, 1359 insertions(+) create mode 100644 docs/source/users/tmodel/canopy.md create mode 100644 pyrealm/canopy_model/model/flora.py create mode 100644 pyrealm_build_data/community/pfts.csv create mode 100644 pyrealm_build_data/community/pfts.json create mode 100644 pyrealm_build_data/community/pfts.toml create mode 100644 pyrealm_build_data/community/pfts_invalid.csv create mode 100644 pyrealm_build_data/community/pfts_invalid.json create mode 100644 pyrealm_build_data/community/pfts_invalid.toml create mode 100644 pyrealm_build_data/community/pfts_partial.csv create mode 100644 pyrealm_build_data/community/pfts_partial.json create mode 100644 pyrealm_build_data/community/pfts_partial.toml create mode 100644 tests/unit/demography/test_flora.py diff --git a/docs/source/users/tmodel/canopy.md b/docs/source/users/tmodel/canopy.md new file mode 100644 index 00000000..36716461 --- /dev/null +++ b/docs/source/users/tmodel/canopy.md @@ -0,0 +1,662 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: pyrealm_python3 + language: python + name: pyrealm_python3 +--- + +# Canopy model + +This notebook walks through the steps in generating the canopy model as (hopefully) used +in Plant-FATE. + +## The T Model + +The T Model provides a numerical description of how tree geometry scales with stem +diameter, and an allocation model of how GPP predicts changes in stem diameter. + +The implementation in `pyrealm` provides a class representing a particular plant +functional type, using a set of traits. The code below creates a PFT with the default +set of trait values. + +```{warning} +This sketch: + +* Assumes a single individual of each stem diameter, but in practice + we are going to want to include a number of individuals to capture cohorts. +* Assumes a single PFT, where we will need to provide a mixed community. +* Consequently handles forest inventory properties in a muddled way: we will + likely package all of the stem data into a single class, probably a community + object. +``` + +```{code-cell} +import numpy as np +import matplotlib.pyplot as plt +from scipy.optimize import root_scalar + +from pyrealm.tmodel import TTree + +np.set_printoptions(precision=3) + +# Plant functional type with default parameterization +pft = TTree(diameters=np.array([0.1, 0.15, 0.2, 0.25, 0.38, 0.4, 1.0])) +pft.traits +``` + +The scaling of a set of trees is automatically calculated using the initial diameters to +the `TTree` instance. This automatically calculates the other dimensions, such as +height, using the underlying scaling equations of the T Model. + +```{code-cell} +pft.height +``` + +```{code-cell} +pft.crown_area +``` + +### Crown shape + +Jaideep's extension of the T Model adds a crown shape model, driven by two parameters +($m$ and $n$) that provide a very flexible description of the vertical crown profile. +These are used to derive two further invariant parameters: $q_m$ scales the canopy +radius to match the predictions of crown area under the T model and $p_{zm}$ is the +proportion of the total stem height at which the maximum crown radius occurs. Both these +values are constant for a plant functional type. + +$$ +\begin{align} +q_m &= m n \left(\dfrac{n-1}{m n -1}\right)^ {1 - \tfrac{1}{n}} + \left(\dfrac{\left(m-1\right) n}{m n -1}\right)^ {m-1} \\[8pt] +p_{zm} &= \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}} +\end{align} +$$ + +For individual stems, with expected height $H$ and crown area $A_c$, we can then +estimate: + +* the height $z_m$ at which the maximum crown radius $r_m$ is found, and +* a slope $r_0$ that scales the relative canopy radius so that the $r_m$ matches + the allometric prediction of $A_c$ from the T Model. + +$$ +\begin{align} +z_m &= H p_{zm}\\[8pt] +r_0 &= \frac{1}{q_m}\sqrt{\frac{A_c}{\pi}} +\end{align} +$$ + +```{code-cell} +def calculate_qm(m, n): + + # Constant q_m + return ( + m + * n + * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) + * (((m - 1) * n) / (m * n - 1)) ** (m - 1) + ) + + +def calculate_stem_canopy_factors(pft, m, n): + + # Height of maximum crown radius + zm = pft.height * ((n - 1) / (m * n - 1)) ** (1 / n) + + # Slope to give Ac at zm + r0 = 1 / qm * np.sqrt(pft.crown_area / np.pi) + + return zm, r0 + + +# Shape parameters for a fairly top heavy crown profile +m = 2 +n = 5 +qm = calculate_qm(m=m, n=n) +zm, r0 = calculate_stem_canopy_factors(pft=pft, m=m, n=n) + +print("qm = ", np.round(qm, 4)) +print("zm = ", zm) +print("r0 = ", r0) +``` + +The following functions then provide the value at height $z$ of relative $q(z)$ and +actual $r(z)$ canopy radius: + +$$ +\begin{align} +q(z) &= m n \left(\dfrac{z}{H}\right) ^ {n -1} + \left( 1 - \left(\dfrac{z}{H}\right) ^ n \right)^{m-1}\\[8pt] +r(z) &= r_0 \; q(z) +\end{align} +$$ + +```{code-cell} +def calculate_relative_canopy_radius_at_z(z, H, m, n): + """Calculate q(z)""" + + z_over_H = z / H + + return m * n * z_over_H ** (n - 1) * (1 - z_over_H**n) ** (m - 1) +``` + +```{code-cell} +# Validate that zm and r0 generate the predicted maximum crown area +q_zm = calculate_relative_canopy_radius_at_z(zm, pft.height, m, n) +rm = r0 * q_zm +print("rm = ", rm) +``` + +```{code-cell} +np.allclose(rm**2 * np.pi, pft.crown_area) +``` + +Vertical crown radius profiles can now be calculated for each stem: + +```{code-cell} +# Create an interpolation from ground to maximum stem height, with 5 cm resolution. +# Also append a set of values _fractionally_ less than the exact height of stems +# so that the height at the top of each stem is included but to avoid floating +# point issues with exact heights. + +zres = 0.05 +z = np.arange(0, pft.height.max() + 1, zres) +z = np.sort(np.concatenate([z, pft.height - 0.00001])) + +# Convert the heights into a column matrix to broadcast against the stems +# and then calculate r(z) = r0 * q(z) +rz = r0 * calculate_relative_canopy_radius_at_z(z[:, None], pft.height, m, n) + +# When z > H, rz < 0, so set radius to 0 where rz < 0 +rz[np.where(rz < 0)] = 0 + +np.cumsum(np.convolve(rm, np.ones(2), "valid") + 0.1) +``` + +Those can be plotted out to show the vertical crown radius profiles + +```{code-cell} +# Separate the stems along the x axis for plotting +stem_x = np.concatenate( + [np.array([0]), np.cumsum(np.convolve(rm, np.ones(2), "valid") + 0.4)] +) + +# Get the canopy sections above and below zm +rz_above_zm = np.where(np.logical_and(rz > 0, np.greater.outer(z, zm)), rz, np.nan) +rz_below_zm = np.where(np.logical_and(rz > 0, np.less_equal.outer(z, zm)), rz, np.nan) + +# Plot the canopy parts +plt.plot(stem_x + rz_below_zm, z, color="khaki") +plt.plot(stem_x - rz_below_zm, z, color="khaki") +plt.plot(stem_x + rz_above_zm, z, color="forestgreen") +plt.plot(stem_x - rz_above_zm, z, color="forestgreen") + +# Add the maximum radius +plt.plot(np.vstack((stem_x - rm, stem_x + rm)), np.vstack((zm, zm)), color="firebrick") + +# Plot the stem centre lines +plt.vlines(stem_x, 0, pft.height, linestyles="-", color="grey") + +plt.gca().set_aspect("equal") +``` + +## Canopy structure + +The canopy structure model uses the perfect plasticity approximation (PPA), which +assumes that plants can arrange their canopies to fill the available space $A$. +It takes the **projected area of stems** $Ap(z)$ within the canopy and finds the heights +at which each canopy layer closes ($z^*_l$ for $l = 1, 2, 3 ...$) where the total projected +area of the canopy equals $lA$. + +### Canopy projected area + +The projected area $A_p$ for a stem with height $H$, a maximum crown area $A_c$ at a +height $z_m$ and $m$, $n$ and $q_m$ for the associated plant functional type is + +$$ +A_p(z)= +\begin{cases} +A_c, & z \le z_m \\ +A_c \left(\dfrac{q(z)}{q_m}\right)^2, & H > z > z_m \\ +0, & z > H +\end{cases} +$$ + +```{code-cell} +Stems = float | np.ndarray + + +def calculate_projected_area( + z: float, + pft, + m: Stems, + n: Stems, + qm: Stems, + zm: Stems, +) -> np.ndarray: + """Calculate projected crown area above a given height. + + This function takes PFT specific parameters (shape parameters) and stem specific + sizes and estimates the projected crown area above a given height $z$. The inputs + can either be scalars describing a single stem or arrays representing a community + of stems. If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can + be scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that + PFT. + + Args: + z: Canopy height + m, n, qm : PFT specific shape parameters + pft, qm, zm: stem data + + """ + + # Calculate q(z) + qz = calculate_relative_canopy_radius_at_z(z, pft.height, m, n) + + # Calculate Ap given z > zm + Ap = pft.crown_area * (qz / qm) ** 2 + # Set Ap = Ac where z <= zm + Ap = np.where(z <= zm, pft.crown_area, Ap) + # Set Ap = 0 where z > H + Ap = np.where(z > pft.height, 0, Ap) + + return Ap +``` + +The code below calculates the projected crown area for each stem and then plots the +vertical profile for individual stems and across the community. + +```{code-cell} +# Calculate the projected area for each stem +Ap_z = calculate_projected_area(z=z[:, None], pft=pft, m=m, n=n, qm=qm, zm=zm) + +# Plot the calculated values for each stem and across the community +fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(10, 5)) + +# Plot the individual stem projected area +ax1.set_ylabel("Height above ground ($z$, m)") +ax1.plot(Ap_z, z) +ax1.set_xlabel("Stem $A_p(z)$ (m2)") + +# Plot the individual stem projected area +ax2.plot(np.nansum(Ap_z, axis=1), z) +ax2.set_xlabel("Total community $A_p(z)$ (m2)") + +plt.tight_layout() +``` + +### Canopy closure and canopy gap fraction + +The total cumulative projected area shown above is modified by a community-level +**canopy gap fraction** ($f_G$) that captures the overall proportion of the canopy area +that is left unfilled by canopy. This gap fraction, capturing processes such as crown +shyness, describes the proportion of open sky visible from the forest floor. + +The definition of the height of canopy layer closure ($z^*_l$) for a given canopy +layer $l = 1, ..., l_m$ is then: + +$$ +\sum_1^{N_s}{ A_p(z^*_l)} = l A(1 - f_G) +$$ + +This can be found numerically using a root solver as: + +$$ +\sum_1^{N_s}{ A_p(z^*_l)} - l A(1 - f_G) = 0 +$$ + +The total number of layers $l_m$ in a canopy, where the final layer may not be fully closed, +can be found given the total crown area across stems as: + +$$ +l_m = \left\lceil \frac{\sum_1^{N_s}{ A_c}}{ A(1 - f_G)}\right\rceil +$$ + +```{code-cell} +def solve_canopy_closure_height( + z: float, + l: int, + A: float, + fG: float, + m: Stems, + n: Stems, + qm: Stems, + pft: Stems, + zm: Stems, +) -> np.ndarray: + """Solver function for canopy closure height. + + This function returns the difference between the total community projected area + at a height $z$ and the total available canopy space for canopy layer $l$, given + the community gap fraction for a given height. It is used with a root solver to + find canopy layer closure heights $z^*_l* for a community. + + Args: + m, n, qm : PFT specific shape parameters + H, Ac, zm: stem specific sizes + A, l: cell area and layer index + fG: community gap fraction + """ + + # Calculate Ap(z) + Ap_z = calculate_projected_area(z=z, pft=pft, m=m, n=n, qm=qm, zm=zm) + + # Return the difference between the projected area and the available space + return Ap_z.sum() - (A * l) * (1 - fG) + + +def calculate_canopy_heights( + A: float, + fG: float, + m: Stems, + n: Stems, + qm: Stems, + pft, + zm: Stems, +): + + # Calculate the number of layers + total_community_ca = pft.crown_area.sum() + n_layers = int(np.ceil(total_community_ca / (A * (1 - fG)))) + + # Data store for z* + z_star = np.zeros(n_layers) + + # Loop over the layers TODO - edge case of completely filled final layer + for lyr in np.arange(n_layers - 1): + z_star[lyr] = root_scalar( + solve_canopy_closure_height, + args=(lyr + 1, A, fG, m, n, qm, pft, zm), + bracket=(0, pft.height.max()), + ).root + + return z_star +``` + +The example below calculates the projected crown area above ground level for the example +stems. These should be identical to the crown area of the stems. + +```{code-cell} +# Set the total available canopy space and community gap fraction +canopy_area = 32 +community_gap_fraction = 2 / 32 + +z_star = calculate_canopy_heights( + A=canopy_area, fG=community_gap_fraction, m=m, n=n, qm=qm, pft=pft, zm=zm +) + +print("z_star = ", z_star) +``` + +We can now plot the canopy stems alongside the community $A_p(z)$ profile, and +superimpose the calculated $z^*_l$ values and the cumulative canopy area for each layer +to confirm that the calculated values coincide with the profile. Note here that the +total area at each closed layer height is omitting the community gap fraction. + +```{code-cell} +community_Ap_z = np.nansum(Ap_z, axis=1) + +fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(10, 5)) + +zcol = "red" + +# Plot the canopy parts +ax1.plot(stem_x + rz_below_zm, z, color="khaki") +ax1.plot(stem_x - rz_below_zm, z, color="khaki") +ax1.plot(stem_x + rz_above_zm, z, color="forestgreen") +ax1.plot(stem_x - rz_above_zm, z, color="forestgreen") + +# Add the maximum radius +ax1.plot(np.vstack((stem_x - rm, stem_x + rm)), np.vstack((zm, zm)), color="firebrick") + +# Plot the stem centre lines +ax1.vlines(stem_x, 0, pft.height, linestyles="-", color="grey") + +ax1.set_ylabel("Height above ground ($z$, m)") +ax1.set_xlabel("Arbitrary stem position") +ax1.hlines(z_star, 0, (stem_x + rm).max(), color=zcol, linewidth=0.5) + +# Plot the projected community crown area by height along with the heights +# at which different canopy layers close +ax2.hlines(z_star, 0, community_Ap_z.max(), color=zcol, linewidth=0.5) +ax2.vlines( + canopy_area * np.arange(1, len(z_star)) * (1 - community_gap_fraction), + 0, + pft.height.max(), + color=zcol, + linewidth=0.5, +) + +ax2.plot(community_Ap_z, z) +ax2.set_xlabel("Projected crown area above height $z$ ($A_p(z)$, m2)") + +# Add z* values on the righthand axis +ax3 = ax2.twinx() + + +def z_star_labels(X): + return [f"$z^*_{l + 1}$ = {z:.2f}" for l, z in enumerate(X)] + + +ax3.set_ylim(ax2.get_ylim()) +ax3.set_yticks(z_star) +ax3.set_yticklabels(z_star_labels(z_star)) + +ax4 = ax2.twiny() + +# Add canopy layer closure areas on top axis +cum_area = np.arange(1, len(z_star)) * canopy_area * (1 - community_gap_fraction) + + +def cum_area_labels(X): + return [f"$A_{l + 1}$ = {z:.1f}" for l, z in enumerate(X)] + + +ax4.set_xlim(ax2.get_xlim()) +ax4.set_xticks(cum_area) +ax4.set_xticklabels(cum_area_labels(cum_area)) + +plt.tight_layout() +``` + +The projected area from individual stems to each canopy layer can then be calculated at +$z^*_l$ and hence the projected area of canopy **within each layer**. + +```{code-cell} +# Calculate the canopy area above z_star for each stem +Ap_z_star = calculate_projected_area(z=z_star[:, None], pft=pft, m=m, n=n, qm=qm, zm=zm) + +print(Ap_z_star) +``` + +```{code-cell} +# Calculate the contribution _within_ each layer per stem +Ap_within_layer = np.diff(Ap_z_star, axis=0, prepend=0) + +print(Ap_within_layer) +``` + +### Leaf area within canopy layers + +The projected area occupied by leaves at a given height $\tilde{A}_{cp}(z)$ is +needed to calculate light transmission through those layers. This differs from the +projected area $A_p(z)$ because, although a tree occupies an area in the canopy +following the PPA, a **crown gap fraction** ($f_g$) reduces the actual leaf area +at a given height $z$. + +The crown gap fraction does not affect the overall projected canopy area at ground +level or the community gap fraction: the amount of clear sky at ground level is +governed purely by $f_G$. Instead it models how leaf gaps in the upper canopy are +filled by leaf area at lower heights. It captures the vertical distribution of +leaf area within the canopy: a higher $f_g$ will give fewer leaves at the top of +the canopy and more leaves further down within the canopy. + +The calculation of $\tilde{A}_{cp}(z)$ is defined as: + +$$ +\tilde{A}_{cp}(z)= +\begin{cases} +0, & z \gt H \\ +A_c \left(\dfrac{q(z)}{q_m}\right)^2 \left(1 - f_g\right), & H \gt z \gt z_m \\ +Ac - A_c \left(\dfrac{q(z)}{q_m}\right)^2 f_g, & zm \gt z +\end{cases} +$$ + +The function below calculates $\tilde{A}_{cp}(z)$. + +```{code-cell} +def calculate_leaf_area( + z: float, + fg: float, + pft, + m: Stems, + n: Stems, + qm: Stems, + zm: Stems, +) -> np.ndarray: + """Calculate leaf area above a given height. + + This function takes PFT specific parameters (shape parameters) and stem specific + sizes and estimates the projected crown area above a given height $z$. The inputs + can either be scalars describing a single stem or arrays representing a community + of stems. If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can + be scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that + PFT. + + Args: + z: Canopy height + fg: crown gap fraction + m, n, qm : PFT specific shape parameters + pft, qm, zm: stem data + """ + + # Calculate q(z) + qz = calculate_relative_canopy_radius_at_z(z, pft.height, m, n) + + # Calculate Ac term + Ac_term = pft.crown_area * (qz / qm) ** 2 + # Set Acp either side of zm + Acp = np.where(z <= zm, pft.crown_area - Ac_term * fg, Ac_term * (1 - fg)) + # Set Ap = 0 where z > H + Acp = np.where(z > pft.height, 0, Acp) + + return Acp +``` + +The plot below shows how the vertical leaf area profile for the community changes for +different values of $f_g$. When $f_g = 0$, then $A_cp(z) = A_p(z)$ (red line) because +there are no crown gaps and hence all of the leaf area is within the crown surface. As +$f_g \to 1$, more of the leaf area is displaced deeper into the canopy, leaves in the +lower crown intercepting light coming through holes in the upper canopy. + +```{code-cell} +fig, ax1 = plt.subplots(1, 1, figsize=(6, 5)) + +for fg in np.arange(0, 1.01, 0.05): + + if fg == 0: + color = "red" + label = "$f_g = 0$" + lwd = 0.5 + elif fg == 1: + color = "blue" + label = "$f_g = 1$" + lwd = 0.5 + else: + color = "black" + label = None + lwd = 0.25 + + Acp_z = calculate_leaf_area(z=z[:, None], fg=fg, pft=pft, m=m, n=n, qm=qm, zm=zm) + ax1.plot(np.nansum(Acp_z, axis=1), z, color=color, linewidth=lwd, label=label) + +ax1.set_xlabel(r"Projected leaf area above height $z$ ($\tilde{A}_{cp}(z)$, m2)") +ax1.legend(frameon=False) +``` + +We can now calculate the crown area occupied by leaves above the height of each closed +layer $z^*_l$: + +```{code-cell} +# Calculate the leaf area above z_star for each stem +crown_gap_fraction = 0.05 +Acp_z_star = calculate_leaf_area( + z=z_star[:, None], fg=crown_gap_fraction, pft=pft, m=m, n=n, qm=qm, zm=zm +) + +print(Acp_z_star) +``` + +And from that, the area occupied by leaves **within each layer**. These values are +similar to the projected crown area within layers (`Ap_within_layer`, above) but +leaf area is displaced into lower layers because $f_g > 0$. + +```{code-cell} +# Calculate the contribution _within_ each layer per stem +Acp_within_layer = np.diff(Acp_z_star, axis=0, prepend=0) + +print(Acp_within_layer) +``` + +### Light transmission through the canopy + +Now we can use the leaf area by layer and the Beer-Lambert equation to calculate light +attenuation through the canopy layers. + +$f_{abs} = 1 - e ^ {-kL}$, + +where $k$ is the light extinction coefficient ($k$) and $L$ is the leaf area index +(LAI). The LAI can be calculated for each stem and layer: + +```{code-cell} +LAI = Acp_within_layer / canopy_area +print(LAI) +``` + +This can be used to calculate the LAI of individual stems but also the LAI of each layer +in the canopy: + +```{code-cell} +LAI_stem = LAI.sum(axis=0) +LAI_layer = LAI.sum(axis=1) + +print("LAI stem = ", LAI_stem) +print("LAI layer = ", LAI_layer) +``` + +The layer LAI values can now be used to calculate the light transmission of each layer and +hence the cumulative light extinction profile through the canopy. + +```{code-cell} +f_abs = 1 - np.exp(-pft.traits.par_ext * LAI_layer) +ext = np.cumproduct(f_abs) + +print("f_abs = ", f_abs) +print("extinction = ", ext) +``` + +One issue that needs to be resolved is that the T Model implementation in `pyrealm` +follows the original implementation of the T Model in having LAI as a fixed trait of +a given plant functional type, so is constant for all stems of that PFT. + +```{code-cell} +print("f_abs = ", (1 - np.exp(-pft.traits.par_ext * pft.traits.lai))) +``` + +## Things to worry about later + +Herbivory - leaf fall (transmission increases, truncate at 0, replace from NSCs) vs leaf +turnover (transmission constant, increased GPP penalty) + +Leaf area dynamics in PlantFATE - acclimation to herbivory and transitory decreases in +transimission, need non-structural carbohydrates to recover from total defoliation. + +Leaf economics. diff --git a/pyrealm/canopy_model/model/flora.py b/pyrealm/canopy_model/model/flora.py new file mode 100644 index 00000000..2b5a7d43 --- /dev/null +++ b/pyrealm/canopy_model/model/flora.py @@ -0,0 +1,230 @@ +"""Base objects for import to the canopy module.""" + +from __future__ import annotations + +import json +import sys +from collections import Counter +from collections.abc import Sequence +from dataclasses import dataclass, field +from pathlib import Path + +import marshmallow_dataclass +import pandas as pd +from marshmallow.exceptions import ValidationError + +if sys.version_info[:2] >= (3, 11): + import tomllib + from tomllib import TOMLDecodeError +else: + import tomli as tomllib + from tomli import TOMLDecodeError + + +@dataclass +class PlantFunctionalType: + """The PlantFunctionalType dataclass. + + This dataclass implements the set of traits required to define a plant functional + type for use in ``pyrealm``. The majority of the traits are those required to + parameterise the T Model :cite:`Li:2014bc`. The + default values are taken from Table 1 of :cite:t:`Li:2014bc`. + + Note that the foliage maintenance respiration fraction is not named in the original + T Model implementation, but has been included as a modifiable trait in this + implementation. This implementation adds two further canopy shape parameters (``m`` + and ``n``), which are then used to calculate two derived attributes (``q_m`` and + ``z_max_ratio``). + """ + + name: str + """The name of the plant functional type.""" + a_hd: float = 116.0 + """Initial slope of height-diameter relationship (:math:`a`, 116.0, -)""" + ca_ratio: float = 390.43 + """Initial ratio of crown area to stem cross-sectional area + (:math:`c`, 390.43, -)""" + h_max: float = 25.33 + """Maximum tree height (:math:`H_m`, 25.33, m)""" + rho_s: float = 200.0 + r"""Sapwood density (:math:`\rho_s`, 200.0, kg Cm-3)""" + lai: float = 1.8 + """Leaf area index within the crown (:math:`L`, 1.8, -)""" + sla: float = 14.0 + r"""Specific leaf area (:math:`\sigma`, 14.0, m2 kg-1 C)""" + tau_f: float = 4.0 + r"""Foliage turnover time (:math:`\tau_f`, 4.0, years)""" + tau_r: float = 1.04 + """Fine-root turnover time (:math:`\tau_r`, 1.04, years)""" + par_ext: float = 0.5 + """Extinction coefficient of photosynthetically active radiation (PAR) (:math:`k`, + 0.5, -)""" + yld: float = 0.17 + """Yield_factor (:math:`y`, 0.17, -)""" + zeta: float = 0.17 + r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, 0.17, kg C m-2)""" + resp_r: float = 0.913 + """Fine-root specific respiration rate (:math:`r_r`, 0.913, year-1)""" + resp_s: float = 0.044 + """Sapwood-specific respiration rate (:math:`r_s`, 0.044, year-1)""" + resp_f: float = 0.1 + """Foliage maintenance respiration fraction (:math:`r_f`, 0.1, -)""" + m: float = 2 + """Canopy shape parameter (:math:`m`, -)""" + n: float = 5 + """Canopy shape parameter (:math:`n`, -)""" + + q_m: float = field(init=False) + """Scaling factor to derive maximum crown radius from crown area.""" + z_max_prop: float = field(init=False) + """Proportion of stem height at which maximum crown radius is found.""" + + def __post_init__(self) -> None: + """Populate derived attributes. + + This method populates the ``q_m`` and ``z_max_ratio`` attributes from the + provided values of ``m`` and ``n``. + """ + + # Calculate q_m + self.q_m = calculate_q_m(m=self.m, n=self.n) + self.z_max_prop = calculate_z_max_proportion(m=self.m, n=self.n) + + +PlantFunctionalTypeSchema = marshmallow_dataclass.class_schema(PlantFunctionalType) +"""Marshmallow validation schema class for validating PlantFunctionalType data.""" + + +def calculate_q_m(m: float, n: float) -> float: + """Calculate a q_m value. + + The value of q_m is a constant canopy scaling parameter derived from the ``m`` and + ``n`` attributes defined for a plant functional type. + + Args: + m: Canopy shape parameter + n: Canopy shape parameter + """ + return ( + m + * n + * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) + * (((m - 1) * n) / (m * n - 1)) ** (m - 1) + ) + + +def calculate_z_max_proportion(m: float, n: float) -> float: + """Calculate the z_m proportion. + + The z_m proportion is the constant proportion of stem height at which the maximum + crown radius is found for a given plant functional type. + + Args: + m: Canopy shape parameter + n: Canopy shape parameter + """ + + return ((n - 1) / (m * n - 1)) ** (1 / n) + + +class Flora(dict[str, PlantFunctionalType]): + """Defines the flora used in a ``virtual_ecosystem`` model. + + The flora is the set of plant functional types used within a particular simulation + and this class provides dictionary-like access to a defined set of + :class:`~virtual_ecosystem.models.plants.functional_types.PlantFunctionalType` + instances. + + Instances of this class should not be altered during model fitting, at least until + the point where plant evolution is included in the modelling process. + + Args: + pfts: A sequence of ``PlantFunctionalType`` instances, which must not have + duplicated + :attr:`~virtual_ecosystem.models.plants.functional_types.PlantFunctionalType.pft_name` + attributes. + """ + + def __init__(self, pfts: Sequence[PlantFunctionalType]) -> None: + # Initialise the dict superclass to implement dict like behaviour + super().__init__() + + # Check the PFT data + if (not isinstance(pfts, Sequence)) or ( + not all([isinstance(v, PlantFunctionalType) for v in pfts]) + ): + raise ValueError( + "The pfts argument must be a sequence of PlantFunctionalType instances" + ) + + # Validate the PFT instances - check there are no duplicate PFT names. + pft_names = Counter([p.name for p in pfts]) + duplicates = [k for k, v in pft_names.items() if v > 1] + + if duplicates: + raise ValueError( + f"Duplicated plant functional type names: {','.join(duplicates)}" + ) + + # Populate the dictionary using the PFT name as key + for name, pft in zip(pft_names, pfts): + self[name] = pft + + @classmethod + def _from_file_data(cls, file_data: dict) -> Flora: + """Create a Flora object from a JSON string. + + Args: + file_data: The payload from a data file defining plant functional types. + """ + try: + pfts = PlantFunctionalTypeSchema().load(file_data["pft"], many=True) # type: ignore[attr-defined] + except ValidationError as excep: + raise excep + + return cls(pfts=pfts) + + @classmethod + def from_json(cls, path: Path) -> Flora: + """Create a Flora object from a JSON file. + + Args: + path: A path to a JSON file of plant functional type definitions. + """ + + try: + file_data = json.load(open(path)) + except (FileNotFoundError, json.JSONDecodeError) as excep: + raise excep + + return cls._from_file_data(file_data=file_data) + + @classmethod + def from_toml(cls, path: Path) -> Flora: + """Create a Flora object from a TOML file. + + Args: + path: A path to a TOML file of plant functional type definitions. + """ + + try: + file_data = tomllib.load(open(path, "rb")) + except (FileNotFoundError, TOMLDecodeError) as excep: + raise excep + + return cls._from_file_data(file_data) + + @classmethod + def from_csv(cls, path: Path) -> Flora: + """Create a Flora object from a CSV file. + + Args: + path: A path to a CSV file of plant functional type definitions. + """ + + try: + data = pd.read_csv(path) + except (FileNotFoundError, pd.errors.ParserError) as excep: + raise excep + + return cls._from_file_data({"pft": data.to_dict(orient="records")}) diff --git a/pyrealm_build_data/community/pfts.csv b/pyrealm_build_data/community/pfts.csv new file mode 100644 index 00000000..1f0c0aab --- /dev/null +++ b/pyrealm_build_data/community/pfts.csv @@ -0,0 +1,3 @@ +name,a_hd,ca_ratio,h_max,lai,par_ext,resp_f,resp_r,resp_s,rho_s,sla,tau_f,tau_r,yld,zeta,m,n +test1,116.0,390.43,25.33,1.8,0.5,0.1,0.913,0.044,200.0,14.0,4.0,1.04,0.17,0.17,2,5 +test2,116.0,390.43,15.33,1.8,0.5,0.1,0.913,0.044,200.0,14.0,4.0,1.04,0.17,0.17,2,5 \ No newline at end of file diff --git a/pyrealm_build_data/community/pfts.json b/pyrealm_build_data/community/pfts.json new file mode 100644 index 00000000..5cafa9d2 --- /dev/null +++ b/pyrealm_build_data/community/pfts.json @@ -0,0 +1,41 @@ +{"pft": [ + { + "name": "test1", + "a_hd": 116.0, + "ca_ratio": 390.43, + "h_max": 25.33, + "lai": 1.8, + "par_ext": 0.5, + "resp_f": 0.1, + "resp_r": 0.913, + "resp_s": 0.044, + "rho_s": 200.0, + "sla": 14.0, + "tau_f": 4.0, + "tau_r": 1.04, + "yld": 0.17, + "zeta": 0.17, + "m": 2, + "n": 5 + }, + { + "name": "test2", + "a_hd": 116.0, + "ca_ratio": 390.43, + "h_max": 15.33, + "lai": 1.8, + "par_ext": 0.5, + "resp_f": 0.1, + "resp_r": 0.913, + "resp_s": 0.044, + "rho_s": 200.0, + "sla": 14.0, + "tau_f": 4.0, + "tau_r": 1.04, + "yld": 0.17, + "zeta": 0.17, + "m": 2, + "n": 5 + } +] +} \ No newline at end of file diff --git a/pyrealm_build_data/community/pfts.toml b/pyrealm_build_data/community/pfts.toml new file mode 100644 index 00000000..4e31c832 --- /dev/null +++ b/pyrealm_build_data/community/pfts.toml @@ -0,0 +1,37 @@ +[[pft]] +a_hd = 116.0 +ca_ratio = 390.43 +h_max = 25.33 +lai = 1.8 +name = 'test1' +par_ext = 0.5 +resp_f = 0.1 +resp_r = 0.913 +resp_s = 0.044 +rho_s = 200.0 +sla = 14.0 +tau_f = 4.0 +tau_r = 1.04 +yld = 0.17 +zeta = 0.17 +m = 2 +n = 5 + +[[pft]] +a_hd = 116.0 +ca_ratio = 390.43 +h_max = 15.33 +lai = 1.8 +name = 'test2' +par_ext = 0.5 +resp_f = 0.1 +resp_r = 0.913 +resp_s = 0.044 +rho_s = 200.0 +sla = 14.0 +tau_f = 4.0 +tau_r = 1.04 +yld = 0.17 +zeta = 0.17 +m = 2 +n = 5 diff --git a/pyrealm_build_data/community/pfts_invalid.csv b/pyrealm_build_data/community/pfts_invalid.csv new file mode 100644 index 00000000..e1e94908 --- /dev/null +++ b/pyrealm_build_data/community/pfts_invalid.csv @@ -0,0 +1,3 @@ +name,a_hd,ca_ratio,h_max,laindex,par_ext,resp_f,resp_r,resp_s,rho_s,sla,tau_f,tau_r,yld,zeta,m,n +test1,116.0,390.43,25.33,1.8,0.5,0.1,0.913,0.044,200.0,14.0,4.0,1.04,0.17,0.17,a,5 +test2,116.0,390.43,15.33,1.8,0.5,0.1,0.913,0.044,200.0,14.0,4.0,1.04,0.17,0.17,a,5 \ No newline at end of file diff --git a/pyrealm_build_data/community/pfts_invalid.json b/pyrealm_build_data/community/pfts_invalid.json new file mode 100644 index 00000000..9bececdc --- /dev/null +++ b/pyrealm_build_data/community/pfts_invalid.json @@ -0,0 +1,41 @@ +{"pft": [ + { + "name": "test1", + "a_hd": 116.0, + "ca_ratio": 390.43, + "h_max": 25.33, + "laindex": 1.8, + "par_ext": 0.5, + "resp_f": 0.1, + "resp_r": 0.913, + "resp_s": 0.044, + "rho_s": 200.0, + "sla": 14.0, + "tau_f": 4.0, + "tau_r": 1.04, + "yld": 0.17, + "zeta": 0.17, + "m": "a", + "n": 5 + }, + { + "name": "test2", + "a_hd": 116.0, + "ca_ratio": 390.43, + "h_max": 15.33, + "laindex": 1.8, + "par_ext": 0.5, + "resp_f": 0.1, + "resp_r": 0.913, + "resp_s": 0.044, + "rho_s": 200.0, + "sla": 14.0, + "tau_f": 4.0, + "tau_r": 1.04, + "yld": 0.17, + "zeta": 0.17, + "m": "a", + "n": 5 + } +] +} \ No newline at end of file diff --git a/pyrealm_build_data/community/pfts_invalid.toml b/pyrealm_build_data/community/pfts_invalid.toml new file mode 100644 index 00000000..1993518f --- /dev/null +++ b/pyrealm_build_data/community/pfts_invalid.toml @@ -0,0 +1,37 @@ +[[pft]] +a_hd = 116.0 +ca_ratio = 390.43 +h_max = 25.33 +laindex = 1.8 +name = 'test1' +par_ext = 0.5 +resp_f = 0.1 +resp_r = 0.913 +resp_s = 0.044 +rho_s = 200.0 +sla = 14.0 +tau_f = 4.0 +tau_r = 1.04 +yld = 0.17 +zeta = 0.17 +m = 'a' +n = 5 + +[[pft]] +a_hd = 116.0 +ca_ratio = 390.43 +h_max = 15.33 +laindex = 1.8 +name = 'test2' +par_ext = 0.5 +resp_f = 0.1 +resp_r = 0.913 +resp_s = 0.044 +rho_s = 200.0 +sla = 14.0 +tau_f = 4.0 +tau_r = 1.04 +yld = 0.17 +zeta = 0.17 +m = 'a' +n = 5 diff --git a/pyrealm_build_data/community/pfts_partial.csv b/pyrealm_build_data/community/pfts_partial.csv new file mode 100644 index 00000000..2b16910b --- /dev/null +++ b/pyrealm_build_data/community/pfts_partial.csv @@ -0,0 +1,3 @@ +name,a_hd,ca_ratio,h_max,par_ext,resp_f,resp_r,resp_s,rho_s,sla,tau_f,tau_r,yld,zeta,m +test1,116.0,390.43,25.33,0.5,0.1,0.913,0.044,200.0,14.0,4.0,1.04,0.17,0.17,2 +test2,116.0,390.43,15.33,0.5,0.1,0.913,0.044,200.0,14.0,4.0,1.04,0.17,0.17,2 \ No newline at end of file diff --git a/pyrealm_build_data/community/pfts_partial.json b/pyrealm_build_data/community/pfts_partial.json new file mode 100644 index 00000000..a51371f6 --- /dev/null +++ b/pyrealm_build_data/community/pfts_partial.json @@ -0,0 +1,40 @@ +{ + "pft": [ + { + "a_hd": 116.0, + "ca_ratio": 390.43, + "h_max": 25.33, + "name": "test1", + "par_ext": 0.5, + "resp_f": 0.1, + "resp_r": 0.913, + "resp_s": 0.044, + "rho_s": 200.0, + "sla": 14.0, + "tau_f": 4.0, + "tau_r": 1.04, + "yld": 0.17, + "zeta": 0.17, + "m": 2, + "n": 5 + }, + { + "a_hd": 116.0, + "ca_ratio": 390.43, + "h_max": 15.33, + "name": "test2", + "par_ext": 0.5, + "resp_f": 0.1, + "resp_r": 0.913, + "resp_s": 0.044, + "rho_s": 200.0, + "sla": 14.0, + "tau_f": 4.0, + "tau_r": 1.04, + "yld": 0.17, + "zeta": 0.17, + "m": 2, + "n": 5 + } + ] +} \ No newline at end of file diff --git a/pyrealm_build_data/community/pfts_partial.toml b/pyrealm_build_data/community/pfts_partial.toml new file mode 100644 index 00000000..9d64a436 --- /dev/null +++ b/pyrealm_build_data/community/pfts_partial.toml @@ -0,0 +1,35 @@ +[[pft]] +a_hd = 116.0 +ca_ratio = 390.43 +h_max = 25.33 +name = 'test1' +par_ext = 0.5 +resp_f = 0.1 +resp_r = 0.913 +resp_s = 0.044 +rho_s = 200.0 +sla = 14.0 +tau_f = 4.0 +tau_r = 1.04 +yld = 0.17 +zeta = 0.17 +m = 2 +n = 5 + +[[pft]] +a_hd = 116.0 +ca_ratio = 390.43 +h_max = 15.33 +name = 'test2' +par_ext = 0.5 +resp_f = 0.1 +resp_r = 0.913 +resp_s = 0.044 +rho_s = 200.0 +sla = 14.0 +tau_f = 4.0 +tau_r = 1.04 +yld = 0.17 +zeta = 0.17 +m = 2 +n = 5 diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py new file mode 100644 index 00000000..98a1a6a7 --- /dev/null +++ b/tests/unit/demography/test_flora.py @@ -0,0 +1,227 @@ +"""Test flora methods.""" + +import sys +from contextlib import nullcontext as does_not_raise +from importlib import resources +from json import JSONDecodeError + +import pytest +from marshmallow.exceptions import ValidationError +from pandas.errors import ParserError + +if sys.version_info[:2] >= (3, 11): + from tomllib import TOMLDecodeError +else: + from tomli import TOMLDecodeError + +# +# Test PlantFunctionalType dataclass +# + + +@pytest.mark.parametrize( + argnames="args,outcome", + argvalues=[ + pytest.param({"name": "broadleaf"}, does_not_raise(), id="correct"), + pytest.param({}, pytest.raises(TypeError), id="no_name"), + ], +) +def test_PlantFunctionalType__init__(args, outcome): + """Test the plant functional type initialisation.""" + + from pyrealm.canopy_model.model.flora import ( + PlantFunctionalType, + calculate_q_m, + calculate_z_max_proportion, + ) + + with outcome: + pft = PlantFunctionalType(**args) + + # Check name attribute and post_init attributes if instantiation succeeds. + if isinstance(outcome, does_not_raise): + assert pft.name == "broadleaf" + # Expected values from defaults + assert pft.q_m == calculate_q_m(m=2, n=5) + assert pft.z_max_prop == calculate_z_max_proportion(m=2, n=5) + + +# +# Test Flora initialisation +# + + +@pytest.fixture() +def flora_inputs(request): + """Fixture providing flora inputs for testing. + + This is using indirect parameterisation in the test largely to isolate the import of + PlantFunctionalType within a method and to allow a single parameterised test to + have a diverse set of inputs. + """ + + from pyrealm.canopy_model.model.flora import PlantFunctionalType + + broadleaf = PlantFunctionalType(name="broadleaf") + conifer = PlantFunctionalType(name="conifer") + + match request.param: + case "not_sequence": + return "Notasequence" + case "sequence_not_all_pfts": + return [1, 2, 3] + case "single_pft": + return [broadleaf] + case "multiple_pfts": + return [broadleaf, conifer] + case "duplicated_names": + return [broadleaf, broadleaf] + + +@pytest.mark.parametrize( + argnames="flora_inputs,outcome", + argvalues=[ + pytest.param("not_sequence", pytest.raises(ValueError)), + pytest.param("sequence_not_all_pfts", pytest.raises(ValueError)), + pytest.param("single_pft", does_not_raise()), + pytest.param("multiple_pfts", does_not_raise()), + pytest.param("duplicated_names", pytest.raises(ValueError)), + ], + indirect=["flora_inputs"], +) +def test_Flora__init__(flora_inputs, outcome): + """Test the plant functional type initialisation.""" + + from pyrealm.canopy_model.model.flora import Flora + + with outcome: + flora = Flora(pfts=flora_inputs) + + # Simple check that PFT instances are correctly keyed by name. + if isinstance(outcome, does_not_raise): + for k, v in flora.items(): + assert k == v.name + + +# +# Test Flora factory methods from JSON, TOML, CSV +# + + +@pytest.mark.parametrize( + argnames="filename,outcome", + argvalues=[ + pytest.param("pfts.json", does_not_raise(), id="correct"), + pytest.param("pfts_partial.json", does_not_raise(), id="partial"), + pytest.param("pfts.toml", pytest.raises(JSONDecodeError), id="format_wrong"), + pytest.param("no.pfts", pytest.raises(FileNotFoundError), id="file_missing"), + pytest.param("pfts_invalid.json", pytest.raises(ValidationError), id="invalid"), + ], +) +def test_flora_from_json(filename, outcome): + """Test JSON loading.""" + from pyrealm.canopy_model.model.flora import Flora + + datapath = resources.files("pyrealm_build_data.community") / filename + + with outcome: + flora = Flora.from_json(datapath) + + if isinstance(outcome, does_not_raise): + # Coarse check of what got loaded + assert len(flora) == 2 + for nm in ["test1", "test2"]: + assert nm in flora + + +@pytest.mark.parametrize( + argnames="filename,outcome", + argvalues=[ + pytest.param("pfts.toml", does_not_raise(), id="correct"), + pytest.param("pfts_partial.toml", does_not_raise(), id="partial"), + pytest.param("pfts.json", pytest.raises(TOMLDecodeError), id="format_wrong"), + pytest.param("no.pfts", pytest.raises(FileNotFoundError), id="file_missing"), + pytest.param("pfts_invalid.toml", pytest.raises(ValidationError), id="invalid"), + ], +) +def test_flora_from_toml(filename, outcome): + """Test TOML loading.""" + from pyrealm.canopy_model.model.flora import Flora + + datapath = resources.files("pyrealm_build_data.community") / filename + + with outcome: + flora = Flora.from_toml(datapath) + + if isinstance(outcome, does_not_raise): + # Coarse check of what got loaded + assert len(flora) == 2 + for nm in ["test1", "test2"]: + assert nm in flora + + +@pytest.mark.parametrize( + argnames="filename,outcome", + argvalues=[ + pytest.param("pfts.csv", does_not_raise(), id="correct"), + pytest.param("pfts.json", pytest.raises(ParserError), id="format_wrong"), + pytest.param("no.pfts", pytest.raises(FileNotFoundError), id="file_missing"), + pytest.param("pfts_partial.csv", does_not_raise(), id="partial"), + pytest.param("pfts_invalid.csv", pytest.raises(ValidationError), id="invalid"), + ], +) +def test_flora_from_csv(filename, outcome): + """Test CSV loading.""" + from pyrealm.canopy_model.model.flora import Flora + + datapath = resources.files("pyrealm_build_data.community") / filename + + with outcome: + flora = Flora.from_csv(datapath) + + if isinstance(outcome, does_not_raise): + # Coarse check of what got loaded + assert len(flora) == 2 + for nm in ["test1", "test2"]: + assert nm in flora + + +# +# Test PlantFunctionalType __post_init__ functions +# + + +@pytest.mark.parametrize( + argnames="m,n,q_m", + argvalues=[(2, 5, 2.9038988210485766), (3, 4, 2.3953681843215673)], +) +def test_calculate_q_m(m, n, q_m): + """Test calculation of q_m.""" + + from pyrealm.canopy_model.model.flora import calculate_q_m + + calculated_q_m = calculate_q_m(m, n) + assert calculated_q_m == pytest.approx(q_m) + + +def test_calculate_q_m_values_raises_exception_for_invalid_input(): + """Test unhappy path for calculating q_m. + + Test that an exception is raised when invalid arguments are provided to the + function. + """ + + pass + + +@pytest.mark.parametrize( + argnames="m,n,z_max_ratio", + argvalues=[(2, 5, 0.8502830004171938), (3, 4, 0.7226568811456053)], +) +def test_calculate_z_max_ratio(m, n, z_max_ratio): + """Test calculation of z_max proportion.""" + + from pyrealm.canopy_model.model.flora import calculate_z_max_proportion + + calculated_zmr = calculate_z_max_proportion(m, n) + assert calculated_zmr == pytest.approx(z_max_ratio) From a19f07536b0e25ccdbf7372c5f15c0b6eff882c1 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 5 Sep 2024 15:00:50 +0100 Subject: [PATCH 062/241] Adding new dependencies --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 8c28b9aa..3de9c202 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,9 @@ python = ">=3.10" scipy = "^1.7.3" tabulate = "^0.8.10" +marshmallow = "^3.22.0" +pandas = "^2.2.2" +marshmallow-dataclass = "^8.7.0" [tool.poetry.group.types.dependencies] pandas-stubs = "^2.2.0.240218" types-tabulate = "^0.9.0.0" From bae7df50cc8c190726fb808db80e64bd710f1f02 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 5 Sep 2024 15:17:45 +0100 Subject: [PATCH 063/241] Updating docs --- docs/source/refs.bib | 1586 ++++++++++++++------------- poetry.lock | 77 +- pyrealm/canopy_model/model/flora.py | 29 +- 3 files changed, 912 insertions(+), 780 deletions(-) diff --git a/docs/source/refs.bib b/docs/source/refs.bib index 4a8b91e0..0dcb8e4a 100644 --- a/docs/source/refs.bib +++ b/docs/source/refs.bib @@ -1,860 +1,908 @@ +@techreport{allen:1998a, + title = {Crop Evapotranspiration - {{Guidelines}} for Computing Crop Water Requirements}, + author = {Allen, Richard G. and Pereira, Luis S and Raes, Dirk and Smith, Martin}, + year = {1998}, + number = {56}, + address = {Rome}, + institution = {FAO}, + file = {/Users/dorme/Zotero/storage/UW9UBHX2/Allen et al. - 1998 - Crop evapotranspiration - Guidelines for computing.pdf} +} -@article{Wang:2020ik, - title = {Acclimation of leaf respiration consistent with optimal photosynthetic capacity}, - volume = {26}, - url = {https://onlinelibrary.wiley.com/doi/10.1111/gcb.14980}, - doi = {10.1111/gcb.14980}, - language = {english}, - number = {4}, - journal = {Global Change Biology}, - author = {Wang, Han and Atkin, Owen K and Keenan, Trevor F and Smith, Nicholas G and Wright, Ian J. and Bloomfield, Keith J and Kattge, Jens and Reich, Peter B and Prentice, I. Colin}, - month = feb, - year = {2020}, - note = {tex.date-added: 2020-11-30T12:23:58GMT - tex.date-modified: 2021-01-22T13:54:24GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Wang/Global\%20Change\%20Biol\%202020\%20Wang.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1111/gcb.14980}, - pages = {2573--2583}, - file = {gcb15314-sup-0004-Supinfo.pdf:/Users/dorme/Zotero/storage/NSCU7SWY/gcb15314-sup-0004-Supinfo.pdf:application/pdf;Global Change Biol 2020 Wang.pdf:/Users/dorme/Zotero/storage/4C9SVQUB/Global Change Biol 2020 Wang.pdf:application/pdf} +@article{Argles:2020cy, + title = {Robust {{Ecosystem Demography}} ({{RED}} Version 1.0): A Parsimonious Approach to Modelling Vegetation Dynamics in {{Earth}} System Models}, + author = {Argles, Arthur P K and Moore, Jonathan R and Huntingford, Chris and Wiltshire, Andrew J and Harper, Anna B and Jones, Chris D and Cox, Peter M}, + year = {2020}, + journal = {Geoscientific Model Development}, + volume = {13}, + number = {9}, + pages = {4067--4089}, + doi = {10.5194/gmd-13-4067-2020}, + date-added = {2020-12-01T16:58:12GMT}, + date-modified = {2021-07-22T14:23:35GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Argles/Geoscientific\%20Model\%20Development\%202020\%20Argles.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.5194/gmd-13-4067-2020}, + file = {/Users/dorme/Zotero/storage/WKQGYNRT/Geoscientific Model Development 2020 Argles.pdf} } -@article{Wang:2017go, - title = {Towards a universal model for carbon dioxide uptake by plants}, - url = {http://dx.doi.org/10.1038/s41477-017-0006-8}, - doi = {10.1038/s41477-017-0006-8}, - abstract = {Nature Plants, doi:10.1038/s41477-017-0006-8}, - journal = {Nature Plants}, - author = {Wang, Han and Prentice, I. Colin and Keenan, Trevor F and Davis, Tyler W and Wright, Ian J. and Cornwell, William K and Evans, Bradley J and Peng, Changhui}, - month = sep, - year = {2017}, - note = {Publisher: Springer US - tex.date-added: 2020-11-30T12:27:00GMT - tex.date-modified: 2021-01-28T09:14:19GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2017/Wang/Nature\%20Plants\%202017\%20Wang.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1038/s41477-017-0006-8}, - pages = {1--8}, - file = {Nature Plants 2017 Wang.pdf:/Users/dorme/Zotero/storage/XIP7696Y/Nature Plants 2017 Wang.pdf:application/pdf} +@article{Atkin:2015hk, + title = {Global Variability in Leaf Respiration in Relation to Climate, Plant Functional Types and Leaf Traits.}, + author = {Atkin, Owen K and Bloomfield, Keith J and Reich, Peter B and Tjoelker, Mark G and Asner, Gregory P. and Bonal, Damien and B{\"o}nisch, Gerhard and Bradford, Matt G and Cernusak, Lucas A and Cosio, Eric G and Creek, Danielle and Crous, Kristine Y and Domingues, Tomas F and Dukes, Jeffrey S and Egerton, John J G and Evans, John R and Farquhar, Graham D and Fyllas, Nikolaos M and Gauthier, Paul P G and Gloor, Emanuel and Gimeno, Teresa E and Griffin, Kevin L and Guerrieri, Rossella and Heskel, Mary A and Huntingford, Chris and Ishida, Fran{\c c}oise Yoko and Kattge, Jens and Lambers, Hans and Liddell, Michael J and Lloyd, Jon and Lusk, Christopher H and Martin, Roberta E and Maksimov, Ayal P and Maximov, Trofim C and Malhi, Yadvinder and Medlyn, Belinda E and Meir, Patrick and Mercado, Lina M and Mirotchnick, Nicholas and Ng, Desmond and Niinemets, {\"U}lo and O'Sullivan, Odhran S and Phillips, Oliver L and Poorter, Lourens and Poot, Pieter and Prentice, I. Colin and Salinas, Norma and Rowland, Lucy M and Ryan, Michael G and Sitch, Stephen and Slot, Martijn and Smith, Nicholas G and Turnbull, Matthew H and VanderWel, Mark C and Valladares, Fernando and Veneklaas, Erik J and Weerasinghe, Lasantha K and Wirth, Christian and Wright, Ian J. and Wythers, Kirk R and Xiang, Jen and Xiang, Shuang and {Zaragoza-Castells}, Joana}, + year = {2015}, + month = apr, + journal = {New Phytologist}, + volume = {206}, + number = {2}, + pages = {614--636}, + doi = {10.1111/nph.13253}, + abstract = {Leaf dark respiration (Rdark ) is an important yet poorly quantified component of the global carbon cycle. Given this, we analyzed a new global database of Rdark and associated leaf traits. Data for 899 species were compiled from 100 sites (from the Arctic to the tropics). Several woody and nonwoody plant functional types (PFTs) were represented. Mixed-effects models were used to disentangle sources of variation in Rdark . Area-based Rdark at the prevailing average daily growth temperature (T) of each site increased only twofold from the Arctic to the tropics, despite a 20{$^\circ$}C increase in growing T (8-28{$^\circ$}C). By contrast, Rdark at a standard T (25{$^\circ$}C, Rdark (25) ) was threefold higher in the Arctic than in the tropics, and twofold higher at arid than at mesic sites. Species and PFTs at cold sites exhibited higher Rdark (25) at a given photosynthetic capacity (Vcmax (25) ) or leaf nitrogen concentration ([N]) than species at warmer sites. Rdark (25) values at any given Vcmax (25) or [N] were higher in herbs than in woody plants. The results highlight variation in Rdark among species and across global gradients in T and aridity. In addition to their ecological significance, the results provide a framework for improving representation of Rdark in terrestrial biosphere models (TBMs) and associated land-surface components of Earth system models (ESMs).}, + affiliation = {ARC Centre of Excellence in Plant Energy Biology, Research School of Biology, The Australian National University, Building 134, Canberra, ACT, 0200, Australia; Division of Plant Sciences, Research School of Biology, The Australian National University, Building 46, Canberra, ACT, 0200, Australia.}, + date-added = {2021-01-28T11:56:12GMT}, + date-modified = {2021-01-28T15:58:45GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2015/Atkin/New\%20Phytol.\%202015\%20Atkin.pdf}, + pmid = {25581061}, + rating = {0}, + uri = {papers3://publication/doi/10.1111/nph.13253}, + file = {/Users/dorme/Zotero/storage/JCS7TM7H/New Phytol. 2015 Atkin.pdf} } -@article{Huber:2009fy, - title = {New international formulation for the viscosity of {H2O}}, - volume = {38}, - url = {http://aip.scitation.org/doi/10.1063/1.3088050}, - doi = {10.1063/1.3088050}, - language = {english}, - number = {2}, - journal = {Journal of Physical and Chemical Reference Data}, - author = {Huber, M L and Perkins, R A and Laesecke, A and Friend, D G and Sengers, J V and Assael, M J and Metaxa, I N and Vogel, E and Mareš, R and Miyagawa, K}, - month = jun, - year = {2009}, - note = {tex.date-added: 2020-12-02T09:52:51GMT - tex.date-modified: 2020-12-17T08:58:40GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2009/Huber/Journal\%20of\%20Physical\%20and\%20Chemical\%20Reference\%20Data\%202009\%20Huber.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1063/1.3088050}, - pages = {101--125}, - file = {Journal of Physical and Chemical Reference Data 2009 Huber.pdf:/Users/dorme/Zotero/storage/D2W4H4S4/Journal of Physical and Chemical Reference Data 2009 Huber.pdf:application/pdf} +@article{badeck:2005a, + title = {Post-Photosynthetic Fractionation of Stable Carbon Isotopes between Plant Organs---a Widespread Phenomenon}, + author = {Badeck, Franz-W. and Tcherkez, Guillaume and Nogu{\'e}s, Salvador and Piel, Cl{\'e}ment and Ghashghaie, Jaleh}, + year = {2005}, + journal = {Rapid Communications in Mass Spectrometry}, + volume = {19}, + number = {11}, + eprint = {https://analyticalsciencejournals.onlinelibrary.wiley.com/doi/pdf/10.1002/rcm.1912}, + pages = {1381--1391}, + doi = {10.1002/rcm.1912}, + abstract = {Abstract Discrimination against 13C during photosynthesis is a well-characterised phenomenon. It leaves behind distinct signatures in organic matter of plants and in the atmosphere. The former is depleted in 13C, the latter is enriched during periods of preponderant photosynthetic activity of terrestrial ecosystems. The intra-annual cycle and latitudinal gradient in atmospheric 13C resulting from photosynthetic and respiratory activities of terrestrial plants have been exploited for the reconstruction of sources and sinks through deconvolution by inverse modelling. Here, we compile evidence for widespread post-photosynthetic fractionation that further modifies the isotopic signatures of individual plant organs and consequently leads to consistent differences in {$\delta$}13C between plant organs. Leaves were on average 0.96‰ and 1.91‰ more depleted than roots and woody stems, respectively. This phenomenon is relevant if the isotopic signature of CO2-exchange fluxes at the ecosystem level is used for the reconstruction of individual sources and sinks. It may also modify the parameterisation of inverse modelling approaches if it leads to different isotopic signatures of organic matter with different residence times within the ecosystems and to a respiratory contribution to the average difference between the isotopic composition of plant organic matter and the atmosphere. We discuss the main hypotheses that can explain the observed inter-organ differences in {$\delta$}13C. Copyright {\copyright} 2005 John Wiley \& Sons, Ltd.}, + file = {/Users/dorme/Zotero/storage/2NXLVXHK/Badeck et al. - 2005 - Post-photosynthetic fractionation of stable carbon.pdf} } -@article{Argles:2020cy, - title = {Robust {Ecosystem} {Demography} ({RED} version 1.0): a parsimonious approach to modelling vegetation dynamics in {Earth} system models}, - volume = {13}, - url = {https://gmd.copernicus.org/articles/13/4067/2020/}, - doi = {10.5194/gmd-13-4067-2020}, - language = {english}, - number = {9}, - journal = {Geoscientific Model Development}, - author = {Argles, Arthur P K and Moore, Jonathan R and Huntingford, Chris and Wiltshire, Andrew J and Harper, Anna B and Jones, Chris D and Cox, Peter M}, - year = {2020}, - note = {tex.date-added: 2020-12-01T16:58:12GMT - tex.date-modified: 2021-07-22T14:23:35GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Argles/Geoscientific\%20Model\%20Development\%202020\%20Argles.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.5194/gmd-13-4067-2020}, - pages = {4067--4089}, - file = {Geoscientific Model Development 2020 Argles.pdf:/Users/dorme/Zotero/storage/6WTVNVIZ/Geoscientific Model Development 2020 Argles.pdf:application/pdf} +@article{BerberanSantos:2009bk, + title = {On the Barometric Formula inside the {{Earth}}}, + author = {{Berberan-Santos}, Mario N and Bodunov, Evgeny N and Pogliani, Lionello}, + year = {2009}, + month = oct, + journal = {Journal of Mathematical Chemistry}, + volume = {47}, + number = {3}, + pages = {990--1004}, + doi = {10.1007/s10910-009-9620-7}, + date-added = {2020-11-30T16:18:45GMT}, + date-modified = {2020-11-30T16:19:02GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2009/Berberan-Santos/J\%20Math\%20Chem\%202009\%20Berberan-Santos.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1007/s10910-009-9620-7}, + file = {/Users/dorme/Zotero/storage/EN33QA2H/J Math Chem 2009 Berberan-Santos.pdf} +} + +@article{berger:1993a, + title = {Insolation and {{Earth}}'s Orbital Periods}, + author = {Berger, Andr{\'e} and Loutre, Marie-France and Tricot, Christian}, + year = {1993}, + journal = {Journal of Geophysical Research: Atmospheres}, + volume = {98}, + number = {D6}, + pages = {10341--10362}, + issn = {2156-2202}, + doi = {10.1029/93JD00222}, + urldate = {2024-08-02}, + abstract = {Solar irradiance received on a horizontal surface depends on the solar output, the semimajor axis of the elliptical orbit of the Earth around the sun (a), the distance from the Earth to the sun (r), and the zenith distance (z). The spectrum of the distance, r, for a given value of the true longitude, {$\lambda$}, displays mainly the precessional periods and, with much less power, half precession periods, eccentricity periods, and some combination tones. The zenith distance or its equivalent, the elevation angle (E), is only a function of obliquity ({$\epsilon$}) for a given latitude, {$\phi$}, true longitude, and hour angle, H. Therefore the insolation at a given constant value of z is only a function of precession and eccentricity. On the other hand, the value of the hour angle, H, corresponding to this fixed value of z varies with {$\varepsilon$}, except for the equinoxes, where H corresponding to a constant z also remains constant through time. Three kinds of insolation have been computed both analytically and numerically: the instantaneous insolation (irradiance) at noon, the daily irradiation, and the irradiations received during particular time intervals of the day defined by two constant values of the zenith distance (diurnal irradiations). Mean irradiances (irradiations divided by the length of the time interval over which they are calculated) are also computed for different time intervals, like the interval between sunrise and sunset, in particular. Examples of these insolations are given in this paper for the equinoxes and the solstices. At the equinoxes, for each latitude, all insolations are only a function of precession (this invalidates the results obtained by Cerveny [1991]). At the solstices, both precession and obliquity are present, although precession dominates for most of the latitudes. Because the lengths of the astronomical seasons are secularly variable (in terms of precession only), a particular calendar day does not always correspond to the same position relative to the sun through geological time. Similarly, a given longitude of the Sun on its orbit does not correspond to the same calendar day. For example, 103 kyr ago, assuming arbitrarily that the spring equinox is always on March 21, autumn began on September 13, and 114 kyr ago, it began on September 27, the length of the summer season being 85 and 98 calendar days, respectively, at these remote times in the past.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/ALTXDVSM/Berger et al. - 1993 - Insolation and Earth's orbital periods.pdf;/Users/dorme/Zotero/storage/HWQ4XSZN/93JD00222.html} } -@article{Atkin:2015hk, - title = {Global variability in leaf respiration in relation to climate, plant functional types and leaf traits.}, - volume = {206}, - url = {http://doi.wiley.com/10.1111/nph.13253}, - doi = {10.1111/nph.13253}, - abstract = {Leaf dark respiration (Rdark ) is an important yet poorly quantified component of the global carbon cycle. Given this, we analyzed a new global database of Rdark and associated leaf traits. Data for 899 species were compiled from 100 sites (from the Arctic to the tropics). Several woody and nonwoody plant functional types (PFTs) were represented. Mixed-effects models were used to disentangle sources of variation in Rdark . Area-based Rdark at the prevailing average daily growth temperature (T) of each site increased only twofold from the Arctic to the tropics, despite a 20°C increase in growing T (8-28°C). By contrast, Rdark at a standard T (25°C, Rdark (25) ) was threefold higher in the Arctic than in the tropics, and twofold higher at arid than at mesic sites. Species and PFTs at cold sites exhibited higher Rdark (25) at a given photosynthetic capacity (Vcmax (25) ) or leaf nitrogen concentration ([N]) than species at warmer sites. Rdark (25) values at any given Vcmax (25) or [N] were higher in herbs than in woody plants. The results highlight variation in Rdark among species and across global gradients in T and aridity. In addition to their ecological significance, the results provide a framework for improving representation of Rdark in terrestrial biosphere models (TBMs) and associated land-surface components of Earth system models (ESMs).}, - language = {english}, - number = {2}, - journal = {New Phytologist}, - author = {Atkin, Owen K and Bloomfield, Keith J and Reich, Peter B and Tjoelker, Mark G and Asner, Gregory P. and Bonal, Damien and Bönisch, Gerhard and Bradford, Matt G and Cernusak, Lucas A and Cosio, Eric G and Creek, Danielle and Crous, Kristine Y and Domingues, Tomas F and Dukes, Jeffrey S and Egerton, John J G and Evans, John R and Farquhar, Graham D and Fyllas, Nikolaos M and Gauthier, Paul P G and Gloor, Emanuel and Gimeno, Teresa E and Griffin, Kevin L and Guerrieri, Rossella and Heskel, Mary A and Huntingford, Chris and Ishida, Françoise Yoko and Kattge, Jens and Lambers, Hans and Liddell, Michael J and Lloyd, Jon and Lusk, Christopher H and Martin, Roberta E and Maksimov, Ayal P and Maximov, Trofim C and Malhi, Yadvinder and Medlyn, Belinda E and Meir, Patrick and Mercado, Lina M and Mirotchnick, Nicholas and Ng, Desmond and Niinemets, Ülo and O’Sullivan, Odhran S and Phillips, Oliver L and Poorter, Lourens and Poot, Pieter and Prentice, I. Colin and Salinas, Norma and Rowland, Lucy M and Ryan, Michael G and Sitch, Stephen and Slot, Martijn and Smith, Nicholas G and Turnbull, Matthew H and VanderWel, Mark C and Valladares, Fernando and Veneklaas, Erik J and Weerasinghe, Lasantha K and Wirth, Christian and Wright, Ian J. and Wythers, Kirk R and Xiang, Jen and Xiang, Shuang and Zaragoza-Castells, Joana}, - month = apr, - year = {2015}, - pmid = {25581061}, - note = {tex.affiliation: ARC Centre of Excellence in Plant Energy Biology, Research School of Biology, The Australian National University, Building 134, Canberra, ACT, 0200, Australia; Division of Plant Sciences, Research School of Biology, The Australian National University, Building 46, Canberra, ACT, 0200, Australia. - tex.date-added: 2021-01-28T11:56:12GMT - tex.date-modified: 2021-01-28T15:58:45GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2015/Atkin/New\%20Phytol.\%202015\%20Atkin.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1111/nph.13253}, - pages = {614--636}, - file = {New Phytol. 2015 Atkin.pdf:/Users/dorme/Zotero/storage/JEF8GCAD/New Phytol. 2015 Atkin.pdf:application/pdf} +@article{berger:1978a, + title = {Long-{{Term Variations}} of {{Daily Insolation}} and {{Quaternary Climatic Changes}}}, + author = {Berger, Andr{\'e}L}, + year = {1978}, + month = dec, + journal = {Journal of the Atmospheric Sciences}, + volume = {35}, + number = {12}, + pages = {2362--2367}, + publisher = {American Meteorological Society}, + issn = {0022-4928, 1520-0469}, + doi = {10.1175/1520-0469(1978)035<2362:LTVODI>2.0.CO;2}, + urldate = {2023-07-13}, + abstract = {Abstract The first part of this note provides all trigonometrical formulas which allow the direct spectral analysis and the computation of those long-term variations of the earth's orbital elements which are of primary interest for the computation of the insolation. The elements are the eccentricity, the longitude of the perihelion, the processional parameter and the obliquity. This new formulary is much more simple to use than the ones previously designed and still provides excellent accuracy, mainly because it takes into account the influence of the most important higher order terms in the series expansions. The second part is devoted to the computation of the daily insolation both for calendar and solar dates.}, + chapter = {Journal of the Atmospheric Sciences}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/DPM5WN32/Berger - 1978 - Long-Term Variations of Daily Insolation and Quate.pdf} } -@article{Stocker:2020dh, - title = {P-model v1.0: an optimality-based light use efficiency model for simulating ecosystem gross primary production}, - volume = {13}, - url = {https://gmd.copernicus.org/articles/13/1545/2020/}, - doi = {10.5194/gmd-13-1545-2020}, - language = {english}, - number = {3}, - journal = {Geoscientific Model Development}, - author = {Stocker, Benjamin D and Wang, Han and Smith, Nicholas G and Harrison, Sandy P and Keenan, Trevor F and Sandoval, David and Davis, Tyler and Prentice, I. Colin}, - year = {2020}, - note = {tex.date-added: 2020-11-30T12:24:06GMT - tex.date-modified: 2021-01-28T11:55:51GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Stocker/Geoscientific\%20Model\%20Development\%202020\%20Stocker.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.5194/gmd-13-1545-2020}, - pages = {1545--1581}, - file = {Geoscientific Model Development 2020 Stocker.pdf:/Users/dorme/Zotero/storage/87D3WF3G/Geoscientific Model Development 2020 Stocker.pdf:application/pdf} +@article{Bernacchi:2003dc, + title = {In Vivo Temperature Response Functions of Parameters Required to Model {{RuBP-limited}} Photosynthesis}, + author = {Bernacchi, C J and Pimentel, C and Long, S P}, + year = {2003}, + month = sep, + journal = {Plant, Cell \& Environment}, + volume = {26}, + number = {9}, + pages = {1419--1430}, + publisher = {John Wiley \& Sons, Ltd}, + doi = {10.1046/j.0016-8025.2003.01050.x}, + abstract = {The leaf model of C3 photosynthesis of Farquhar, von Caemmerer \& Berry (Planta 149, 78--90, 1980) provides the basis for scaling carbon exchange from leaf to canopy and Earth-System models, and is wid...}, + date-added = {2020-11-30T14:15:56GMT}, + date-modified = {2020-11-30T14:42:52GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2003/Bernacchi/Plant\%20Cell\%20\&\%20Environment\%202003\%20Bernacchi.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1046/j.0016-8025.2003.01050.x}, + file = {/Users/dorme/Zotero/storage/7J2I98DM/Plant Cell & Environment 2003 Bernacchi.pdf} } -@article{BerberanSantos:2009bk, - title = {On the barometric formula inside the {Earth}}, - volume = {47}, - url = {http://link.springer.com/10.1007/s10910-009-9620-7}, - doi = {10.1007/s10910-009-9620-7}, - language = {english}, - number = {3}, - journal = {Journal of Mathematical Chemistry}, - author = {Berberan-Santos, Mario N and Bodunov, Evgeny N and Pogliani, Lionello}, - month = oct, - year = {2009}, - note = {tex.date-added: 2020-11-30T16:18:45GMT - tex.date-modified: 2020-11-30T16:19:02GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2009/Berberan-Santos/J\%20Math\%20Chem\%202009\%20Berberan-Santos.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1007/s10910-009-9620-7}, - pages = {990--1004}, - file = {J Math Chem 2009 Berberan-Santos.pdf:/Users/dorme/Zotero/storage/7WD7PHD7/J Math Chem 2009 Berberan-Santos.pdf:application/pdf} +@article{Bernacchi:2001kg, + title = {Improved Temperature Response Functions for Models of {{Rubisco-limited}} Photosynthesis}, + author = {Bernacchi, C J and Singsaas, E L and Pimentel, C and Portis Jr, A R and Long, S P}, + year = {2001}, + journal = {Plant, Cell \& Environment}, + volume = {24}, + number = {2}, + pages = {253--259}, + doi = {10.1111/j.1365-3040.2001.00668.x}, + date-added = {2020-11-30T12:24:10GMT}, + date-modified = {2020-11-30T14:42:53GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2001/Bernacchi/Plant\%20Cell\%20\&\%20Environment\%202001\%20Bernacchi.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1111/j.1365-3040.2001.00668.x}, + file = {/Users/dorme/Zotero/storage/FI9562Z3/Plant Cell & Environment 2001 Bernacchi.pdf} } -@book{Fisher:1975tm, - title = {Equation of state of pure water and sea water}, - url = {https://apps.dtic.mil/dtic/tr/fulltext/u2/a017775.pdf}, - publisher = {Scripps Institution of Oceanography}, - author = {Fisher, F H and Dial Jr, O E}, - year = {1975}, - note = {tex.date-added: 2020-11-30T12:27:10GMT - tex.date-modified: 2021-01-21T15:04:43GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Books/1975/Fisher/1975\%20Fisher.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/uuid/5D2C2C96-7975-4AB9-8314-A988EFA489FF}, - file = {1975 Fisher.pdf:/Users/dorme/Zotero/storage/MNQYGV9P/1975 Fisher.pdf:application/pdf} +@article{boyd:2015a, + title = {Temperature Response of {{C4}} Photosynthesis: {{Biochemical}} Analysis of {{Rubisco}}, {{Phosphoenolpyruvate Carboxylase}} and {{Carbonic Anhydrase}} in {{Setaria}} Viridis.}, + shorttitle = {Temperature Response of {{C4}} Photosynthesis}, + author = {Boyd, Ryan Allen and Gandin, Anthony and Cousins, Asaph B}, + year = {2015}, + month = sep, + journal = {Plant Physiology}, + pages = {pp.00586.2015}, + issn = {0032-0889, 1532-2548}, + doi = {10.1104/pp.15.00586}, + urldate = {2022-05-20}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/P866H95S/Boyd et al. - 2015 - Temperature response of C4 photosynthesis Biochem.pdf} } -@article{DeKauwe:2015im, - title = {A test of an optimal stomatal conductance scheme within the {CABLE} land surface model}, - volume = {8}, - url = {https://gmd.copernicus.org/articles/8/431/2015/gmd-8-431-2015.pdf}, - doi = {10.5194/gmd-8-431-2015}, - abstract = {¡p¿¡strong class="journal-contentHeaderColor"¿Abstract.¡/strong¿ Stomatal conductance (¡i¿g¡/i¿¡sub¿s¡/sub¿) affects the fluxes of carbon, energy and water between the vegetated land surface and the atmosphere. We test an implementation of an optimal stomatal conductance model within the Community Atmosphere Biosphere Land Exchange (CABLE) land surface model (LSM). In common with many LSMs, CABLE does not differentiate between ¡i¿g¡/i¿¡sub¿s¡/sub¿ model parameters in relation to plant functional type (PFT), but instead only in relation to photosynthetic pathway. We constrained the key model parameter "¡i¿g¡/i¿¡sub¿1¡/sub¿", which represents plant water use strategy, by PFT, based on a global synthesis of stomatal behaviour. As proof of concept, we also demonstrate that the ¡i¿g¡/i¿¡sub¿1¡/sub¿ parameter can be estimated using two long-term average (1960–1990) bioclimatic variables: (i) temperature and (ii) an indirect estimate of annual plant water availability. The new stomatal model, in conjunction with PFT parameterisations, resulted in a large reduction in annual fluxes of transpiration ({\textasciitilde} 30\% compared to the standard CABLE simulations) across evergreen needleleaf, tundra and C4 grass regions. Differences in other regions of the globe were typically small. Model performance against upscaled data products was not degraded, but did not noticeably reduce existing model–data biases. We identified assumptions relating to the coupling of the vegetation to the atmosphere and the parameterisation of the minimum stomatal conductance as areas requiring further investigation in both CABLE and potentially other LSMs. We conclude that optimisation theory can yield a simple and tractable approach to predicting stomatal conductance in LSMs.¡/p¿}, - language = {english}, - number = {2}, - journal = {Geoscientific Model Development}, - author = {De Kauwe, M G and Kala, J and Lin, Y S and Pitman, A J and Medlyn, B E and Duursma, R A and Abramowitz, G and Wang, Y P and Miralles, D G}, - month = feb, - year = {2015}, - note = {Publisher: Copernicus GmbH - tex.date-added: 2021-11-11T14:04:21GMT - tex.date-modified: 2021-11-11T14:13:27GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2015/De\%20Kauwe/Geoscientific\%20Model\%20Development\%202015\%20De\%20Kauwe.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.5194/gmd-8-431-2015}, - pages = {431--452}, - file = {Geoscientific Model Development 2015 De Kauwe.pdf:/Users/dorme/Zotero/storage/2SQR2JU6/Geoscientific Model Development 2015 De Kauwe.pdf:application/pdf;Geoscientific Model Development 2015 De Kauwe.pdf:/Users/dorme/Zotero/storage/Y65YLM8W/Geoscientific Model Development 2015 De Kauwe.pdf:application/pdf} +@article{cai:2020a, + title = {Recent Trends in Gross Primary Production and Their Drivers: Analysis and Modelling at Flux-Site and Global Scales}, + shorttitle = {Recent Trends in Gross Primary Production and Their Drivers}, + author = {Cai, Wenjia and Prentice, Iain Colin}, + year = {2020}, + month = dec, + journal = {Environmental Research Letters}, + volume = {15}, + number = {12}, + pages = {124050}, + issn = {1748-9326}, + doi = {10.1088/1748-9326/abc64e}, + urldate = {2022-05-16}, + abstract = {Abstract Gross primary production (GPP) by terrestrial ecosystems is the largest flux in the global carbon cycle, and its continuing increase in response to environmental changes is key to land ecosystems' capacity to offset anthropogenic CO 2 emissions. However, the CO 2 - and climate-sensitivities of GPP vary among models. We applied the `P model'---a parameter-sparse and extensively tested light use efficiency (LUE) model, driven by CO 2 , climate and remotely sensed greenness data---at 29 sites with multi-year eddy-covariance flux measurements. Observed (both positive and negative) GPP trends at these sites were predicted, albeit with some bias. Increasing LUE (due to rising atmospheric CO 2 concentration) and green vegetation cover were the primary controls of modelled GPP trends across sites. Global GPP simulated by the same model increased by 0.46 {\textpm} 0.09 Pg C yr --2 during 1982--2016. This increase falls in the mid-range rate of simulated increase by the TRENDY v8 ensemble of state-of-the-art ecosystem models. The modelled LUE increase during 1900--2013 was 15\%, similar to a published estimate based on deuterium isotopomers. Rising CO 2 was the largest contributor to the modelled GPP increase. Greening, which may in part be caused by rising CO 2 , ranked second but dominated the modelled GPP change over large areas, including semi-arid vegetation on all continents. Warming caused a small net reduction in modelled global GPP, but dominated the modelled GPP increase in high northern latitudes. These findings strengthen the evidence that rising LUE due to rising CO 2 level and increased green vegetation cover (fAPAR) are the main causes of increasing GPP, and thereby, the terrestrial carbon sink.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/9YJ8TV4Y/Cai and Prentice - 2020 - Recent trends in gross primary production and thei.pdf} } -@article{Moore:2018dv, - title = {Equilibrium forest demography explains the distribution of tree sizes across {North} {America}}, - volume = {13}, - url = {https://iopscience.iop.org/article/10.1088/1748-9326/aad6d1}, - doi = {10.1088/1748-9326/aad6d1}, - abstract = {Environmental Research Letters, 13(2018) 084019. doi:10.1088/1748-9326/aad6d1}, - number = {8}, - journal = {Environmental Research Letters}, - author = {Moore, Jonathan R and Zhu, Kai and Huntingford, Chris and Cox, Peter M}, - month = aug, - year = {2018}, - note = {Publisher: IOP Publishing - tex.date-added: 2020-12-01T16:56:53GMT - tex.date-modified: 2020-12-17T08:58:39GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Moore/Environ\%20Res\%20Lett\%202018\%20Moore.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1088/1748-9326/aad6d1}, - pages = {084019--10}, - file = {Environ Res Lett 2018 Moore.pdf:/Users/dorme/Zotero/storage/XT8SWLIA/Environ Res Lett 2018 Moore.pdf:application/pdf} +@article{chen:2008a, + title = {The Equation of State of Pure Water Determined from Sound Speeds}, + author = {Chen, Chen-Tung and Fine, Rana A. and Millero, Frank J.}, + year = {2008}, + month = aug, + journal = {The Journal of Chemical Physics}, + volume = {66}, + number = {5}, + pages = {2142--2144}, + issn = {0021-9606}, + doi = {10.1063/1.434179}, + urldate = {2023-07-04}, + abstract = {The equation of state of water valid over the range 0--100\,{$^\circ$}C and 0--1000 bar has been determined from the high pressure sound velocities of Wilson, which were reanalyzed by Chen and Millero. The equation of state has a maximum error of {\textpm}0.01 bar-1 in isothermal compressibility and is in the form of a secant bulk modulus: K=V0P/(V0-V) =K0+AP+BP2, where K, K0, and V, V0 are the secant bulk moduli and specific volumes at applied pressures P and 0 (1 atm), respectively; A and B are temperature dependent parameters. The good agreement (to within 20{\texttimes}10-6 cm3\,g-1) of specific volumes calculated using the above equation with those obtained from other modifications of the Wilson sound velocity data demonstrates the reliability of the sound velocity method for determining equations of state.}, + file = {/Users/dorme/Zotero/storage/HHYLGDG4/Chen et al. - 2008 - The equation of state of pure water determined fro.pdf;/Users/dorme/Zotero/storage/M6MBWTPL/The-equation-of-state-of-pure-water-determined.html} } -@article{Smith:2019dv, - title = {Global photosynthetic capacity is optimized to the environment}, - volume = {22}, - url = {https://onlinelibrary.wiley.com/doi/10.1111/ele.13210}, - doi = {10.1111/ele.13210}, - language = {english}, - number = {3}, - journal = {Ecology Letters}, - author = {Smith, Nicholas G and Keenan, Trevor F and Colin Prentice, I and Wang, Han and Wright, Ian J. and Niinemets, Ülo and Crous, Kristine Y and Domingues, Tomas F and Guerrieri, Rossella and Yoko Ishida, F and Kattge, Jens and Kruger, Eric L and Maire, Vincent and Rogers, Alistair and Serbin, Shawn P and Tarvainen, Lasse and Togashi, Henrique F and Townsend, Philip A and Wang, Meng and Weerasinghe, Lasantha K and Zhou, Shuang Xi}, - month = jan, - year = {2019}, - note = {tex.date-added: 2020-12-02T15:16:49GMT - tex.date-modified: 2021-01-25T10:03:32GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2019/Smith/Ecol\%20Lett\%202019\%20Smith.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1111/ele.13210}, - pages = {506--517}, - file = {Ecol Lett 2019 Smith.pdf:/Users/dorme/Zotero/storage/3YQVDBCU/Ecol Lett 2019 Smith.pdf:application/pdf} +@article{davis:2017a, + title = {Simple Process-Led Algorithms for Simulating Habitats ({{SPLASH}} v.1.0): Robust Indices of Radiation, Evapotranspiration and Plant-Available Moisture}, + shorttitle = {Simple Process-Led Algorithms for Simulating Habitats ({{SPLASH}} v.1.0)}, + author = {Davis, Tyler W. and Prentice, I. Colin and Stocker, Benjamin D. and Thomas, Rebecca T. and Whitley, Rhys J. and Wang, Han and Evans, Bradley J. and {Gallego-Sala}, Angela V. and Sykes, Martin T. and Cramer, Wolfgang}, + year = {2017}, + month = feb, + journal = {Geoscientific Model Development}, + volume = {10}, + number = {2}, + pages = {689--708}, + publisher = {Copernicus GmbH}, + issn = {1991-959X}, + doi = {10.5194/gmd-10-689-2017}, + urldate = {2023-07-05}, + abstract = {Bioclimatic indices for use in studies of ecosystem function, species distribution, and vegetation dynamics under changing climate scenarios depend on estimates of surface fluxes and other quantities, such as radiation, evapotranspiration and soil moisture, for which direct observations are sparse. These quantities can be derived indirectly from meteorological variables, such as near-surface air temperature, precipitation and cloudiness. Here we present a consolidated set of simple process-led algorithms for simulating habitats (SPLASH) allowing robust approximations of key quantities at ecologically relevant timescales. We specify equations, derivations, simplifications, and assumptions for the estimation of daily and monthly quantities of top-of-the-atmosphere solar radiation, net surface radiation, photosynthetic photon flux density, evapotranspiration (potential, equilibrium, and actual), condensation, soil moisture, and runoff, based on analysis of their relationship to fundamental climatic drivers. The climatic drivers include a minimum of three meteorological inputs: precipitation, air temperature, and fraction of bright sunshine hours. Indices, such as the moisture index, the climatic water deficit, and the Priestley--Taylor coefficient, are also defined. The SPLASH code is transcribed in C++, FORTRAN, Python, and R. A total of 1 year of results are presented at the local and global scales to exemplify the spatiotemporal patterns of daily and monthly model outputs along with comparisons to other model results.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/CDUHE8TA/Davis et al. - 2017 - Simple process-led algorithms for simulating habit.pdf} } -@phdthesis{Lancelot:2020tm, - title = {A novel computational model to predict forest dynamics}, - url = {https://imperialcollegelondon.app.box.com/}, - author = {Lancelot, Maxime}, - month = aug, - year = {2020}, - note = {tex.affiliation: Imperial College London - tex.date-added: 2020-11-30T12:25:21GMT - tex.date-modified: 2020-11-30T14:42:52GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Books/2020/Lancelot/2020\%20Lancelot.pdf - tex.rating: 0 - tex.uri: papers3://publication/uuid/D73D9C6F-36C9-461D-A90C-784809C52BCB}, - file = {2020 Lancelot.pdf:/Users/dorme/Zotero/storage/YGXR7FCI/2020 Lancelot.pdf:application/pdf} +@article{DeKauwe:2015im, + title = {A Test of an Optimal Stomatal Conductance Scheme within the {{CABLE}} Land Surface Model}, + author = {De Kauwe, M G and Kala, J and Lin, Y S and Pitman, A J and Medlyn, B E and Duursma, R A and Abramowitz, G and Wang, Y P and Miralles, D G}, + year = {2015}, + month = feb, + journal = {Geoscientific Model Development}, + volume = {8}, + number = {2}, + pages = {431--452}, + publisher = {Copernicus GmbH}, + doi = {10.5194/gmd-8-431-2015}, + abstract = {{\textexclamdown}p{\textquestiondown}{\textexclamdown}strong class="journal-contentHeaderColor"{\textquestiondown}Abstract.{\textexclamdown}/strong{\textquestiondown} Stomatal conductance ({\textexclamdown}i{\textquestiondown}g{\textexclamdown}/i{\textquestiondown}{\textexclamdown}sub{\textquestiondown}s{\textexclamdown}/sub{\textquestiondown}) affects the fluxes of carbon, energy and water between the vegetated land surface and the atmosphere. We test an implementation of an optimal stomatal conductance model within the Community Atmosphere Biosphere Land Exchange (CABLE) land surface model (LSM). In common with many LSMs, CABLE does not differentiate between {\textexclamdown}i{\textquestiondown}g{\textexclamdown}/i{\textquestiondown}{\textexclamdown}sub{\textquestiondown}s{\textexclamdown}/sub{\textquestiondown} model parameters in relation to plant functional type (PFT), but instead only in relation to photosynthetic pathway. We constrained the key model parameter "{\textexclamdown}i{\textquestiondown}g{\textexclamdown}/i{\textquestiondown}{\textexclamdown}sub{\textquestiondown}1{\textexclamdown}/sub{\textquestiondown}", which represents plant water use strategy, by PFT, based on a global synthesis of stomatal behaviour. As proof of concept, we also demonstrate that the {\textexclamdown}i{\textquestiondown}g{\textexclamdown}/i{\textquestiondown}{\textexclamdown}sub{\textquestiondown}1{\textexclamdown}/sub{\textquestiondown} parameter can be estimated using two long-term average (1960--1990) bioclimatic variables: (i) temperature and (ii) an indirect estimate of annual plant water availability. The new stomatal model, in conjunction with PFT parameterisations, resulted in a large reduction in annual fluxes of transpiration ({\textasciitilde} 30\% compared to the standard CABLE simulations) across evergreen needleleaf, tundra and C4 grass regions. Differences in other regions of the globe were typically small. Model performance against upscaled data products was not degraded, but did not noticeably reduce existing model--data biases. We identified assumptions relating to the coupling of the vegetation to the atmosphere and the parameterisation of the minimum stomatal conductance as areas requiring further investigation in both CABLE and potentially other LSMs. We conclude that optimisation theory can yield a simple and tractable approach to predicting stomatal conductance in LSMs.{\textexclamdown}/p{\textquestiondown}}, + date-added = {2021-11-11T14:04:21GMT}, + date-modified = {2021-11-11T14:13:27GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2015/De\%20Kauwe/Geoscientific\%20Model\%20Development\%202015\%20De\%20Kauwe.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.5194/gmd-8-431-2015}, + file = {/Users/dorme/Zotero/storage/8WDYDVKQ/Geoscientific Model Development 2015 De Kauwe.pdf;/Users/dorme/Zotero/storage/WXI7ASHC/Geoscientific Model Development 2015 De Kauwe.pdf} } -@article{Kattge:2007db, - title = {Temperature acclimation in a biochemical model of photosynthesis: a reanalysis of data from 36 species}, - volume = {30}, - url = {http://doi.wiley.com/10.1111/j.1365-3040.2007.01690.x}, - doi = {10.1111/j.1365-3040.2007.01690.x}, - abstract = {The Farquhar et al. model of C3 photosynthesis is frequently used to study the effect of global changes on the biosphere. Its two main parameters representing photosynthetic capacity, Vcmax and Jmax, have been observed to acclimate to plant growth temperature for single species, but a general formulation has never been derived. Here, we present a reanalysis of data from 36 plant species to quantify the temperature dependence of Vcmax and Jmax with a focus on plant growth temperature, ie the plants' average ambient …}, - language = {english}, - number = {9}, - journal = {Plant, Cell \& Environment}, - author = {Kattge, Jens and Knorr, Wolfgang}, - month = sep, - year = {2007}, - note = {tex.date-added: 2020-11-30T14:04:07GMT - tex.date-modified: 2020-12-02T16:14:05GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2007/Kattge/Plant\%20Cell\%20\&\%20Environment\%202007\%20Kattge.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1111/j.1365-3040.2007.01690.x}, - pages = {1176--1190}, - file = {Plant Cell & Environment 2007 Kattge.pdf:/Users/dorme/Zotero/storage/UTXF2JRP/Plant Cell & Environment 2007 Kattge.pdf:application/pdf} +@article{Diaz:2016by, + title = {The Global Spectrum of Plant Form and Function}, + author = {D{\'i}az, Sandra and Kattge, Jens and Cornelissen, Johannes H C and Wright, Ian J. and Lavorel, Sandra and Dray, St{\'e}phane and Reu, Bj{\"o}rn and Kleyer, Michael and Wirth, Christian and Prentice, I. Colin and Garnier, Eric and B{\"o}nisch, Gerhard and Westoby, Mark and Poorter, Hendrik and Reich, Peter B and Moles, Angela T and Dickie, John and Gillison, Andrew N and Zanne, Amy E and Chave, J{\'e}r{\^o}me and Wright, S Joseph and Sheremet'ev, Serge N and Jactel, Herv{\'e} and Baraloto, Christopher and Cerabolini, Bruno and Pierce, Simon and Shipley, Bill and Kirkup, Donald and Casanoves, Fernando and Joswig, Julia S and G{\"u}nther, Angela and Falczuk, Valeria and R{\"u}ger, Nadja and Mahecha, Miguel D and Gorn{\'e}, Lucas D}, + year = {2016}, + month = jan, + journal = {Nature}, + volume = {529}, + number = {7585}, + pages = {167--171}, + publisher = {Nature Publishing Group}, + doi = {10.1038/nature16489}, + abstract = {Nature 529, 167 (2016). doi:10.1038/nature16489}, + date-added = {2021-06-14T12:23:21GMT}, + date-modified = {2021-11-11T14:13:27GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2016/D\%C3\%ADaz/Nature\%202016\%20D\%C3\%ADaz.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1038/nature16489}, + file = {/Users/dorme/Zotero/storage/RGG46LIG/Nature 2016 Díaz.pdf} } -@article{Heskel:2016fg, - title = {Convergence in the temperature response of leaf respiration across biomes and plant functional types}, - volume = {113}, - url = {http://www.pnas.org/lookup/doi/10.1073/pnas.1520282113}, - doi = {10.1073/pnas.1520282113}, - language = {english}, - number = {14}, - journal = {Proceedings of the National Academy of Sciences of the United States of America}, - author = {Heskel, Mary A and O’Sullivan, Odhran S and Reich, Peter B and Tjoelker, Mark G and Weerasinghe, Lasantha K and Penillard, Aurore and Egerton, John J G and Creek, Danielle and Bloomfield, Keith J and Xiang, Jen and Sinca, Felipe and Stangl, Zsofia R and Martinez-de la Torre, Alberto and Griffin, Kevin L and Huntingford, Chris and Hurry, Vaughan and Meir, Patrick and Turnbull, Matthew H and Atkin, Owen K}, - month = apr, - year = {2016}, - note = {tex.date-added: 2020-11-30T13:55:54GMT - tex.date-modified: 2020-11-30T14:42:52GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2016/Heskel/PNAS\%202016\%20Heskel.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1073/pnas.1520282113}, - pages = {3832--3837}, - file = {PNAS 2016 Heskel.pdf:/Users/dorme/Zotero/storage/YR5JESPC/PNAS 2016 Heskel.pdf:application/pdf;PNAS 2016 Heskel.pdf:/Users/dorme/Zotero/storage/ZTIEDG3M/PNAS 2016 Heskel.pdf:application/pdf} +@article{Farquhar:1980ft, + title = {A Biochemical Model of Photosynthetic {{CO2}} Assimilation in Leaves of {{C3}} Species.}, + author = {Farquhar, G D and {von Caemmerer}, S and Berry, J A}, + year = {1980}, + month = jun, + journal = {Planta}, + volume = {149}, + number = {1}, + pages = {78--90}, + doi = {10.1007/BF00386231}, + abstract = {Various aspects of the biochemistry of photosynthetic carbon assimilation in C3 plants are integrated into a form compatible with studies of gas exchange in leaves. These aspects include the kinetic properties of ribulose bisphosphate carboxylase-oxygenase; the requirements of the photosynthetic carbon reduction and photorespiratory carbon oxidation cycles for reduced pyridine nucleotides; the dependence of electron transport on photon flux and the presence of a temperature dependent upper limit to electron transport. The measurements of gas exchange with which the model outputs may be compared include those of the temperature and partial pressure of CO2(p(CO2)) dependencies of quantum yield, the variation of compensation point with temperature and partial pressure of O2(p(O2)), the dependence of net CO2 assimilation rate on p(CO2) and irradiance, and the influence of p(CO2) and irradiance on the temperature dependence of assimilation rate.}, + affiliation = {Department of Environmental Biology, Research School of Biological Sciences, Australian National University, P.O. Box 475, 2601, Canberra City, ACT, Australia.}, + date-added = {2020-12-17T09:47:58GMT}, + date-modified = {2020-12-17T09:49:44GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/1980/Farquhar/Planta\%201980\%20Farquhar.pdf}, + pmid = {24306196}, + rating = {0}, + uri = {papers3://publication/doi/10.1007/BF00386231}, + file = {/Users/dorme/Zotero/storage/PGDMWNFK/Planta 1980 Farquhar.pdf;/Users/dorme/Zotero/storage/YNCRDMLJ/Planta 1980 Farquhar.pdf} } -@article{Prentice:2014bc, - title = {Balancing the costs of carbon gain and water transport: testing a new theoretical framework for plant functional ecology}, - volume = {17}, - url = {http://doi.wiley.com/10.1111/ele.12211}, - doi = {10.1111/ele.12211}, - language = {english}, - number = {1}, - journal = {Ecology Letters}, - author = {Prentice, I. Colin and Dong, Ning and Gleason, Sean M and Maire, Vincent and Wright, Ian J.}, - year = {2014}, - note = {tex.date-added: 2020-12-01T13:22:48GMT - tex.date-modified: 2021-01-21T15:04:43GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Prentice/Ecol\%20Lett\%202014\%20Prentice.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1111/ele.12211}, - pages = {82--91}, - file = {Ecol Lett 2014 Prentice.pdf:/Users/dorme/Zotero/storage/SZVZVTJS/Ecol Lett 2014 Prentice.pdf:application/pdf} +@article{farquhar:1982a, + title = {On the Relationship between Carbon Isotope Discrimination and the Intercellular Carbon Dioxide Concentration in Leaves}, + author = {Farquhar, Graham D and O'Leary, Marion H and Berry, Joseph A}, + year = {1982}, + journal = {Australian Journal of Plant Physiology}, + volume = {9}, + number = {2}, + pages = {121}, + issn = {1445-4408}, + doi = {10.1071/PP9820121}, + urldate = {2022-05-20}, + abstract = {Theory is developed to explain the carbon isotopic composition of plants. It is shown how diffusion of gaseous COz can significantly affect carbon isotopic discrimination. The effects on discrimination by diffusion and carboxylation are integrated, yielding a simple relationship between discrimination and the ratio of the intercellular and atmospheric partial pressures of COZ. The effects of dark respiration and photorespiration are also considered, and it is suggested that they have relatively little effect on discrimination other than cia their effects on intercellular p(COz). It is also suggested that various environmental factors such as light, temperature, salinity and drought will also have effects via changes in intercellular p(C0,). A simple method is suggested for assessing water use efficiencies in the field.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/8ACJPME5/Farquhar et al. - 1982 - On the Relationship Between Carbon Isotope Discrim.pdf} } -@article{Stocker:2018be, - title = {Quantifying soil moisture impacts on light use efficiency across biomes}, - volume = {218}, - url = {http://doi.wiley.com/10.1111/nph.15123}, - doi = {10.1111/nph.15123}, - abstract = {Terrestrial primary productivity and carbon cycle impacts of droughts are commonly quantified using vapour pressure deficit (VPD) data and remotely sensed greenness, without accounting for soil moisture. However, soil moisture limitation is known to strongly affect plant physiology. Here, we investigate light use efficiency, the ratio of gross primary productivity (GPP) to absorbed light. We derive its fractional reduction due to soil moisture (fLUE), separated from VPD and greenness changes, using artificial neural networks trained …}, - language = {english}, - number = {4}, - journal = {New Phytologist}, - author = {Stocker, Benjamin D and Zscheischler, Jakob and Keenan, Trevor F and Prentice, I. Colin and Penuelas, Josep and Seneviratne, Sonia I}, - month = mar, - year = {2018}, - note = {tex.date-added: 2021-01-25T09:23:00GMT - tex.date-modified: 2021-01-28T15:58:46GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Stocker/New\%20Phytol.\%202018\%20Stocker.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1111/nph.15123}, - pages = {1430--1449}, - file = {New Phytol. 2018 Stocker.pdf:/Users/dorme/Zotero/storage/5AZW6ZK9/New Phytol. 2018 Stocker.pdf:application/pdf} +@book{Fisher:1975tm, + title = {Equation of State of Pure Water and Sea Water}, + author = {Fisher, F H and Dial Jr, O E}, + year = {1975}, + publisher = {Scripps Institution of Oceanography}, + date-added = {2020-11-30T12:27:10GMT}, + date-modified = {2021-01-21T15:04:43GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Books/1975/Fisher/1975\%20Fisher.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/uuid/5D2C2C96-7975-4AB9-8314-A988EFA489FF}, + file = {/Users/dorme/Zotero/storage/3K2X7BU7/1975 Fisher.pdf} } -@book{HEllenbergBerlinGeobotanicalInstituteETH:fe, - title = {A key to {Raunkiaer} plant life forms with revised subdivision.}, - url = {https://ci.nii.ac.jp/naid/10004142697/}, - abstract = {CiNii 国立情報学研究所 学術情報ナビゲータ[サイニィ]. メニュー 検索 …}, - author = {{H Ellenberg - Berlin Geobotanical Institute ETH} and {Stiftung} and {1967}}, - doi = {10.5169/seals-377651}, - note = {tex.date-added: 2020-12-07T11:13:07GMT - tex.date-modified: 2020-12-17T08:58:40GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Books/Unknown/H\%20Ellenberg\%C2\%A0-\%20Berlin\%20Geobotanical\%20Institute\%20ETH/H\%20Ellenberg\%C2\%A0-\%20Berlin\%20Geobotanical\%20Institute\%20ETH.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.5169/seals-377651} +@article{frank:2015a, + title = {Water-Use Efficiency and Transpiration across {{European}} Forests during the {{Anthropocene}}}, + author = {Frank, D. C. and Poulter, B. and Saurer, M. and Esper, J. and Huntingford, C. and Helle, G. and Treydte, K. and Zimmermann, N. E. and Schleser, G.~H. and Ahlstr{\"o}m, A. and Ciais, P. and Friedlingstein, P. and Levis, S. and Lomas, M. and Sitch, S. and Viovy, N. and {Andreu-Hayles}, L. and Bednarz, Z. and Berninger, F. and Boettger, T. and D`Alessandro, C. M. and Daux, V. and Filot, M. and Grabner, M. and Gutierrez, E. and Haupt, M. and Hilasvuori, E. and Jungner, H. and {Kalela-Brundin}, M. and Krapiec, M. and Leuenberger, M. and Loader, N. J. and Marah, H. and {Masson-Delmotte}, V. and Pazdur, A. and Pawelczyk, S. and Pierre, M. and Planells, O. and Pukiene, R. and {Reynolds-Henne}, C. E. and Rinne, K. T. and Saracino, A. and Sonninen, E. and Stievenard, M. and Switsur, V. R. and Szczepanek, M. and {Szychowska-Krapiec}, E. and Todaro, L. and Waterhouse, J.~S. and Weigl, M.}, + year = {2015}, + month = jun, + journal = {Nature Climate Change}, + volume = {5}, + number = {6}, + pages = {579--583}, + issn = {1758-6798}, + doi = {10.1038/nclimate2614}, + abstract = {Considering the combined effects of CO2 fertilization and climate change drivers on plant physiology leads to a modest increase in simulated European forest transpiration in spite of the effects of CO2-induced stomatal closure.}, + file = {/Users/dorme/Zotero/storage/CNDFZFBW/Frank et al. - 2015 - Water-use efficiency and transpiration across Euro.pdf} } -@article{Walker:2014ce, - title = {The relationship of leaf photosynthetic traits - {Vcmaxand} {Jmax}- to leaf nitrogen, leaf phosphorus, and specific leaf area: a meta-analysis and modeling study}, - volume = {4}, - url = {http://doi.wiley.com/10.1002/ece3.1173}, - doi = {10.1002/ece3.1173}, - language = {english}, - number = {16}, - journal = {Ecology and Evolution}, - author = {Walker, Anthony P and Beckerman, Andrew P and Gu, Lianhong and Kattge, Jens and Cernusak, Lucas A and Domingues, Tomas F and Scales, Joanna C and Wohlfahrt, Georg and Wullschleger, Stan D and Woodward, F Ian}, - month = jul, - year = {2014}, - note = {tex.date-added: 2020-12-07T11:43:53GMT - tex.date-modified: 2020-12-17T08:58:39GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Walker/Ecology\%20and\%20Evolution\%202014\%20Walker.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1002/ece3.1173}, - pages = {3218--3235}, - file = {Ecology and Evolution 2014 Walker.pdf:/Users/dorme/Zotero/storage/WVL2ZGGZ/Ecology and Evolution 2014 Walker.pdf:application/pdf} +@article{graven:2020a, + title = {Changes to {{Carbon Isotopes}} in {{Atmospheric CO}} {\textsubscript{2}} {{Over}} the {{Industrial Era}} and {{Into}} the {{Future}}}, + author = {Graven, Heather and Keeling, Ralph F. and Rogelj, Joeri}, + year = {2020}, + month = nov, + journal = {Global Biogeochemical Cycles}, + volume = {34}, + number = {11}, + issn = {0886-6236, 1944-9224}, + doi = {10.1029/2019GB006170}, + urldate = {2022-05-23}, + abstract = {In this ``Grand Challenges'' paper, we review how the carbon isotopic composition of atmospheric CO2 has changed since the Industrial Revolution due to human activities and their influence on the natural carbon cycle, and we provide new estimates of possible future changes for a range of scenarios. Emissions of CO2 from fossil fuel combustion and land use change reduce the ratio of 13C/12C in atmospheric CO2 ({$\delta$}13CO2). This is because 12C is preferentially assimilated during photosynthesis and {$\delta$}13C in plant-derived carbon in terrestrial ecosystems and fossil fuels is lower than atmospheric {$\delta$}13CO2. Emissions of CO2 from fossil fuel combustion also reduce the ratio of 14C/C in atmospheric CO2 ({$\Delta$}14CO2) because 14C is absent in million-year-old fossil fuels, which have been stored for much longer than the radioactive decay time of 14C. Atmospheric {$\Delta$}14CO2 rapidly increased in the 1950s to 1960s because of 14C produced during nuclear bomb testing. The resulting trends in {$\delta$}13C and {$\Delta$}14C in atmospheric CO2 are influenced not only by these human emissions but also by natural carbon exchanges that mix carbon between the atmosphere and ocean and terrestrial ecosystems. This mixing caused {$\Delta$}14CO2 to return toward preindustrial levels in the first few decades after the spike from nuclear testing. More recently, as the bomb 14C excess is now mostly well mixed with the decadally overturning carbon reservoirs, fossil fuel emissions have become the main factor driving further decreases in atmospheric {$\Delta$}14CO2. For {$\delta$}13CO2, in addition to exchanges between reservoirs, the extent to which 12C is preferentially assimilated during photosynthesis appears to have increased, slowing down the recent {$\delta$}13CO2 trend slightly. A new compilation of ice core and flask {$\delta$}13CO2 observations indicates that the decline in {$\delta$}13CO2 since the preindustrial period is less than some prior estimates, which may have incorporated artifacts owing to offsets from different laboratories' measurements. Atmospheric observations of {$\delta$}13CO2 have been used to investigate carbon fluxes and the functioning of plants, and they are used for comparison with {$\delta$}13C in other materials such as tree rings. Atmospheric observations of {$\Delta$}14CO2 have been used to quantify the rate of air-sea gas exchange and ocean circulation, and the rate of net primary production and the turnover time of carbon in plant material and soils. Atmospheric observations of {$\Delta$}14CO2 are also used for comparison with {$\Delta$}14C in other materials in many fields such as archaeology, forensics, and physiology. Another major application is the assessment of regional emissions of CO2 from fossil fuel combustion using {$\Delta$}14CO2 observations and models. In the future, {$\delta$}13CO2 and {$\Delta$}14CO2 will continue to change. The sign and magnitude of the changes are mainly determined by global fossil fuel emissions. We present here simulations of future {$\delta$}13CO2 and {$\Delta$}14CO2 for six scenarios based on the shared socioeconomic pathways (SSPs) from the 6th Coupled Model Intercomparison Project (CMIP6). Applications using atmospheric {$\delta$}13CO2 and {$\Delta$}14CO2 observations in carbon cycle science and many other fields will be affected by these future changes. We recommend an increased effort toward making coordinated measurements of {$\delta$}13C and {$\Delta$}14C across the Earth System and for further development of isotopic modeling and model-data analysis tools.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/BFT23X8N/Graven et al. - 2020 - Changes to Carbon Isotopes in Atmospheric CO .pdf} } -@article{Peng:2021ky, - title = {Global climate and nutrient controls of photosynthetic capacity}, - url = {http://dx.doi.org/10.1038/s42003-021-01985-7}, - doi = {10.1038/s42003-021-01985-7}, - abstract = {Communications Biology, doi:10.1038/s42003-021-01985-7}, - journal = {Communications Biology}, - author = {Peng, Yunke and Bloomfield, Keith J and Cernusak, Lucas A and Domingues, Tomas F and Prentice, I. Colin}, - month = apr, - year = {2021}, - note = {Publisher: Springer US - tex.date-added: 2021-06-14T08:31:31GMT - tex.date-modified: 2021-11-11T14:13:27GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2021/Peng/Communications\%20Biology\%202021\%20Peng.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1038/s42003-021-01985-7}, - pages = {1--9}, - file = {Communications Biology 2021 Peng.pdf:/Users/dorme/Zotero/storage/U8Q5LA52/Communications Biology 2021 Peng.pdf:application/pdf} +@book{HEllenbergBerlinGeobotanicalInstituteETH:fe, + title = {A Key to {{Raunkiaer}} Plant Life Forms with Revised Subdivision.}, + author = {{H Ellenberg - Berlin Geobotanical Institute ETH} and {Stiftung} and {1967}}, + doi = {10.5169/seals-377651}, + abstract = {CiNii 国立情報学研究所 学術情報ナビゲータ[サイニィ]. メニュー 検索 {\dots}}, + date-added = {2020-12-07T11:13:07GMT}, + date-modified = {2020-12-17T08:58:40GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Books/Unknown/H\%20Ellenberg\%C2\%A0-\%20Berlin\%20Geobotanical\%20Institute\%20ETH/H\%20Ellenberg\%C2\%A0-\%20Berlin\%20Geobotanical\%20Institute\%20ETH.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.5169/seals-377651} } -@article{Bernacchi:2001kg, - title = {Improved temperature response functions for models of {Rubisco}-limited photosynthesis}, - volume = {24}, - url = {http://doi.wiley.com/10.1111/j.1365-3040.2001.00668.x}, - doi = {10.1111/j.1365-3040.2001.00668.x}, - language = {english}, - number = {2}, - journal = {Plant, Cell \& Environment}, - author = {Bernacchi, C J and Singsaas, E L and Pimentel, C and Portis Jr, A R and Long, S P}, - year = {2001}, - note = {tex.date-added: 2020-11-30T12:24:10GMT - tex.date-modified: 2020-11-30T14:42:53GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2001/Bernacchi/Plant\%20Cell\%20\&\%20Environment\%202001\%20Bernacchi.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1111/j.1365-3040.2001.00668.x}, - pages = {253--259}, - file = {Plant Cell & Environment 2001 Bernacchi.pdf:/Users/dorme/Zotero/storage/NQZRL4RI/Plant Cell & Environment 2001 Bernacchi.pdf:application/pdf} +@article{henderson-sellers:1984a, + title = {A New Formula for Latent Heat of Vaporization of Water as a Function of Temperature}, + author = {{Henderson-Sellers}, B.}, + year = {1984}, + journal = {Quarterly Journal of the Royal Meteorological Society}, + volume = {110}, + number = {466}, + pages = {1186--1190}, + issn = {1477-870X}, + doi = {10.1002/qj.49711046626}, + urldate = {2023-07-04}, + abstract = {Existing formulae and approximations for the latent heat of vaporization of water, Lv, are reviewed. Using an analytical approximation to the saturated vapour pressure as a function of temperature, a new, temperature-dependent function for Lv is derived.}, + copyright = {Copyright {\copyright} 1984 Royal Meteorological Society}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/RHK394FU/qj.html} } -@article{Li:2014bc, - title = {Simulation of tree-ring widths with a model for primary production, carbon allocation, and growth}, - volume = {11}, - url = {https://bg.copernicus.org/articles/11/6711/2014/}, - doi = {10.5194/bg-11-6711-2014}, - language = {english}, - number = {23}, - journal = {Biogeosciences (Online)}, - author = {Li, G and Harrison, S P and Prentice, I. C. and Falster, D}, - year = {2014}, - note = {tex.date-added: 2020-12-01T16:59:12GMT - tex.date-modified: 2021-11-11T13:59:21GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Li/Biogeosciences\%202014\%20Li.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.5194/bg-11-6711-2014}, - pages = {6711--6724}, - file = {Biogeosciences 2014 Li.pdf:/Users/dorme/Zotero/storage/346S9AQK/Biogeosciences 2014 Li.pdf:application/pdf} +@article{hengl:2017a, + title = {{{SoilGrids250m}}: {{Global}} Gridded Soil Information Based on Machine Learning}, + shorttitle = {{{SoilGrids250m}}}, + author = {Hengl, Tomislav and de Jesus, Jorge Mendes and Heuvelink, Gerard B. M. and Gonzalez, Maria Ruiperez and Kilibarda, Milan and Blagoti{\'c}, Aleksandar and Shangguan, Wei and Wright, Marvin N. and Geng, Xiaoyuan and {Bauer-Marschallinger}, Bernhard and Guevara, Mario Antonio and Vargas, Rodrigo and MacMillan, Robert A. and Batjes, Niels H. and Leenaars, Johan G. B. and Ribeiro, Eloi and Wheeler, Ichsani and Mantel, Stephan and Kempen, Bas}, + year = {2017}, + month = feb, + journal = {PLOS ONE}, + volume = {12}, + number = {2}, + pages = {e0169748}, + publisher = {Public Library of Science}, + issn = {1932-6203}, + doi = {10.1371/journal.pone.0169748}, + urldate = {2023-07-05}, + abstract = {This paper describes the technical development and accuracy assessment of the most recent and improved version of the SoilGrids system at 250m resolution (June 2016 update). SoilGrids provides global predictions for standard numeric soil properties (organic carbon, bulk density, Cation Exchange Capacity (CEC), pH, soil texture fractions and coarse fragments) at seven standard depths (0, 5, 15, 30, 60, 100 and 200 cm), in addition to predictions of depth to bedrock and distribution of soil classes based on the World Reference Base (WRB) and USDA classification systems (ca. 280 raster layers in total). Predictions were based on ca. 150,000 soil profiles used for training and a stack of 158 remote sensing-based soil covariates (primarily derived from MODIS land products, SRTM DEM derivatives, climatic images and global landform and lithology maps), which were used to fit an ensemble of machine learning methods---random forest and gradient boosting and/or multinomial logistic regression---as implemented in the R packages ranger, xgboost, nnet and caret. The results of 10--fold cross-validation show that the ensemble models explain between 56\% (coarse fragments) and 83\% (pH) of variation with an overall average of 61\%. Improvements in the relative accuracy considering the amount of variation explained, in comparison to the previous version of SoilGrids at 1 km spatial resolution, range from 60 to 230\%. Improvements can be attributed to: (1) the use of machine learning instead of linear regression, (2) to considerable investments in preparing finer resolution covariate layers and (3) to insertion of additional soil profiles. Further development of SoilGrids could include refinement of methods to incorporate input uncertainties and derivation of posterior probability distributions (per pixel), and further automation of spatial modeling so that soil maps can be generated for potentially hundreds of soil variables. Another area of future research is the development of methods for multiscale merging of SoilGrids predictions with local and/or national gridded soil products (e.g. up to 50 m spatial resolution) so that increasingly more accurate, complete and consistent global soil information can be produced. SoilGrids are available under the Open Data Base License.}, + langid = {english}, + keywords = {Agricultural soil science,Forecasting,Glaciers,Machine learning,Remote sensing,Shannon index,Soil pH,Trees}, + file = {/Users/dorme/Zotero/storage/2YL6J66K/Hengl et al. - 2017 - SoilGrids250m Global gridded soil information bas.pdf} } -@article{Bernacchi:2003dc, - title = {In vivo temperature response functions of parameters required to model {RuBP}-limited photosynthesis}, - volume = {26}, - url = {https://onlinelibrary-wiley-com.iclibezp1.cc.ic.ac.uk/doi/full/10.1046/j.0016-8025.2003.01050.x}, - doi = {10.1046/j.0016-8025.2003.01050.x}, - abstract = {The leaf model of C3 photosynthesis of Farquhar, von Caemmerer \& Berry (Planta 149, 78–90, 1980) provides the basis for scaling carbon exchange from leaf to canopy and Earth-System models, and is wid...}, - language = {english}, - number = {9}, - journal = {Plant, Cell \& Environment}, - author = {Bernacchi, C J and Pimentel, C and Long, S P}, - month = sep, - year = {2003}, - note = {Publisher: John Wiley \& Sons, Ltd - tex.date-added: 2020-11-30T14:15:56GMT - tex.date-modified: 2020-11-30T14:42:52GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2003/Bernacchi/Plant\%20Cell\%20\&\%20Environment\%202003\%20Bernacchi.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1046/j.0016-8025.2003.01050.x}, - pages = {1419--1430}, - file = {Plant Cell & Environment 2003 Bernacchi.pdf:/Users/dorme/Zotero/storage/K2EX6ZIL/Plant Cell & Environment 2003 Bernacchi.pdf:application/pdf} +@article{Heskel:2016fg, + title = {Convergence in the Temperature Response of Leaf Respiration across Biomes and Plant Functional Types}, + author = {Heskel, Mary A and O'Sullivan, Odhran S and Reich, Peter B and Tjoelker, Mark G and Weerasinghe, Lasantha K and Penillard, Aurore and Egerton, John J G and Creek, Danielle and Bloomfield, Keith J and Xiang, Jen and Sinca, Felipe and Stangl, Zsofia R and {Martinez-de la Torre}, Alberto and Griffin, Kevin L and Huntingford, Chris and Hurry, Vaughan and Meir, Patrick and Turnbull, Matthew H and Atkin, Owen K}, + year = {2016}, + month = apr, + journal = {Proceedings of the National Academy of Sciences of the United States of America}, + volume = {113}, + number = {14}, + pages = {3832--3837}, + doi = {10.1073/pnas.1520282113}, + date-added = {2020-11-30T13:55:54GMT}, + date-modified = {2020-11-30T14:42:52GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2016/Heskel/PNAS\%202016\%20Heskel.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1073/pnas.1520282113}, + file = {/Users/dorme/Zotero/storage/22X4KLAX/PNAS 2016 Heskel.pdf;/Users/dorme/Zotero/storage/LC3HMVT7/PNAS 2016 Heskel.pdf} } -@article{Diaz:2016by, - title = {The global spectrum of plant form and function}, - volume = {529}, - url = {http://dx.doi.org/10.1038/nature16489}, - doi = {10.1038/nature16489}, - abstract = {Nature 529, 167 (2016). doi:10.1038/nature16489}, - number = {7585}, - journal = {Nature}, - author = {Díaz, Sandra and Kattge, Jens and Cornelissen, Johannes H C and Wright, Ian J. and Lavorel, Sandra and Dray, Stéphane and Reu, Björn and Kleyer, Michael and Wirth, Christian and Prentice, I. Colin and Garnier, Eric and Bönisch, Gerhard and Westoby, Mark and Poorter, Hendrik and Reich, Peter B and Moles, Angela T and Dickie, John and Gillison, Andrew N and Zanne, Amy E and Chave, Jérôme and Wright, S Joseph and Sheremet’ev, Serge N and Jactel, Hervé and Baraloto, Christopher and Cerabolini, Bruno and Pierce, Simon and Shipley, Bill and Kirkup, Donald and Casanoves, Fernando and Joswig, Julia S and Günther, Angela and Falczuk, Valeria and Rüger, Nadja and Mahecha, Miguel D and Gorné, Lucas D}, - month = jan, - year = {2016}, - note = {Publisher: Nature Publishing Group - tex.date-added: 2021-06-14T12:23:21GMT - tex.date-modified: 2021-11-11T14:13:27GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2016/D\%C3\%ADaz/Nature\%202016\%20D\%C3\%ADaz.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1038/nature16489}, - pages = {167--171}, - file = {Nature 2016 Díaz.pdf:/Users/dorme/Zotero/storage/5DWC9AW2/Nature 2016 Díaz.pdf:application/pdf} +@article{Huber:2009fy, + title = {New International Formulation for the Viscosity of {{H2O}}}, + author = {Huber, M L and Perkins, R A and Laesecke, A and Friend, D G and Sengers, J V and Assael, M J and Metaxa, I N and Vogel, E and Mare{\v s}, R and Miyagawa, K}, + year = {2009}, + month = jun, + journal = {Journal of Physical and Chemical Reference Data}, + volume = {38}, + number = {2}, + pages = {101--125}, + doi = {10.1063/1.3088050}, + date-added = {2020-12-02T09:52:51GMT}, + date-modified = {2020-12-17T08:58:40GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2009/Huber/Journal\%20of\%20Physical\%20and\%20Chemical\%20Reference\%20Data\%202009\%20Huber.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1063/1.3088050}, + file = {/Users/dorme/Zotero/storage/HREIVFC4/Journal of Physical and Chemical Reference Data 2009 Huber.pdf} } -@article{Lin:2015wh, - title = {Optimal stomatal behaviour around the world}, - volume = {5}, - url = {https://doi.org/10.1038/nclimate2550}, - abstract = {Stomatal conductance is a land-surface attribute that links the water and carbon cycles. Analysis of a global database covering a wide range of plant functional types and biomes now provides a framework for predicting the behaviour of stomatal conductance that can be applied to model ecosystem productivity, energy balance and ecohydrological processes in a changing climate.}, - number = {5}, - journal = {Nature Climate Change}, - author = {Lin, Yan-Shih and Medlyn, Belinda E and Duursma, Remko A and Prentice, I. Colin and Wang, Han and Baig, Sofia and Eamus, Derek and de Dios, Victor Resco and Mitchell, Patrick and Ellsworth, David S and de Beeck, Maarten Op and Wallin, Goran and Uddling, Johan and Tarvainen, Lasse and Linderson, Maj-Lena and Cernusak, Lucas A and Nippert, Jesse B and Ocheltree, Troy W and Tissue, David T and Martin-StPaul, Nicolas K and Rogers, Alistair and Warren, Jeff M and De Angelis, Paolo and Hikosaka, Kouki and Han, Qingmin and Onoda, Yusuke and Gimeno, Teresa E and Barton, Craig V M and Bennie, Jonathan and Bonal, Damien and Bosc, Alexandre and Low, Markus and Macinins-Ng, Cate and Rey, Ana and Rowland, Lucy and Setterfield, Samantha A and Tausz-Posch, Sabine and Zaragoza-Castells, Joana and Broadmeadow, Mark S J and Drake, John E and Freeman, Michael and Ghannoum, Oula and Hutley, Lindsay B and Kelly, Jeff W and Kikuzawa, Kihachiro and Kolari, Pasi and Koyama, Kohei and Limousin, Jean-Marc and Meir, Patrick and Lola da Costa, Antonio C and Mikkelsen, Teis N and Salinas, Norma and Sun, Wei and Wingate, Lisa}, - year = {2015}, - note = {tex.date-added: 2021-11-11T14:12:05GMT - tex.date-modified: 2021-11-11T14:13:27GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2015/Lin/2015\%20Lin-2.pdf - tex.rating: 0 - tex.uri: papers3://publication/uuid/61D6E8CB-F257-4021-AC24-2DF4D72C298E}, - pages = {459--464}, - file = {2015 Lin-2.pdf:/Users/dorme/Zotero/storage/WV3XV4SD/2015 Lin-2.pdf:application/pdf} +@article{Kattge:2007db, + title = {Temperature Acclimation in a Biochemical Model of Photosynthesis: A Reanalysis of Data from 36 Species}, + author = {Kattge, Jens and Knorr, Wolfgang}, + year = {2007}, + month = sep, + journal = {Plant, Cell \& Environment}, + volume = {30}, + number = {9}, + pages = {1176--1190}, + doi = {10.1111/j.1365-3040.2007.01690.x}, + abstract = {The Farquhar et al. model of C3 photosynthesis is frequently used to study the effect of global changes on the biosphere. Its two main parameters representing photosynthetic capacity, Vcmax and Jmax, have been observed to acclimate to plant growth temperature for single species, but a general formulation has never been derived. Here, we present a reanalysis of data from 36 plant species to quantify the temperature dependence of Vcmax and Jmax with a focus on plant growth temperature, ie the plants' average ambient {\dots}}, + date-added = {2020-11-30T14:04:07GMT}, + date-modified = {2020-12-02T16:14:05GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2007/Kattge/Plant\%20Cell\%20\&\%20Environment\%202007\%20Kattge.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1111/j.1365-3040.2007.01690.x}, + file = {/Users/dorme/Zotero/storage/WCL92RHJ/Plant Cell & Environment 2007 Kattge.pdf} } -@article{Farquhar:1980ft, - title = {A biochemical model of photosynthetic {CO2} assimilation in leaves of {C3} species.}, - volume = {149}, - url = {http://link.springer.com/10.1007/BF00386231}, - doi = {10.1007/BF00386231}, - abstract = {Various aspects of the biochemistry of photosynthetic carbon assimilation in C3 plants are integrated into a form compatible with studies of gas exchange in leaves. These aspects include the kinetic properties of ribulose bisphosphate carboxylase-oxygenase; the requirements of the photosynthetic carbon reduction and photorespiratory carbon oxidation cycles for reduced pyridine nucleotides; the dependence of electron transport on photon flux and the presence of a temperature dependent upper limit to electron transport. The measurements of gas exchange with which the model outputs may be compared include those of the temperature and partial pressure of CO2(p(CO2)) dependencies of quantum yield, the variation of compensation point with temperature and partial pressure of O2(p(O2)), the dependence of net CO2 assimilation rate on p(CO2) and irradiance, and the influence of p(CO2) and irradiance on the temperature dependence of assimilation rate.}, - language = {english}, - number = {1}, - journal = {Planta}, - author = {Farquhar, G D and von Caemmerer, S and Berry, J A}, - month = jun, - year = {1980}, - pmid = {24306196}, - note = {tex.affiliation: Department of Environmental Biology, Research School of Biological Sciences, Australian National University, P.O. Box 475, 2601, Canberra City, ACT, Australia. - tex.date-added: 2020-12-17T09:47:58GMT - tex.date-modified: 2020-12-17T09:49:44GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/1980/Farquhar/Planta\%201980\%20Farquhar.pdf - tex.rating: 0 - tex.uri: papers3://publication/doi/10.1007/BF00386231}, - pages = {78--90}, - file = {Planta 1980 Farquhar.pdf:/Users/dorme/Zotero/storage/WFTRGJRB/Planta 1980 Farquhar.pdf:application/pdf;Planta 1980 Farquhar.pdf:/Users/dorme/Zotero/storage/FP3457LT/Planta 1980 Farquhar.pdf:application/pdf} +@article{kennedy:2019a, + title = {Implementing {{Plant Hydraulics}} in the {{Community Land Model}}, {{Version}} 5}, + author = {Kennedy, Daniel and Swenson, Sean and Oleson, Keith W. and Lawrence, David M. and Fisher, Rosie and {Lola da Costa}, Antonio Carlos and Gentine, Pierre}, + year = {2019}, + month = feb, + journal = {Journal of Advances in Modeling Earth Systems}, + volume = {11}, + number = {2}, + pages = {485--513}, + issn = {19422466}, + doi = {10.1029/2018MS001500}, + urldate = {2022-07-21}, + abstract = {Version 5 of the Community Land Model (CLM5) introduces the plant hydraulic stress (PHS) configuration of vegetation water use, which is described and compared with the corresponding parameterization from CLM4.5. PHS updates vegetation water stress and root water uptake to better reflect plant hydraulic theory, advancing the physical basis of the model. The new configuration introduces prognostic vegetation water potential, modeled at the root, stem, and leaf levels. Leaf water potential replaces soil potential as the basis for stomatal conductance water stress, and root water potential is used to implement hydraulic root water uptake, replacing a transpiration partitioning function. Point simulations of a tropical forest site (Caxiuan{\~a}, Brazil) under ambient conditions and partial precipitation exclusion highlight the differences between PHS and the previous CLM implementation. Model description and simulation results are contextualized with a list of benefits and limitations of the new model formulation, including hypotheses that were not testable in previous versions of the model. Key results include reductions in transpiration and soil moisture biases relative to a control model under both ambient and exclusion conditions, correcting excessive dry season soil moisture stress in the control model. PHS implements hydraulic gradient root water uptake, which allows hydraulic redistribution and compensatory root water uptake and results in PHS utilizing a larger portion of the soil column to buffer shortfalls in precipitation. The new model structure, which bases water stress on leaf water potential, could have significant implications for vegetation-climate feedbacks, including increased sensitivity of photosynthesis to atmospheric vapor pressure deficit.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/X6XIHAEF/Kennedy et al. - 2019 - Implementing Plant Hydraulics in the Community Lan.pdf} } -@article{Togashi:2018es, - title = {Functional trait variation related to gap dynamics in tropical moist forests$_{\textrm{{A}}}$ vegetation modelling perspective}, - volume = {35}, - url = {https://doi.org/10.1016/j.ppees.2018.10.004}, - doi = {10.1016/j.ppees.2018.10.004}, - abstract = {Perspectives in Plant Ecology, Evolution and Systematics, 35 (2018) 52-64. doi:10.1016/j.ppees.2018.10.004}, - journal = {Perspectives in Plant Ecology, Evolution and Systematics}, - author = {Togashi, Henrique Fürstenau and Atkin, Owen K and Bloomfield, Keith J and Bradford, Matt and Cao, Kunfang and Dong, Ning and Evans, Bradley J and Fan, Zexin and Harrison, Sandy P and Hua, Zhu and Liddell, Michael J and Lloyd, Jon and Ni, Jian and Wang, Han and Weerasinghe, Lasantha K and Prentice, Iain Colin}, - month = dec, - year = {2018}, - note = {Publisher: Elsevier - tex.date-added: 2020-12-01T17:02:03GMT - tex.date-modified: 2020-12-17T08:58:40GMT - tex.local-url: file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Togashi/Perspectives\%20in\%20Plant\%20Ecology\%20Evolution\%20and\%20Systematics\%202018\%20Togashi.pdf - tex.rating: 0 - tex.read: Yes - tex.uri: papers3://publication/doi/10.1016/j.ppees.2018.10.004}, - pages = {52--64}, - file = {Perspectives in Plant Ecology Evolution and Systematics 2018 Togashi.pdf:/Users/dorme/Zotero/storage/7T29HQCL/Perspectives in Plant Ecology Evolution and Systematics 2018 Togashi.pdf:application/pdf} +@phdthesis{Lancelot:2020tm, + title = {A Novel Computational Model to Predict Forest Dynamics}, + author = {Lancelot, Maxime}, + year = {2020}, + month = aug, + affiliation = {Imperial College London}, + date-added = {2020-11-30T12:25:21GMT}, + date-modified = {2020-11-30T14:42:52GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Books/2020/Lancelot/2020\%20Lancelot.pdf}, + rating = {0}, + uri = {papers3://publication/uuid/D73D9C6F-36C9-461D-A90C-784809C52BCB}, + file = {/Users/dorme/Zotero/storage/86NBGKCA/2020 Lancelot.pdf} } -@article{cai:2020a, - title = {Recent trends in gross primary production and their drivers: analysis and modelling at flux-site and global scales}, - volume = {15}, - issn = {1748-9326}, - shorttitle = {Recent trends in gross primary production and their drivers}, - url = {https://iopscience.iop.org/article/10.1088/1748-9326/abc64e}, - doi = {10.1088/1748-9326/abc64e}, - abstract = {Abstract - - Gross primary production (GPP) by terrestrial ecosystems is the largest flux in the global carbon cycle, and its continuing increase in response to environmental changes is key to land ecosystems’ capacity to offset anthropogenic CO - 2 - emissions. However, the CO - 2 - - and climate-sensitivities of GPP vary among models. We applied the ‘P model’—a parameter-sparse and extensively tested light use efficiency (LUE) model, driven by CO - 2 - , climate and remotely sensed greenness data—at 29 sites with multi-year eddy-covariance flux measurements. Observed (both positive and negative) GPP trends at these sites were predicted, albeit with some bias. Increasing LUE (due to rising atmospheric CO - 2 - concentration) and green vegetation cover were the primary controls of modelled GPP trends across sites. Global GPP simulated by the same model increased by 0.46 ± 0.09 Pg C yr - –2 - during 1982–2016. This increase falls in the mid-range rate of simulated increase by the TRENDY v8 ensemble of state-of-the-art ecosystem models. The modelled LUE increase during 1900–2013 was 15\%, similar to a published estimate based on deuterium isotopomers. Rising CO - 2 - was the largest contributor to the modelled GPP increase. Greening, which may in part be caused by rising CO - 2 - , ranked second but dominated the modelled GPP change over large areas, including semi-arid vegetation on all continents. Warming caused a small net reduction in modelled global GPP, but dominated the modelled GPP increase in high northern latitudes. These findings strengthen the evidence that rising LUE due to rising CO - 2 - level and increased green vegetation cover (fAPAR) are the main causes of increasing GPP, and thereby, the terrestrial carbon sink.}, - language = {en}, - number = {12}, - urldate = {2022-05-16}, - journal = {Environmental Research Letters}, - author = {Cai, Wenjia and Prentice, Iain Colin}, - month = dec, - year = {2020}, - pages = {124050}, - file = {Cai and Prentice - 2020 - Recent trends in gross primary production and thei.pdf:/Users/dorme/Zotero/storage/NGHELDVI/Cai and Prentice - 2020 - Recent trends in gross primary production and thei.pdf:application/pdf} +@article{lavergne:2022a, + title = {A Semi-Empirical Model for Primary Production, Isotopic Discrimination and Competition of {{C3}} and {{C4}} Plants}, + author = {Lavergne, Ali{\'e}nor and Harrison, Sandy P. and Atsawawaranunt, Kamolphat and Dong, Ning and Prentice, Iain Colin}, + year = {2022}, + journal = {Global Ecology and Biogeography (submitted)}, + file = {/Users/dorme/Zotero/storage/I797PRT2/Lavergneetal_GEB.docx} } @article{lavergne:2020a, - title = {Impacts of soil water stress on the acclimated stomatal limitation of photosynthesis: {Insights} from stable carbon isotope data}, - volume = {26}, - issn = {1354-1013, 1365-2486}, - shorttitle = {Impacts of soil water stress on the acclimated stomatal limitation of photosynthesis}, - url = {https://onlinelibrary.wiley.com/doi/10.1111/gcb.15364}, - doi = {10.1111/gcb.15364}, - abstract = {Atmospheric aridity and drought both influence physiological function in plant leaves, but their relative contributions to changes in the ratio of leaf internal to ambient partial pressure of CO2 (χ) – an index of adjustments in both stomatal conductance and photosynthetic rate to environmental conditions – are difficult to disentangle. Many stomatal models predicting χ include the influence of only one of these drivers. In particular, the least-cost optimality hypothesis considers the effect of atmospheric demand for water on χ but does not predict how soils with reduced water further influence χ, potentially leading to an overestimation of χ under dry conditions. Here, we use a large network of stable carbon isotope measurements in C3 woody plants to examine the acclimated response of χ to soil water stress. We estimate the ratio of cost factors for carboxylation and transpiration (β) expected from the theory to explain the variance in the data, and investigate the responses of β (and thus χ) to soil water content and suction across seed plant groups, leaf phenological types and regions. Overall, β decreases linearly with soil drying, implying that the cost of water transport along the soil–plant–atmosphere continuum increases as water available in the soil decreases. However, despite contrasting hydraulic strategies, the stomatal responses of angiosperms and gymnosperms to soil water tend to converge, consistent with the optimality theory. The prediction of β as a simple, empirical function of soil water significantly improves χ predictions by up to 6.3 ± 2.3\% (mean ± SD of adjusted-R2) over 1980–2018 and results in a reduction of around 2\% of mean χ values across the globe. Our results highlight the importance of soil water status on stomatal functions and plant water-use efficiency, and suggest the implementation of trait-based hydraulic functions into the model to account for soil water stress.}, - language = {en}, - number = {12}, - urldate = {2022-05-19}, - journal = {Global Change Biology}, - author = {Lavergne, Aliénor and Sandoval, David and Hare, Vincent J. and Graven, Heather and Prentice, Iain Colin}, - month = dec, - year = {2020}, - pages = {7158--7172}, - file = {Lavergne et al. - 2020 - Impacts of soil water stress on the acclimated sto.pdf:/Users/dorme/Zotero/storage/ULV9VU2Y/Lavergne et al. - 2020 - Impacts of soil water stress on the acclimated sto.pdf:application/pdf} + title = {Impacts of Soil Water Stress on the Acclimated Stomatal Limitation of Photosynthesis: {{Insights}} from Stable Carbon Isotope Data}, + shorttitle = {Impacts of Soil Water Stress on the Acclimated Stomatal Limitation of Photosynthesis}, + author = {Lavergne, Ali{\'e}nor and Sandoval, David and Hare, Vincent J. and Graven, Heather and Prentice, Iain Colin}, + year = {2020}, + month = dec, + journal = {Global Change Biology}, + volume = {26}, + number = {12}, + pages = {7158--7172}, + issn = {1354-1013, 1365-2486}, + doi = {10.1111/gcb.15364}, + urldate = {2022-05-19}, + abstract = {Atmospheric aridity and drought both influence physiological function in plant leaves, but their relative contributions to changes in the ratio of leaf internal to ambient partial pressure of CO2 ({$\chi$}) -- an index of adjustments in both stomatal conductance and photosynthetic rate to environmental conditions -- are difficult to disentangle. Many stomatal models predicting {$\chi$} include the influence of only one of these drivers. In particular, the least-cost optimality hypothesis considers the effect of atmospheric demand for water on {$\chi$} but does not predict how soils with reduced water further influence {$\chi$}, potentially leading to an overestimation of {$\chi$} under dry conditions. Here, we use a large network of stable carbon isotope measurements in C3 woody plants to examine the acclimated response of {$\chi$} to soil water stress. We estimate the ratio of cost factors for carboxylation and transpiration ({$\beta$}) expected from the theory to explain the variance in the data, and investigate the responses of {$\beta$} (and thus {$\chi$}) to soil water content and suction across seed plant groups, leaf phenological types and regions. Overall, {$\beta$} decreases linearly with soil drying, implying that the cost of water transport along the soil--plant--atmosphere continuum increases as water available in the soil decreases. However, despite contrasting hydraulic strategies, the stomatal responses of angiosperms and gymnosperms to soil water tend to converge, consistent with the optimality theory. The prediction of {$\beta$} as a simple, empirical function of soil water significantly improves {$\chi$} predictions by up to 6.3 {\textpm} 2.3\% (mean {\textpm} SD of adjusted-R2) over 1980--2018 and results in a reduction of around 2\% of mean {$\chi$} values across the globe. Our results highlight the importance of soil water status on stomatal functions and plant water-use efficiency, and suggest the implementation of trait-based hydraulic functions into the model to account for soil water stress.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/ECFRUWX5/Lavergne et al. - 2020 - Impacts of soil water stress on the acclimated sto.pdf} } -@article{farquhar:1982a, - title = {On the relationship between carbon isotope discrimination and the intercellular carbon dioxide concentration in leaves}, - volume = {9}, - issn = {1445-4408}, - url = {http://www.publish.csiro.au/?paper=PP9820121}, - doi = {10.1071/PP9820121}, - abstract = {Theory is developed to explain the carbon isotopic composition of plants. It is shown how diffusion of gaseous COz can significantly affect carbon isotopic discrimination. The effects on discrimination by diffusion and carboxylation are integrated, yielding a simple relationship between discrimination and the ratio of the intercellular and atmospheric partial pressures of COZ. The effects of dark respiration and photorespiration are also considered, and it is suggested that they have relatively little effect on discrimination other than cia their effects on intercellular p(COz). It is also suggested that various environmental factors such as light, temperature, salinity and drought will also have effects via changes in intercellular p(C0,). A simple method is suggested for assessing water use efficiencies in the field.}, - language = {en}, - number = {2}, - urldate = {2022-05-20}, - journal = {Australian Journal of Plant Physiology}, - author = {Farquhar, Graham D and O'Leary, Marion H and Berry, Joseph A}, - year = {1982}, - pages = {121}, - file = {Farquhar et al. - 1982 - On the Relationship Between Carbon Isotope Discrim.pdf:/Users/dorme/Zotero/storage/QMMIYWRA/Farquhar et al. - 1982 - On the Relationship Between Carbon Isotope Discrim.pdf:application/pdf} +@article{Li:2014bc, + title = {Simulation of Tree-Ring Widths with a Model for Primary Production, Carbon Allocation, and Growth}, + author = {Li, G and Harrison, S P and Prentice, I. C. and Falster, D}, + year = {2014}, + journal = {Biogeosciences (Online)}, + volume = {11}, + number = {23}, + pages = {6711--6724}, + doi = {10.5194/bg-11-6711-2014}, + date-added = {2020-12-01T16:59:12GMT}, + date-modified = {2021-11-11T13:59:21GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Li/Biogeosciences\%202014\%20Li.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.5194/bg-11-6711-2014}, + file = {/Users/dorme/Zotero/storage/HAR4D2NE/Biogeosciences 2014 Li.pdf} } -@article{voncaemmerer:2014a, - title = {Carbon isotope discrimination as a tool to explore {C4} photosynthesis}, - volume = {65}, - issn = {1460-2431, 0022-0957}, - url = {https://academic.oup.com/jxb/article-lookup/doi/10.1093/jxb/eru127}, - doi = {10.1093/jxb/eru127}, - abstract = {Photosynthetic carbon isotope discrimination is a non-destructive tool for investigating C4 metabolism. Tuneable diode laser absorption spectroscopy provides new opportunities for making rapid, concurrent measurements of carbon isotope discrimination and CO2 assimilation over a range of environmental conditions, and this has facilitated the use of carbon isotope discrimination as a probe of C4 metabolism. In spite of the significant progress made in recent years, understanding how photosynthetic carbon isotope discrimination measured concurrently with gas exchange relates to carbon isotope composition of leaf and plant dry matter remains a challenge that requires resolution if this technique is to be successfully applied as a screening tool in crop breeding and phylogenetic research. In this review, we update our understanding of the factors and assumptions that underlie variations in photosynthetic carbon isotope discrimination in C4 leaves. Closing the main gaps in our understanding of carbon isotope discrimination during C4 photosynthesis may help advance research aimed at developing higher productivity and efficiency in key C4 food, feed, and biofuel crops.}, - language = {en}, - number = {13}, - urldate = {2022-05-20}, - journal = {Journal of Experimental Botany}, - author = {von Caemmerer, Susanne and Ghannoum, Oula and Pengelly, Jasper J. L. and Cousins, Asaph B.}, - month = jul, - year = {2014}, - pages = {3459--3470}, - file = {Caemmerer et al. - 2014 - Carbon isotope discrimination as a tool to explore.pdf:/Users/dorme/Zotero/storage/EVAEICEV/Caemmerer et al. - 2014 - Carbon isotope discrimination as a tool to explore.pdf:application/pdf} +@article{Lin:2015wh, + title = {Optimal Stomatal Behaviour around the World}, + author = {Lin, Yan-Shih and Medlyn, Belinda E and Duursma, Remko A and Prentice, I. Colin and Wang, Han and Baig, Sofia and Eamus, Derek and {de Dios}, Victor Resco and Mitchell, Patrick and Ellsworth, David S and {de Beeck}, Maarten Op and Wallin, Goran and Uddling, Johan and Tarvainen, Lasse and Linderson, Maj-Lena and Cernusak, Lucas A and Nippert, Jesse B and Ocheltree, Troy W and Tissue, David T and {Martin-StPaul}, Nicolas K and Rogers, Alistair and Warren, Jeff M and De Angelis, Paolo and Hikosaka, Kouki and Han, Qingmin and Onoda, Yusuke and Gimeno, Teresa E and Barton, Craig V M and Bennie, Jonathan and Bonal, Damien and Bosc, Alexandre and Low, Markus and {Macinins-Ng}, Cate and Rey, Ana and Rowland, Lucy and Setterfield, Samantha A and {Tausz-Posch}, Sabine and {Zaragoza-Castells}, Joana and Broadmeadow, Mark S J and Drake, John E and Freeman, Michael and Ghannoum, Oula and Hutley, Lindsay B and Kelly, Jeff W and Kikuzawa, Kihachiro and Kolari, Pasi and Koyama, Kohei and Limousin, Jean-Marc and Meir, Patrick and {Lola da Costa}, Antonio C and Mikkelsen, Teis N and Salinas, Norma and Sun, Wei and Wingate, Lisa}, + year = {2015}, + journal = {Nature Climate Change}, + volume = {5}, + number = {5}, + pages = {459--464}, + abstract = {Stomatal conductance is a land-surface attribute that links the water and carbon cycles. Analysis of a global database covering a wide range of plant functional types and biomes now provides a framework for predicting the behaviour of stomatal conductance that can be applied to model ecosystem productivity, energy balance and ecohydrological processes in a changing climate.}, + date-added = {2021-11-11T14:12:05GMT}, + date-modified = {2021-11-11T14:13:27GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2015/Lin/2015\%20Lin-2.pdf}, + rating = {0}, + uri = {papers3://publication/uuid/61D6E8CB-F257-4021-AC24-2DF4D72C298E}, + file = {/Users/dorme/Zotero/storage/J7WANJNI/2015 Lin-2.pdf} +} + +@article{long:1993a, + title = {Quantum Yields for Uptake of Carbon Dioxide in {{C3}} Vascular Plants of Contrasting Habitats and Taxonomic Groupings}, + author = {Long, S. P. and Postl, W. F. and {Bolh{\'a}r-Nordenkampf}, H. R.}, + year = {1993}, + month = feb, + journal = {Planta}, + volume = {189}, + number = {2}, + pages = {226--234}, + issn = {1432-2048}, + doi = {10.1007/BF00195081}, + urldate = {2024-07-19}, + abstract = {The maximum quantum yields ({$\phi$}a,c) for CO2 uptake in low-oxygen atmospheres were determined for 11 species of C3 vascular plants of diverse taxa, habitat and life form using an Ulbricht-sphere leaf chamber. Comparisons were also made between tissues of varied age within species. The species examined were Psilotum nudum (L.) P. Beauv., Davallia bullata Wall. ex Hook., Cycas revoluta Thunb., Araucaria heterophylla (Salisb.) Franco, Picea abies (L.) Karst., Nerium oleander L., Ruellia humilis Nutt., Pilea microphylla (L.) Karst., Beaucarnea stricta Lem., Oplismenus hirtellus (L.) P. Beauv. and Poa annua L. Quantum yields were calculated from the initial slopes of the response of CO2 uptake to the quantity of photons absorbed in conditions of diffuse lighting. Regression analysis of variance of the initial slopes of the response of CO2 uptake to photon absorption failed to show any statistically significant differences between age classes within species or between the mature photosynthetic organs of different species. The constancy of {$\phi$}a,c was apparent despite marked variation in the light-saturated rates of CO2 uptake within and between species. The mean {$\phi$}a,c was 0.093{\textpm}0.003 for 11 species. By contrast, surface absorptance varied markedly between species from 0.90 to 0.60, producing proportional variation in the quantum yield calculated on an incidentlight basis. The ratio of variable to maximum fluorescence emission at 695 nm for the same tissues also failed to show any statistically significant variation between species, with a mean of 0.838{\textpm}0.008. Mean values of {$\phi$}a,c reported here for C3 species, in the absence of photorespiration, are higher than reported in previous surveys of vascular plants, but consistent with recent estimates of the quantum yields of O2 evolution.}, + langid = {english}, + keywords = {C3 plant,Photosynthesis,Quantum yield (O2 CO2 uptake)}, + file = {/Users/dorme/Zotero/storage/88PTVDYD/Long et al. - 1993 - Quantum yields for uptake of carbon dioxide in C3 .pdf} } -@article{boyd:2015a, - title = {Temperature response of {C4} photosynthesis: {Biochemical} analysis of {Rubisco}, {Phosphoenolpyruvate} {Carboxylase} and {Carbonic} {Anhydrase} in {Setaria} viridis.}, - issn = {0032-0889, 1532-2548}, - shorttitle = {Temperature response of {C4} photosynthesis}, - url = {https://academic.oup.com/plphys/article/169/3/1850-1861/6114196}, - doi = {10.1104/pp.15.00586}, - language = {en}, - urldate = {2022-05-20}, - journal = {Plant Physiology}, - author = {Boyd, Ryan Allen and Gandin, Anthony and Cousins, Asaph B}, - month = sep, - year = {2015}, - pages = {pp.00586.2015}, - file = {Boyd et al. - 2015 - Temperature response of C4 photosynthesis Biochem.pdf:/Users/dorme/Zotero/storage/RHH98FWY/Boyd et al. - 2015 - Temperature response of C4 photosynthesis Biochem.pdf:application/pdf} +@article{mengoli:2022a, + title = {Ecosystem {{Photosynthesis}} in {{Land}}-{{Surface Models}}: {{A First}}-{{Principles Approach Incorporating Acclimation}}}, + shorttitle = {Ecosystem {{Photosynthesis}} in {{Land}}-{{Surface Models}}}, + author = {Mengoli, Giulia and Agust{\'i}-Panareda, Anna and Boussetta, Souhail and Harrison, Sandy P. and Trotta, Carlo and Prentice, I. Colin}, + year = {2022}, + month = jan, + journal = {Journal of Advances in Modeling Earth Systems}, + volume = {14}, + number = {1}, + issn = {1942-2466, 1942-2466}, + doi = {10.1029/2021MS002767}, + urldate = {2022-05-26}, + abstract = {Vegetation regulates land-atmosphere, water, and energy exchanges and is an essential component of land-surface models (LSMs). However, LSMs have been handicapped by assumptions that equate acclimated photosynthetic responses to the environment with the fast responses observable in the laboratory. The effects of acclimation can be taken into account by including PFT-specific values of photosynthetic parameters, but at the cost of increasing parameter requirements. Here, we develop an alternative approach for including acclimation in LSMs by adopting the P model, an existing light-use efficiency model for gross primary production (GPP) that implicitly predicts the acclimation of photosynthetic parameters on a weekly to monthly timescale via optimality principles. We demonstrate that it is possible to explicitly separate the fast and slow photosynthetic responses to environmental conditions, allowing the simulation of GPP at the sub-daily timesteps required for coupling in an LSM. The resulting model reproduces the diurnal cycles of GPP recorded by eddy-covariance flux towers in a temperate grassland and boreal, temperate and tropical forests. The best performance is achieved when biochemical capacities are adjusted to match recent midday conditions. Comparison between this model and the operational LSM in the European Centre for Medium-range Weather Forecasts climate model shows that the new model has better predictive power in most of the sites and years analyzed, particularly in summer and autumn. Our analyses suggest a simple and parameter-sparse method to include both instantaneous and acclimated responses within an LSM framework, with potential applications in weather, climate, and carbon-cycle modeling.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/KAFPVD6H/2021ms002767-sup-0002-supporting information si-s02.pdf;/Users/dorme/Zotero/storage/VU8B6HP8/Mengoli et al. - 2022 - Ecosystem Photosynthesis in Land‐Surface Models A.pdf;/Users/dorme/Zotero/storage/ZQBUWXEK/2021ms002767-sup-0001-supporting information si-s01.pdf} } -@article{graven:2020a, - title = {Changes to {Carbon} {Isotopes} in {Atmospheric} {CO} $_{\textrm{2}}$ {Over} the {Industrial} {Era} and {Into} the {Future}}, - volume = {34}, - issn = {0886-6236, 1944-9224}, - url = {https://onlinelibrary.wiley.com/doi/10.1029/2019GB006170}, - doi = {10.1029/2019GB006170}, - abstract = {In this “Grand Challenges” paper, we review how the carbon isotopic composition of atmospheric CO2 has changed since the Industrial Revolution due to human activities and their influence on the natural carbon cycle, and we provide new estimates of possible future changes for a range of scenarios. Emissions of CO2 from fossil fuel combustion and land use change reduce the ratio of 13C/12C in atmospheric CO2 (δ13CO2). This is because 12C is preferentially assimilated during photosynthesis and δ13C in plant‐derived carbon in terrestrial ecosystems and fossil fuels is lower than atmospheric δ13CO2. Emissions of CO2 from fossil fuel combustion also reduce the ratio of 14C/C in atmospheric CO2 (Δ14CO2) because 14C is absent in million‐year‐old fossil fuels, which have been stored for much longer than the radioactive decay time of 14C. Atmospheric Δ14CO2 rapidly increased in the 1950s to 1960s because of 14C produced during nuclear bomb testing. The resulting trends in δ13C and Δ14C in atmospheric CO2 are influenced not only by these human emissions but also by natural carbon exchanges that mix carbon between the atmosphere and ocean and terrestrial ecosystems. This mixing caused Δ14CO2 to return toward preindustrial levels in the first few decades after the spike from nuclear testing. More recently, as the bomb 14C excess is now mostly well mixed with the decadally overturning carbon reservoirs, fossil fuel emissions have become the main factor driving further decreases in atmospheric Δ14CO2. For δ13CO2, in addition to exchanges between reservoirs, the extent to which 12C is preferentially assimilated during photosynthesis appears to have increased, slowing down the recent δ13CO2 trend slightly. A new compilation of ice core and flask δ13CO2 observations indicates that the decline in δ13CO2 since the preindustrial period is less than some prior estimates, which may have incorporated artifacts owing to offsets from different laboratories' measurements. Atmospheric observations of δ13CO2 have been used to investigate carbon fluxes and the functioning of plants, and they are used for comparison with δ13C in other materials such as tree rings. Atmospheric observations of Δ14CO2 have been used to quantify the rate of air‐sea gas exchange and ocean circulation, and the rate of net primary production and the turnover time of carbon in plant material and soils. Atmospheric observations of Δ14CO2 are also used for comparison with Δ14C in other materials in many fields such as archaeology, forensics, and physiology. Another major application is the assessment of regional emissions of CO2 from fossil fuel combustion using Δ14CO2 observations and models. In the future, δ13CO2 and Δ14CO2 will continue to change. The sign and magnitude of the changes are mainly determined by global fossil fuel emissions. We present here simulations of future δ13CO2 and Δ14CO2 for six scenarios based on the shared socioeconomic pathways (SSPs) from the 6th Coupled Model Intercomparison Project (CMIP6). Applications using atmospheric δ13CO2 and Δ14CO2 observations in carbon cycle science and many other fields will be affected by these future changes. We recommend an increased effort toward making coordinated measurements of δ13C and Δ14C across the Earth System and for further development of isotopic modeling and model‐data analysis tools.}, - language = {en}, - number = {11}, - urldate = {2022-05-23}, - journal = {Global Biogeochemical Cycles}, - author = {Graven, Heather and Keeling, Ralph F. and Rogelj, Joeri}, - month = nov, - year = {2020}, - file = {Graven et al. - 2020 - Changes to Carbon Isotopes in Atmospheric CO .pdf:/Users/dorme/Zotero/storage/XUCC46IU/Graven et al. - 2020 - Changes to Carbon Isotopes in Atmospheric CO .pdf:application/pdf} +@article{mengoli:2023a, + title = {A Global Function of Climatic Aridity Accounts for Soil Moisture Stress on Carbon Assimilation}, + author = {Mengoli, Giulia and Harrison, Sandy P. and Prentice, I. Colin}, + year = {2023}, + month = jun, + journal = {EGUsphere}, + pages = {1--19}, + publisher = {Copernicus GmbH}, + doi = {10.5194/egusphere-2023-1261}, + urldate = {2023-07-03}, + abstract = {{$<$}p{$><$}strong class="journal-contentHeaderColor"{$>$}Abstract.{$<$}/strong{$>$} The coupling between carbon uptake and water loss through stomata implies that gross primary production (GPP) can be limited by soil water availability through reduced leaf area and/or reduced stomatal conductance. Vegetation and land-surface models typically assume that GPP is highest under well-watered conditions and apply a stress function to reduce GPP with declining soil moisture below a critical threshold, which may be universal or prescribed by vegetation type. It is unclear how well current schemes represent the water conservation strategies of plants in different climates. Here eddy-covariance flux data are used to investigate empirically how soil moisture influences the light-use efficiency (LUE) of GPP. Well-watered GPP is estimated using the P model, a first-principles LUE model driven by atmospheric data and remotely sensed green vegetation cover. Breakpoint regression is used to relate the daily value of the ratio \β(\θ) (flux-derived GPP/modelled well-watered GPP) to soil moisture, which is estimated using a generic water-balance model. Maximum LUE, even during wetter periods, is shown to decline with increasing climatic aridity index (AI). The critical soil-moisture threshold also declines with AI. Moreover, for any AI, there is a value of soil moisture at which \β(\θ) is maximized, and this value declines with increasing AI. Thus, ecosystems adapted to seasonally dry conditions use water more conservatively (relative to well-watered ecosystems) when soil moisture is high, but maintain higher GPP when soil moisture is low. An empirical non-linear function of AI expressing these relationships is derived by non-linear regression, and used to generate a \β(\θ) function that provides a multiplier for well-watered GPP as simulated by the P model. Substantially improved GPP simulation is shown during both unstressed and water-stressed conditions, compared to the reference model version that ignores soil-moisture stress, and to an earlier formulation in which maximum LUE was not reduced. This scheme may provide a step towards better-founded representations of carbon-water cycle coupling in vegetation and land-surface models.{$<$}/p{$>$}}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/GMFKIMVQ/Mengoli et al. - 2023 - A global function of climatic aridity accounts for.pdf} } -@article{mengoli:2022a, - title = {Ecosystem {Photosynthesis} in {Land}‐{Surface} {Models}: {A} {First}‐{Principles} {Approach} {Incorporating} {Acclimation}}, - volume = {14}, - issn = {1942-2466, 1942-2466}, - shorttitle = {Ecosystem {Photosynthesis} in {Land}‐{Surface} {Models}}, - url = {https://onlinelibrary.wiley.com/doi/10.1029/2021MS002767}, - doi = {10.1029/2021MS002767}, - abstract = {Vegetation regulates land-atmosphere, water, and energy exchanges and is an essential component of land-surface models (LSMs). However, LSMs have been handicapped by assumptions that equate acclimated photosynthetic responses to the environment with the fast responses observable in the laboratory. The effects of acclimation can be taken into account by including PFT-specific values of photosynthetic parameters, but at the cost of increasing parameter requirements. Here, we develop an alternative approach for including acclimation in LSMs by adopting the P model, an existing light-use efficiency model for gross primary production (GPP) that implicitly predicts the acclimation of photosynthetic parameters on a weekly to monthly timescale via optimality principles. We demonstrate that it is possible to explicitly separate the fast and slow photosynthetic responses to environmental conditions, allowing the simulation of GPP at the sub-daily timesteps required for coupling in an LSM. The resulting model reproduces the diurnal cycles of GPP recorded by eddy-covariance flux towers in a temperate grassland and boreal, temperate and tropical forests. The best performance is achieved when biochemical capacities are adjusted to match recent midday conditions. Comparison between this model and the operational LSM in the European Centre for Medium-range Weather Forecasts climate model shows that the new model has better predictive power in most of the sites and years analyzed, particularly in summer and autumn. Our analyses suggest a simple and parameter-sparse method to include both instantaneous and acclimated responses within an LSM framework, with potential applications in weather, climate, and carbon-cycle modeling.}, - language = {en}, - number = {1}, - urldate = {2022-05-26}, - journal = {Journal of Advances in Modeling Earth Systems}, - author = {Mengoli, Giulia and Agustí‐Panareda, Anna and Boussetta, Souhail and Harrison, Sandy P. and Trotta, Carlo and Prentice, I. Colin}, - month = jan, - year = {2022}, - file = {2021ms002767-sup-0001-supporting information si-s01.pdf:/Users/dorme/Zotero/storage/YC3IEKUM/2021ms002767-sup-0001-supporting information si-s01.pdf:application/pdf;2021ms002767-sup-0002-supporting information si-s02.pdf:/Users/dorme/Zotero/storage/TP5WW2YH/2021ms002767-sup-0002-supporting information si-s02.pdf:application/pdf;Mengoli et al. - 2022 - Ecosystem Photosynthesis in Land‐Surface Models A.pdf:/Users/dorme/Zotero/storage/JU7AZTI4/Mengoli et al. - 2022 - Ecosystem Photosynthesis in Land‐Surface Models A.pdf:application/pdf} +@article{Moore:2018dv, + title = {Equilibrium Forest Demography Explains the Distribution of Tree Sizes across {{North America}}}, + author = {Moore, Jonathan R and Zhu, Kai and Huntingford, Chris and Cox, Peter M}, + year = {2018}, + month = aug, + journal = {Environmental Research Letters}, + volume = {13}, + number = {8}, + pages = {084019--10}, + publisher = {IOP Publishing}, + doi = {10.1088/1748-9326/aad6d1}, + abstract = {Environmental Research Letters, 13(2018) 084019. doi:10.1088/1748-9326/aad6d1}, + date-added = {2020-12-01T16:56:53GMT}, + date-modified = {2020-12-17T08:58:39GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Moore/Environ\%20Res\%20Lett\%202018\%20Moore.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1088/1748-9326/aad6d1}, + file = {/Users/dorme/Zotero/storage/9Z93DUPX/Environ Res Lett 2018 Moore.pdf} +} + +@article{murphy:2021a, + title = {A Derivation Error That Affects Carbon Balance Models Exists in the Current Implementation of the Modified {{Arrhenius}} Function}, + author = {Murphy, Bridget K. and Stinziano, Joseph R.}, + year = {2021}, + journal = {New Phytologist}, + volume = {231}, + number = {6}, + pages = {2371--2381}, + issn = {1469-8137}, + doi = {10.1111/nph.16883}, + urldate = {2024-07-25}, + abstract = {Understanding biological temperature responses is crucial to predicting global carbon fluxes. The current approach to modelling temperature responses of photosynthetic capacity in large scale modelling efforts uses a modified Arrhenius equation. We rederived the modified Arrhenius equation from the source publication from 1942 and uncovered a missing term that was dropped by 2002. We compare fitted temperature response parameters between the correct and incorrect derivation of the modified Arrhenius equation. We find that most parameters are minimally affected, though activation energy is impacted quite substantially. We then scaled the impact of these small errors to whole plant carbon balance and found that the impact of the rederivation of the modified Arrhenius equation on modelled daily carbon gain causes a meaningful deviation of c. 18\% day-1. This suggests that the error in the derivation of the modified Arrhenius equation has impacted the accuracy of predictions of carbon fluxes at larger scales since {$>$} 40\% of Earth System Models contain the erroneous derivation. We recommend that the derivation error be corrected in modelling efforts moving forward.}, + copyright = {{\copyright} 2020 The Authors New Phytologist {\copyright} 2020 New Phytologist Trust}, + langid = {english}, + keywords = {Arrhenius,carbon balance,gas exchange,modelling,photosynthesis,temperature}, + file = {/Users/dorme/Zotero/storage/NZTU5A6H/Murphy and Stinziano - 2021 - A derivation error that affects carbon balance mod.pdf;/Users/dorme/Zotero/storage/5Y2669L6/nph.html} } -@article{lavergne:2022a, - title = {A semi-empirical model for primary production, isotopic discrimination and competition of {C3} and {C4} plants}, - journal = {Global Ecology and Biogeography (submitted)}, - author = {Lavergne, Aliénor and Harrison, Sandy P. and Atsawawaranunt, Kamolphat and Dong, Ning and Prentice, Iain Colin}, - year = {2022}, - file = {Lavergneetal_GEB.docx:/Users/dorme/Zotero/storage/C4HSADV3/Lavergneetal_GEB.docx:application/vnd.openxmlformats-officedocument.wordprocessingml.document} +@article{Peng:2021ky, + title = {Global Climate and Nutrient Controls of Photosynthetic Capacity}, + author = {Peng, Yunke and Bloomfield, Keith J and Cernusak, Lucas A and Domingues, Tomas F and Prentice, I. Colin}, + year = {2021}, + month = apr, + journal = {Communications Biology}, + pages = {1--9}, + publisher = {Springer US}, + doi = {10.1038/s42003-021-01985-7}, + abstract = {Communications Biology, doi:10.1038/s42003-021-01985-7}, + date-added = {2021-06-14T08:31:31GMT}, + date-modified = {2021-11-11T14:13:27GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2021/Peng/Communications\%20Biology\%202021\%20Peng.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1038/s42003-021-01985-7}, + file = {/Users/dorme/Zotero/storage/ZPIDVNUB/Communications Biology 2021 Peng.pdf} } -@article{kennedy:2019a, - title = {Implementing {Plant} {Hydraulics} in the {Community} {Land} {Model}, {Version} 5}, - volume = {11}, - issn = {19422466}, - url = {http://doi.wiley.com/10.1029/2018MS001500}, - doi = {10.1029/2018MS001500}, - abstract = {Version 5 of the Community Land Model (CLM5) introduces the plant hydraulic stress (PHS) configuration of vegetation water use, which is described and compared with the corresponding parameterization from CLM4.5. PHS updates vegetation water stress and root water uptake to better reflect plant hydraulic theory, advancing the physical basis of the model. The new configuration introduces prognostic vegetation water potential, modeled at the root, stem, and leaf levels. Leaf water potential replaces soil potential as the basis for stomatal conductance water stress, and root water potential is used to implement hydraulic root water uptake, replacing a transpiration partitioning function. Point simulations of a tropical forest site (Caxiuanã, Brazil) under ambient conditions and partial precipitation exclusion highlight the differences between PHS and the previous CLM implementation. Model description and simulation results are contextualized with a list of benefits and limitations of the new model formulation, including hypotheses that were not testable in previous versions of the model. Key results include reductions in transpiration and soil moisture biases relative to a control model under both ambient and exclusion conditions, correcting excessive dry season soil moisture stress in the control model. PHS implements hydraulic gradient root water uptake, which allows hydraulic redistribution and compensatory root water uptake and results in PHS utilizing a larger portion of the soil column to buffer shortfalls in precipitation. The new model structure, which bases water stress on leaf water potential, could have significant implications for vegetation-climate feedbacks, including increased sensitivity of photosynthesis to atmospheric vapor pressure deficit.}, - language = {en}, - number = {2}, - urldate = {2022-07-21}, - journal = {Journal of Advances in Modeling Earth Systems}, - author = {Kennedy, Daniel and Swenson, Sean and Oleson, Keith W. and Lawrence, David M. and Fisher, Rosie and Lola da Costa, Antonio Carlos and Gentine, Pierre}, - month = feb, - year = {2019}, - pages = {485--513}, - file = {Kennedy et al. - 2019 - Implementing Plant Hydraulics in the Community Lan.pdf:/Users/dorme/Zotero/storage/DK2KUV85/Kennedy et al. - 2019 - Implementing Plant Hydraulics in the Community Lan.pdf:application/pdf} +@article{Prentice:2014bc, + title = {Balancing the Costs of Carbon Gain and Water Transport: Testing a New Theoretical Framework for Plant Functional Ecology}, + author = {Prentice, I. Colin and Dong, Ning and Gleason, Sean M and Maire, Vincent and Wright, Ian J.}, + year = {2014}, + journal = {Ecology Letters}, + volume = {17}, + number = {1}, + pages = {82--91}, + doi = {10.1111/ele.12211}, + date-added = {2020-12-01T13:22:48GMT}, + date-modified = {2021-01-21T15:04:43GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Prentice/Ecol\%20Lett\%202014\%20Prentice.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1111/ele.12211}, + file = {/Users/dorme/Zotero/storage/MDRBDVTF/Ecol Lett 2014 Prentice.pdf} } -@article{badeck:2005a, - title = {Post-photosynthetic fractionation of stable carbon isotopes between plant organs—a widespread phenomenon}, - volume = {19}, - url = {https://analyticalsciencejournals.onlinelibrary.wiley.com/doi/abs/10.1002/rcm.1912}, - doi = {https://doi.org/10.1002/rcm.1912}, - abstract = {Abstract Discrimination against 13C during photosynthesis is a well-characterised phenomenon. It leaves behind distinct signatures in organic matter of plants and in the atmosphere. The former is depleted in 13C, the latter is enriched during periods of preponderant photosynthetic activity of terrestrial ecosystems. The intra-annual cycle and latitudinal gradient in atmospheric 13C resulting from photosynthetic and respiratory activities of terrestrial plants have been exploited for the reconstruction of sources and sinks through deconvolution by inverse modelling. Here, we compile evidence for widespread post-photosynthetic fractionation that further modifies the isotopic signatures of individual plant organs and consequently leads to consistent differences in δ13C between plant organs. Leaves were on average 0.96‰ and 1.91‰ more depleted than roots and woody stems, respectively. This phenomenon is relevant if the isotopic signature of CO2-exchange fluxes at the ecosystem level is used for the reconstruction of individual sources and sinks. It may also modify the parameterisation of inverse modelling approaches if it leads to different isotopic signatures of organic matter with different residence times within the ecosystems and to a respiratory contribution to the average difference between the isotopic composition of plant organic matter and the atmosphere. We discuss the main hypotheses that can explain the observed inter-organ differences in δ13C. Copyright © 2005 John Wiley \& Sons, Ltd.}, - number = {11}, - journal = {Rapid Communications in Mass Spectrometry}, - author = {Badeck, Franz-W. and Tcherkez, Guillaume and Nogués, Salvador and Piel, Clément and Ghashghaie, Jaleh}, - year = {2005}, - note = {tex.eprint: https://analyticalsciencejournals.onlinelibrary.wiley.com/doi/pdf/10.1002/rcm.1912}, - pages = {1381--1391}, - file = {Badeck et al. - 2005 - Post-photosynthetic fractionation of stable carbon.pdf:/Users/dorme/Zotero/storage/A8TG832F/Badeck et al. - 2005 - Post-photosynthetic fractionation of stable carbon.pdf:application/pdf} +@article{Smith:2019dv, + title = {Global Photosynthetic Capacity Is Optimized to the Environment}, + author = {Smith, Nicholas G and Keenan, Trevor F and Colin Prentice, I and Wang, Han and Wright, Ian J. and Niinemets, {\"U}lo and Crous, Kristine Y and Domingues, Tomas F and Guerrieri, Rossella and Yoko Ishida, F and Kattge, Jens and Kruger, Eric L and Maire, Vincent and Rogers, Alistair and Serbin, Shawn P and Tarvainen, Lasse and Togashi, Henrique F and Townsend, Philip A and Wang, Meng and Weerasinghe, Lasantha K and Zhou, Shuang Xi}, + year = {2019}, + month = jan, + journal = {Ecology Letters}, + volume = {22}, + number = {3}, + pages = {506--517}, + doi = {10.1111/ele.13210}, + date-added = {2020-12-02T15:16:49GMT}, + date-modified = {2021-01-25T10:03:32GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2019/Smith/Ecol\%20Lett\%202019\%20Smith.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1111/ele.13210}, + file = {/Users/dorme/Zotero/storage/EIWDBL6T/Ecol Lett 2019 Smith.pdf} } -@article{frank:2015a, - title = {Water-use efficiency and transpiration across {European} forests during the {Anthropocene}}, - volume = {5}, - issn = {1758-6798}, - url = {https://doi.org/10.1038/nclimate2614}, - doi = {10.1038/nclimate2614}, - abstract = {Considering the combined effects of CO2 fertilization and climate change drivers on plant physiology leads to a modest increase in simulated European forest transpiration in spite of the effects of CO2-induced stomatal closure.}, - number = {6}, - journal = {Nature Climate Change}, - author = {Frank, D. C. and Poulter, B. and Saurer, M. and Esper, J. and Huntingford, C. and Helle, G. and Treydte, K. and Zimmermann, N. E. and Schleser, G. H. and Ahlström, A. and Ciais, P. and Friedlingstein, P. and Levis, S. and Lomas, M. and Sitch, S. and Viovy, N. and Andreu-Hayles, L. and Bednarz, Z. and Berninger, F. and Boettger, T. and D‘Alessandro, C. M. and Daux, V. and Filot, M. and Grabner, M. and Gutierrez, E. and Haupt, M. and Hilasvuori, E. and Jungner, H. and Kalela-Brundin, M. and Krapiec, M. and Leuenberger, M. and Loader, N. J. and Marah, H. and Masson-Delmotte, V. and Pazdur, A. and Pawelczyk, S. and Pierre, M. and Planells, O. and Pukiene, R. and Reynolds-Henne, C. E. and Rinne, K. T. and Saracino, A. and Sonninen, E. and Stievenard, M. and Switsur, V. R. and Szczepanek, M. and Szychowska-Krapiec, E. and Todaro, L. and Waterhouse, J. S. and Weigl, M.}, - month = jun, - year = {2015}, - pages = {579--583}, - file = {Frank et al. - 2015 - Water-use efficiency and transpiration across Euro.pdf:/Users/dorme/Zotero/storage/DQE7I4U4/Frank et al. - 2015 - Water-use efficiency and transpiration across Euro.pdf:application/pdf} +@article{Stocker:2020dh, + title = {P-Model v1.0: An Optimality-Based Light Use Efficiency Model for Simulating Ecosystem Gross Primary Production}, + author = {Stocker, Benjamin D and Wang, Han and Smith, Nicholas G and Harrison, Sandy P and Keenan, Trevor F and Sandoval, David and Davis, Tyler and Prentice, I. Colin}, + year = {2020}, + journal = {Geoscientific Model Development}, + volume = {13}, + number = {3}, + pages = {1545--1581}, + doi = {10.5194/gmd-13-1545-2020}, + date-added = {2020-11-30T12:24:06GMT}, + date-modified = {2021-01-28T11:55:51GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Stocker/Geoscientific\%20Model\%20Development\%202020\%20Stocker.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.5194/gmd-13-1545-2020}, + file = {/Users/dorme/Zotero/storage/J4YM5X2R/Geoscientific Model Development 2020 Stocker.pdf} } -@article{mengoli:2023a, - title = {A global function of climatic aridity accounts for soil moisture stress on carbon assimilation}, - url = {https://egusphere.copernicus.org/preprints/2023/egusphere-2023-1261/}, - doi = {10.5194/egusphere-2023-1261}, - abstract = {{\textless}p{\textgreater}{\textless}strong class="journal-contentHeaderColor"{\textgreater}Abstract.{\textless}/strong{\textgreater} The coupling between carbon uptake and water loss through stomata implies that gross primary production (GPP) can be limited by soil water availability through reduced leaf area and/or reduced stomatal conductance. Vegetation and land-surface models typically assume that GPP is highest under well-watered conditions and apply a stress function to reduce GPP with declining soil moisture below a critical threshold, which may be universal or prescribed by vegetation type. It is unclear how well current schemes represent the water conservation strategies of plants in different climates. Here eddy-covariance flux data are used to investigate empirically how soil moisture influences the light-use efficiency (LUE) of GPP. Well-watered GPP is estimated using the P model, a first-principles LUE model driven by atmospheric data and remotely sensed green vegetation cover. Breakpoint regression is used to relate the daily value of the ratio \β(\θ) (flux-derived GPP/modelled well-watered GPP) to soil moisture, which is estimated using a generic water-balance model. Maximum LUE, even during wetter periods, is shown to decline with increasing climatic aridity index (AI). The critical soil-moisture threshold also declines with AI. Moreover, for any AI, there is a value of soil moisture at which \β(\θ) is maximized, and this value declines with increasing AI. Thus, ecosystems adapted to seasonally dry conditions use water more conservatively (relative to well-watered ecosystems) when soil moisture is high, but maintain higher GPP when soil moisture is low. An empirical non-linear function of AI expressing these relationships is derived by non-linear regression, and used to generate a \β(\θ) function that provides a multiplier for well-watered GPP as simulated by the P model. Substantially improved GPP simulation is shown during both unstressed and water-stressed conditions, compared to the reference model version that ignores soil-moisture stress, and to an earlier formulation in which maximum LUE was not reduced. This scheme may provide a step towards better-founded representations of carbon-water cycle coupling in vegetation and land-surface models.{\textless}/p{\textgreater}}, - language = {English}, - urldate = {2023-07-03}, - journal = {EGUsphere}, - author = {Mengoli, Giulia and Harrison, Sandy P. and Prentice, I. Colin}, - month = jun, - year = {2023}, - note = {Publisher: Copernicus GmbH}, - pages = {1--19}, - file = {Full Text PDF:/Users/dorme/Zotero/storage/JVIB9NS3/Mengoli et al. - 2023 - A global function of climatic aridity accounts for.pdf:application/pdf} +@article{Stocker:2018be, + title = {Quantifying Soil Moisture Impacts on Light Use Efficiency across Biomes}, + author = {Stocker, Benjamin D and Zscheischler, Jakob and Keenan, Trevor F and Prentice, I. Colin and Penuelas, Josep and Seneviratne, Sonia I}, + year = {2018}, + month = mar, + journal = {New Phytologist}, + volume = {218}, + number = {4}, + pages = {1430--1449}, + doi = {10.1111/nph.15123}, + abstract = {Terrestrial primary productivity and carbon cycle impacts of droughts are commonly quantified using vapour pressure deficit (VPD) data and remotely sensed greenness, without accounting for soil moisture. However, soil moisture limitation is known to strongly affect plant physiology. Here, we investigate light use efficiency, the ratio of gross primary productivity (GPP) to absorbed light. We derive its fractional reduction due to soil moisture (fLUE), separated from VPD and greenness changes, using artificial neural networks trained {\dots}}, + date-added = {2021-01-25T09:23:00GMT}, + date-modified = {2021-01-28T15:58:46GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Stocker/New\%20Phytol.\%202018\%20Stocker.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1111/nph.15123}, + file = {/Users/dorme/Zotero/storage/E6PPD38Z/New Phytol. 2018 Stocker.pdf} } -@techreport{allen:1998a, - address = {Rome}, - title = {Crop evapotranspiration - {Guidelines} for computing crop water requirements}, - number = {56}, - institution = {FAO}, - author = {Allen, Richard G. and Pereira, Luis S and Raes, Dirk and Smith, Martin}, - year = {1998}, - file = {Allen et al. - 1998 - Crop evapotranspiration - Guidelines for computing.pdf:/Users/dorme/Zotero/storage/68AVA64R/Allen et al. - 1998 - Crop evapotranspiration - Guidelines for computing.pdf:application/pdf} +@article{Togashi:2018es, + title = {Functional Trait Variation Related to Gap Dynamics in Tropical Moist forests{{{\textsubscript{A}}}} Vegetation Modelling Perspective}, + author = {Togashi, Henrique F{\"u}rstenau and Atkin, Owen K and Bloomfield, Keith J and Bradford, Matt and Cao, Kunfang and Dong, Ning and Evans, Bradley J and Fan, Zexin and Harrison, Sandy P and Hua, Zhu and Liddell, Michael J and Lloyd, Jon and Ni, Jian and Wang, Han and Weerasinghe, Lasantha K and Prentice, Iain Colin}, + year = {2018}, + month = dec, + journal = {Perspectives in Plant Ecology, Evolution and Systematics}, + volume = {35}, + pages = {52--64}, + publisher = {Elsevier}, + doi = {10.1016/j.ppees.2018.10.004}, + abstract = {Perspectives in Plant Ecology, Evolution and Systematics, 35 (2018) 52-64. doi:10.1016/j.ppees.2018.10.004}, + date-added = {2020-12-01T17:02:03GMT}, + date-modified = {2020-12-17T08:58:40GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2018/Togashi/Perspectives\%20in\%20Plant\%20Ecology\%20Evolution\%20and\%20Systematics\%202018\%20Togashi.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1016/j.ppees.2018.10.004}, + file = {/Users/dorme/Zotero/storage/L4HJJSBU/Perspectives in Plant Ecology Evolution and Systematics 2018 Togashi.pdf} } @article{tsilingiris:2008a, - title = {Thermophysical and transport properties of humid air at temperature range between 0 and 100°{C}}, - volume = {49}, - issn = {0196-8904}, - url = {https://www.sciencedirect.com/science/article/pii/S0196890407003329}, - doi = {10.1016/j.enconman.2007.09.015}, + title = {Thermophysical and Transport Properties of Humid Air at Temperature Range between 0 and 100{$^\circ$}{{C}}}, + author = {Tsilingiris, P. T.}, + year = {2008}, + month = may, + journal = {Energy Conversion and Management}, + volume = {49}, + number = {5}, + pages = {1098--1110}, + issn = {0196-8904}, + doi = {10.1016/j.enconman.2007.09.015}, + urldate = {2023-07-04}, abstract = {The aim of the present investigation is evaluation of the thermophysical and transport properties of moist air as a function of mixture temperature with relative humidity as a parameter, ranging between dry air and saturation conditions. Based on a literature review of the most widely available analytical procedures and methods, a number of developed correlations are presented, which are employed with recent gas mixture component properties as input parameters, to derive the temperature and humidity dependence of mixture density, viscosity, specific heat capacity, thermal conductivity, thermal diffusivity and Prandtl number under conditions corresponding to the total barometric pressure of 101.3kPa. The derived results at an accuracy level suitable for engineering calculations were plotted and compared with adequate accuracy with existing results from previous analytical calculations and measured data from earlier experimental investigations. The saturated mixture properties were also appropriately fitted, and the fitting expressions suitable for computer calculations are also presented.}, - language = {en}, - number = {5}, - urldate = {2023-07-04}, - journal = {Energy Conversion and Management}, - author = {Tsilingiris, P. T.}, - month = may, - year = {2008}, - keywords = {Density, Prandtl number, Specific heat capacity, Thermal conductivity, Thermal diffusivity, Thermophysical properties, Viscosity}, - pages = {1098--1110}, - file = {ScienceDirect Full Text PDF:/Users/dorme/Zotero/storage/EZSDLB2V/Tsilingiris - 2008 - Thermophysical and transport properties of humid a.pdf:application/pdf;ScienceDirect Snapshot:/Users/dorme/Zotero/storage/IZWWYPC8/S0196890407003329.html:text/html} -} - -@article{henderson-sellers:1984a, - title = {A new formula for latent heat of vaporization of water as a function of temperature}, - volume = {110}, - copyright = {Copyright © 1984 Royal Meteorological Society}, - issn = {1477-870X}, - url = {https://onlinelibrary.wiley.com/doi/abs/10.1002/qj.49711046626}, - doi = {10.1002/qj.49711046626}, - abstract = {Existing formulae and approximations for the latent heat of vaporization of water, Lv, are reviewed. Using an analytical approximation to the saturated vapour pressure as a function of temperature, a new, temperature-dependent function for Lv is derived.}, - language = {en}, - number = {466}, - urldate = {2023-07-04}, - journal = {Quarterly Journal of the Royal Meteorological Society}, - author = {Henderson-Sellers, B.}, - year = {1984}, - note = {\_eprint: https://onlinelibrary.wiley.com/doi/pdf/10.1002/qj.49711046626}, - pages = {1186--1190}, - file = {Snapshot:/Users/dorme/Zotero/storage/WJAU4R6F/qj.html:text/html} + langid = {english}, + keywords = {Density,Prandtl number,Specific heat capacity,Thermal conductivity,Thermal diffusivity,Thermophysical properties,Viscosity}, + file = {/Users/dorme/Zotero/storage/CUISZDZT/Tsilingiris - 2008 - Thermophysical and transport properties of humid a.pdf;/Users/dorme/Zotero/storage/RFS82MFU/S0196890407003329.html} } -@article{chen:2008a, - title = {The equation of state of pure water determined from sound speeds}, - volume = {66}, - issn = {0021-9606}, - url = {https://doi.org/10.1063/1.434179}, - doi = {10.1063/1.434179}, - abstract = {The equation of state of water valid over the range 0–100 °C and 0–1000 bar has been determined from the high pressure sound velocities of Wilson, which were reanalyzed by Chen and Millero. The equation of state has a maximum error of ±0.01 bar−1 in isothermal compressibility and is in the form of a secant bulk modulus: K=V0P/(V0−V) =K0+AP+BP2, where K, K0, and V, V0 are the secant bulk moduli and specific volumes at applied pressures P and 0 (1 atm), respectively; A and B are temperature dependent parameters. The good agreement (to within 20×10−6 cm3 g−1) of specific volumes calculated using the above equation with those obtained from other modifications of the Wilson sound velocity data demonstrates the reliability of the sound velocity method for determining equations of state.}, - number = {5}, - urldate = {2023-07-04}, - journal = {The Journal of Chemical Physics}, - author = {Chen, Chen‐Tung and Fine, Rana A. and Millero, Frank J.}, - month = aug, - year = {2008}, - pages = {2142--2144}, - file = {Full Text PDF:/Users/dorme/Zotero/storage/2WBI492T/Chen et al. - 2008 - The equation of state of pure water determined fro.pdf:application/pdf;Snapshot:/Users/dorme/Zotero/storage/IRHA5IDN/The-equation-of-state-of-pure-water-determined.html:text/html} +@article{voncaemmerer:2014a, + title = {Carbon Isotope Discrimination as a Tool to Explore {{C4}} Photosynthesis}, + author = {{von Caemmerer}, Susanne and Ghannoum, Oula and Pengelly, Jasper J. L. and Cousins, Asaph B.}, + year = {2014}, + month = jul, + journal = {Journal of Experimental Botany}, + volume = {65}, + number = {13}, + pages = {3459--3470}, + issn = {1460-2431, 0022-0957}, + doi = {10.1093/jxb/eru127}, + urldate = {2022-05-20}, + abstract = {Photosynthetic carbon isotope discrimination is a non-destructive tool for investigating C4 metabolism. Tuneable diode laser absorption spectroscopy provides new opportunities for making rapid, concurrent measurements of carbon isotope discrimination and CO2 assimilation over a range of environmental conditions, and this has facilitated the use of carbon isotope discrimination as a probe of C4 metabolism. In spite of the significant progress made in recent years, understanding how photosynthetic carbon isotope discrimination measured concurrently with gas exchange relates to carbon isotope composition of leaf and plant dry matter remains a challenge that requires resolution if this technique is to be successfully applied as a screening tool in crop breeding and phylogenetic research. In this review, we update our understanding of the factors and assumptions that underlie variations in photosynthetic carbon isotope discrimination in C4 leaves. Closing the main gaps in our understanding of carbon isotope discrimination during C4 photosynthesis may help advance research aimed at developing higher productivity and efficiency in key C4 food, feed, and biofuel crops.}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/DBGBCVUB/Caemmerer et al. - 2014 - Carbon isotope discrimination as a tool to explore.pdf} } -@article{hengl:2017a, - title = {{SoilGrids250m}: {Global} gridded soil information based on machine learning}, - volume = {12}, - issn = {1932-6203}, - shorttitle = {{SoilGrids250m}}, - url = {https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0169748}, - doi = {10.1371/journal.pone.0169748}, - abstract = {This paper describes the technical development and accuracy assessment of the most recent and improved version of the SoilGrids system at 250m resolution (June 2016 update). SoilGrids provides global predictions for standard numeric soil properties (organic carbon, bulk density, Cation Exchange Capacity (CEC), pH, soil texture fractions and coarse fragments) at seven standard depths (0, 5, 15, 30, 60, 100 and 200 cm), in addition to predictions of depth to bedrock and distribution of soil classes based on the World Reference Base (WRB) and USDA classification systems (ca. 280 raster layers in total). Predictions were based on ca. 150,000 soil profiles used for training and a stack of 158 remote sensing-based soil covariates (primarily derived from MODIS land products, SRTM DEM derivatives, climatic images and global landform and lithology maps), which were used to fit an ensemble of machine learning methods—random forest and gradient boosting and/or multinomial logistic regression—as implemented in the R packages ranger, xgboost, nnet and caret. The results of 10–fold cross-validation show that the ensemble models explain between 56\% (coarse fragments) and 83\% (pH) of variation with an overall average of 61\%. Improvements in the relative accuracy considering the amount of variation explained, in comparison to the previous version of SoilGrids at 1 km spatial resolution, range from 60 to 230\%. Improvements can be attributed to: (1) the use of machine learning instead of linear regression, (2) to considerable investments in preparing finer resolution covariate layers and (3) to insertion of additional soil profiles. Further development of SoilGrids could include refinement of methods to incorporate input uncertainties and derivation of posterior probability distributions (per pixel), and further automation of spatial modeling so that soil maps can be generated for potentially hundreds of soil variables. Another area of future research is the development of methods for multiscale merging of SoilGrids predictions with local and/or national gridded soil products (e.g. up to 50 m spatial resolution) so that increasingly more accurate, complete and consistent global soil information can be produced. SoilGrids are available under the Open Data Base License.}, - language = {en}, - number = {2}, - urldate = {2023-07-05}, - journal = {PLOS ONE}, - author = {Hengl, Tomislav and Jesus, Jorge Mendes de and Heuvelink, Gerard B. M. and Gonzalez, Maria Ruiperez and Kilibarda, Milan and Blagotić, Aleksandar and Shangguan, Wei and Wright, Marvin N. and Geng, Xiaoyuan and Bauer-Marschallinger, Bernhard and Guevara, Mario Antonio and Vargas, Rodrigo and MacMillan, Robert A. and Batjes, Niels H. and Leenaars, Johan G. B. and Ribeiro, Eloi and Wheeler, Ichsani and Mantel, Stephan and Kempen, Bas}, - month = feb, - year = {2017}, - note = {Publisher: Public Library of Science}, - keywords = {Agricultural soil science, Forecasting, Glaciers, Machine learning, Remote sensing, Shannon index, Soil pH, Trees}, - pages = {e0169748}, - file = {Full Text PDF:/Users/dorme/Zotero/storage/VS5FRVSK/Hengl et al. - 2017 - SoilGrids250m Global gridded soil information bas.pdf:application/pdf} +@article{Walker:2014ce, + title = {The Relationship of Leaf Photosynthetic Traits - {{Vcmaxand Jmax-}} to Leaf Nitrogen, Leaf Phosphorus, and Specific Leaf Area: A Meta-Analysis and Modeling Study}, + author = {Walker, Anthony P and Beckerman, Andrew P and Gu, Lianhong and Kattge, Jens and Cernusak, Lucas A and Domingues, Tomas F and Scales, Joanna C and Wohlfahrt, Georg and Wullschleger, Stan D and Woodward, F Ian}, + year = {2014}, + month = jul, + journal = {Ecology and Evolution}, + volume = {4}, + number = {16}, + pages = {3218--3235}, + doi = {10.1002/ece3.1173}, + date-added = {2020-12-07T11:43:53GMT}, + date-modified = {2020-12-17T08:58:39GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2014/Walker/Ecology\%20and\%20Evolution\%202014\%20Walker.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1002/ece3.1173}, + file = {/Users/dorme/Zotero/storage/N8LKZ4EP/Ecology and Evolution 2014 Walker.pdf} } -@article{davis:2017a, - title = {Simple process-led algorithms for simulating habitats ({SPLASH} v.1.0): robust indices of radiation, evapotranspiration and plant-available moisture}, - volume = {10}, - issn = {1991-959X}, - shorttitle = {Simple process-led algorithms for simulating habitats ({SPLASH} v.1.0)}, - url = {https://gmd.copernicus.org/articles/10/689/2017/}, - doi = {10.5194/gmd-10-689-2017}, - abstract = {Bioclimatic indices for use in studies of ecosystem function, species distribution, and vegetation dynamics under changing climate scenarios depend on estimates of surface fluxes and other quantities, such as radiation, evapotranspiration and soil moisture, for which direct observations are sparse. These quantities can be derived indirectly from meteorological variables, such as near-surface air temperature, precipitation and cloudiness. Here we present a consolidated set of simple process-led algorithms for simulating habitats (SPLASH) allowing robust approximations of key quantities at ecologically relevant timescales. We specify equations, derivations, simplifications, and assumptions for the estimation of daily and monthly quantities of top-of-the-atmosphere solar radiation, net surface radiation, photosynthetic photon flux density, evapotranspiration (potential, equilibrium, and actual), condensation, soil moisture, and runoff, based on analysis of their relationship to fundamental climatic drivers. The climatic drivers include a minimum of three meteorological inputs: precipitation, air temperature, and fraction of bright sunshine hours. Indices, such as the moisture index, the climatic water deficit, and the Priestley–Taylor coefficient, are also defined. The SPLASH code is transcribed in C++, FORTRAN, Python, and R. A total of 1 year of results are presented at the local and global scales to exemplify the spatiotemporal patterns of daily and monthly model outputs along with comparisons to other model results.}, - language = {English}, - number = {2}, - urldate = {2023-07-05}, - journal = {Geoscientific Model Development}, - author = {Davis, Tyler W. and Prentice, I. Colin and Stocker, Benjamin D. and Thomas, Rebecca T. and Whitley, Rhys J. and Wang, Han and Evans, Bradley J. and Gallego-Sala, Angela V. and Sykes, Martin T. and Cramer, Wolfgang}, - month = feb, - year = {2017}, - note = {Publisher: Copernicus GmbH}, - pages = {689--708}, - file = {Full Text PDF:/Users/dorme/Zotero/storage/RUZWLGHT/Davis et al. - 2017 - Simple process-led algorithms for simulating habit.pdf:application/pdf} +@article{Wang:2020ik, + title = {Acclimation of Leaf Respiration Consistent with Optimal Photosynthetic Capacity}, + author = {Wang, Han and Atkin, Owen K and Keenan, Trevor F and Smith, Nicholas G and Wright, Ian J. and Bloomfield, Keith J and Kattge, Jens and Reich, Peter B and Prentice, I. Colin}, + year = {2020}, + month = feb, + journal = {Global Change Biology}, + volume = {26}, + number = {4}, + pages = {2573--2583}, + doi = {10.1111/gcb.14980}, + date-added = {2020-11-30T12:23:58GMT}, + date-modified = {2021-01-22T13:54:24GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Wang/Global\%20Change\%20Biol\%202020\%20Wang.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1111/gcb.14980}, + file = {/Users/dorme/Zotero/storage/2XYW4BF4/gcb15314-sup-0004-Supinfo.pdf;/Users/dorme/Zotero/storage/RAGU56IZ/Global Change Biol 2020 Wang.pdf} } -@article{berger:1978a, - title = {Long-{Term} {Variations} of {Daily} {Insolation} and {Quaternary} {Climatic} {Changes}}, - volume = {35}, - issn = {0022-4928, 1520-0469}, - url = {https://journals.ametsoc.org/view/journals/atsc/35/12/1520-0469_1978_035_2362_ltvodi_2_0_co_2.xml}, - doi = {10.1175/1520-0469(1978)035<2362:LTVODI>2.0.CO;2}, - abstract = {Abstract The first part of this note provides all trigonometrical formulas which allow the direct spectral analysis and the computation of those long-term variations of the earth’s orbital elements which are of primary interest for the computation of the insolation. The elements are the eccentricity, the longitude of the perihelion, the processional parameter and the obliquity. This new formulary is much more simple to use than the ones previously designed and still provides excellent accuracy, mainly because it takes into account the influence of the most important higher order terms in the series expansions. The second part is devoted to the computation of the daily insolation both for calendar and solar dates.}, - language = {EN}, - number = {12}, - urldate = {2023-07-13}, - journal = {Journal of the Atmospheric Sciences}, - author = {Berger, AndréL}, - month = dec, - year = {1978}, - note = {Publisher: American Meteorological Society - Section: Journal of the Atmospheric Sciences}, - pages = {2362--2367}, - file = {Full Text PDF:/Users/dorme/Zotero/storage/M9UHD7J8/Berger - 1978 - Long-Term Variations of Daily Insolation and Quate.pdf:application/pdf} +@article{Wang:2017go, + title = {Towards a Universal Model for Carbon Dioxide Uptake by Plants}, + author = {Wang, Han and Prentice, I. Colin and Keenan, Trevor F and Davis, Tyler W and Wright, Ian J. and Cornwell, William K and Evans, Bradley J and Peng, Changhui}, + year = {2017}, + month = sep, + journal = {Nature Plants}, + pages = {1--8}, + publisher = {Springer US}, + doi = {10.1038/s41477-017-0006-8}, + abstract = {Nature Plants, doi:10.1038/s41477-017-0006-8}, + date-added = {2020-11-30T12:27:00GMT}, + date-modified = {2021-01-28T09:14:19GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2017/Wang/Nature\%20Plants\%202017\%20Wang.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1038/s41477-017-0006-8}, + file = {/Users/dorme/Zotero/storage/D4RYI3NP/Nature Plants 2017 Wang.pdf} +} + +@book{woolf:1968a, + title = {On the {{Computation}} of {{Solar Elevation Angles}} and the {{Determination}} of {{Sunrise}} and {{Sunset Times}}}, + author = {Woolf, Harold M.}, + year = {1968}, + publisher = {{National Aeronautics and Space Administration}}, + langid = {english} +} + +@book{duffie:2013a, + title = {Solar {{Engineering}} of {{Thermal Processes}}}, + author = {Duffie, John A. and Beckman, William A.}, + year = {2013}, + month = apr, + publisher = {John Wiley \& Sons}, + abstract = {The updated fourth edition of the "bible" of solar energy theory and applications Over several editions, Solar Engineering of Thermal Processes has become a classic solar engineering text and reference. This revised Fourth Edition offers current coverage of solar energy theory, systems design, and applications in different market sectors along with an emphasis on solar system design and analysis using simulations to help readers translate theory into practice. An important resource for students of solar engineering, solar energy, and alternative energy as well as professionals working in the power and energy industry or related fields, Solar Engineering of Thermal Processes, Fourth Edition features: Increased coverage of leading-edge topics such as photovoltaics and the design of solar cells and heaters A brand-new chapter on applying CombiSys (a readymade TRNSYS simulation program available for free download) to simulate a solar heated house with solar- heated domestic hot water Additional simulation problems available through a companion website An extensive array of homework problems and exercises}, + googlebooks = {5uDdUfMgXYQC}, + isbn = {978-1-118-41541-2}, + langid = {english}, + keywords = {Technology & Engineering / Electronics / General,Technology & Engineering / Mechanical,Technology & Engineering / Power Resources / General} +} + +@article{linacre:1968a, + title = {Estimating the Net-Radiation Flux}, + author = {Linacre, E. T.}, + year = {1968}, + month = jan, + journal = {Agricultural Meteorology}, + volume = {5}, + number = {1}, + pages = {49--63}, + issn = {0002-1571}, + doi = {10.1016/0002-1571(68)90022-8}, + urldate = {2024-08-02}, + abstract = {A major influence controlling the water loss from irrigated crops is the net-radiation intensity Qn, but measurements of this are not normally available, and so attempts are often made to deduce it from other climatic data, such as the solar-radiation. Here it is shown that the relationship between net and solar-radiation intensities depends on the degree of cloudiness and the ambient temperature. By making appropriate assumptions, a series of expressions for Qn is derived, with decreasing accuracy but increasing simplicity of estimation. It appears that clouds lower the net-radiation intensity when it exceeds a critical value in the region of 0.02 cal./cm2 min, but increase it when the intensity is lower.}, + file = {/Users/dorme/Zotero/storage/UY4NRV4W/0002157168900228.html} +} + +@article{sandoval:in_prep, + title = {Aridity and Growth Temperature Effects on Phio Manuscript}, + author = {Sandoval, David}, + year = {in\_prep}, + journal = {Placeholder}, + volume = {?}, + pages = {??-??} +} + +@techreport{joshi:2022a, + title = {Plant-{{FATE}}: {{Predicting}} the Adaptive Responses of Biodiverse Plant Communities Using Functional-Trait Evolution}, + author = {Joshi, Jaideep and Prentice, Iain Colin and Br{\"a}nnstr{\"o}m, {\AA}ke and Singh, Shipra and Hofhansl, Florian and Dieckmann, Ulf}, + year = {2022}, + month = mar, + number = {EGU22-9994}, + institution = {Copernicus Meetings}, + doi = {10.5194/egusphere-egu22-9994}, + urldate = {2024-09-05}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/47RVAZGK/EGU22-9994.html} } diff --git a/poetry.lock b/poetry.lock index da069290..be32578c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1794,6 +1794,48 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "marshmallow" +version = "3.22.0" +description = "A lightweight library for converting complex datatypes to and from native Python datatypes." +optional = false +python-versions = ">=3.8" +files = [ + {file = "marshmallow-3.22.0-py3-none-any.whl", hash = "sha256:71a2dce49ef901c3f97ed296ae5051135fd3febd2bf43afe0ae9a82143a494d9"}, + {file = "marshmallow-3.22.0.tar.gz", hash = "sha256:4972f529104a220bb8637d595aa4c9762afbe7f7a77d82dc58c1615d70c5823e"}, +] + +[package.dependencies] +packaging = ">=17.0" + +[package.extras] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] +docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.13)", "sphinx (==8.0.2)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] +tests = ["pytest", "pytz", "simplejson"] + +[[package]] +name = "marshmallow-dataclass" +version = "8.7.0" +description = "Python library to convert dataclasses into marshmallow schemas." +optional = false +python-versions = ">=3.8" +files = [ + {file = "marshmallow_dataclass-8.7.0-py3-none-any.whl", hash = "sha256:9e528d72b83f2b6b0f60cb29fd38781a6f7ce2155295adb1ed33289826a93c4b"}, + {file = "marshmallow_dataclass-8.7.0.tar.gz", hash = "sha256:0218008fec3fd4b5f739b2a0c6d7593bcc403308f6da953e341e4e359e268849"}, +] + +[package.dependencies] +marshmallow = ">=3.18.0" +typeguard = ">=4.0.0,<4.1.0" +typing-extensions = {version = ">=4.2.0", markers = "python_version < \"3.11\""} +typing-inspect = ">=0.9.0,<0.10.0" + +[package.extras] +dev = ["pre-commit (>=2.17,<3.0)", "pytest (>=5.4)", "pytest-mypy-plugins (>=1.2.0)", "sphinx"] +docs = ["sphinx"] +lint = ["pre-commit (>=2.17,<3.0)"] +tests = ["pytest (>=5.4)", "pytest-mypy-plugins (>=1.2.0)"] + [[package]] name = "matplotlib" version = "3.9.1" @@ -3753,6 +3795,24 @@ files = [ docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] +[[package]] +name = "typeguard" +version = "4.0.1" +description = "Run-time type checker for Python" +optional = false +python-versions = ">=3.7.4" +files = [ + {file = "typeguard-4.0.1-py3-none-any.whl", hash = "sha256:43f55cc9953f26dae362adb973b6c9ad6b97bfffcc6757277912eddd5cfa345b"}, + {file = "typeguard-4.0.1.tar.gz", hash = "sha256:db35142d1f92fc8c1b954e5cc03b57810428f9cd4e4604647bdf5764fc5bbba9"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.7.0", markers = "python_version < \"3.12\""} + +[package.extras] +doc = ["Sphinx (<7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["mypy (>=1.2.0)", "pytest (>=7)"] + [[package]] name = "types-python-dateutil" version = "2.9.0.20240316" @@ -3797,6 +3857,21 @@ files = [ {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +[[package]] +name = "typing-inspect" +version = "0.9.0" +description = "Runtime inspection utilities for typing module." +optional = false +python-versions = "*" +files = [ + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, +] + +[package.dependencies] +mypy-extensions = ">=0.3.0" +typing-extensions = ">=3.7.4" + [[package]] name = "tzdata" version = "2024.1" @@ -3954,4 +4029,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = ">=3.10" -content-hash = "47bf9006da7dea679c3ebd0892d08041d477bbcc3d898326280382a6e48777c8" +content-hash = "aef31655540ecd90f7e317fe133563bcfa68b2dadbd711cb61389563fd57e555" diff --git a/pyrealm/canopy_model/model/flora.py b/pyrealm/canopy_model/model/flora.py index 2b5a7d43..17cb9e61 100644 --- a/pyrealm/canopy_model/model/flora.py +++ b/pyrealm/canopy_model/model/flora.py @@ -1,4 +1,12 @@ -"""Base objects for import to the canopy module.""" +"""The flora module implements definitions of: + +* The PlantFunctionalType dataclass, which is used to parameterise the traits of + different plant functional types. +* The Flora class, which is simply a dictionary of named plant functional types for use + in describing a plant community in a simulation. The Flora class also defines factory + methods to create instances from plant functional type data stored in JSON, TOML or + CSV formats. +""" # noqa: D415 from __future__ import annotations @@ -26,15 +34,16 @@ class PlantFunctionalType: """The PlantFunctionalType dataclass. This dataclass implements the set of traits required to define a plant functional - type for use in ``pyrealm``. The majority of the traits are those required to - parameterise the T Model :cite:`Li:2014bc`. The - default values are taken from Table 1 of :cite:t:`Li:2014bc`. - - Note that the foliage maintenance respiration fraction is not named in the original - T Model implementation, but has been included as a modifiable trait in this - implementation. This implementation adds two further canopy shape parameters (``m`` - and ``n``), which are then used to calculate two derived attributes (``q_m`` and - ``z_max_ratio``). + type for use in ``pyrealm``. The majority of the traits and their default values are + those required to parameterise the T Model :cite:`Li:2014bc`. + + The foliage maintenance respiration fraction is not named in the original T Model + implementation, but has been included as a modifiable trait in this implementation. + This implementation adds two further canopy shape parameters (``m`` and ``n``), + which are then used to calculate two derived attributes (``q_m`` and + ``z_max_ratio``). These are used to define the vertical distribution of leaves + around a stem and follow the implementation developed in the PlantFATE model + :cite:`joshi:2022a`. """ name: str From 4429507a47f29a9d5e78156586a68718aa13ca4c Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 6 Sep 2024 10:17:29 +0100 Subject: [PATCH 064/241] Doc fixes and module structure updates --- docs/source/_toc.yml | 1 + docs/source/api/demography_api.md | 29 +++++++++++++++++++ docs/source/users/tmodel/canopy.md | 6 ++-- .../model => demography}/flora.py | 6 ++-- tests/unit/demography/test_flora.py | 16 +++++----- 5 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 docs/source/api/demography_api.md rename pyrealm/{canopy_model/model => demography}/flora.py (97%) diff --git a/docs/source/_toc.yml b/docs/source/_toc.yml index 51ceec9f..421eec13 100644 --- a/docs/source/_toc.yml +++ b/docs/source/_toc.yml @@ -27,6 +27,7 @@ subtrees: - file: users/pmodel/c3c4model.md - file: users/pmodel/isotopic_discrimination.md - file: users/tmodel/tmodel.md + - file: users/tmodel/canopy.md - file: users/splash.md - file: users/constants.md - file: users/hygro.md diff --git a/docs/source/api/demography_api.md b/docs/source/api/demography_api.md new file mode 100644 index 00000000..db14bcbd --- /dev/null +++ b/docs/source/api/demography_api.md @@ -0,0 +1,29 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.16.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +# The {mod}`~pyrealm.demography` module + +```{eval-rst} +.. automodule:: pyrealm.demography + :autosummary: + :members: +``` + +## The {mod}`~pyrealm.demography.flora` module + +```{eval-rst} +.. automodule:: pyrealm.demography.flora + :autosummary: + :members: +``` diff --git a/docs/source/users/tmodel/canopy.md b/docs/source/users/tmodel/canopy.md index 36716461..c7887f37 100644 --- a/docs/source/users/tmodel/canopy.md +++ b/docs/source/users/tmodel/canopy.md @@ -7,9 +7,9 @@ jupytext: format_version: 0.13 jupytext_version: 1.16.4 kernelspec: - display_name: pyrealm_python3 + display_name: python3 language: python - name: pyrealm_python3 + name: python3 --- # Canopy model @@ -637,7 +637,7 @@ hence the cumulative light extinction profile through the canopy. ```{code-cell} f_abs = 1 - np.exp(-pft.traits.par_ext * LAI_layer) -ext = np.cumproduct(f_abs) +ext = np.cumprod(f_abs) print("f_abs = ", f_abs) print("extinction = ", ext) diff --git a/pyrealm/canopy_model/model/flora.py b/pyrealm/demography/flora.py similarity index 97% rename from pyrealm/canopy_model/model/flora.py rename to pyrealm/demography/flora.py index 17cb9e61..149a121f 100644 --- a/pyrealm/canopy_model/model/flora.py +++ b/pyrealm/demography/flora.py @@ -141,16 +141,14 @@ class Flora(dict[str, PlantFunctionalType]): The flora is the set of plant functional types used within a particular simulation and this class provides dictionary-like access to a defined set of - :class:`~virtual_ecosystem.models.plants.functional_types.PlantFunctionalType` - instances. + :class:`~pyrealm.demography.flora.PlantFunctionalType` instances. Instances of this class should not be altered during model fitting, at least until the point where plant evolution is included in the modelling process. Args: pfts: A sequence of ``PlantFunctionalType`` instances, which must not have - duplicated - :attr:`~virtual_ecosystem.models.plants.functional_types.PlantFunctionalType.pft_name` + duplicated :attr:`~pyrealm.demography.flora.PlantFunctionalType.name` attributes. """ diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index 98a1a6a7..87cff8ef 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -29,7 +29,7 @@ def test_PlantFunctionalType__init__(args, outcome): """Test the plant functional type initialisation.""" - from pyrealm.canopy_model.model.flora import ( + from pyrealm.demography.flora import ( PlantFunctionalType, calculate_q_m, calculate_z_max_proportion, @@ -60,7 +60,7 @@ def flora_inputs(request): have a diverse set of inputs. """ - from pyrealm.canopy_model.model.flora import PlantFunctionalType + from pyrealm.demography.flora import PlantFunctionalType broadleaf = PlantFunctionalType(name="broadleaf") conifer = PlantFunctionalType(name="conifer") @@ -92,7 +92,7 @@ def flora_inputs(request): def test_Flora__init__(flora_inputs, outcome): """Test the plant functional type initialisation.""" - from pyrealm.canopy_model.model.flora import Flora + from pyrealm.demography.flora import Flora with outcome: flora = Flora(pfts=flora_inputs) @@ -120,7 +120,7 @@ def test_Flora__init__(flora_inputs, outcome): ) def test_flora_from_json(filename, outcome): """Test JSON loading.""" - from pyrealm.canopy_model.model.flora import Flora + from pyrealm.demography.flora import Flora datapath = resources.files("pyrealm_build_data.community") / filename @@ -146,7 +146,7 @@ def test_flora_from_json(filename, outcome): ) def test_flora_from_toml(filename, outcome): """Test TOML loading.""" - from pyrealm.canopy_model.model.flora import Flora + from pyrealm.demography.flora import Flora datapath = resources.files("pyrealm_build_data.community") / filename @@ -172,7 +172,7 @@ def test_flora_from_toml(filename, outcome): ) def test_flora_from_csv(filename, outcome): """Test CSV loading.""" - from pyrealm.canopy_model.model.flora import Flora + from pyrealm.demography.flora import Flora datapath = resources.files("pyrealm_build_data.community") / filename @@ -198,7 +198,7 @@ def test_flora_from_csv(filename, outcome): def test_calculate_q_m(m, n, q_m): """Test calculation of q_m.""" - from pyrealm.canopy_model.model.flora import calculate_q_m + from pyrealm.demography.flora import calculate_q_m calculated_q_m = calculate_q_m(m, n) assert calculated_q_m == pytest.approx(q_m) @@ -221,7 +221,7 @@ def test_calculate_q_m_values_raises_exception_for_invalid_input(): def test_calculate_z_max_ratio(m, n, z_max_ratio): """Test calculation of z_max proportion.""" - from pyrealm.canopy_model.model.flora import calculate_z_max_proportion + from pyrealm.demography.flora import calculate_z_max_proportion calculated_zmr = calculate_z_max_proportion(m, n) assert calculated_zmr == pytest.approx(z_max_ratio) From 6e1856c3a9682ee72847aa939a5eda195a2e7bd5 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 6 Sep 2024 11:04:36 +0100 Subject: [PATCH 065/241] Initial import of @amyoctocat files for this subset from #231 --- pyrealm/demography/community.py | 237 ++++++++++++++++++ pyrealm/demography/t_model_functions.py | 92 +++++++ pyrealm/demography/t_model_functions_extra.py | 53 ++++ pyrealm_build_data/community/communities.csv | 13 + pyrealm_build_data/community/communities.json | 72 ++++++ tests/unit/demography/test_community.py | 15 ++ ...st_jaideeps_t_model_extension_functions.py | 22 ++ 7 files changed, 504 insertions(+) create mode 100644 pyrealm/demography/community.py create mode 100644 pyrealm/demography/t_model_functions.py create mode 100644 pyrealm/demography/t_model_functions_extra.py create mode 100644 pyrealm_build_data/community/communities.csv create mode 100644 pyrealm_build_data/community/communities.json create mode 100644 tests/unit/demography/test_community.py create mode 100644 tests/unit/demography/test_jaideeps_t_model_extension_functions.py diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py new file mode 100644 index 00000000..c2bd29ac --- /dev/null +++ b/pyrealm/demography/community.py @@ -0,0 +1,237 @@ +"""Contains a class representing properties of a community.""" + +from __future__ import annotations + +import numpy as np +import pandas as pd +from numpy.typing import NDArray + +from pyrealm.demography import t_model_functions as t_model +from pyrealm.demography import t_model_functions_extra as t_model_extra +from pyrealm.demography.flora import Flora, PlantFunctionalType + + +class Community: + """Class containing properties of a community. + + A community is a group of plants in a given location. A location consists of a cell + with a specified area and ID. + + A community is broken down into cohorts, ie a collection of plants with the same + diameter at breast height (DBH) and plant functional type (PFT). This is + represented inside the class as a struct of arrays, with each element in a given + array representing a property of a cohort. The properties of a given cohort are + spread across the arrays and associated positionally, e.g. a cohort that has its + pft_h_max in the third element of the pft_h_max_values array will have the number + of individuals in the cohort in the third element of the + cohort_number_of_individuals array. Care must therefore be taken to + modify all the arrays when adding and removing cohorts. + + In addition to the properties the class is initialised with, the following + properties are calculated during initialisation and exposed publicly: + geometry of cohorts calculated using the t model, and canopy factors from + Jaideep's extension to the t model. + + A method is also provided to load community data from a csv file. + """ + + def __init__( + self, + cell_id: int, + cell_area: float, + cohort_dbh_values: NDArray[np.float32], + cohort_number_of_individuals: NDArray[np.int_], + cohort_pft_names: NDArray[np.str_], + flora: Flora, + ): + # community wide properties + self.cell_id: int = cell_id + self.cell_area: float = cell_area + self.flora: Flora = flora + self.number_of_cohorts: int = len(cohort_dbh_values) + + # arrays representing properties of cohorts + self.cohort_dbh_values: NDArray[np.float32] = cohort_dbh_values + self.cohort_number_of_individuals: NDArray[np.int_] = ( + cohort_number_of_individuals + ) + self.cohort_pft_names: NDArray[np.str_] = cohort_pft_names + + # initialise empty arrays representing properties of plant functional types + self.pft_a_hd_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_ca_ratio_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_h_max_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_lai_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_par_ext_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_resp_f_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_resp_r_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_resp_s_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_rho_s_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_sla_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_tau_f_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_tau_r_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_yld_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_zeta_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_m_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + self.pft_n_values: NDArray[np.float32] = np.empty( + self.number_of_cohorts, dtype=np.float32 + ) + + self.__populate_pft_arrays() + + # Create arrays containing values relating to T Model geometry + self.t_model_heights = t_model.calculate_heights( + self.pft_h_max_values, self.pft_a_hd_values, self.cohort_dbh_values + ) + + self.t_model_crown_areas = t_model.calculate_crown_areas( + self.pft_ca_ratio_values, + self.pft_a_hd_values, + self.cohort_dbh_values, + self.t_model_heights, + ) + + self.t_model_crown_fractions = t_model.calculate_crown_fractions( + self.t_model_heights, self.pft_a_hd_values, self.cohort_dbh_values + ) + + self.t_model_stem_masses = t_model.calculate_stem_masses( + self.cohort_dbh_values, self.t_model_heights, self.pft_rho_s_values + ) + + self.t_model_foliage_masses = t_model.calculate_foliage_masses( + self.t_model_crown_areas, self.pft_lai_values, self.pft_sla_values + ) + + self.t_model_swd_masses = t_model.calculate_swd_masses( + self.t_model_crown_areas, + self.pft_rho_s_values, + self.t_model_heights, + self.t_model_crown_fractions, + self.pft_ca_ratio_values, + ) + + # Create arrays containing properties pertaining to Jaideep's t model + # extension + self.canopy_factor_q_m_values = t_model_extra.calculate_q_m_values( + self.pft_m_values, self.pft_n_values + ) + self.canopy_factor_r_0_values = t_model_extra.calculate_r_0_values( + self.canopy_factor_q_m_values, self.t_model_crown_areas + ) + self.canopy_factor_z_m_values = t_model_extra.calculate_z_max_values( + self.pft_m_values, self.pft_n_values, self.t_model_heights + ) + + @classmethod + def load_communities_from_csv( + cls, cell_area: float, csv_path: str, flora: Flora + ) -> list[Community]: + """Loads a list of communities from a csv provided in the appropriate format. + + The csv should contain the following columns: cell_id, + diameter_at_breast_height, plant_functional_type, number_of_individuals. Each + row in the csv should represent one cohort. + + :param cell_area: the area of the cell at each location, this is assumed to be + the same across all the locations in the csv. + :param csv_path: path to the csv containing community data, as detailed above. + :param flora: a flora object, ie a dictionary of plant functional properties, + keyed by pft name. + :return: a list of community objects, loaded from the csv + file. + """ + community_data = pd.read_csv(csv_path) + + data_grouped_by_community = community_data.groupby(community_data.cell_id) + + communities = [] + + for cell_id in data_grouped_by_community.groups: + community_dataframe = data_grouped_by_community.get_group(cell_id) + dbh_values = community_dataframe["diameter_at_breast_height"].to_numpy( + dtype=np.float32 + ) + number_of_individuals = community_dataframe[ + "number_of_individuals" + ].to_numpy(dtype=np.int_) + pft_names = community_dataframe["plant_functional_type"].to_numpy(dtype=str) + community_object = Community( + cell_id, # type:ignore + cell_area, + dbh_values, + number_of_individuals, + pft_names, + flora, + ) + communities.append(community_object) + + return communities + + def __populate_pft_arrays(self) -> None: + """Populate plant functional type arrays. + + Populate the initialised arrays containing properties relating to plant + functional type by looking up the plant functional type in the Flora dictionary, + extracting the properties and inserting them into the relevant position in the + array. + :return: None + """ + for i in range(0, self.number_of_cohorts): + pft = self.__look_up_plant_functional_type(self.cohort_pft_names[i]) + self.pft_a_hd_values[i] = pft.a_hd + self.pft_ca_ratio_values[i] = pft.ca_ratio + self.pft_h_max_values[i] = pft.h_max + self.pft_lai_values[i] = pft.lai + self.pft_par_ext_values[i] = pft.par_ext + self.pft_resp_f_values[i] = pft.resp_f + self.pft_resp_r_values[i] = pft.resp_r + self.pft_resp_s_values[i] = pft.resp_s + self.pft_rho_s_values[i] = pft.rho_s + self.pft_sla_values[i] = pft.sla + self.pft_tau_f_values[i] = pft.tau_f + self.pft_tau_r_values[i] = pft.tau_r + self.pft_yld_values[i] = pft.yld + self.pft_zeta_values[i] = pft.zeta + self.pft_m_values[i] = pft.m + self.pft_n_values[i] = pft.n + + def __look_up_plant_functional_type(self, pft_name: str) -> PlantFunctionalType: + """Retrieve plant functional type for a cohort from the flora dictionary.""" + pft = self.flora.get(pft_name) + + if pft is None: + raise Exception( + f"Cohort data supplied with in an invalid PFT name: {pft_name}" + ) + return pft diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py new file mode 100644 index 00000000..92d00c59 --- /dev/null +++ b/pyrealm/demography/t_model_functions.py @@ -0,0 +1,92 @@ +"""Populate t model arrays. + +Populate the relevant initialised arrays with properties calculated using the +t model. +:return: None +""" + +import numpy as np +from numpy.typing import NDArray + + +def calculate_heights( + pft_h_max_values: NDArray[np.float32], + pft_a_hd_values: NDArray[np.float32], + diameters_at_breast_height: NDArray[np.float32], +) -> NDArray[np.float32]: + """Height of tree from diameter, Equation (4) of Li ea.""" + heights = pft_h_max_values * ( + 1 - np.exp(-pft_a_hd_values * diameters_at_breast_height / pft_h_max_values) + ) + + return heights + + +def calculate_crown_areas( + pft_ca_ratio_values: NDArray[np.float32], + pft_a_hd_values: NDArray[np.float32], + diameters_at_breast_height: NDArray[np.float32], + heights: NDArray[np.float32], +) -> NDArray[np.float32]: + """Crown area of tree, Equation (8) of Li ea.""" + t_model_crown_areas = ( + (np.pi * pft_ca_ratio_values / (4 * pft_a_hd_values)) + * diameters_at_breast_height + * heights + ) + + return t_model_crown_areas + + +def calculate_crown_fractions( + heights: NDArray[np.float32], + pft_a_hd_values: NDArray[np.float32], + diameters_at_breast_height: NDArray[np.float32], +) -> NDArray[np.float32]: + """Crown fraction, Equation (11) of Li ea.""" + crown_fractions = heights / (pft_a_hd_values * diameters_at_breast_height) + + return crown_fractions + + +def calculate_stem_masses( + diameters_at_breast_height: NDArray[np.float32], + heights: NDArray[np.float32], + pft_rho_s_values: NDArray[np.float32], +) -> NDArray[np.float32]: + """Mass of stems.""" + stem_masses = ( + (np.pi / 8) * (diameters_at_breast_height**2) * heights * pft_rho_s_values + ) + + return stem_masses + + +def calculate_foliage_masses( + crown_areas: NDArray[np.float32], + pft_lai_values: NDArray[np.float32], + pft_sla_values: NDArray[np.float32], +) -> NDArray[np.float32]: + """Mass of foliage.""" + foliage_masses = crown_areas * pft_lai_values * (1 / pft_sla_values) + + return foliage_masses + + +def calculate_swd_masses( + crown_areas: NDArray[np.float32], + pft_rho_s_values: NDArray[np.float32], + heights: NDArray[np.float32], + crown_fractions: NDArray[np.float32], + pft_ca_ratio_values: NDArray[np.float32], +) -> NDArray[np.float32]: + """Mass of ???""" + swd_masses = ( + crown_areas + * pft_rho_s_values + * heights + * (1 - crown_fractions / 2) + / pft_ca_ratio_values + ) + + return swd_masses diff --git a/pyrealm/demography/t_model_functions_extra.py b/pyrealm/demography/t_model_functions_extra.py new file mode 100644 index 00000000..42029082 --- /dev/null +++ b/pyrealm/demography/t_model_functions_extra.py @@ -0,0 +1,53 @@ +"""Canopy Factors from Jaideep's extension to the T Model. + +Utilities to calculate and store the canopy factors from Jaideep's extension to +the T Model. +""" + +import numpy as np +from numpy.typing import NDArray + + +def calculate_q_m_values( + m: NDArray[np.float32], n: NDArray[np.float32] +) -> NDArray[np.float32]: + """Placeholder.""" + return ( + m + * n + * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) + * (((m - 1) * n) / (m * n - 1)) ** (m - 1) + ) + + +def calculate_z_max_values( + m: NDArray[np.float32], n: NDArray[np.float32], height: NDArray[np.float32] +) -> NDArray[np.float32]: + """Calculate z_m, the height of maximum crown radius.""" + # Height of maximum crown radius + z_max = height * ((n - 1) / (m * n - 1)) ** (1 / n) + return z_max + + +def calculate_r_0_values( + q_m: NDArray[np.float32], crown_area: NDArray[np.float32] +) -> NDArray[np.float32]: + """Calculate stem canopy factors from Jaideep's extension to the T Model.""" + # Scaling factor to give expected A_c (crown area) at + # z_m (height of maximum crown radius) + r_0 = 1 / q_m * np.sqrt(crown_area / np.pi) + + return r_0 + + +def calculate_relative_canopy_radii( + z: float, + height: NDArray[np.float32], + m: NDArray[np.float32], + n: NDArray[np.float32], +) -> NDArray[np.float32]: + """Calculate q(z) at a given height, z.""" + + z_over_height = z / height + + return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) diff --git a/pyrealm_build_data/community/communities.csv b/pyrealm_build_data/community/communities.csv new file mode 100644 index 00000000..9ed1464a --- /dev/null +++ b/pyrealm_build_data/community/communities.csv @@ -0,0 +1,13 @@ +cell_id,plant_functional_type,diameter_at_breast_height,number_of_individuals +1,test1,0.2,6 +1,test1,0.25,6 +1,test1,0.3,3 +1,test1,0.35,1 +1,test2,0.5,1 +1,test2,0.6,1 +2,test1,0.2,6 +2,test1,0.25,6 +2,test1,0.3,3 +2,test1,0.35,1 +2,test2,0.5,1 +2,test2,0.6,1 \ No newline at end of file diff --git a/pyrealm_build_data/community/communities.json b/pyrealm_build_data/community/communities.json new file mode 100644 index 00000000..b5ac705d --- /dev/null +++ b/pyrealm_build_data/community/communities.json @@ -0,0 +1,72 @@ +[ + { + "cell_id": 1, + "cohorts": [ + { + "pft_name": "test1", + "dbh": 0.2, + "number_of_members": 6 + }, + { + "pft_name": "test1", + "dbh": 0.25, + "number_of_members": 6 + }, + { + "pft_name": "test1", + "dbh": 0.3, + "number_of_members": 3 + }, + { + "pft_name": "test1", + "dbh": 0.35, + "number_of_members": 1 + }, + { + "pft_name": "test2", + "dbh": 0.5, + "number_of_members": 1 + }, + { + "pft_name": "test2", + "dbh": 0.6, + "number_of_members": 1 + } + ] + }, + { + "cell_id": 2, + "cohorts": [ + { + "pft_name": "test1", + "dbh": 0.2, + "number_of_members": 6 + }, + { + "pft_name": "test1", + "dbh": 0.25, + "number_of_members": 6 + }, + { + "pft_name": "test1", + "dbh": 0.3, + "number_of_members": 3 + }, + { + "pft_name": "test1", + "dbh": 0.35, + "number_of_members": 1 + }, + { + "pft_name": "test2", + "dbh": 0.5, + "number_of_members": 1 + }, + { + "pft_name": "test2", + "dbh": 0.6, + "number_of_members": 1 + } + ] + } +] diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py new file mode 100644 index 00000000..32412c4f --- /dev/null +++ b/tests/unit/demography/test_community.py @@ -0,0 +1,15 @@ +"""test the community object in community.py initialises as expected.""" + + +def test_initialisation(): + """Test happy path for initialisation. + + test that when a new community object is instantiated, it contains the expected + properties. + """ + pass + + +def test_import_from_csv(): + """Test that a community can be successfully imported from a csv.""" + pass diff --git a/tests/unit/demography/test_jaideeps_t_model_extension_functions.py b/tests/unit/demography/test_jaideeps_t_model_extension_functions.py new file mode 100644 index 00000000..dd71c729 --- /dev/null +++ b/tests/unit/demography/test_jaideeps_t_model_extension_functions.py @@ -0,0 +1,22 @@ +"""Test the functions in jaideeps_t_model_extension_functions.py.""" + + +def test_calculate_z_max_values(): + """Test happy path for calculating z_max.""" + + pass + + +def test_calculate_r_0_values(): + """Test happy path for calculating r_0.""" + pass + + +def test_calculate_projected_canopy_area_for_individuals(): + """Test happy path for calculating canopy area for individuals.""" + pass + + +def test_calculate_relative_canopy_radii(): + """Test happy path for calculating relative canopy radii for individuals.""" + pass From 58458ab4c53d6be667ab391b432e2e8852eb2854 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 6 Sep 2024 13:31:34 +0100 Subject: [PATCH 066/241] Firming up example proposed input formats for community --- pyrealm_build_data/community/communities.csv | 26 +-- pyrealm_build_data/community/communities.json | 148 +++++++++--------- pyrealm_build_data/community/communities.toml | 67 ++++++++ pyrealm_build_data/community/community.json | 36 +++++ pyrealm_build_data/community/community.toml | 32 ++++ 5 files changed, 224 insertions(+), 85 deletions(-) create mode 100644 pyrealm_build_data/community/communities.toml create mode 100644 pyrealm_build_data/community/community.json create mode 100644 pyrealm_build_data/community/community.toml diff --git a/pyrealm_build_data/community/communities.csv b/pyrealm_build_data/community/communities.csv index 9ed1464a..ee97c938 100644 --- a/pyrealm_build_data/community/communities.csv +++ b/pyrealm_build_data/community/communities.csv @@ -1,13 +1,13 @@ -cell_id,plant_functional_type,diameter_at_breast_height,number_of_individuals -1,test1,0.2,6 -1,test1,0.25,6 -1,test1,0.3,3 -1,test1,0.35,1 -1,test2,0.5,1 -1,test2,0.6,1 -2,test1,0.2,6 -2,test1,0.25,6 -2,test1,0.3,3 -2,test1,0.35,1 -2,test2,0.5,1 -2,test2,0.6,1 \ No newline at end of file +cell_id,cell_area,plant_functional_type,diameter_at_breast_height,number_of_individuals +1,100,test1,0.2,6 +1,100,test1,0.25,6 +1,100,test1,0.3,3 +1,100,test1,0.35,1 +1,100,test2,0.5,1 +1,100,test2,0.6,1 +2,100,test1,0.2,6 +2,100,test1,0.25,6 +2,100,test1,0.3,3 +2,100,test1,0.35,1 +2,100,test2,0.5,1 +2,100,test2,0.6,1 \ No newline at end of file diff --git a/pyrealm_build_data/community/communities.json b/pyrealm_build_data/community/communities.json index b5ac705d..f20baefe 100644 --- a/pyrealm_build_data/community/communities.json +++ b/pyrealm_build_data/community/communities.json @@ -1,72 +1,76 @@ -[ - { - "cell_id": 1, - "cohorts": [ - { - "pft_name": "test1", - "dbh": 0.2, - "number_of_members": 6 - }, - { - "pft_name": "test1", - "dbh": 0.25, - "number_of_members": 6 - }, - { - "pft_name": "test1", - "dbh": 0.3, - "number_of_members": 3 - }, - { - "pft_name": "test1", - "dbh": 0.35, - "number_of_members": 1 - }, - { - "pft_name": "test2", - "dbh": 0.5, - "number_of_members": 1 - }, - { - "pft_name": "test2", - "dbh": 0.6, - "number_of_members": 1 - } - ] - }, - { - "cell_id": 2, - "cohorts": [ - { - "pft_name": "test1", - "dbh": 0.2, - "number_of_members": 6 - }, - { - "pft_name": "test1", - "dbh": 0.25, - "number_of_members": 6 - }, - { - "pft_name": "test1", - "dbh": 0.3, - "number_of_members": 3 - }, - { - "pft_name": "test1", - "dbh": 0.35, - "number_of_members": 1 - }, - { - "pft_name": "test2", - "dbh": 0.5, - "number_of_members": 1 - }, - { - "pft_name": "test2", - "dbh": 0.6, - "number_of_members": 1 - } - ] - } -] +{ + "cells": [ + { + "cell_id": 1, + "cell_area": 100, + "cohorts": [ + { + "pft_name": "test1", + "dbh": 0.2, + "number_of_members": 6 + }, + { + "pft_name": "test1", + "dbh": 0.25, + "number_of_members": 6 + }, + { + "pft_name": "test1", + "dbh": 0.3, + "number_of_members": 3 + }, + { + "pft_name": "test1", + "dbh": 0.35, + "number_of_members": 1 + }, + { + "pft_name": "test2", + "dbh": 0.5, + "number_of_members": 1 + }, + { + "pft_name": "test2", + "dbh": 0.6, + "number_of_members": 1 + } + ] + }, + { + "cell_id": 1, + "cell_area": 100, + "cohorts": [ + { + "pft_name": "test1", + "dbh": 0.2, + "number_of_members": 6 + }, + { + "pft_name": "test1", + "dbh": 0.25, + "number_of_members": 6 + }, + { + "pft_name": "test1", + "dbh": 0.3, + "number_of_members": 3 + }, + { + "pft_name": "test1", + "dbh": 0.35, + "number_of_members": 1 + }, + { + "pft_name": "test2", + "dbh": 0.5, + "number_of_members": 1 + }, + { + "pft_name": "test2", + "dbh": 0.6, + "number_of_members": 1 + } + ] + } + ] +} \ No newline at end of file diff --git a/pyrealm_build_data/community/communities.toml b/pyrealm_build_data/community/communities.toml new file mode 100644 index 00000000..d7e29caa --- /dev/null +++ b/pyrealm_build_data/community/communities.toml @@ -0,0 +1,67 @@ +[[cells]] +cell_area = 100 +cell_id = 1 + +[[cells.cohorts]] +dbh = 0.2 +number_of_members = 6 +pft_name = "test1" + +[[cells.cohorts]] +dbh = 0.25 +number_of_members = 6 +pft_name = "test1" + +[[cells.cohorts]] +dbh = 0.3 +number_of_members = 3 +pft_name = "test1" + +[[cells.cohorts]] +dbh = 0.35 +number_of_members = 1 +pft_name = "test1" + +[[cells.cohorts]] +dbh = 0.5 +number_of_members = 1 +pft_name = "test2" + +[[cells.cohorts]] +dbh = 0.6 +number_of_members = 1 +pft_name = "test2" + +[[cells]] +cell_area = 100 +cell_id = 1 + +[[cells.cohorts]] +dbh = 0.2 +number_of_members = 6 +pft_name = "test1" + +[[cells.cohorts]] +dbh = 0.25 +number_of_members = 6 +pft_name = "test1" + +[[cells.cohorts]] +dbh = 0.3 +number_of_members = 3 +pft_name = "test1" + +[[cells.cohorts]] +dbh = 0.35 +number_of_members = 1 +pft_name = "test1" + +[[cells.cohorts]] +dbh = 0.5 +number_of_members = 1 +pft_name = "test2" + +[[cells.cohorts]] +dbh = 0.6 +number_of_members = 1 +pft_name = "test2" diff --git a/pyrealm_build_data/community/community.json b/pyrealm_build_data/community/community.json new file mode 100644 index 00000000..b2abc4b6 --- /dev/null +++ b/pyrealm_build_data/community/community.json @@ -0,0 +1,36 @@ +{ + "cell_id": 1, + "cell_area": 100, + "cohorts": [ + { + "pft_name": "test1", + "dbh": 0.2, + "number_of_members": 6 + }, + { + "pft_name": "test1", + "dbh": 0.25, + "number_of_members": 6 + }, + { + "pft_name": "test1", + "dbh": 0.3, + "number_of_members": 3 + }, + { + "pft_name": "test1", + "dbh": 0.35, + "number_of_members": 1 + }, + { + "pft_name": "test2", + "dbh": 0.5, + "number_of_members": 1 + }, + { + "pft_name": "test2", + "dbh": 0.6, + "number_of_members": 1 + } + ] +} \ No newline at end of file diff --git a/pyrealm_build_data/community/community.toml b/pyrealm_build_data/community/community.toml new file mode 100644 index 00000000..383ccb05 --- /dev/null +++ b/pyrealm_build_data/community/community.toml @@ -0,0 +1,32 @@ +cell_area = 100 +cell_id = 1 + +[[cohorts]] +dbh = 0.2 +number_of_members = 6 +pft_name = "test1" + +[[cohorts]] +dbh = 0.25 +number_of_members = 6 +pft_name = "test1" + +[[cohorts]] +dbh = 0.3 +number_of_members = 3 +pft_name = "test1" + +[[cohorts]] +dbh = 0.35 +number_of_members = 1 +pft_name = "test1" + +[[cohorts]] +dbh = 0.5 +number_of_members = 1 +pft_name = "test2" + +[[cohorts]] +dbh = 0.6 +number_of_members = 1 +pft_name = "test2" From 484d4e5508e3e34fb1a721897444ade9d3d3babc Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 6 Sep 2024 13:34:22 +0100 Subject: [PATCH 067/241] Amalgamating T model function modules --- pyrealm/demography/t_model_functions.py | 47 +++++++++++++++- pyrealm/demography/t_model_functions_extra.py | 53 ------------------- 2 files changed, 46 insertions(+), 54 deletions(-) delete mode 100644 pyrealm/demography/t_model_functions_extra.py diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 92d00c59..0dad42e4 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -2,7 +2,7 @@ Populate the relevant initialised arrays with properties calculated using the t model. -:return: None + """ import numpy as np @@ -90,3 +90,48 @@ def calculate_swd_masses( ) return swd_masses + + +def calculate_q_m_values( + m: NDArray[np.float32], n: NDArray[np.float32] +) -> NDArray[np.float32]: + """Placeholder.""" + return ( + m + * n + * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) + * (((m - 1) * n) / (m * n - 1)) ** (m - 1) + ) + + +def calculate_z_max_values( + m: NDArray[np.float32], n: NDArray[np.float32], height: NDArray[np.float32] +) -> NDArray[np.float32]: + """Calculate z_m, the height of maximum crown radius.""" + # Height of maximum crown radius + z_max = height * ((n - 1) / (m * n - 1)) ** (1 / n) + return z_max + + +def calculate_r_0_values( + q_m: NDArray[np.float32], crown_area: NDArray[np.float32] +) -> NDArray[np.float32]: + """Calculate stem canopy factors from Jaideep's extension to the T Model.""" + # Scaling factor to give expected A_c (crown area) at + # z_m (height of maximum crown radius) + r_0 = 1 / q_m * np.sqrt(crown_area / np.pi) + + return r_0 + + +def calculate_relative_canopy_radii( + z: float, + height: NDArray[np.float32], + m: NDArray[np.float32], + n: NDArray[np.float32], +) -> NDArray[np.float32]: + """Calculate q(z) at a given height, z.""" + + z_over_height = z / height + + return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) diff --git a/pyrealm/demography/t_model_functions_extra.py b/pyrealm/demography/t_model_functions_extra.py deleted file mode 100644 index 42029082..00000000 --- a/pyrealm/demography/t_model_functions_extra.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Canopy Factors from Jaideep's extension to the T Model. - -Utilities to calculate and store the canopy factors from Jaideep's extension to -the T Model. -""" - -import numpy as np -from numpy.typing import NDArray - - -def calculate_q_m_values( - m: NDArray[np.float32], n: NDArray[np.float32] -) -> NDArray[np.float32]: - """Placeholder.""" - return ( - m - * n - * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) - * (((m - 1) * n) / (m * n - 1)) ** (m - 1) - ) - - -def calculate_z_max_values( - m: NDArray[np.float32], n: NDArray[np.float32], height: NDArray[np.float32] -) -> NDArray[np.float32]: - """Calculate z_m, the height of maximum crown radius.""" - # Height of maximum crown radius - z_max = height * ((n - 1) / (m * n - 1)) ** (1 / n) - return z_max - - -def calculate_r_0_values( - q_m: NDArray[np.float32], crown_area: NDArray[np.float32] -) -> NDArray[np.float32]: - """Calculate stem canopy factors from Jaideep's extension to the T Model.""" - # Scaling factor to give expected A_c (crown area) at - # z_m (height of maximum crown radius) - r_0 = 1 / q_m * np.sqrt(crown_area / np.pi) - - return r_0 - - -def calculate_relative_canopy_radii( - z: float, - height: NDArray[np.float32], - m: NDArray[np.float32], - n: NDArray[np.float32], -) -> NDArray[np.float32]: - """Calculate q(z) at a given height, z.""" - - z_over_height = z / height - - return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) From 1856b9d8b4a9fb497f3a6140524093fdb50c1098 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 6 Sep 2024 14:05:40 +0100 Subject: [PATCH 068/241] Initial refactor to dataclass --- pyrealm/demography/community.py | 161 ++++++++++++------------ pyrealm/demography/t_model_functions.py | 4 +- 2 files changed, 83 insertions(+), 82 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index c2bd29ac..84f0daac 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -2,15 +2,28 @@ from __future__ import annotations +import json +import sys +from dataclasses import dataclass, field + +import marshmallow_dataclass import numpy as np import pandas as pd +from marshmallow.exceptions import ValidationError from numpy.typing import NDArray from pyrealm.demography import t_model_functions as t_model -from pyrealm.demography import t_model_functions_extra as t_model_extra from pyrealm.demography.flora import Flora, PlantFunctionalType +if sys.version_info[:2] >= (3, 11): + import tomllib + from tomllib import TOMLDecodeError +else: + import tomli as tomllib + from tomli import TOMLDecodeError + +@dataclass class Community: """Class containing properties of a community. @@ -35,79 +48,70 @@ class Community: A method is also provided to load community data from a csv file. """ - def __init__( - self, - cell_id: int, - cell_area: float, - cohort_dbh_values: NDArray[np.float32], - cohort_number_of_individuals: NDArray[np.int_], - cohort_pft_names: NDArray[np.str_], - flora: Flora, - ): - # community wide properties - self.cell_id: int = cell_id - self.cell_area: float = cell_area - self.flora: Flora = flora - self.number_of_cohorts: int = len(cohort_dbh_values) - - # arrays representing properties of cohorts - self.cohort_dbh_values: NDArray[np.float32] = cohort_dbh_values - self.cohort_number_of_individuals: NDArray[np.int_] = ( - cohort_number_of_individuals - ) - self.cohort_pft_names: NDArray[np.str_] = cohort_pft_names + # Dataclass attributes for initialisation + # - community wide properties + cell_id: int + cell_area: float + flora: Flora + + # - arrays representing properties of cohorts + cohort_dbh_values: NDArray[np.float32] + cohort_number_of_individuals: NDArray[np.int_] + cohort_pft_names: NDArray[np.str_] + + # Post init properties + number_of_cohorts: int = field(init=False) + + # - arrays representing properties of plant functional types + pft_a_hd_values: NDArray[np.float32] = field(init=False) + pft_ca_ratio_values: NDArray[np.float32] = field(init=False) + pft_h_max_values: NDArray[np.float32] = field(init=False) + pft_lai_values: NDArray[np.float32] = field(init=False) + pft_par_ext_values: NDArray[np.float32] = field(init=False) + pft_resp_f_values: NDArray[np.float32] = field(init=False) + pft_resp_r_values: NDArray[np.float32] = field(init=False) + pft_resp_s_values: NDArray[np.float32] = field(init=False) + pft_rho_s_values: NDArray[np.float32] = field(init=False) + pft_sla_values: NDArray[np.float32] = field(init=False) + pft_tau_f_values: NDArray[np.float32] = field(init=False) + pft_tau_r_values: NDArray[np.float32] = field(init=False) + pft_yld_values: NDArray[np.float32] = field(init=False) + pft_zeta_values: NDArray[np.float32] = field(init=False) + pft_m_values: NDArray[np.float32] = field(init=False) + pft_n_values: NDArray[np.float32] = field(init=False) + pft_q_m_values: NDArray[np.float32] = field(init=False) + pft_z_max_prop_values: NDArray[np.float32] = field(init=False) + + # Create arrays containing values relating to T Model geometry + t_model_heights: NDArray[np.float32] = field(init=False) + t_model_crown_areas: NDArray[np.float32] = field(init=False) + t_model_crown_fractions: NDArray[np.float32] = field(init=False) + t_model_stem_masses: NDArray[np.float32] = field(init=False) + t_model_foliage_masses: NDArray[np.float32] = field(init=False) + t_model_swd_masses: NDArray[np.float32] = field(init=False) + t_model_r_0_values: NDArray[np.float32] = field(init=False) + t_model_z_m_values: NDArray[np.float32] = field(init=False) + + def __post_init__(self) -> None: + """Populate derived community attributes. + + The ``__post_init__`` method populates arrays of PFT values, unpacking the data + in the ``Flora`` object into arrays of per-cohort values. It then calculates the + predictions of the T Model for each cohort, again as arrays of per-cohort + values. + """ - # initialise empty arrays representing properties of plant functional types - self.pft_a_hd_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_ca_ratio_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_h_max_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_lai_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_par_ext_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_resp_f_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_resp_r_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_resp_s_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_rho_s_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_sla_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_tau_f_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_tau_r_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_yld_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_zeta_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_m_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) - self.pft_n_values: NDArray[np.float32] = np.empty( - self.number_of_cohorts, dtype=np.float32 - ) + # Populate the pft + self._populate_pft_arrays() + self._calculate_t_model() - self.__populate_pft_arrays() + def _calculate_t_model(self) -> None: + """Calculate T Model predictions across cohorts. + + This method populates or updates the community attributes predicted by the T + Model :cite:`Li:2014bc` and by the canopy shape extensions to the T Model + implemented in PlantFate :cite:`joshi:2022a`. + """ # Create arrays containing values relating to T Model geometry self.t_model_heights = t_model.calculate_heights( @@ -143,14 +147,11 @@ def __init__( # Create arrays containing properties pertaining to Jaideep's t model # extension - self.canopy_factor_q_m_values = t_model_extra.calculate_q_m_values( - self.pft_m_values, self.pft_n_values - ) - self.canopy_factor_r_0_values = t_model_extra.calculate_r_0_values( - self.canopy_factor_q_m_values, self.t_model_crown_areas + self.canopy_factor_r_0_values = t_model.calculate_r_0_values( + self.pft_q_m_values, self.t_model_crown_areas ) - self.canopy_factor_z_m_values = t_model_extra.calculate_z_max_values( - self.pft_m_values, self.pft_n_values, self.t_model_heights + self.canopy_factor_z_m_values = t_model.calculate_z_max_values( + self.pft_z_max_prop_values, self.t_model_heights ) @classmethod @@ -198,7 +199,7 @@ def load_communities_from_csv( return communities - def __populate_pft_arrays(self) -> None: + def _populate_pft_arrays(self) -> None: """Populate plant functional type arrays. Populate the initialised arrays containing properties relating to plant diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 0dad42e4..9cd6d957 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -105,11 +105,11 @@ def calculate_q_m_values( def calculate_z_max_values( - m: NDArray[np.float32], n: NDArray[np.float32], height: NDArray[np.float32] + z_max_prop: NDArray[np.float32], height: NDArray[np.float32] ) -> NDArray[np.float32]: """Calculate z_m, the height of maximum crown radius.""" # Height of maximum crown radius - z_max = height * ((n - 1) / (m * n - 1)) ** (1 / n) + z_max = height * z_max_prop return z_max From 34c10e5aae7a12bee5cec0339c605b2ac0976e80 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 6 Sep 2024 15:07:01 +0100 Subject: [PATCH 069/241] Make loading from file strict --- pyrealm/demography/flora.py | 118 ++++++++++++++++++++++------ tests/unit/demography/test_flora.py | 80 ++++++++++++++++++- 2 files changed, 168 insertions(+), 30 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 149a121f..81e22265 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -29,8 +29,82 @@ from tomli import TOMLDecodeError -@dataclass -class PlantFunctionalType: +@dataclass(frozen=True) +class PlantFunctionalTypeStrict: + """The PlantFunctionalTypeStrict dataclass. + + This dataclass implements the set of traits required to define a plant functional + type for use in ``pyrealm``. The majority of the traits and their default values are + those required to parameterise the T Model :cite:`Li:2014bc`. + + The foliage maintenance respiration fraction is not named in the original T Model + implementation, but has been included as a modifiable trait in this implementation. + This implementation adds two further canopy shape parameters (``m`` and ``n``), + which are then used to calculate two derived attributes (``q_m`` and + ``z_max_ratio``). These are used to define the vertical distribution of leaves + around a stem and follow the implementation developed in the PlantFATE model + :cite:`joshi:2022a`. + """ + + name: str + """The name of the plant functional type.""" + a_hd: float + """Initial slope of height-diameter relationship (:math:`a`, 116.0, -)""" + ca_ratio: float + """Initial ratio of crown area to stem cross-sectional area + (:math:`c`, 390.43, -)""" + h_max: float + """Maximum tree height (:math:`H_m`, 25.33, m)""" + rho_s: float + r"""Sapwood density (:math:`\rho_s`, 200.0, kg Cm-3)""" + lai: float + """Leaf area index within the crown (:math:`L`, 1.8, -)""" + sla: float + r"""Specific leaf area (:math:`\sigma`, 14.0, m2 kg-1 C)""" + tau_f: float + r"""Foliage turnover time (:math:`\tau_f`, 4.0, years)""" + tau_r: float + """Fine-root turnover time (:math:`\tau_r`, 1.04, years)""" + par_ext: float + """Extinction coefficient of photosynthetically active radiation (PAR) (:math:`k`, + 0.5, -)""" + yld: float + """Yield_factor (:math:`y`, 0.17, -)""" + zeta: float + r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, 0.17, kg C m-2)""" + resp_r: float + """Fine-root specific respiration rate (:math:`r_r`, 0.913, year-1)""" + resp_s: float + """Sapwood-specific respiration rate (:math:`r_s`, 0.044, year-1)""" + resp_f: float + """Foliage maintenance respiration fraction (:math:`r_f`, 0.1, -)""" + m: float + """Canopy shape parameter (:math:`m`, -)""" + n: float + """Canopy shape parameter (:math:`n`, -)""" + + q_m: float = field(init=False) + """Scaling factor to derive maximum crown radius from crown area.""" + z_max_prop: float = field(init=False) + """Proportion of stem height at which maximum crown radius is found.""" + + def __post_init__(self) -> None: + """Populate derived attributes. + + This method populates the ``q_m`` and ``z_max_ratio`` attributes from the + provided values of ``m`` and ``n``. + """ + + # Calculate q_m and z_max proportion. Need to use __setattr__ because the + # dataclass is frozen. + object.__setattr__(self, "q_m", calculate_q_m(m=self.m, n=self.n)) + object.__setattr__( + self, "z_max_prop", calculate_z_max_proportion(m=self.m, n=self.n) + ) + + +@dataclass(frozen=True) +class PlantFunctionalType(PlantFunctionalTypeStrict): """The PlantFunctionalType dataclass. This dataclass implements the set of traits required to define a plant functional @@ -83,25 +157,16 @@ class PlantFunctionalType: n: float = 5 """Canopy shape parameter (:math:`n`, -)""" - q_m: float = field(init=False) - """Scaling factor to derive maximum crown radius from crown area.""" - z_max_prop: float = field(init=False) - """Proportion of stem height at which maximum crown radius is found.""" - - def __post_init__(self) -> None: - """Populate derived attributes. - - This method populates the ``q_m`` and ``z_max_ratio`` attributes from the - provided values of ``m`` and ``n``. - """ - - # Calculate q_m - self.q_m = calculate_q_m(m=self.m, n=self.n) - self.z_max_prop = calculate_z_max_proportion(m=self.m, n=self.n) +PlantFunctionalTypeSchema = marshmallow_dataclass.class_schema( + PlantFunctionalTypeStrict +) +"""Marshmallow validation schema class for validating PlantFunctionalType data. -PlantFunctionalTypeSchema = marshmallow_dataclass.class_schema(PlantFunctionalType) -"""Marshmallow validation schema class for validating PlantFunctionalType data.""" +This schema explicitly uses the strict version of the dataclass, which enforces complete +descriptions of plant functional type data rather than allowing partial data and filling +in gaps from the default values. +""" def calculate_q_m(m: float, n: float) -> float: @@ -136,29 +201,30 @@ def calculate_z_max_proportion(m: float, n: float) -> float: return ((n - 1) / (m * n - 1)) ** (1 / n) -class Flora(dict[str, PlantFunctionalType]): +class Flora(dict[str, type[PlantFunctionalTypeStrict]]): """Defines the flora used in a ``virtual_ecosystem`` model. The flora is the set of plant functional types used within a particular simulation and this class provides dictionary-like access to a defined set of - :class:`~pyrealm.demography.flora.PlantFunctionalType` instances. + :class:`~pyrealm.demography.flora.PlantFunctionalType` or + :class:`~pyrealm.demography.flora.PlantFunctionalTypeStrict` instances. Instances of this class should not be altered during model fitting, at least until the point where plant evolution is included in the modelling process. Args: - pfts: A sequence of ``PlantFunctionalType`` instances, which must not have - duplicated :attr:`~pyrealm.demography.flora.PlantFunctionalType.name` - attributes. + pfts: A sequence of ``PlantFunctionalType`` or ``PlantFunctionalTypeStrict`` + instances, which must not have duplicated + :attr:`~pyrealm.demography.flora.PlantFunctionalTypeStrict.name` attributes. """ - def __init__(self, pfts: Sequence[PlantFunctionalType]) -> None: + def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: # Initialise the dict superclass to implement dict like behaviour super().__init__() # Check the PFT data if (not isinstance(pfts, Sequence)) or ( - not all([isinstance(v, PlantFunctionalType) for v in pfts]) + not all([isinstance(v, PlantFunctionalTypeStrict) for v in pfts]) ): raise ValueError( "The pfts argument must be a sequence of PlantFunctionalType instances" diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index 87cff8ef..72164314 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -14,6 +14,62 @@ else: from tomli import TOMLDecodeError + +STRICT_PFT_ARGS = dict( + a_hd=116.0, + ca_ratio=390.43, + h_max=15.33, + lai=1.8, + name="broadleaf", + par_ext=0.5, + resp_f=0.1, + resp_r=0.913, + resp_s=0.044, + rho_s=200.0, + sla=14.0, + tau_f=4.0, + tau_r=1.04, + yld=0.17, + zeta=0.17, + m=2, + n=5, +) +"""A dictionary of the full set of arguments needed for PlantFunctionalTypeStrict.""" + + +# +# Test PlantFunctionalTypeStrict dataclass +# + + +@pytest.mark.parametrize( + argnames="args,outcome", + argvalues=[ + pytest.param(STRICT_PFT_ARGS, does_not_raise(), id="full"), + pytest.param({"name": "broadleaf"}, pytest.raises(TypeError), id="partial"), + pytest.param({}, pytest.raises(TypeError), id="empty"), + ], +) +def test_PlantFunctionalTypeStrict__init__(args, outcome): + """Test the plant functional type initialisation.""" + + from pyrealm.demography.flora import ( + PlantFunctionalTypeStrict, + calculate_q_m, + calculate_z_max_proportion, + ) + + with outcome: + pft = PlantFunctionalTypeStrict(**args) + + # Check name attribute and post_init attributes if instantiation succeeds. + if isinstance(outcome, does_not_raise): + assert pft.name == "broadleaf" + # Expected values from defaults + assert pft.q_m == calculate_q_m(m=2, n=5) + assert pft.z_max_prop == calculate_z_max_proportion(m=2, n=5) + + # # Test PlantFunctionalType dataclass # @@ -60,10 +116,14 @@ def flora_inputs(request): have a diverse set of inputs. """ - from pyrealm.demography.flora import PlantFunctionalType + from pyrealm.demography.flora import PlantFunctionalType, PlantFunctionalTypeStrict broadleaf = PlantFunctionalType(name="broadleaf") conifer = PlantFunctionalType(name="conifer") + broadleaf_strict = PlantFunctionalTypeStrict(**STRICT_PFT_ARGS) + conifer_strict_args = STRICT_PFT_ARGS.copy() + conifer_strict_args["name"] = "conifer" + conifer_strict = PlantFunctionalType(**conifer_strict_args) match request.param: case "not_sequence": @@ -72,10 +132,18 @@ def flora_inputs(request): return [1, 2, 3] case "single_pft": return [broadleaf] + case "single_pft_strict": + return [broadleaf_strict] case "multiple_pfts": return [broadleaf, conifer] + case "multiple_pfts_strict": + return [broadleaf_strict, conifer_strict] + case "multiple_pfts_mixed": + return [broadleaf_strict, conifer] case "duplicated_names": return [broadleaf, broadleaf] + case "duplicated_names_mixed": + return [broadleaf_strict, broadleaf] @pytest.mark.parametrize( @@ -84,8 +152,12 @@ def flora_inputs(request): pytest.param("not_sequence", pytest.raises(ValueError)), pytest.param("sequence_not_all_pfts", pytest.raises(ValueError)), pytest.param("single_pft", does_not_raise()), + pytest.param("single_pft_strict", does_not_raise()), pytest.param("multiple_pfts", does_not_raise()), + pytest.param("multiple_pfts_strict", does_not_raise()), + pytest.param("multiple_pfts_mixed", does_not_raise()), pytest.param("duplicated_names", pytest.raises(ValueError)), + pytest.param("duplicated_names_mixed", pytest.raises(ValueError)), ], indirect=["flora_inputs"], ) @@ -112,7 +184,7 @@ def test_Flora__init__(flora_inputs, outcome): argnames="filename,outcome", argvalues=[ pytest.param("pfts.json", does_not_raise(), id="correct"), - pytest.param("pfts_partial.json", does_not_raise(), id="partial"), + pytest.param("pfts_partial.json", pytest.raises(ValidationError), id="partial"), pytest.param("pfts.toml", pytest.raises(JSONDecodeError), id="format_wrong"), pytest.param("no.pfts", pytest.raises(FileNotFoundError), id="file_missing"), pytest.param("pfts_invalid.json", pytest.raises(ValidationError), id="invalid"), @@ -138,7 +210,7 @@ def test_flora_from_json(filename, outcome): argnames="filename,outcome", argvalues=[ pytest.param("pfts.toml", does_not_raise(), id="correct"), - pytest.param("pfts_partial.toml", does_not_raise(), id="partial"), + pytest.param("pfts_partial.toml", pytest.raises(ValidationError), id="partial"), pytest.param("pfts.json", pytest.raises(TOMLDecodeError), id="format_wrong"), pytest.param("no.pfts", pytest.raises(FileNotFoundError), id="file_missing"), pytest.param("pfts_invalid.toml", pytest.raises(ValidationError), id="invalid"), @@ -166,7 +238,7 @@ def test_flora_from_toml(filename, outcome): pytest.param("pfts.csv", does_not_raise(), id="correct"), pytest.param("pfts.json", pytest.raises(ParserError), id="format_wrong"), pytest.param("no.pfts", pytest.raises(FileNotFoundError), id="file_missing"), - pytest.param("pfts_partial.csv", does_not_raise(), id="partial"), + pytest.param("pfts_partial.csv", pytest.raises(ValidationError), id="partial"), pytest.param("pfts_invalid.csv", pytest.raises(ValidationError), id="invalid"), ], ) From 4ce664d347eb7b72a1681de2ad686c88aef8ed01 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 6 Sep 2024 15:54:09 +0100 Subject: [PATCH 070/241] Docstring updates --- pyrealm/demography/flora.py | 137 +++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 64 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 81e22265..6c754a7d 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -1,7 +1,13 @@ """The flora module implements definitions of: -* The PlantFunctionalType dataclass, which is used to parameterise the traits of - different plant functional types. +* The ``PlantFunctionalType`` and ``PlantFunctionalTypeStrict`` dataclasses, which are + used to parameterise the traits of different plant functional types. The + ``PlantFunctionalType`` dataclass is a subclass of ``PlantFunctionalTypeStrict`` that + simply adds default values to the attributes. +* The ``PlantFunctionalTypeStrict`` dataclass is used as the basis of a ``marshmallow`` + schema for validating the creation of plant functional types from data files. This + intentionally enforces a complete description of the traits in the input data. The + ``PlantFunctionalType`` is provided as a more convenient API for programmatic use. * The Flora class, which is simply a dictionary of named plant functional types for use in describing a plant community in a simulation. The Flora class also defines factory methods to create instances from plant functional type data stored in JSON, TOML or @@ -34,54 +40,59 @@ class PlantFunctionalTypeStrict: """The PlantFunctionalTypeStrict dataclass. This dataclass implements the set of traits required to define a plant functional - type for use in ``pyrealm``. The majority of the traits and their default values are - those required to parameterise the T Model :cite:`Li:2014bc`. - - The foliage maintenance respiration fraction is not named in the original T Model - implementation, but has been included as a modifiable trait in this implementation. - This implementation adds two further canopy shape parameters (``m`` and ``n``), - which are then used to calculate two derived attributes (``q_m`` and - ``z_max_ratio``). These are used to define the vertical distribution of leaves - around a stem and follow the implementation developed in the PlantFATE model - :cite:`joshi:2022a`. + type for use in ``pyrealm``. + + * Most traits are taken from the definition of the T Model of plant growth and GPP + allocation :cite:`Li:2014bc`. + * The foliage maintenance respiration fraction was not explicitly included in + :cite:t:`Li:2014bc` - there was assumed to be a 10% penalty on GPP before + calculating the other component - but has been explicitly included here. + * This implementation adds two further canopy shape parameters (``m`` and ``n``), + which are then used to calculate two derived attributes (``q_m`` and + ``z_max_ratio``). These are used to define the vertical distribution of leaves + around a stem and follow the implementation developed in the PlantFATE model + :cite:`joshi:2022a`. + + See also :class:`~pyrealm.demography.flora.PlantFunctionalType` for the default + values implemented in that subclass. """ name: str - """The name of the plant functional type.""" + r"""The name of the plant functional type.""" a_hd: float - """Initial slope of height-diameter relationship (:math:`a`, 116.0, -)""" + r"""Initial slope of height-diameter relationship (:math:`a`, -)""" ca_ratio: float - """Initial ratio of crown area to stem cross-sectional area - (:math:`c`, 390.43, -)""" + r"""Initial ratio of crown area to stem cross-sectional area + (:math:`c`, -)""" h_max: float - """Maximum tree height (:math:`H_m`, 25.33, m)""" + r"""Maximum tree height (:math:`H_m`, m)""" rho_s: float - r"""Sapwood density (:math:`\rho_s`, 200.0, kg Cm-3)""" + r"""Sapwood density (:math:`\rho_s`, kg Cm-3)""" lai: float - """Leaf area index within the crown (:math:`L`, 1.8, -)""" + """Leaf area index within the crown (:math:`L`, -)""" sla: float - r"""Specific leaf area (:math:`\sigma`, 14.0, m2 kg-1 C)""" + r"""Specific leaf area (:math:`\sigma`, m2 kg-1 C)""" tau_f: float - r"""Foliage turnover time (:math:`\tau_f`, 4.0, years)""" + r"""Foliage turnover time (:math:`\tau_f`,years)""" tau_r: float - """Fine-root turnover time (:math:`\tau_r`, 1.04, years)""" + r"""Fine-root turnover time (:math:`\tau_r`, years)""" par_ext: float - """Extinction coefficient of photosynthetically active radiation (PAR) (:math:`k`, - 0.5, -)""" + r"""Extinction coefficient of photosynthetically active radiation (PAR) (:math:`k`, + -)""" yld: float - """Yield_factor (:math:`y`, 0.17, -)""" + r"""Yield factor (:math:`y`, -)""" zeta: float - r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, 0.17, kg C m-2)""" + r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, kg C m-2)""" resp_r: float - """Fine-root specific respiration rate (:math:`r_r`, 0.913, year-1)""" + r"""Fine-root specific respiration rate (:math:`r_r`, year-1)""" resp_s: float - """Sapwood-specific respiration rate (:math:`r_s`, 0.044, year-1)""" + r"""Sapwood-specific respiration rate (:math:`r_s`, year-1)""" resp_f: float - """Foliage maintenance respiration fraction (:math:`r_f`, 0.1, -)""" + r"""Foliage maintenance respiration fraction (:math:`r_f`, -)""" m: float - """Canopy shape parameter (:math:`m`, -)""" + r"""Canopy shape parameter (:math:`m`, -)""" n: float - """Canopy shape parameter (:math:`n`, -)""" + r"""Canopy shape parameter (:math:`n`, -)""" q_m: float = field(init=False) """Scaling factor to derive maximum crown radius from crown area.""" @@ -105,57 +116,55 @@ def __post_init__(self) -> None: @dataclass(frozen=True) class PlantFunctionalType(PlantFunctionalTypeStrict): - """The PlantFunctionalType dataclass. - - This dataclass implements the set of traits required to define a plant functional - type for use in ``pyrealm``. The majority of the traits and their default values are - those required to parameterise the T Model :cite:`Li:2014bc`. - - The foliage maintenance respiration fraction is not named in the original T Model - implementation, but has been included as a modifiable trait in this implementation. - This implementation adds two further canopy shape parameters (``m`` and ``n``), - which are then used to calculate two derived attributes (``q_m`` and - ``z_max_ratio``). These are used to define the vertical distribution of leaves - around a stem and follow the implementation developed in the PlantFATE model - :cite:`joshi:2022a`. + r"""The PlantFunctionalType dataclass. + + This dataclass is a subclass of + :class:`~pyrealm.demography.flora.PlantFunctionalTypeStrict` that implements exactly + the same set of traits but provides default values. This class is intended as a + convenience API for programmatic use, where the parent provides a strict schema for + generating plant functional type instances from data. + + The table below lists the attributes and default values taken from Table 1 of + :cite:t:`Li:2014bc` + + .. csv-table:: + :header: "Attribute", "Default", "Unit" + :widths: 15, 10, 30 + + a_hd, 116.0, - + ca_ratio, 390.43, - + h_max, 25.33, m + rho_s, 200.0, kg Cm-3 + lai, 1.8, - + sla, 14.0, m2 kg-1 C + tau_f, 4.0, years + tau_r, 1.04, years + par_ext, 0.5, - + yld, 0.17, - + zeta, 0.17, kg C m-2 + resp_r, 0.913, year-1 + resp_s, 0.044, year-1 + resp_f, 0.1, - + m, 2, - + n, 5, - """ - name: str - """The name of the plant functional type.""" a_hd: float = 116.0 - """Initial slope of height-diameter relationship (:math:`a`, 116.0, -)""" ca_ratio: float = 390.43 - """Initial ratio of crown area to stem cross-sectional area - (:math:`c`, 390.43, -)""" h_max: float = 25.33 - """Maximum tree height (:math:`H_m`, 25.33, m)""" rho_s: float = 200.0 - r"""Sapwood density (:math:`\rho_s`, 200.0, kg Cm-3)""" lai: float = 1.8 - """Leaf area index within the crown (:math:`L`, 1.8, -)""" sla: float = 14.0 - r"""Specific leaf area (:math:`\sigma`, 14.0, m2 kg-1 C)""" tau_f: float = 4.0 - r"""Foliage turnover time (:math:`\tau_f`, 4.0, years)""" tau_r: float = 1.04 - """Fine-root turnover time (:math:`\tau_r`, 1.04, years)""" par_ext: float = 0.5 - """Extinction coefficient of photosynthetically active radiation (PAR) (:math:`k`, - 0.5, -)""" yld: float = 0.17 - """Yield_factor (:math:`y`, 0.17, -)""" zeta: float = 0.17 - r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, 0.17, kg C m-2)""" resp_r: float = 0.913 - """Fine-root specific respiration rate (:math:`r_r`, 0.913, year-1)""" resp_s: float = 0.044 - """Sapwood-specific respiration rate (:math:`r_s`, 0.044, year-1)""" resp_f: float = 0.1 - """Foliage maintenance respiration fraction (:math:`r_f`, 0.1, -)""" m: float = 2 - """Canopy shape parameter (:math:`m`, -)""" n: float = 5 - """Canopy shape parameter (:math:`n`, -)""" PlantFunctionalTypeSchema = marshmallow_dataclass.class_schema( From a0e6a40d8c3dfded561667c0eff51a1621a65bf8 Mon Sep 17 00:00:00 2001 From: David Orme Date: Sun, 8 Sep 2024 11:09:24 +0100 Subject: [PATCH 071/241] Adding array structured PFT data to Flora --- pyrealm/demography/flora.py | 329 +++++++++++++++++++++++++ pyrealm_build_data/community/pfts.toml | 37 +++ 2 files changed, 366 insertions(+) create mode 100644 pyrealm/demography/flora.py create mode 100644 pyrealm_build_data/community/pfts.toml diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py new file mode 100644 index 00000000..b607a372 --- /dev/null +++ b/pyrealm/demography/flora.py @@ -0,0 +1,329 @@ +"""The flora module implements definitions of: + +* The ``PlantFunctionalType`` and ``PlantFunctionalTypeStrict`` dataclasses, which are + used to parameterise the traits of different plant functional types. The + ``PlantFunctionalType`` dataclass is a subclass of ``PlantFunctionalTypeStrict`` that + simply adds default values to the attributes. +* The ``PlantFunctionalTypeStrict`` dataclass is used as the basis of a ``marshmallow`` + schema for validating the creation of plant functional types from data files. This + intentionally enforces a complete description of the traits in the input data. The + ``PlantFunctionalType`` is provided as a more convenient API for programmatic use. +* The Flora class, which is simply a dictionary of named plant functional types for use + in describing a plant community in a simulation. The Flora class also defines factory + methods to create instances from plant functional type data stored in JSON, TOML or + CSV formats. +""" # noqa: D415 + +from __future__ import annotations + +import json +import sys +from collections import Counter +from collections.abc import Sequence +from dataclasses import dataclass, field, fields +from pathlib import Path + +import marshmallow_dataclass +import numpy as np +import pandas as pd +from marshmallow.exceptions import ValidationError +from numpy.typing import NDArray + +if sys.version_info[:2] >= (3, 11): + import tomllib + from tomllib import TOMLDecodeError +else: + import tomli as tomllib + from tomli import TOMLDecodeError + + +@dataclass(frozen=True) +class PlantFunctionalTypeStrict: + """The PlantFunctionalTypeStrict dataclass. + + This dataclass implements the set of traits required to define a plant functional + type for use in ``pyrealm``. + + * Most traits are taken from the definition of the T Model of plant growth and GPP + allocation :cite:`Li:2014bc`. + * The foliage maintenance respiration fraction was not explicitly included in + :cite:t:`Li:2014bc` - there was assumed to be a 10% penalty on GPP before + calculating the other component - but has been explicitly included here. + * This implementation adds two further canopy shape parameters (``m`` and ``n``), + which are then used to calculate two derived attributes (``q_m`` and + ``z_max_ratio``). These are used to define the vertical distribution of leaves + around a stem and follow the implementation developed in the PlantFATE model + :cite:`joshi:2022a`. + + See also :class:`~pyrealm.demography.flora.PlantFunctionalType` for the default + values implemented in that subclass. + """ + + name: str + r"""The name of the plant functional type.""" + a_hd: float + r"""Initial slope of height-diameter relationship (:math:`a`, -)""" + ca_ratio: float + r"""Initial ratio of crown area to stem cross-sectional area + (:math:`c`, -)""" + h_max: float + r"""Maximum tree height (:math:`H_m`, m)""" + rho_s: float + r"""Sapwood density (:math:`\rho_s`, kg Cm-3)""" + lai: float + """Leaf area index within the crown (:math:`L`, -)""" + sla: float + r"""Specific leaf area (:math:`\sigma`, m2 kg-1 C)""" + tau_f: float + r"""Foliage turnover time (:math:`\tau_f`,years)""" + tau_r: float + r"""Fine-root turnover time (:math:`\tau_r`, years)""" + par_ext: float + r"""Extinction coefficient of photosynthetically active radiation (PAR) (:math:`k`, + -)""" + yld: float + r"""Yield factor (:math:`y`, -)""" + zeta: float + r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, kg C m-2)""" + resp_r: float + r"""Fine-root specific respiration rate (:math:`r_r`, year-1)""" + resp_s: float + r"""Sapwood-specific respiration rate (:math:`r_s`, year-1)""" + resp_f: float + r"""Foliage maintenance respiration fraction (:math:`r_f`, -)""" + m: float + r"""Canopy shape parameter (:math:`m`, -)""" + n: float + r"""Canopy shape parameter (:math:`n`, -)""" + + q_m: float = field(init=False) + """Scaling factor to derive maximum crown radius from crown area.""" + z_max_prop: float = field(init=False) + """Proportion of stem height at which maximum crown radius is found.""" + + def __post_init__(self) -> None: + """Populate derived attributes. + + This method populates the ``q_m`` and ``z_max_ratio`` attributes from the + provided values of ``m`` and ``n``. + """ + + # Calculate q_m and z_max proportion. Need to use __setattr__ because the + # dataclass is frozen. + object.__setattr__(self, "q_m", calculate_q_m(m=self.m, n=self.n)) + object.__setattr__( + self, "z_max_prop", calculate_z_max_proportion(m=self.m, n=self.n) + ) + + +@dataclass(frozen=True) +class PlantFunctionalType(PlantFunctionalTypeStrict): + r"""The PlantFunctionalType dataclass. + + This dataclass is a subclass of + :class:`~pyrealm.demography.flora.PlantFunctionalTypeStrict` that implements exactly + the same set of traits but provides default values. This class is intended as a + convenience API for programmatic use, where the parent provides a strict schema for + generating plant functional type instances from data. + + The table below lists the attributes and default values taken from Table 1 of + :cite:t:`Li:2014bc` + + .. csv-table:: + :header: "Attribute", "Default", "Unit" + :widths: 15, 10, 30 + + a_hd, 116.0, - + ca_ratio, 390.43, - + h_max, 25.33, m + rho_s, 200.0, kg Cm-3 + lai, 1.8, - + sla, 14.0, m2 kg-1 C + tau_f, 4.0, years + tau_r, 1.04, years + par_ext, 0.5, - + yld, 0.17, - + zeta, 0.17, kg C m-2 + resp_r, 0.913, year-1 + resp_s, 0.044, year-1 + resp_f, 0.1, - + m, 2, - + n, 5, - + """ + + a_hd: float = 116.0 + ca_ratio: float = 390.43 + h_max: float = 25.33 + rho_s: float = 200.0 + lai: float = 1.8 + sla: float = 14.0 + tau_f: float = 4.0 + tau_r: float = 1.04 + par_ext: float = 0.5 + yld: float = 0.17 + zeta: float = 0.17 + resp_r: float = 0.913 + resp_s: float = 0.044 + resp_f: float = 0.1 + m: float = 2 + n: float = 5 + + +PlantFunctionalTypeSchema = marshmallow_dataclass.class_schema( + PlantFunctionalTypeStrict +) +"""Marshmallow validation schema class for validating PlantFunctionalType data. + +This schema explicitly uses the strict version of the dataclass, which enforces complete +descriptions of plant functional type data rather than allowing partial data and filling +in gaps from the default values. +""" + + +def calculate_q_m(m: float, n: float) -> float: + """Calculate a q_m value. + + The value of q_m is a constant canopy scaling parameter derived from the ``m`` and + ``n`` attributes defined for a plant functional type. + + Args: + m: Canopy shape parameter + n: Canopy shape parameter + """ + return ( + m + * n + * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) + * (((m - 1) * n) / (m * n - 1)) ** (m - 1) + ) + + +def calculate_z_max_proportion(m: float, n: float) -> float: + """Calculate the z_m proportion. + + The z_m proportion is the constant proportion of stem height at which the maximum + crown radius is found for a given plant functional type. + + Args: + m: Canopy shape parameter + n: Canopy shape parameter + """ + + return ((n - 1) / (m * n - 1)) ** (1 / n) + + +class Flora(dict[str, type[PlantFunctionalTypeStrict]]): + """Defines the flora used in a ``virtual_ecosystem`` model. + + The flora is the set of plant functional types used within a particular simulation + and this class provides dictionary-like access to a defined set of + :class:`~pyrealm.demography.flora.PlantFunctionalType` or + :class:`~pyrealm.demography.flora.PlantFunctionalTypeStrict` instances. + + Instances of this class should not be altered during model fitting, at least until + the point where plant evolution is included in the modelling process. + + Args: + pfts: A sequence of ``PlantFunctionalType`` or ``PlantFunctionalTypeStrict`` + instances, which must not have duplicated + :attr:`~pyrealm.demography.flora.PlantFunctionalTypeStrict.name` attributes. + """ + + def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: + # Initialise the dict superclass to implement dict like behaviour + super().__init__() + + # Check the PFT data + if (not isinstance(pfts, Sequence)) or ( + not all([isinstance(v, PlantFunctionalTypeStrict) for v in pfts]) + ): + raise ValueError( + "The pfts argument must be a sequence of PlantFunctionalType instances" + ) + + # Validate the PFT instances - check there are no duplicate PFT names. + pft_names = Counter([p.name for p in pfts]) + duplicates = [k for k, v in pft_names.items() if v > 1] + + if duplicates: + raise ValueError( + f"Duplicated plant functional type names: {','.join(duplicates)}" + ) + + # Populate the dictionary using the PFT name as key + for name, pft in zip(pft_names, pfts): + self[name] = pft + + # Generate an array representation to facilitate creating across cohort values + self.arrays: dict[str, NDArray] = {} + """A dictionary of trait values as numpy arrays. + + The 'name' array can be used to get the index of different traits and allow + the values in the other arrays to be easily unpacked across cohorts. + """ + + pft_fields = [f.name for f in fields(PlantFunctionalTypeStrict)] + + for pft_field in pft_fields: + self.arrays[pft_field] = np.array( + [getattr(pft, pft_field) for pft in self.values()] + ) + + @classmethod + def _from_file_data(cls, file_data: dict) -> Flora: + """Create a Flora object from a JSON string. + + Args: + file_data: The payload from a data file defining plant functional types. + """ + try: + pfts = PlantFunctionalTypeSchema().load(file_data["pft"], many=True) # type: ignore[attr-defined] + except ValidationError as excep: + raise excep + + return cls(pfts=pfts) + + @classmethod + def from_json(cls, path: Path) -> Flora: + """Create a Flora object from a JSON file. + + Args: + path: A path to a JSON file of plant functional type definitions. + """ + + try: + file_data = json.load(open(path)) + except (FileNotFoundError, json.JSONDecodeError) as excep: + raise excep + + return cls._from_file_data(file_data=file_data) + + @classmethod + def from_toml(cls, path: Path) -> Flora: + """Create a Flora object from a TOML file. + + Args: + path: A path to a TOML file of plant functional type definitions. + """ + + try: + file_data = tomllib.load(open(path, "rb")) + except (FileNotFoundError, TOMLDecodeError) as excep: + raise excep + + return cls._from_file_data(file_data) + + @classmethod + def from_csv(cls, path: Path) -> Flora: + """Create a Flora object from a CSV file. + + Args: + path: A path to a CSV file of plant functional type definitions. + """ + + try: + data = pd.read_csv(path) + except (FileNotFoundError, pd.errors.ParserError) as excep: + raise excep + + return cls._from_file_data({"pft": data.to_dict(orient="records")}) diff --git a/pyrealm_build_data/community/pfts.toml b/pyrealm_build_data/community/pfts.toml new file mode 100644 index 00000000..4e31c832 --- /dev/null +++ b/pyrealm_build_data/community/pfts.toml @@ -0,0 +1,37 @@ +[[pft]] +a_hd = 116.0 +ca_ratio = 390.43 +h_max = 25.33 +lai = 1.8 +name = 'test1' +par_ext = 0.5 +resp_f = 0.1 +resp_r = 0.913 +resp_s = 0.044 +rho_s = 200.0 +sla = 14.0 +tau_f = 4.0 +tau_r = 1.04 +yld = 0.17 +zeta = 0.17 +m = 2 +n = 5 + +[[pft]] +a_hd = 116.0 +ca_ratio = 390.43 +h_max = 15.33 +lai = 1.8 +name = 'test2' +par_ext = 0.5 +resp_f = 0.1 +resp_r = 0.913 +resp_s = 0.044 +rho_s = 200.0 +sla = 14.0 +tau_f = 4.0 +tau_r = 1.04 +yld = 0.17 +zeta = 0.17 +m = 2 +n = 5 From 2280d694c2d32c3a19643c00bed1677fa30803f2 Mon Sep 17 00:00:00 2001 From: David Orme Date: Sun, 8 Sep 2024 11:15:53 +0100 Subject: [PATCH 072/241] Validating pft names in cohorts in Community __init__ --- pyrealm/demography/community.py | 90 ++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 84f0daac..18bb9c8c 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -13,7 +13,7 @@ from numpy.typing import NDArray from pyrealm.demography import t_model_functions as t_model -from pyrealm.demography.flora import Flora, PlantFunctionalType +from pyrealm.demography.flora import Flora, PlantFunctionalTypeStrict if sys.version_info[:2] >= (3, 11): import tomllib @@ -101,7 +101,16 @@ def __post_init__(self) -> None: values. """ - # Populate the pft + # Check the initial PFT values are known + unknown_pfts = set(self.cohort_pft_names).difference(self.flora.keys()) + + if unknown_pfts: + raise ValueError( + f"Plant functional types unknown in flora: {','.join(unknown_pfts)}" + ) + + # Populate the pft arrays and then calculate the geometry and other T model + # components self._populate_pft_arrays() self._calculate_t_model() @@ -154,6 +163,45 @@ def _calculate_t_model(self) -> None: self.pft_z_max_prop_values, self.t_model_heights ) + def _populate_pft_arrays(self) -> None: + """Populate plant functional type arrays. + + Populate the initialised arrays containing properties relating to plant + functional type by looking up the plant functional type in the Flora dictionary, + extracting the properties and inserting them into the relevant position in the + array. + :return: None + """ + for i in range(0, self.number_of_cohorts): + pft = self.__look_up_plant_functional_type(self.cohort_pft_names[i]) + self.pft_a_hd_values[i] = pft.a_hd + self.pft_ca_ratio_values[i] = pft.ca_ratio + self.pft_h_max_values[i] = pft.h_max + self.pft_lai_values[i] = pft.lai + self.pft_par_ext_values[i] = pft.par_ext + self.pft_resp_f_values[i] = pft.resp_f + self.pft_resp_r_values[i] = pft.resp_r + self.pft_resp_s_values[i] = pft.resp_s + self.pft_rho_s_values[i] = pft.rho_s + self.pft_sla_values[i] = pft.sla + self.pft_tau_f_values[i] = pft.tau_f + self.pft_tau_r_values[i] = pft.tau_r + self.pft_yld_values[i] = pft.yld + self.pft_zeta_values[i] = pft.zeta + self.pft_m_values[i] = pft.m + self.pft_n_values[i] = pft.n + + def __look_up_plant_functional_type( + self, pft_name: str + ) -> type[PlantFunctionalTypeStrict]: + """Retrieve plant functional type for a cohort from the flora dictionary.""" + + if pft_name not in self.flora: + raise Exception( + f"Cohort data supplied with in an invalid PFT name: {pft_name}" + ) + return self.flora[pft_name] + @classmethod def load_communities_from_csv( cls, cell_area: float, csv_path: str, flora: Flora @@ -198,41 +246,3 @@ def load_communities_from_csv( communities.append(community_object) return communities - - def _populate_pft_arrays(self) -> None: - """Populate plant functional type arrays. - - Populate the initialised arrays containing properties relating to plant - functional type by looking up the plant functional type in the Flora dictionary, - extracting the properties and inserting them into the relevant position in the - array. - :return: None - """ - for i in range(0, self.number_of_cohorts): - pft = self.__look_up_plant_functional_type(self.cohort_pft_names[i]) - self.pft_a_hd_values[i] = pft.a_hd - self.pft_ca_ratio_values[i] = pft.ca_ratio - self.pft_h_max_values[i] = pft.h_max - self.pft_lai_values[i] = pft.lai - self.pft_par_ext_values[i] = pft.par_ext - self.pft_resp_f_values[i] = pft.resp_f - self.pft_resp_r_values[i] = pft.resp_r - self.pft_resp_s_values[i] = pft.resp_s - self.pft_rho_s_values[i] = pft.rho_s - self.pft_sla_values[i] = pft.sla - self.pft_tau_f_values[i] = pft.tau_f - self.pft_tau_r_values[i] = pft.tau_r - self.pft_yld_values[i] = pft.yld - self.pft_zeta_values[i] = pft.zeta - self.pft_m_values[i] = pft.m - self.pft_n_values[i] = pft.n - - def __look_up_plant_functional_type(self, pft_name: str) -> PlantFunctionalType: - """Retrieve plant functional type for a cohort from the flora dictionary.""" - pft = self.flora.get(pft_name) - - if pft is None: - raise Exception( - f"Cohort data supplied with in an invalid PFT name: {pft_name}" - ) - return pft From 242f0757662ec59ebfd1a136a96d2dd2e26c9579 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 8 Sep 2024 10:23:49 +0000 Subject: [PATCH 073/241] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/source/api/demography_api.md | 1 - docs/source/users/tmodel/canopy.md | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/source/api/demography_api.md b/docs/source/api/demography_api.md index db14bcbd..1244feff 100644 --- a/docs/source/api/demography_api.md +++ b/docs/source/api/demography_api.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/tmodel/canopy.md b/docs/source/users/tmodel/canopy.md index c7887f37..b0911b87 100644 --- a/docs/source/users/tmodel/canopy.md +++ b/docs/source/users/tmodel/canopy.md @@ -5,7 +5,6 @@ jupytext: extension: .md format_name: myst format_version: 0.13 - jupytext_version: 1.16.4 kernelspec: display_name: python3 language: python @@ -60,9 +59,13 @@ pft.height ``` ```{code-cell} +:lines_to_next_cell: 2 + pft.crown_area ``` ++++ {"lines_to_next_cell": 2} + ### Crown shape Jaideep's extension of the T Model adds a crown shape model, driven by two parameters @@ -95,6 +98,8 @@ r_0 &= \frac{1}{q_m}\sqrt{\frac{A_c}{\pi}} $$ ```{code-cell} +:lines_to_next_cell: 2 + def calculate_qm(m, n): # Constant q_m @@ -128,6 +133,8 @@ print("zm = ", zm) print("r0 = ", r0) ``` ++++ {"lines_to_next_cell": 2} + The following functions then provide the value at height $z$ of relative $q(z)$ and actual $r(z)$ canopy radius: @@ -275,6 +282,8 @@ The code below calculates the projected crown area for each stem and then plots vertical profile for individual stems and across the community. ```{code-cell} +:lines_to_next_cell: 2 + # Calculate the projected area for each stem Ap_z = calculate_projected_area(z=z[:, None], pft=pft, m=m, n=n, qm=qm, zm=zm) @@ -293,6 +302,8 @@ ax2.set_xlabel("Total community $A_p(z)$ (m2)") plt.tight_layout() ``` ++++ {"lines_to_next_cell": 2} + ### Canopy closure and canopy gap fraction The total cumulative projected area shown above is modified by a community-level @@ -478,12 +489,16 @@ print(Ap_z_star) ``` ```{code-cell} +:lines_to_next_cell: 2 + # Calculate the contribution _within_ each layer per stem Ap_within_layer = np.diff(Ap_z_star, axis=0, prepend=0) print(Ap_within_layer) ``` ++++ {"lines_to_next_cell": 2} + ### Leaf area within canopy layers The projected area occupied by leaves at a given height $\tilde{A}_{cp}(z)$ is From f081777b3923ed226f8d1a54bd03a2f5dcc5e725 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 9 Sep 2024 16:10:18 +0100 Subject: [PATCH 074/241] Use pandas to represent flora data as arrays --- pyrealm/demography/flora.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index b607a372..9719647d 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -27,7 +27,6 @@ import numpy as np import pandas as pd from marshmallow.exceptions import ValidationError -from numpy.typing import NDArray if sys.version_info[:2] >= (3, 11): import tomllib @@ -254,21 +253,23 @@ def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: for name, pft in zip(pft_names, pfts): self[name] = pft - # Generate an array representation to facilitate creating across cohort values - self.arrays: dict[str, NDArray] = {} - """A dictionary of trait values as numpy arrays. - - The 'name' array can be used to get the index of different traits and allow - the values in the other arrays to be easily unpacked across cohorts. - """ - + # Generate an dataframe representation to facilitate merging to cohort data. + # - assemble pft fields into arrays + data = {} pft_fields = [f.name for f in fields(PlantFunctionalTypeStrict)] for pft_field in pft_fields: - self.arrays[pft_field] = np.array( + data[pft_field] = np.array( [getattr(pft, pft_field) for pft in self.values()] ) + self.data: pd.DataFrame = pd.DataFrame(data) + """A dataframe of trait values as numpy arrays. + + The 'name' column can be used with cohort names to broadcast plant functional + type data out to cohorts. + """ + @classmethod def _from_file_data(cls, file_data: dict) -> Flora: """Create a Flora object from a JSON string. From a3b9689a9fe4d6c6c22bb5c3c89fd0881840e657 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 9 Sep 2024 16:12:23 +0100 Subject: [PATCH 075/241] Implementing community as a pandas dataframe of cohort data --- docs/source/api/demography_api.md | 16 +++ pyrealm/demography/community.py | 138 ++++++++++++------------ pyrealm/demography/t_model_functions.py | 28 +++-- tests/unit/demography/test_community.py | 51 ++++++++- tests/unit/demography/test_flora.py | 11 +- 5 files changed, 160 insertions(+), 84 deletions(-) diff --git a/docs/source/api/demography_api.md b/docs/source/api/demography_api.md index 1244feff..c327e76b 100644 --- a/docs/source/api/demography_api.md +++ b/docs/source/api/demography_api.md @@ -26,3 +26,19 @@ kernelspec: :autosummary: :members: ``` + +## The {mod}`~pyrealm.demography.community` module + +```{eval-rst} +.. automodule:: pyrealm.demography.community + :autosummary: + :members: +``` + +## The {mod}`~pyrealm.demography.t_model_functions` module + +```{eval-rst} +.. automodule:: pyrealm.demography.t_model_functions + :autosummary: + :members: +``` diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 18bb9c8c..0088476e 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -4,7 +4,7 @@ import json import sys -from dataclasses import dataclass, field +from dataclasses import dataclass, field, InitVar import marshmallow_dataclass import numpy as np @@ -55,32 +55,15 @@ class Community: flora: Flora # - arrays representing properties of cohorts - cohort_dbh_values: NDArray[np.float32] - cohort_number_of_individuals: NDArray[np.int_] - cohort_pft_names: NDArray[np.str_] + cohort_dbh_values: InitVar[NDArray[np.float32]] + cohort_n_individuals: InitVar[NDArray[np.int_]] + cohort_pft_names: InitVar[NDArray[np.str_]] # Post init properties number_of_cohorts: int = field(init=False) - # - arrays representing properties of plant functional types - pft_a_hd_values: NDArray[np.float32] = field(init=False) - pft_ca_ratio_values: NDArray[np.float32] = field(init=False) - pft_h_max_values: NDArray[np.float32] = field(init=False) - pft_lai_values: NDArray[np.float32] = field(init=False) - pft_par_ext_values: NDArray[np.float32] = field(init=False) - pft_resp_f_values: NDArray[np.float32] = field(init=False) - pft_resp_r_values: NDArray[np.float32] = field(init=False) - pft_resp_s_values: NDArray[np.float32] = field(init=False) - pft_rho_s_values: NDArray[np.float32] = field(init=False) - pft_sla_values: NDArray[np.float32] = field(init=False) - pft_tau_f_values: NDArray[np.float32] = field(init=False) - pft_tau_r_values: NDArray[np.float32] = field(init=False) - pft_yld_values: NDArray[np.float32] = field(init=False) - pft_zeta_values: NDArray[np.float32] = field(init=False) - pft_m_values: NDArray[np.float32] = field(init=False) - pft_n_values: NDArray[np.float32] = field(init=False) - pft_q_m_values: NDArray[np.float32] = field(init=False) - pft_z_max_prop_values: NDArray[np.float32] = field(init=False) + # Dataframe of cohort + cohort_data: pd.DataFrame = field(init=False) # Create arrays containing values relating to T Model geometry t_model_heights: NDArray[np.float32] = field(init=False) @@ -92,26 +75,36 @@ class Community: t_model_r_0_values: NDArray[np.float32] = field(init=False) t_model_z_m_values: NDArray[np.float32] = field(init=False) - def __post_init__(self) -> None: + def __post_init__( + self, + cohort_dbh_values: NDArray[np.float32], + cohort_n_individuals: NDArray[np.int_], + cohort_pft_names: NDArray[np.str_], + ) -> None: """Populate derived community attributes. - The ``__post_init__`` method populates arrays of PFT values, unpacking the data - in the ``Flora`` object into arrays of per-cohort values. It then calculates the - predictions of the T Model for each cohort, again as arrays of per-cohort - values. + The ``__post_init__`` builds a pandas dataframe of PFT values and T model + predictions across the initial cohort data. """ # Check the initial PFT values are known - unknown_pfts = set(self.cohort_pft_names).difference(self.flora.keys()) + unknown_pfts = set(cohort_pft_names).difference(self.flora.keys()) if unknown_pfts: raise ValueError( f"Plant functional types unknown in flora: {','.join(unknown_pfts)}" ) - # Populate the pft arrays and then calculate the geometry and other T model - # components - self._populate_pft_arrays() + # + cohort_data = pd.DataFrame( + { + "name": cohort_pft_names, + "dbh": cohort_dbh_values, + "n_individuals": cohort_n_individuals, + } + ) + # Add the pft trait data to the cohort data + self.cohort_data = pd.merge(cohort_data, self.flora.data) self._calculate_t_model() def _calculate_t_model(self) -> None: @@ -122,46 +115,48 @@ def _calculate_t_model(self) -> None: implemented in PlantFate :cite:`joshi:2022a`. """ - # Create arrays containing values relating to T Model geometry - self.t_model_heights = t_model.calculate_heights( - self.pft_h_max_values, self.pft_a_hd_values, self.cohort_dbh_values - ) - - self.t_model_crown_areas = t_model.calculate_crown_areas( - self.pft_ca_ratio_values, - self.pft_a_hd_values, - self.cohort_dbh_values, - self.t_model_heights, - ) - - self.t_model_crown_fractions = t_model.calculate_crown_fractions( - self.t_model_heights, self.pft_a_hd_values, self.cohort_dbh_values - ) - - self.t_model_stem_masses = t_model.calculate_stem_masses( - self.cohort_dbh_values, self.t_model_heights, self.pft_rho_s_values + # Add data to cohort dataframes capturing the T Model geometry + self.cohort_data["height"] = t_model.calculate_heights( + h_max=self.cohort_data["h_max"], + a_hd=self.cohort_data["a_hd"], + dbh=self.cohort_data["dbh"], ) - self.t_model_foliage_masses = t_model.calculate_foliage_masses( - self.t_model_crown_areas, self.pft_lai_values, self.pft_sla_values - ) - - self.t_model_swd_masses = t_model.calculate_swd_masses( - self.t_model_crown_areas, - self.pft_rho_s_values, - self.t_model_heights, - self.t_model_crown_fractions, - self.pft_ca_ratio_values, - ) - - # Create arrays containing properties pertaining to Jaideep's t model - # extension - self.canopy_factor_r_0_values = t_model.calculate_r_0_values( - self.pft_q_m_values, self.t_model_crown_areas - ) - self.canopy_factor_z_m_values = t_model.calculate_z_max_values( - self.pft_z_max_prop_values, self.t_model_heights - ) + # self.t_model_crown_areas = t_model.calculate_crown_areas( + # self.pft_ca_ratio_values, + # self.pft_a_hd_values, + # self.cohort_dbh_values, + # self.t_model_heights, + # ) + + # self.t_model_crown_fractions = t_model.calculate_crown_fractions( + # self.t_model_heights, self.pft_a_hd_values, self.cohort_dbh_values + # ) + + # self.t_model_stem_masses = t_model.calculate_stem_masses( + # self.cohort_dbh_values, self.t_model_heights, self.pft_rho_s_values + # ) + + # self.t_model_foliage_masses = t_model.calculate_foliage_masses( + # self.t_model_crown_areas, self.pft_lai_values, self.pft_sla_values + # ) + + # self.t_model_swd_masses = t_model.calculate_swd_masses( + # self.t_model_crown_areas, + # self.pft_rho_s_values, + # self.t_model_heights, + # self.t_model_crown_fractions, + # self.pft_ca_ratio_values, + # ) + + # # Create arrays containing properties pertaining to Jaideep's t model + # # extension + # self.canopy_factor_r_0_values = t_model.calculate_r_0_values( + # self.pft_q_m_values, self.t_model_crown_areas + # ) + # self.canopy_factor_z_m_values = t_model.calculate_z_max_values( + # self.pft_z_max_prop_values, self.t_model_heights + # ) def _populate_pft_arrays(self) -> None: """Populate plant functional type arrays. @@ -172,6 +167,9 @@ def _populate_pft_arrays(self) -> None: array. :return: None """ + + # Get the index of the cohort pfts in the array representation of + for i in range(0, self.number_of_cohorts): pft = self.__look_up_plant_functional_type(self.cohort_pft_names[i]) self.pft_a_hd_values[i] = pft.a_hd diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 9cd6d957..21a83ade 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -7,19 +7,27 @@ import numpy as np from numpy.typing import NDArray +from pandas import Series -def calculate_heights( - pft_h_max_values: NDArray[np.float32], - pft_a_hd_values: NDArray[np.float32], - diameters_at_breast_height: NDArray[np.float32], -) -> NDArray[np.float32]: - """Height of tree from diameter, Equation (4) of Li ea.""" - heights = pft_h_max_values * ( - 1 - np.exp(-pft_a_hd_values * diameters_at_breast_height / pft_h_max_values) - ) +def calculate_heights(h_max: Series, a_hd: Series, dbh: Series) -> Series: + r"""Calculate tree height under the T Model. + + The height of tree is calculated from individual diameters at breast height, along + with the maximum height and initial slope of the height/diameter relationship of the + plant functional type :cite:p:`{Equation 4, }Li:2014bc`: + + .. math:: + + H_{max} \left(1 - \exp(-a_{HD} \cdot \textrm{DBH} / H_{max})\right) + + Args: + h_max: Maximum height of the PFT + a_hd: Initial slope of the height/diameter relationship of the PFT + dbh: Diameter at breast height of individuals + """ - return heights + return h_max * (1 - np.exp(-a_hd * dbh / h_max)) def calculate_crown_areas( diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index 32412c4f..b90a1aa5 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -1,13 +1,58 @@ """test the community object in community.py initialises as expected.""" +from contextlib import nullcontext as does_not_raise -def test_initialisation(): +import numpy as np +import pytest + + +@pytest.fixture +def fixture_flora(): + """Simple flora object for use in community tests.""" + + from pyrealm.demography.flora import Flora, PlantFunctionalType + + return Flora( + [ + PlantFunctionalType(name="broadleaf", h_max=30), + PlantFunctionalType(name="conifer", h_max=20), + ] + ) + + +@pytest.mark.parametrize( + argnames="cell_id,cell_area,cohort_pfts,cohort_dbh,cohort_n,outcome", + argvalues=[ + pytest.param( + 1, + 100, + np.array(["broadleaf", "broadleaf", "conifer"]), + np.array([0.2, 0.1, 0.2]), + np.array([2, 10, 3]), + does_not_raise(), + id="correct", + ) + ], +) +def test_Community_initialisation( + fixture_flora, cell_id, cell_area, cohort_pfts, cohort_dbh, cohort_n, outcome +): """Test happy path for initialisation. - test that when a new community object is instantiated, it contains the expected + Test that when a new community object is instantiated, it contains the expected properties. """ - pass + + from pyrealm.demography.community import Community + + community = Community( + cell_id=cell_id, + cell_area=cell_area, + cohort_pft_names=cohort_pfts, + cohort_dbh_values=cohort_dbh, + cohort_n_individuals=cohort_n, + flora=fixture_flora, + ) def test_import_from_csv(): diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index 72164314..e921a131 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -2,9 +2,11 @@ import sys from contextlib import nullcontext as does_not_raise +from dataclasses import fields from importlib import resources from json import JSONDecodeError +import pandas as pd import pytest from marshmallow.exceptions import ValidationError from pandas.errors import ParserError @@ -169,11 +171,18 @@ def test_Flora__init__(flora_inputs, outcome): with outcome: flora = Flora(pfts=flora_inputs) - # Simple check that PFT instances are correctly keyed by name. if isinstance(outcome, does_not_raise): + # Simple check that PFT instances are correctly keyed by name. for k, v in flora.items(): assert k == v.name + # Check data view is correct + assert isinstance(flora.data, pd.DataFrame) + assert flora.data.shape == ( + len(flora_inputs), + len(fields(list(flora.values())[0])), + ) + # # Test Flora factory methods from JSON, TOML, CSV From b1b64a917e8ce4b38e6603fd94d26703ae221d58 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 17:48:55 +0000 Subject: [PATCH 076/241] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.3 → v0.6.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.3...v0.6.4) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0e4fc674..8fec970f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ repos: - id: debug-statements - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.3 + rev: v0.6.4 hooks: # Run the linter. - id: ruff From 08922fa5a9571aae0f41eecc30c8c26d71121dea Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 10 Sep 2024 09:02:49 +0100 Subject: [PATCH 077/241] Updating T Model functions and populating T model predictions in cohort data --- pyrealm/demography/community.py | 254 +++++++++++------------- pyrealm/demography/t_model_functions.py | 231 +++++++++++++-------- tests/unit/demography/test_community.py | 40 +++- 3 files changed, 296 insertions(+), 229 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 0088476e..45363662 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -2,25 +2,26 @@ from __future__ import annotations -import json -import sys -from dataclasses import dataclass, field, InitVar +# import json +# import sys +from dataclasses import InitVar, dataclass, field -import marshmallow_dataclass +# import marshmallow_dataclass import numpy as np import pandas as pd -from marshmallow.exceptions import ValidationError + +# from marshmallow.exceptions import ValidationError from numpy.typing import NDArray from pyrealm.demography import t_model_functions as t_model -from pyrealm.demography.flora import Flora, PlantFunctionalTypeStrict +from pyrealm.demography.flora import Flora -if sys.version_info[:2] >= (3, 11): - import tomllib - from tomllib import TOMLDecodeError -else: - import tomli as tomllib - from tomli import TOMLDecodeError +# if sys.version_info[:2] >= (3, 11): +# import tomllib +# from tomllib import TOMLDecodeError +# else: +# import tomli as tomllib +# from tomli import TOMLDecodeError @dataclass @@ -65,16 +66,6 @@ class Community: # Dataframe of cohort cohort_data: pd.DataFrame = field(init=False) - # Create arrays containing values relating to T Model geometry - t_model_heights: NDArray[np.float32] = field(init=False) - t_model_crown_areas: NDArray[np.float32] = field(init=False) - t_model_crown_fractions: NDArray[np.float32] = field(init=False) - t_model_stem_masses: NDArray[np.float32] = field(init=False) - t_model_foliage_masses: NDArray[np.float32] = field(init=False) - t_model_swd_masses: NDArray[np.float32] = field(init=False) - t_model_r_0_values: NDArray[np.float32] = field(init=False) - t_model_z_m_values: NDArray[np.float32] = field(init=False) - def __post_init__( self, cohort_dbh_values: NDArray[np.float32], @@ -95,7 +86,14 @@ def __post_init__( f"Plant functional types unknown in flora: {','.join(unknown_pfts)}" ) - # + # Check the cohort inputs are of equal length + if not ( + (cohort_dbh_values.shape == cohort_n_individuals.shape) + and (cohort_dbh_values.shape == cohort_pft_names.shape) + ): + raise ValueError("Cohort data are not equally sized") + + # Convert to a dataframe cohort_data = pd.DataFrame( { "name": cohort_pft_names, @@ -103,12 +101,16 @@ def __post_init__( "n_individuals": cohort_n_individuals, } ) - # Add the pft trait data to the cohort data + # Broadcast the pft trait data to the cohort data by merging with the flora data + # and then store as the cohort data attribute self.cohort_data = pd.merge(cohort_data, self.flora.data) + self.number_of_cohorts = self.cohort_data.shape[0] + + # Populate the T model fields self._calculate_t_model() def _calculate_t_model(self) -> None: - """Calculate T Model predictions across cohorts. + """Calculate T Model predictions across cohort data. This method populates or updates the community attributes predicted by the T Model :cite:`Li:2014bc` and by the canopy shape extensions to the T Model @@ -116,131 +118,99 @@ def _calculate_t_model(self) -> None: """ # Add data to cohort dataframes capturing the T Model geometry + # - Classic T Model scaling self.cohort_data["height"] = t_model.calculate_heights( h_max=self.cohort_data["h_max"], a_hd=self.cohort_data["a_hd"], dbh=self.cohort_data["dbh"], ) - # self.t_model_crown_areas = t_model.calculate_crown_areas( - # self.pft_ca_ratio_values, - # self.pft_a_hd_values, - # self.cohort_dbh_values, - # self.t_model_heights, - # ) - - # self.t_model_crown_fractions = t_model.calculate_crown_fractions( - # self.t_model_heights, self.pft_a_hd_values, self.cohort_dbh_values - # ) - - # self.t_model_stem_masses = t_model.calculate_stem_masses( - # self.cohort_dbh_values, self.t_model_heights, self.pft_rho_s_values - # ) - - # self.t_model_foliage_masses = t_model.calculate_foliage_masses( - # self.t_model_crown_areas, self.pft_lai_values, self.pft_sla_values - # ) - - # self.t_model_swd_masses = t_model.calculate_swd_masses( - # self.t_model_crown_areas, - # self.pft_rho_s_values, - # self.t_model_heights, - # self.t_model_crown_fractions, - # self.pft_ca_ratio_values, - # ) - - # # Create arrays containing properties pertaining to Jaideep's t model - # # extension - # self.canopy_factor_r_0_values = t_model.calculate_r_0_values( - # self.pft_q_m_values, self.t_model_crown_areas - # ) - # self.canopy_factor_z_m_values = t_model.calculate_z_max_values( - # self.pft_z_max_prop_values, self.t_model_heights - # ) - - def _populate_pft_arrays(self) -> None: - """Populate plant functional type arrays. - - Populate the initialised arrays containing properties relating to plant - functional type by looking up the plant functional type in the Flora dictionary, - extracting the properties and inserting them into the relevant position in the - array. - :return: None - """ + self.cohort_data["crown_area"] = t_model.calculate_crown_areas( + ca_ratio=self.cohort_data["ca_ratio"], + a_hd=self.cohort_data["a_hd"], + dbh=self.cohort_data["dbh"], + height=self.cohort_data["height"], + ) - # Get the index of the cohort pfts in the array representation of - - for i in range(0, self.number_of_cohorts): - pft = self.__look_up_plant_functional_type(self.cohort_pft_names[i]) - self.pft_a_hd_values[i] = pft.a_hd - self.pft_ca_ratio_values[i] = pft.ca_ratio - self.pft_h_max_values[i] = pft.h_max - self.pft_lai_values[i] = pft.lai - self.pft_par_ext_values[i] = pft.par_ext - self.pft_resp_f_values[i] = pft.resp_f - self.pft_resp_r_values[i] = pft.resp_r - self.pft_resp_s_values[i] = pft.resp_s - self.pft_rho_s_values[i] = pft.rho_s - self.pft_sla_values[i] = pft.sla - self.pft_tau_f_values[i] = pft.tau_f - self.pft_tau_r_values[i] = pft.tau_r - self.pft_yld_values[i] = pft.yld - self.pft_zeta_values[i] = pft.zeta - self.pft_m_values[i] = pft.m - self.pft_n_values[i] = pft.n - - def __look_up_plant_functional_type( - self, pft_name: str - ) -> type[PlantFunctionalTypeStrict]: - """Retrieve plant functional type for a cohort from the flora dictionary.""" - - if pft_name not in self.flora: - raise Exception( - f"Cohort data supplied with in an invalid PFT name: {pft_name}" - ) - return self.flora[pft_name] - - @classmethod - def load_communities_from_csv( - cls, cell_area: float, csv_path: str, flora: Flora - ) -> list[Community]: - """Loads a list of communities from a csv provided in the appropriate format. - - The csv should contain the following columns: cell_id, - diameter_at_breast_height, plant_functional_type, number_of_individuals. Each - row in the csv should represent one cohort. - - :param cell_area: the area of the cell at each location, this is assumed to be - the same across all the locations in the csv. - :param csv_path: path to the csv containing community data, as detailed above. - :param flora: a flora object, ie a dictionary of plant functional properties, - keyed by pft name. - :return: a list of community objects, loaded from the csv - file. - """ - community_data = pd.read_csv(csv_path) + self.cohort_data["crown_fraction"] = t_model.calculate_crown_fractions( + a_hd=self.cohort_data["a_hd"], + dbh=self.cohort_data["dbh"], + height=self.cohort_data["height"], + ) - data_grouped_by_community = community_data.groupby(community_data.cell_id) + self.cohort_data["stem_mass"] = t_model.calculate_stem_masses( + rho_s=self.cohort_data["rho_s"], + dbh=self.cohort_data["dbh"], + height=self.cohort_data["height"], + ) - communities = [] + self.cohort_data["foliage_mass"] = t_model.calculate_foliage_masses( + sla=self.cohort_data["sla"], + lai=self.cohort_data["lai"], + crown_area=self.cohort_data["crown_area"], + ) - for cell_id in data_grouped_by_community.groups: - community_dataframe = data_grouped_by_community.get_group(cell_id) - dbh_values = community_dataframe["diameter_at_breast_height"].to_numpy( - dtype=np.float32 - ) - number_of_individuals = community_dataframe[ - "number_of_individuals" - ].to_numpy(dtype=np.int_) - pft_names = community_dataframe["plant_functional_type"].to_numpy(dtype=str) - community_object = Community( - cell_id, # type:ignore - cell_area, - dbh_values, - number_of_individuals, - pft_names, - flora, - ) - communities.append(community_object) + self.cohort_data["sapwood_mass"] = t_model.calculate_sapwood_masses( + rho_s=self.cohort_data["rho_s"], + ca_ratio=self.cohort_data["ca_ratio"], + height=self.cohort_data["height"], + crown_area=self.cohort_data["crown_area"], + crown_fraction=self.cohort_data["crown_fraction"], + ) + + # Canopy shape extension to T Model from PlantFATE + self.cohort_data["canopy_z_max"] = t_model.calculate_canopy_z_max( + z_max_prop=self.cohort_data["z_max_prop"], + height=self.cohort_data["height"], + ) + self.cohort_data["canopy_r0"] = t_model.calculate_canopy_r0( + q_m=self.cohort_data["q_m"], + crown_area=self.cohort_data["crown_area"], + ) - return communities + # @classmethod + # def load_communities_from_csv( + # cls, cell_area: float, csv_path: str, flora: Flora + # ) -> list[Community]: + # """Loads a list of communities from a csv provided in the appropriate format. + + # The csv should contain the following columns: cell_id, + # diameter_at_breast_height, plant_functional_type, number_of_individuals. Each + # row in the csv should represent one cohort. + + # :param cell_area: the area of the cell at each location, this is assumed to be + # the same across all the locations in the csv. + # :param csv_path: path to the csv containing community data, as detailed above. + # :param flora: a flora object, ie a dictionary of plant functional properties, + # keyed by pft name. + # :return: a list of community objects, loaded from the csv + # file. + # """ + # community_data = pd.read_csv(csv_path) + + # data_grouped_by_community = community_data.groupby(community_data.cell_id) + + # communities = [] + + # for cell_id in data_grouped_by_community.groups: + # community_dataframe = data_grouped_by_community.get_group(cell_id) + # dbh_values = community_dataframe["diameter_at_breast_height"].to_numpy( + # dtype=np.float32 + # ) + # number_of_individuals = community_dataframe[ + # "number_of_individuals" + # ].to_numpy(dtype=np.int_) + # pft_names = community_dataframe["plant_functional_type"].to_numpy( + # dtype=str + # ) + # community_object = Community( + # cell_id, # type:ignore + # cell_area, + # dbh_values, + # number_of_individuals, + # pft_names, + # flora, + # ) + # communities.append(community_object) + + # return communities diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 21a83ade..2b1f39b4 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -1,9 +1,9 @@ -"""Populate t model arrays. - -Populate the relevant initialised arrays with properties calculated using the -t model. - -""" +"""The ``t_model`` module provides the basic scaling relationships of the T Model +:cite:`Li:2014bc`:. This provides scaling relationships using the plant functional type +traits defined in the :mod:`~pyrealm.demography.flora` module and the diameter at breast +height of individual stems to define the stem geometry, masses, respiration and hence +the calculate stem growth given net primary productivity. +""" # noqa: D205 import numpy as np from numpy.typing import NDArray @@ -13,13 +13,14 @@ def calculate_heights(h_max: Series, a_hd: Series, dbh: Series) -> Series: r"""Calculate tree height under the T Model. - The height of tree is calculated from individual diameters at breast height, along - with the maximum height and initial slope of the height/diameter relationship of the - plant functional type :cite:p:`{Equation 4, }Li:2014bc`: + The height of trees (:math:`H`) are calculated from individual diameters at breast + height (:math:`D`), along with the maximum height (:math:`H_{m}`) and initial slope + of the height/diameter relationship (:math:`a`) of the plant functional types + :cite:p:`{Equation 4, }Li:2014bc`: .. math:: - H_{max} \left(1 - \exp(-a_{HD} \cdot \textrm{DBH} / H_{max})\right) + H = H_{m} \left(1 - \exp(-a \cdot D / H_{m})\right) Args: h_max: Maximum height of the PFT @@ -31,79 +32,124 @@ def calculate_heights(h_max: Series, a_hd: Series, dbh: Series) -> Series: def calculate_crown_areas( - pft_ca_ratio_values: NDArray[np.float32], - pft_a_hd_values: NDArray[np.float32], - diameters_at_breast_height: NDArray[np.float32], - heights: NDArray[np.float32], -) -> NDArray[np.float32]: - """Crown area of tree, Equation (8) of Li ea.""" - t_model_crown_areas = ( - (np.pi * pft_ca_ratio_values / (4 * pft_a_hd_values)) - * diameters_at_breast_height - * heights - ) + ca_ratio: Series, a_hd: Series, dbh: Series, height: Series +) -> Series: + r"""Calculate tree crown area under the T Model. - return t_model_crown_areas + The tree crown area (:math:`A_{c}`)is calculated from individual diameters at breast + height (:math:`D`) and stem height (:math:`H`), along with the crown area ratio + (:math:`c`)and the initial slope of the height/diameter relationship (:math:`a`) of + the plant functional type :cite:p:`{Equation 8, }Li:2014bc`: + .. math:: -def calculate_crown_fractions( - heights: NDArray[np.float32], - pft_a_hd_values: NDArray[np.float32], - diameters_at_breast_height: NDArray[np.float32], -) -> NDArray[np.float32]: - """Crown fraction, Equation (11) of Li ea.""" - crown_fractions = heights / (pft_a_hd_values * diameters_at_breast_height) + A_{c} =\frac{\pi c}{4 a} D H - return crown_fractions + Args: + ca_ratio: Crown area ratio of the PFT + a_hd: Initial slope of the height/diameter relationship of the PFT + dbh: Diameter at breast height of individuals + height: Stem height of individuals + """ -def calculate_stem_masses( - diameters_at_breast_height: NDArray[np.float32], - heights: NDArray[np.float32], - pft_rho_s_values: NDArray[np.float32], -) -> NDArray[np.float32]: - """Mass of stems.""" - stem_masses = ( - (np.pi / 8) * (diameters_at_breast_height**2) * heights * pft_rho_s_values - ) + return ((np.pi * ca_ratio) / (4 * a_hd)) * dbh * height - return stem_masses +def calculate_crown_fractions(a_hd: Series, height: Series, dbh: Series) -> Series: + r"""Calculate tree crown fraction under the T Model. -def calculate_foliage_masses( - crown_areas: NDArray[np.float32], - pft_lai_values: NDArray[np.float32], - pft_sla_values: NDArray[np.float32], -) -> NDArray[np.float32]: - """Mass of foliage.""" - foliage_masses = crown_areas * pft_lai_values * (1 / pft_sla_values) + The crown fraction (:math:`f_{c}`)is calculated from individual diameters at breast + height and stem height (:math:`D`), along with the initial slope of the height / + diameter relationship (:math:`a`) of the plant functional type + :cite:p:`{Equation 11, }Li:2014bc`: - return foliage_masses + .. math:: + \frac{H}{a D} -def calculate_swd_masses( - crown_areas: NDArray[np.float32], - pft_rho_s_values: NDArray[np.float32], - heights: NDArray[np.float32], - crown_fractions: NDArray[np.float32], - pft_ca_ratio_values: NDArray[np.float32], -) -> NDArray[np.float32]: - """Mass of ???""" - swd_masses = ( - crown_areas - * pft_rho_s_values - * heights - * (1 - crown_fractions / 2) - / pft_ca_ratio_values - ) + Args: + a_hd: Initial slope of the height/diameter relationship of the PFT + dbh: Diameter at breast height of individuals + height: Stem height of individuals + """ + + return height / (a_hd * dbh) + + +def calculate_stem_masses(rho_s: Series, height: Series, dbh: Series) -> Series: + r"""Calculate stem mass under the T Model. + + The stem mass (:math:`W_{s}`) is calculated from individual diameters at breast + height (:math:`D`) and stem height (:math:`H`), along with the wood density + (:math:`\rho_s`)of the plant functional type :cite:p:`{Equation 6, }Li:2014bc`: + + .. math:: + + (\pi / 8) \rho_s D^2 H - return swd_masses + Args: + rho_s: Wood density of the PFT + dbh: Diameter at breast height of individuals + height: Stem height of individuals + """ + + return (np.pi / 8) * rho_s * (dbh**2) * height + + +def calculate_foliage_masses(sla: Series, lai: Series, crown_area: Series) -> Series: + r"""Calculate foliage mass under the T Model. + + The foliage mass (:math:`W_{f}`) is calculated from the crown area (:math:`A_{c}`), + along with the specific leaf area (:math:`\sigma`) and leaf area index (:math:`L`) + of the plant functional type :cite:p:`Li:2014bc`: + + .. math:: + + W_f = (1 / \sigma) A_c L + + Args: + sla: Specific leaf area of the PFT + lai: Leaf area index of the PFT + crown_area: Crown area of individuals + """ + + return crown_area * lai * (1 / sla) + + +def calculate_sapwood_masses( + rho_s: Series, + ca_ratio: Series, + height: Series, + crown_area: Series, + crown_fraction: Series, +) -> Series: + r"""Calculate sapwood mass under the T Model. + + The sapwood mass (:math:`W_{\cdot s}`) is calculated from the individual crown area + (:math:`A_{c}`), height :math:`H` and canopy fraction (:math:`f_{c}`) along with the + wood density (:math:`\rho_s`) and crown area ratio :math:`A_{c}` of the plant + functional type :cite:p:`{Equation 14, }Li:2014bc`: + + .. math:: + + W_{\cdot s} = \frac{A_c \rho_s H (1 - f_c / 2)}{c} + + Args: + rho_s: Wood density of the PFT + ca_ratio: Crown area ratio of the PFT + height: Stem height of individuals + crown_area: Crown area of individuals + crown_fraction: Crown fraction of individuals + """ + + return crown_area * rho_s * height * (1 - crown_fraction / 2) / ca_ratio def calculate_q_m_values( m: NDArray[np.float32], n: NDArray[np.float32] ) -> NDArray[np.float32]: - """Placeholder.""" + """Calculate q_m.""" return ( m * n @@ -112,24 +158,53 @@ def calculate_q_m_values( ) -def calculate_z_max_values( - z_max_prop: NDArray[np.float32], height: NDArray[np.float32] -) -> NDArray[np.float32]: - """Calculate z_m, the height of maximum crown radius.""" - # Height of maximum crown radius - z_max = height * z_max_prop - return z_max +def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: + r"""Calculate scaling factor for height of maximum crown radius. + This scaling factor (:math:`r_0`) is derived from the canopy shape parameters + (:math:`m,n,q_m`) for plant functional types and the estimated crown area + (:math:`A_c`) of individuals. The shape parameters are defined as part of the + extension of the T Model presented by :cite:t:`joshi:2022a` and :math:`r_0` is used + to scale the crown area such that the crown area at the maximum crown radius fits + the expectations of the T Model. -def calculate_r_0_values( - q_m: NDArray[np.float32], crown_area: NDArray[np.float32] -) -> NDArray[np.float32]: - """Calculate stem canopy factors from Jaideep's extension to the T Model.""" + .. math:: + + r_0 = 1/q_m \sqrt{A_c / \pi} + + Args: + q_m: Canopy shape parameter of the PFT + crown_area: Crown area of individuals + """ # Scaling factor to give expected A_c (crown area) at # z_m (height of maximum crown radius) - r_0 = 1 / q_m * np.sqrt(crown_area / np.pi) - return r_0 + return 1 / q_m * np.sqrt(crown_area / np.pi) + + +def calculate_canopy_z_max(z_max_prop: Series, height: Series) -> Series: + r"""Calculate height of maximum crown radius. + + The height of the maximum crown radius (:math:`z_m`) is derived from the canopy + shape parameters (:math:`m,n`) and the resulting fixed proportion (:math:`p_{zm}`) + for plant functional types. These shape parameters are defined as part of the + extension of the T Model presented by :cite:t:`joshi:2022a`. + + The value :math:`z_m` is the height above ground where the largest canopy radius is + found, given the proportion and the estimated stem height (:math:`H`) of + individuals. + + .. math:: + + z_m = p_{zm} H + + Args: + z_max_prop: Canopy shape parameter of the PFT + height: Crown area of individuals + """ + """Calculate z_m, the height of maximum crown radius.""" + + return height * z_max_prop def calculate_relative_canopy_radii( diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index b90a1aa5..a1e9d861 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -31,7 +31,25 @@ def fixture_flora(): np.array([2, 10, 3]), does_not_raise(), id="correct", - ) + ), + pytest.param( + 1, + 100, + np.array(["broadleaf", "broadleaf", "juniper"]), + np.array([0.2, 0.1, 0.2]), + np.array([2, 10, 3]), + pytest.raises(ValueError), + id="unknown_pft", + ), + pytest.param( + 1, + 100, + np.array(["broadleaf", "broadleaf", "juniper"]), + np.array([0.2, 0.1, 0.2]), + np.array([2, 10, 3, 4]), + pytest.raises(ValueError), + id="unequal_cohort_data_lengths", + ), ], ) def test_Community_initialisation( @@ -45,14 +63,18 @@ def test_Community_initialisation( from pyrealm.demography.community import Community - community = Community( - cell_id=cell_id, - cell_area=cell_area, - cohort_pft_names=cohort_pfts, - cohort_dbh_values=cohort_dbh, - cohort_n_individuals=cohort_n, - flora=fixture_flora, - ) + with outcome: + community = Community( + cell_id=cell_id, + cell_area=cell_area, + cohort_pft_names=cohort_pfts, + cohort_dbh_values=cohort_dbh, + cohort_n_individuals=cohort_n, + flora=fixture_flora, + ) + + if isinstance(outcome, does_not_raise): + assert community def test_import_from_csv(): From f4fe6a7cd80ad9c5f0e35e89d45b467644db65dd Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 10 Sep 2024 09:17:51 +0100 Subject: [PATCH 078/241] Moving q_m and p_zm calculations back into t model functions module from flora --- pyrealm/demography/flora.py | 41 +++------------- pyrealm/demography/t_model_functions.py | 62 ++++++++++++++++--------- 2 files changed, 48 insertions(+), 55 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 9719647d..74849c61 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -28,6 +28,11 @@ import pandas as pd from marshmallow.exceptions import ValidationError +from pyrealm.demography.t_model_functions import ( + calculate_canopy_q_m, + calculate_canopy_z_max_proportion, +) + if sys.version_info[:2] >= (3, 11): import tomllib from tomllib import TOMLDecodeError @@ -109,9 +114,9 @@ def __post_init__(self) -> None: # Calculate q_m and z_max proportion. Need to use __setattr__ because the # dataclass is frozen. - object.__setattr__(self, "q_m", calculate_q_m(m=self.m, n=self.n)) + object.__setattr__(self, "q_m", calculate_canopy_q_m(m=self.m, n=self.n)) object.__setattr__( - self, "z_max_prop", calculate_z_max_proportion(m=self.m, n=self.n) + self, "z_max_prop", calculate_canopy_z_max_proportion(m=self.m, n=self.n) ) @@ -179,38 +184,6 @@ class PlantFunctionalType(PlantFunctionalTypeStrict): """ -def calculate_q_m(m: float, n: float) -> float: - """Calculate a q_m value. - - The value of q_m is a constant canopy scaling parameter derived from the ``m`` and - ``n`` attributes defined for a plant functional type. - - Args: - m: Canopy shape parameter - n: Canopy shape parameter - """ - return ( - m - * n - * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) - * (((m - 1) * n) / (m * n - 1)) ** (m - 1) - ) - - -def calculate_z_max_proportion(m: float, n: float) -> float: - """Calculate the z_m proportion. - - The z_m proportion is the constant proportion of stem height at which the maximum - crown radius is found for a given plant functional type. - - Args: - m: Canopy shape parameter - n: Canopy shape parameter - """ - - return ((n - 1) / (m * n - 1)) ** (1 / n) - - class Flora(dict[str, type[PlantFunctionalTypeStrict]]): """Defines the flora used in a ``virtual_ecosystem`` model. diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 2b1f39b4..fb0e7a13 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -146,10 +146,16 @@ def calculate_sapwood_masses( return crown_area * rho_s * height * (1 - crown_fraction / 2) / ca_ratio -def calculate_q_m_values( - m: NDArray[np.float32], n: NDArray[np.float32] -) -> NDArray[np.float32]: - """Calculate q_m.""" +def calculate_canopy_q_m(m: float, n: float) -> float: + """Calculate a q_m value. + + The value of q_m is a constant canopy scaling parameter derived from the ``m`` and + ``n`` attributes defined for a plant functional type. + + Args: + m: Canopy shape parameter + n: Canopy shape parameter + """ return ( m * n @@ -158,28 +164,18 @@ def calculate_q_m_values( ) -def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: - r"""Calculate scaling factor for height of maximum crown radius. +def calculate_canopy_z_max_proportion(m: float, n: float) -> float: + """Calculate the z_m proportion. - This scaling factor (:math:`r_0`) is derived from the canopy shape parameters - (:math:`m,n,q_m`) for plant functional types and the estimated crown area - (:math:`A_c`) of individuals. The shape parameters are defined as part of the - extension of the T Model presented by :cite:t:`joshi:2022a` and :math:`r_0` is used - to scale the crown area such that the crown area at the maximum crown radius fits - the expectations of the T Model. - - .. math:: - - r_0 = 1/q_m \sqrt{A_c / \pi} + The z_m proportion is the constant proportion of stem height at which the maximum + crown radius is found for a given plant functional type. Args: - q_m: Canopy shape parameter of the PFT - crown_area: Crown area of individuals + m: Canopy shape parameter + n: Canopy shape parameter """ - # Scaling factor to give expected A_c (crown area) at - # z_m (height of maximum crown radius) - return 1 / q_m * np.sqrt(crown_area / np.pi) + return ((n - 1) / (m * n - 1)) ** (1 / n) def calculate_canopy_z_max(z_max_prop: Series, height: Series) -> Series: @@ -207,6 +203,30 @@ def calculate_canopy_z_max(z_max_prop: Series, height: Series) -> Series: return height * z_max_prop +def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: + r"""Calculate scaling factor for height of maximum crown radius. + + This scaling factor (:math:`r_0`) is derived from the canopy shape parameters + (:math:`m,n,q_m`) for plant functional types and the estimated crown area + (:math:`A_c`) of individuals. The shape parameters are defined as part of the + extension of the T Model presented by :cite:t:`joshi:2022a` and :math:`r_0` is used + to scale the crown area such that the crown area at the maximum crown radius fits + the expectations of the T Model. + + .. math:: + + r_0 = 1/q_m \sqrt{A_c / \pi} + + Args: + q_m: Canopy shape parameter of the PFT + crown_area: Crown area of individuals + """ + # Scaling factor to give expected A_c (crown area) at + # z_m (height of maximum crown radius) + + return 1 / q_m * np.sqrt(crown_area / np.pi) + + def calculate_relative_canopy_radii( z: float, height: NDArray[np.float32], From f1750a5401fdb8a939a45d01daf9b26a6703d69d Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 10 Sep 2024 19:52:08 +0100 Subject: [PATCH 079/241] Update T model and fix broken tests --- poetry.lock | 15 ++++++-------- pyproject.toml | 1 + pyrealm/demography/t_model_functions.py | 9 ++++----- tests/unit/demography/test_flora.py | 26 ++++++++++++------------- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/poetry.lock b/poetry.lock index aca832f9..7481dbd5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2394,20 +2394,17 @@ xml = ["lxml (>=4.9.2)"] [[package]] name = "pandas-stubs" -version = "2.2.2.240603" +version = "2.2.2.240909" description = "Type annotations for pandas" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "pandas_stubs-2.2.2.240603-py3-none-any.whl", hash = "sha256:e08ce7f602a4da2bff5a67475ba881c39f2a4d4f7fccc1cba57c6f35a379c6c0"}, - {file = "pandas_stubs-2.2.2.240603.tar.gz", hash = "sha256:2dcc86e8fa6ea41535a4561c1f08b3942ba5267b464eff2e99caeee66f9e4cd1"}, + {file = "pandas_stubs-2.2.2.240909-py3-none-any.whl", hash = "sha256:e230f5fa4065f9417804f4d65cd98f86c002efcc07933e8abcd48c3fad9c30a2"}, + {file = "pandas_stubs-2.2.2.240909.tar.gz", hash = "sha256:3c0951a2c3e45e3475aed9d80b7147ae82f176b9e42e9fb321cfdebf3d411b3d"}, ] [package.dependencies] -numpy = [ - {version = ">=1.23.5", markers = "python_version >= \"3.9\" and python_version < \"3.12\""}, - {version = ">=1.26.0", markers = "python_version >= \"3.12\" and python_version < \"3.13\""}, -] +numpy = ">=1.23.5" types-pytz = ">=2022.1.1" [[package]] @@ -4034,4 +4031,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = ">=3.10" -content-hash = "aef31655540ecd90f7e317fe133563bcfa68b2dadbd711cb61389563fd57e555" +content-hash = "027e109eac2546ede7c68a77c56cf5a02a961c8893771d6a6d6545a1fbcd6f96" diff --git a/pyproject.toml b/pyproject.toml index a170c766..2823f7cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ tabulate = "^0.8.10" marshmallow = "^3.22.0" pandas = "^2.2.2" marshmallow-dataclass = "^8.7.0" +pandas-stubs = "^2.2.2.240909" [tool.poetry.group.types.dependencies] pandas-stubs = "^2.2.0.240218" types-tabulate = "^0.9.0.0" diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index fb0e7a13..607d1892 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -6,7 +6,6 @@ """ # noqa: D205 import numpy as np -from numpy.typing import NDArray from pandas import Series @@ -229,10 +228,10 @@ def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: def calculate_relative_canopy_radii( z: float, - height: NDArray[np.float32], - m: NDArray[np.float32], - n: NDArray[np.float32], -) -> NDArray[np.float32]: + height: Series, + m: Series, + n: Series, +) -> Series: """Calculate q(z) at a given height, z.""" z_over_height = z / height diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index e921a131..ad975788 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -57,8 +57,8 @@ def test_PlantFunctionalTypeStrict__init__(args, outcome): from pyrealm.demography.flora import ( PlantFunctionalTypeStrict, - calculate_q_m, - calculate_z_max_proportion, + calculate_canopy_q_m, + calculate_canopy_z_max_proportion, ) with outcome: @@ -68,8 +68,8 @@ def test_PlantFunctionalTypeStrict__init__(args, outcome): if isinstance(outcome, does_not_raise): assert pft.name == "broadleaf" # Expected values from defaults - assert pft.q_m == calculate_q_m(m=2, n=5) - assert pft.z_max_prop == calculate_z_max_proportion(m=2, n=5) + assert pft.q_m == calculate_canopy_q_m(m=2, n=5) + assert pft.z_max_prop == calculate_canopy_z_max_proportion(m=2, n=5) # @@ -89,8 +89,8 @@ def test_PlantFunctionalType__init__(args, outcome): from pyrealm.demography.flora import ( PlantFunctionalType, - calculate_q_m, - calculate_z_max_proportion, + calculate_canopy_q_m, + calculate_canopy_z_max_proportion, ) with outcome: @@ -100,8 +100,8 @@ def test_PlantFunctionalType__init__(args, outcome): if isinstance(outcome, does_not_raise): assert pft.name == "broadleaf" # Expected values from defaults - assert pft.q_m == calculate_q_m(m=2, n=5) - assert pft.z_max_prop == calculate_z_max_proportion(m=2, n=5) + assert pft.q_m == calculate_canopy_q_m(m=2, n=5) + assert pft.z_max_prop == calculate_canopy_z_max_proportion(m=2, n=5) # @@ -180,7 +180,7 @@ def test_Flora__init__(flora_inputs, outcome): assert isinstance(flora.data, pd.DataFrame) assert flora.data.shape == ( len(flora_inputs), - len(fields(list(flora.values())[0])), + len(fields(next(iter(flora.values())))), ) @@ -279,9 +279,9 @@ def test_flora_from_csv(filename, outcome): def test_calculate_q_m(m, n, q_m): """Test calculation of q_m.""" - from pyrealm.demography.flora import calculate_q_m + from pyrealm.demography.flora import calculate_canopy_q_m - calculated_q_m = calculate_q_m(m, n) + calculated_q_m = calculate_canopy_q_m(m, n) assert calculated_q_m == pytest.approx(q_m) @@ -302,7 +302,7 @@ def test_calculate_q_m_values_raises_exception_for_invalid_input(): def test_calculate_z_max_ratio(m, n, z_max_ratio): """Test calculation of z_max proportion.""" - from pyrealm.demography.flora import calculate_z_max_proportion + from pyrealm.demography.flora import calculate_canopy_z_max_proportion - calculated_zmr = calculate_z_max_proportion(m, n) + calculated_zmr = calculate_canopy_z_max_proportion(m, n) assert calculated_zmr == pytest.approx(z_max_ratio) From 7305b474f1cca60e084c58a26141b0edbcb17226 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 10 Sep 2024 20:04:48 +0100 Subject: [PATCH 080/241] T Model docstring updates --- pyrealm/demography/t_model_functions.py | 30 ++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 607d1892..9c2fd903 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -85,7 +85,7 @@ def calculate_stem_masses(rho_s: Series, height: Series, dbh: Series) -> Series: .. math:: - (\pi / 8) \rho_s D^2 H + W_s = (\pi / 8) \rho_s D^2 H Args: rho_s: Wood density of the PFT @@ -164,10 +164,14 @@ def calculate_canopy_q_m(m: float, n: float) -> float: def calculate_canopy_z_max_proportion(m: float, n: float) -> float: - """Calculate the z_m proportion. + r"""Calculate the z_m proportion. - The z_m proportion is the constant proportion of stem height at which the maximum - crown radius is found for a given plant functional type. + The z_m proportion (:math:`p_{zm}`) is the constant proportion of stem height at + which the maximum crown radius is found for a given plant functional type. + + .. math:: + + p_{zm} = \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}} Args: m: Canopy shape parameter @@ -232,7 +236,23 @@ def calculate_relative_canopy_radii( m: Series, n: Series, ) -> Series: - """Calculate q(z) at a given height, z.""" + r"""Calculate relative canopy radius at a given height. + + The canopy shape parameters ``m`` and ``n`` define the vertical distribution of + canopy along the stem. For a stem of a given total height, this function calculates + the relative canopy radius at a given height :math:`z`: + + .. math:: + + q(z) = m n \left(\dfrac{z}{H}\right) ^ {n -1} + \left( 1 - \left(\dfrac{z}{H}\right) ^ n \right)^{m-1} + + Args: + z: Height at which to calculate relative radius + height: Total height of individual stem + m: Canopy shape parameter of PFT + n: Canopy shape parameter of PFT + """ z_over_height = z / height From 20873671275226aa9d612a3e30e8a7ee77d40d99 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 11 Sep 2024 12:57:14 +0100 Subject: [PATCH 081/241] Explicit testing of exception messages in community data validation --- pyrealm/demography/community.py | 109 +++++++++++++++++++++++- tests/unit/demography/test_community.py | 87 +++++++++++++++++++ 2 files changed, 193 insertions(+), 3 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 45363662..780edac6 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -5,12 +5,12 @@ # import json # import sys from dataclasses import InitVar, dataclass, field +from typing import Any -# import marshmallow_dataclass import numpy as np import pandas as pd - -# from marshmallow.exceptions import ValidationError +from marshmallow import Schema, fields, validates_schema +from marshmallow.exceptions import ValidationError from numpy.typing import NDArray from pyrealm.demography import t_model_functions as t_model @@ -24,6 +24,39 @@ # from tomli import TOMLDecodeError +class CommunitySchema(Schema): + """A validation schema for community initialisation data. + + This schema can be used to validate the data being used to create a Community + instance via one of the factory methods. It does not validate the Flora argument, + which is loaded and validated separately. + """ + + cell_id = fields.Integer(required=True) + cell_area = fields.Float(required=True) + cohort_dbh_values = fields.List(fields.Float(), required=True) + cohort_n_individuals = fields.List(fields.Integer(), required=True) + cohort_pft_names = fields.List(fields.Str(), required=True) + + @validates_schema + def validate_array_lengths(self, data: dict, **kwargs: Any) -> None: + """Schema wide validation. + + This checks that the cohort data arrays are of equal length. + + Args: + data: Data passed to the validator + kwargs: Additional keyword arguments passed by marshmallow + """ + + len_dbh = len(data["cohort_dbh_values"]) + len_n = len(data["cohort_n_individuals"]) + len_pft = len(data["cohort_pft_names"]) + + if not ((len_dbh == len_n) and (len_dbh == len_pft)): + raise ValidationError("Cohort arrays of unequal length.") + + @dataclass class Community: """Class containing properties of a community. @@ -168,6 +201,76 @@ def _calculate_t_model(self) -> None: crown_area=self.cohort_data["crown_area"], ) + @classmethod + def _from_file_data(cls, flora: Flora, file_data: dict) -> Community: + """Create a Flora object from a JSON string. + + Args: + flora: The Flora instance to be used with the community + file_data: The payload from a data file defining plant functional types. + """ + + # Validate the input data against the schema. + try: + community_data = CommunitySchema().load(data=file_data) # type: ignore[attr-defined] + except ValidationError as excep: + raise excep + + # Pass validated data into class instance + return cls( + cell_id=community_data["cell_id"], + cell_area=community_data["cell_area"], + cohort_dbh_values=np.array(community_data["cohort_dbh_values"]), + cohort_n_individuals=np.array(community_data["cohort_n_individuals"]), + cohort_pft_names=np.array(community_data["cohort_pft_names"]), + flora=flora, + ) + + # @classmethod + # def from_json(cls, path: Path) -> Flora: + # """Create a Flora object from a JSON file. + + # Args: + # path: A path to a JSON file of plant functional type definitions. + # """ + + # try: + # file_data = json.load(open(path)) + # except (FileNotFoundError, json.JSONDecodeError) as excep: + # raise excep + + # return cls._from_file_data(file_data=file_data) + + # @classmethod + # def from_toml(cls, path: Path) -> Flora: + # """Create a Flora object from a TOML file. + + # Args: + # path: A path to a TOML file of plant functional type definitions. + # """ + + # try: + # file_data = tomllib.load(open(path, "rb")) + # except (FileNotFoundError, TOMLDecodeError) as excep: + # raise excep + + # return cls._from_file_data(file_data) + + # @classmethod + # def from_csv(cls, path: Path) -> Flora: + # """Create a Flora object from a CSV file. + + # Args: + # path: A path to a CSV file of plant functional type definitions. + # """ + + # try: + # data = pd.read_csv(path) + # except (FileNotFoundError, pd.errors.ParserError) as excep: + # raise excep + + # return cls._from_file_data({"pft": data.to_dict(orient="records")}) + # @classmethod # def load_communities_from_csv( # cls, cell_area: float, csv_path: str, flora: Flora diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index a1e9d861..8fad5bf6 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -4,6 +4,7 @@ import numpy as np import pytest +from marshmallow.exceptions import ValidationError @pytest.fixture @@ -74,9 +75,95 @@ def test_Community_initialisation( ) if isinstance(outcome, does_not_raise): + # TODO - test something here assert community +@pytest.mark.parametrize( + argnames="file_data,outcome,excep_message", + argvalues=[ + pytest.param( + { + "cell_id": 1, + "cell_area": 100, + "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), + "cohort_n_individuals": np.array([2, 10, 3]), + "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + }, + does_not_raise(), + None, + id="correct_numpy_arrays", + ), + pytest.param( + { + "cell_id": 1, + "cell_area": 100, + "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], + "cohort_n_individuals": [2, 10, 3], + "cohort_dbh_values": [0.2, 0.1, 0.2], + }, + does_not_raise(), + None, + id="correct_list", + ), + pytest.param( + { + "cell_id": 1, + "cell_area": 100, + "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], + "cohort_n_individuals": [2], + "cohort_dbh_values": [0.2, 0.1, 0.2], + }, + pytest.raises(ValidationError), + {"_schema": ["Cohort arrays of unequal length."]}, + id="unequal_cohort_arrays", + ), + pytest.param( + { + "cell_area": 100, + "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], + "cohort_n_individuals": [2, 10, 3], + "cohort_dbh_values": [0.2, 0.1, 0.2], + }, + pytest.raises(ValidationError), + {"cell_id": ["Missing data for required field."]}, + id="missing_field", + ), + pytest.param( + { + "cell_id": 1, + "cell_area": 100, + "cell_elevation": 100, + "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], + "cohort_n_individuals": [2, 10, 3], + "cohort_dbh_values": [0.2, 0.1, 0.2], + }, + pytest.raises(ValidationError), + {"cell_elevation": ["Unknown field."]}, + id="extra_field", + ), + ], +) +def test_Community__from_file_data(fixture_flora, file_data, outcome, excep_message): + """Test happy path for initialisation. + + Test that when a new community object is instantiated, it contains the expected + properties. + """ + + from pyrealm.demography.community import Community + + with outcome as excep: + community = Community._from_file_data(flora=fixture_flora, file_data=file_data) + + if isinstance(outcome, does_not_raise): + # TODO - test something here + assert community + return + + assert excep.value.messages == excep_message + + def test_import_from_csv(): """Test that a community can be successfully imported from a csv.""" pass From 7fb901f122fef1c87baa56ac7980952fc05ef909 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 11 Sep 2024 14:13:06 +0100 Subject: [PATCH 082/241] Implementation of Community.from_csv and testing --- pyrealm/demography/community.py | 73 +++++++++++---- tests/unit/demography/test_community.py | 112 +++++++++++++++++++++++- 2 files changed, 165 insertions(+), 20 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 780edac6..4729cda6 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -2,9 +2,11 @@ from __future__ import annotations +from dataclasses import InitVar, dataclass, field + # import json # import sys -from dataclasses import InitVar, dataclass, field +from pathlib import Path from typing import Any import numpy as np @@ -32,10 +34,10 @@ class CommunitySchema(Schema): which is loaded and validated separately. """ - cell_id = fields.Integer(required=True) + cell_id = fields.Integer(required=True, strict=True) cell_area = fields.Float(required=True) cohort_dbh_values = fields.List(fields.Float(), required=True) - cohort_n_individuals = fields.List(fields.Integer(), required=True) + cohort_n_individuals = fields.List(fields.Integer(strict=True), required=True) cohort_pft_names = fields.List(fields.Str(), required=True) @validates_schema @@ -226,6 +228,56 @@ def _from_file_data(cls, flora: Flora, file_data: dict) -> Community: flora=flora, ) + @classmethod + def from_csv(cls, path: Path, flora: Flora) -> Community: + """Create a Community object from a CSV file. + + This factory method checks that the required fields are present in the CSV data + and that the cell_id and cell_area values are constant. It then passes the data + through further validation using the + `meth`:`~pyrealm.demography.community.Community._from_file_data` method and + returns a Community instance. + + Args: + path: A path to a CSV file of community data + flora: A Flora instance providing plant functional types used in the + community data + """ + + # Load the data + try: + community_data = pd.read_csv(path) + except (FileNotFoundError, pd.errors.ParserError) as excep: + raise excep + + # Check required fields are present + required_fields = set(CommunitySchema().fields.keys()) + missing_fields = required_fields.difference(community_data.columns) + if missing_fields: + raise ValueError( + f"Missing fields in community data: {','.join(missing_fields)}" + ) + + # Check cell area and cell id consistent + if not all(community_data["cell_id"] == community_data["cell_id"][0]): + raise ValueError( + "Multiple cell id values fields in community data, see load_communities" + ) + + if not all(community_data["cell_area"] == community_data["cell_area"][0]): + raise ValueError("Cell area varies in community data") + + return cls._from_file_data( + file_data=dict( + cell_id=community_data["cell_id"][0], + cell_area=community_data["cell_area"][0], + cohort_dbh_values=np.array(community_data["cohort_dbh_values"]), + cohort_n_individuals=np.array(community_data["cohort_n_individuals"]), + cohort_pft_names=np.array(community_data["cohort_pft_names"]), + ), + flora=flora, + ) + # @classmethod # def from_json(cls, path: Path) -> Flora: # """Create a Flora object from a JSON file. @@ -256,21 +308,6 @@ def _from_file_data(cls, flora: Flora, file_data: dict) -> Community: # return cls._from_file_data(file_data) - # @classmethod - # def from_csv(cls, path: Path) -> Flora: - # """Create a Flora object from a CSV file. - - # Args: - # path: A path to a CSV file of plant functional type definitions. - # """ - - # try: - # data = pd.read_csv(path) - # except (FileNotFoundError, pd.errors.ParserError) as excep: - # raise excep - - # return cls._from_file_data({"pft": data.to_dict(orient="records")}) - # @classmethod # def load_communities_from_csv( # cls, cell_area: float, csv_path: str, flora: Flora diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index 8fad5bf6..d90acc6d 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -142,6 +142,42 @@ def test_Community_initialisation( {"cell_elevation": ["Unknown field."]}, id="extra_field", ), + pytest.param( + { + "cell_id": 1, + "cell_area": "a", + "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], + "cohort_n_individuals": [2, 10, 3], + "cohort_dbh_values": [0.2, 0.1, 0.2], + }, + pytest.raises(ValidationError), + {"cell_area": ["Not a valid number."]}, + id="wrong_type_in_simple_field", + ), + pytest.param( + { + "cell_id": 1, + "cell_area": 100, + "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], + "cohort_n_individuals": [2, 10.2, 3], + "cohort_dbh_values": [0.2, 0.1, 0.2], + }, + pytest.raises(ValidationError), + {"cohort_n_individuals": {1: ["Not a valid integer."]}}, + id="float_in_n_individuals", + ), + pytest.param( + { + "cell_id": 1, + "cell_area": 100, + "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], + "cohort_n_individuals": [2, 10, 3], + "cohort_dbh_values": [0.2, "a", 0.2], + }, + pytest.raises(ValidationError), + {"cohort_dbh_values": {1: ["Not a valid number."]}}, + id="float_in_n_individuals", + ), ], ) def test_Community__from_file_data(fixture_flora, file_data, outcome, excep_message): @@ -161,9 +197,81 @@ def test_Community__from_file_data(fixture_flora, file_data, outcome, excep_mess assert community return + # Note that value.messages is an extension provided by marshmallow.ValidationError assert excep.value.messages == excep_message -def test_import_from_csv(): +@pytest.mark.parametrize( + argnames="file_data,outcome,excep_message", + argvalues=[ + pytest.param( + """cell_id,cell_area,cohort_pft_names,cohort_dbh_values,cohort_n_individuals +1,100,broadleaf,0.2,6 +1,100,broadleaf,0.25,6 +1,100,broadleaf,0.3,3 +1,100,broadleaf,0.35,1 +1,100,conifer,0.5,1 +1,100,conifer,0.6,1 +""", + does_not_raise(), + None, + id="correct", + ), + pytest.param( + """cell_id,cell_elevation,cohort_pft_names,cohort_dbh_values,cohort_n_individuals +1,100,broadleaf,0.2,6 +1,100,broadleaf,0.25,6 +1,100,broadleaf,0.3,3 +1,100,broadleaf,0.35,1 +1,100,conifer,0.5,1 +1,100,conifer,0.6,1 +""", + pytest.raises(ValueError), + "Missing fields in community data: cell_area", + id="missing_field", + ), + pytest.param( + """cell_id,cell_area,cohort_pft_names,cohort_dbh_values,cohort_n_individuals +1,100,broadleaf,0.2,6 +1,100,broadleaf,0.25,6 +1,100,broadleaf,0.3,3 +1,100,broadleaf,0.35,1 +11,100,conifer,0.5,1 +1,100,conifer,0.6,1 +""", + pytest.raises(ValueError), + "Multiple cell id values fields in community data, see load_communities", + id="not_just_one_cell_id", + ), + pytest.param( + """cell_id,cell_area,cohort_pft_names,cohort_dbh_values,cohort_n_individuals +1,100,broadleaf,0.2,6 +1,100,broadleaf,0.25,6 +1,100,broadleaf,0.3,3 +1,100,broadleaf,0.35,1 +1,200,conifer,0.5,1 +1,100,conifer,0.6,1 +""", + pytest.raises(ValueError), + "Cell area varies in community data", + id="not_just_one_cell_area", + ), + ], +) +def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_message): """Test that a community can be successfully imported from a csv.""" - pass + + from pyrealm.demography.community import Community + + temp_file = tmp_path / "data.csv" + temp_file.write_text(file_data, encoding="utf-8") + + with outcome as excep: + community = Community.from_csv(path=temp_file, flora=fixture_flora) + + if isinstance(outcome, does_not_raise): + # TODO - test something here + assert community + return + + assert str(excep.value) == excep_message From c6a186e45a4cc7b6e36148a1ab0146ee28d9de28 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 12 Sep 2024 15:31:33 +0100 Subject: [PATCH 083/241] Firming up community serialisation formats, more direct factory methods with different marshmallow schemas --- pyrealm/demography/community.py | 354 +++++++++++++++----- pyrealm_build_data/community/community.json | 36 +- pyrealm_build_data/community/community.toml | 36 +- tests/unit/demography/test_community.py | 284 ++++++++++------ 4 files changed, 475 insertions(+), 235 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 4729cda6..9ee7a0bd 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -1,29 +1,40 @@ -"""Contains a class representing properties of a community.""" +"""This modules provides the Community class, which contains the set of size-structured +cohorts of plants across a range of plant functional types that occur a given location +(or 'cell') with a given cell id number and area. + +The class provides factory methods to create Community instances from CSV, JSON and TOML +files, using :mod:`marshmallow` schemas to both validate the input data and to perform +post processing to align the input formats to the initialisation arguments to the +Community class. + +Internally, the cohort data in the Community class is represented as a pandas dataframe, +which makes it possible to update cohort attributes in parallel across all cohorts but +also provide a clean interface for adding and removing cohorts to a Community. +""" # noqa: D205 from __future__ import annotations +import json +import sys from dataclasses import InitVar, dataclass, field - -# import json -# import sys from pathlib import Path from typing import Any import numpy as np import pandas as pd -from marshmallow import Schema, fields, validates_schema +from marshmallow import Schema, fields, post_load, validates_schema from marshmallow.exceptions import ValidationError from numpy.typing import NDArray from pyrealm.demography import t_model_functions as t_model from pyrealm.demography.flora import Flora -# if sys.version_info[:2] >= (3, 11): -# import tomllib -# from tomllib import TOMLDecodeError -# else: -# import tomli as tomllib -# from tomli import TOMLDecodeError +if sys.version_info[:2] >= (3, 11): + import tomllib + from tomllib import TOMLDecodeError +else: + import tomli as tomllib + from tomli import TOMLDecodeError class CommunitySchema(Schema): @@ -59,6 +70,164 @@ def validate_array_lengths(self, data: dict, **kwargs: Any) -> None: raise ValidationError("Cohort arrays of unequal length.") +class CohortSchema(Schema): + """A validation schema for Cohort data. + + This schema can be used to validate the ``cohorts`` components of JSON and TOML + community data files. + """ + + dbh_value = fields.Float(required=True) + n_individuals = fields.Integer(strict=True, required=True) + pft_name = fields.Str(required=True) + + +class CommunityStructuredDataSchema(Schema): + """A validation schema for Cohort data in a structured format (JSON/TOML). + + This schema can be used to validate data for creating a Community instance stored in + a structured format such as JSON or TOML. The format is expected to provide a cell + area and id along with an array of cohort objects providing the plant functional + type name, diameter at breast height (DBH) and number of individuals (see + :class:`~pyrealm.demography.community.CohortSchema`). Example inputs with this + structure are: + + .. code-block:: toml + :caption: TOML + + cell_area = 100 + cell_id = 1 + + [[cohorts]] + dbh_value = 0.2 + n_individuals = 6 + pft_name = "broadleaf" + + [[cohorts]] + dbh_value = 0.25 + n_individuals = 6 + pft_name = "conifer" + + .. code-block:: json + :caption: JSON + + { + "cell_id": 1, + "cell_area": 100, + "cohorts": [ + { + "pft_name": "broadleaf", + "dbh_value": 0.2, + "n_individuals": 6 + }, + { + "pft_name": "broadleaf", + "dbh_value": 0.25, + "n_individuals": 6 + }] + } + + Any data validated with this schema is post-processed to convert the cohort objects + into the arrays of cohort data required to initialise instances of the + :class:`~pyrealm.demography.community.Community` class. + """ + + cell_id = fields.Integer(required=True, strict=True) + cell_area = fields.Float(required=True) + cohorts = fields.List(fields.Nested(CohortSchema), required=True) + + @post_load + def cohort_objects_to_arrays(self, data: dict, **kwargs: Any) -> dict: + """Convert cohorts to arrays. + + This post load method converts the cohort objects into arrays, which is the + format used to initialise a Community object. + + Args: + data: Data passed to the validator + kwargs: Additional keyword arguments passed by marshmallow + """ + + data["cohort_dbh_values"] = np.array([c["dbh_value"] for c in data["cohorts"]]) + data["cohort_n_individuals"] = np.array( + [c["n_individuals"] for c in data["cohorts"]] + ) + data["cohort_pft_names"] = np.array([c["pft_name"] for c in data["cohorts"]]) + + del data["cohorts"] + + return data + + +class CommunityCSVDataSchema(Schema): + """A validation schema for community initialisation data in CSV format. + + This schema can be used to validate data for creating a Community instance stored in + CSV format. The file is expected to provide fields providing cell id and cell area + and then functional type name, diameter at breast height (DBH) and number of + individuals. Each row is taken to represent a cohort and the cell id and area + *must** be consistent across rows. + + .. code-block:: csv + cell_id,cell_area,cohort_pft_names,cohort_dbh_values,cohort_n_individuals + 1,100,broadleaf,0.2,6 + 1,100,broadleaf,0.25,6 + 1,100,broadleaf,0.3,3 + 1,100,broadleaf,0.35,1 + 1,100,conifer,0.5,1 + 1,100,conifer,0.6,1 + + The input data is expected to be converted to a dictionary of lists, representing + the field, as for example by using :meth:`~pd.DataFrame.to_dict('list')`. + + The schema automatically validates that the cell id and area are consistent and then + post-processing is used to simplify those fields to the scalar inputs required to + initialise instances of the :class:`~pyrealm.demography.community.Community` class + and to convert the cohort data into arrays, + """ + + cell_id = fields.List(fields.Integer(strict=True), required=True) + cell_area = fields.List(fields.Float(), required=True) + cohort_dbh_values = fields.List(fields.Float(), required=True) + cohort_n_individuals = fields.List(fields.Integer(strict=True), required=True) + cohort_pft_names = fields.List(fields.Str(), required=True) + + @validates_schema + def validate_consistent_cell_data(self, data: dict, **kwargs: Any) -> None: + """Schema wide validation. + + Args: + data: Data passed to the validator + kwargs: Additional keyword arguments passed by marshmallow + """ + + # Check cell area and cell id consistent + if not all([c == data["cell_id"][0] for c in data["cell_id"]]): + raise ValueError( + "Multiple cell id values fields in community data, see load_communities" + ) + + if not all([c == data["cell_area"][0] for c in data["cell_area"]]): + raise ValueError("Cell area varies in community data") + + @post_load + def make_cell_data_scalar(self, data: dict, **kwargs: Any) -> dict: + """Make cell data scalar. + + This post load method reduces the repeated cell id and cell area across CSV data + rows into the scalar inputs required to initialise a Community object. + """ + + data["cell_id"] = data["cell_id"][0] + data["cell_area"] = data["cell_area"][0] + + data["cohort_dbh_values"] = np.array(data["cohort_dbh_values"]) + data["cohort_n_individuals"] = np.array(data["cohort_n_individuals"]) + data["cohort_pft_names"] = np.array(data["cohort_pft_names"]) + + return data + + @dataclass class Community: """Class containing properties of a community. @@ -107,26 +276,41 @@ def __post_init__( cohort_n_individuals: NDArray[np.int_], cohort_pft_names: NDArray[np.str_], ) -> None: - """Populate derived community attributes. + """Validate inputs and populate derived community attributes. The ``__post_init__`` builds a pandas dataframe of PFT values and T model - predictions across the initial cohort data. + predictions across the validated initial cohort data. """ - # Check the initial PFT values are known - unknown_pfts = set(cohort_pft_names).difference(self.flora.keys()) + # Check cell area and cell id + if not (isinstance(self.cell_area, float | int) and self.cell_area > 0): + raise ValueError("Community cell area must be a positive number.") - if unknown_pfts: - raise ValueError( - f"Plant functional types unknown in flora: {','.join(unknown_pfts)}" - ) + if not (isinstance(self.cell_id, int) and self.cell_id >= 0): + raise ValueError("Community cell id must be a integer >= 0.") + + # Check cohort data types + if not ( + isinstance(cohort_dbh_values, np.ndarray) + and isinstance(cohort_n_individuals, np.ndarray) + and isinstance(cohort_pft_names, np.ndarray) + ): + raise ValueError("Cohort data not passed as numpy arrays.") # Check the cohort inputs are of equal length if not ( (cohort_dbh_values.shape == cohort_n_individuals.shape) and (cohort_dbh_values.shape == cohort_pft_names.shape) ): - raise ValueError("Cohort data are not equally sized") + raise ValueError("Cohort arrays are of unequal length") + + # Check the initial PFT values are known + unknown_pfts = set(cohort_pft_names).difference(self.flora.keys()) + + if unknown_pfts: + raise ValueError( + f"Plant functional types unknown in flora: {','.join(unknown_pfts)}" + ) # Convert to a dataframe cohort_data = pd.DataFrame( @@ -203,31 +387,6 @@ def _calculate_t_model(self) -> None: crown_area=self.cohort_data["crown_area"], ) - @classmethod - def _from_file_data(cls, flora: Flora, file_data: dict) -> Community: - """Create a Flora object from a JSON string. - - Args: - flora: The Flora instance to be used with the community - file_data: The payload from a data file defining plant functional types. - """ - - # Validate the input data against the schema. - try: - community_data = CommunitySchema().load(data=file_data) # type: ignore[attr-defined] - except ValidationError as excep: - raise excep - - # Pass validated data into class instance - return cls( - cell_id=community_data["cell_id"], - cell_area=community_data["cell_area"], - cohort_dbh_values=np.array(community_data["cohort_dbh_values"]), - cohort_n_individuals=np.array(community_data["cohort_n_individuals"]), - cohort_pft_names=np.array(community_data["cohort_pft_names"]), - flora=flora, - ) - @classmethod def from_csv(cls, path: Path, flora: Flora) -> Community: """Create a Community object from a CSV file. @@ -246,67 +405,78 @@ def from_csv(cls, path: Path, flora: Flora) -> Community: # Load the data try: - community_data = pd.read_csv(path) + file_data = pd.read_csv(path) except (FileNotFoundError, pd.errors.ParserError) as excep: raise excep - # Check required fields are present - required_fields = set(CommunitySchema().fields.keys()) - missing_fields = required_fields.difference(community_data.columns) - if missing_fields: - raise ValueError( - f"Missing fields in community data: {','.join(missing_fields)}" - ) + # Validate the data - there is an inconsequential typing issue here: + # Argument "data" to "load" of "Schema" has incompatible type + # "dict[Hashable, Any]"; + # expected "Mapping[str, Any] | Iterable[Mapping[str, Any]]" + try: + file_data = CommunityCSVDataSchema().load(data=file_data.to_dict("list")) # type: ignore[arg-type] + except ValidationError as excep: + raise excep - # Check cell area and cell id consistent - if not all(community_data["cell_id"] == community_data["cell_id"][0]): - raise ValueError( - "Multiple cell id values fields in community data, see load_communities" - ) + return cls(**file_data, flora=flora) - if not all(community_data["cell_area"] == community_data["cell_area"][0]): - raise ValueError("Cell area varies in community data") + @classmethod + def from_json(cls, path: Path, flora: Flora) -> Community: + """Create a Community object from a JSON file. - return cls._from_file_data( - file_data=dict( - cell_id=community_data["cell_id"][0], - cell_area=community_data["cell_area"][0], - cohort_dbh_values=np.array(community_data["cohort_dbh_values"]), - cohort_n_individuals=np.array(community_data["cohort_n_individuals"]), - cohort_pft_names=np.array(community_data["cohort_pft_names"]), - ), - flora=flora, - ) + This factory method loads community data from a JSON community file and + validates it using + `class`:`~pyrealm.demography.community.CommunityStructuredDataSchema` before + using the data to initialise a Community instance. - # @classmethod - # def from_json(cls, path: Path) -> Flora: - # """Create a Flora object from a JSON file. + Args: + path: A path to a JSON file of community data + flora: A Flora instance providing plant functional types used in the + community data + """ - # Args: - # path: A path to a JSON file of plant functional type definitions. - # """ + # Load the data + try: + file_data = json.load(open(path)) + except (FileNotFoundError, json.JSONDecodeError) as excep: + raise excep - # try: - # file_data = json.load(open(path)) - # except (FileNotFoundError, json.JSONDecodeError) as excep: - # raise excep + # Validate the data + try: + file_data = CommunityStructuredDataSchema().load(data=file_data) + except ValidationError as excep: + raise excep - # return cls._from_file_data(file_data=file_data) + return cls(**file_data, flora=flora) - # @classmethod - # def from_toml(cls, path: Path) -> Flora: - # """Create a Flora object from a TOML file. + @classmethod + def from_toml(cls, path: Path, flora: Flora) -> Community: + """Create a Community object from a TOML file. - # Args: - # path: A path to a TOML file of plant functional type definitions. - # """ + This factory method loads community data from a TOML community file and + validates it using + `class`:`~pyrealm.demography.community.CommunityStructuredDataSchema` before + using the data to initialise a Community instance. + + Args: + path: A path to a TOML file of community data + flora: A Flora instance providing plant functional types used in the + community data + """ + + # Load the data + try: + file_data = tomllib.load(open(path, "rb")) + except (FileNotFoundError, TOMLDecodeError) as excep: + raise excep - # try: - # file_data = tomllib.load(open(path, "rb")) - # except (FileNotFoundError, TOMLDecodeError) as excep: - # raise excep + # Validate the data + try: + file_data = CommunityStructuredDataSchema().load(data=file_data) + except ValidationError as excep: + raise excep - # return cls._from_file_data(file_data) + return cls(**file_data, flora=flora) # @classmethod # def load_communities_from_csv( diff --git a/pyrealm_build_data/community/community.json b/pyrealm_build_data/community/community.json index b2abc4b6..a7cf235a 100644 --- a/pyrealm_build_data/community/community.json +++ b/pyrealm_build_data/community/community.json @@ -3,34 +3,34 @@ "cell_area": 100, "cohorts": [ { - "pft_name": "test1", - "dbh": 0.2, - "number_of_members": 6 + "pft_name": "broadleaf", + "dbh_value": 0.2, + "n_individuals": 6 }, { - "pft_name": "test1", - "dbh": 0.25, - "number_of_members": 6 + "pft_name": "broadleaf", + "dbh_value": 0.25, + "n_individuals": 6 }, { - "pft_name": "test1", - "dbh": 0.3, - "number_of_members": 3 + "pft_name": "broadleaf", + "dbh_value": 0.3, + "n_individuals": 3 }, { - "pft_name": "test1", - "dbh": 0.35, - "number_of_members": 1 + "pft_name": "broadleaf", + "dbh_value": 0.35, + "n_individuals": 1 }, { - "pft_name": "test2", - "dbh": 0.5, - "number_of_members": 1 + "pft_name": "conifer", + "dbh_value": 0.5, + "n_individuals": 1 }, { - "pft_name": "test2", - "dbh": 0.6, - "number_of_members": 1 + "pft_name": "conifer", + "dbh_value": 0.6, + "n_individuals": 1 } ] } \ No newline at end of file diff --git a/pyrealm_build_data/community/community.toml b/pyrealm_build_data/community/community.toml index 383ccb05..7681abca 100644 --- a/pyrealm_build_data/community/community.toml +++ b/pyrealm_build_data/community/community.toml @@ -2,31 +2,31 @@ cell_area = 100 cell_id = 1 [[cohorts]] -dbh = 0.2 -number_of_members = 6 -pft_name = "test1" +dbh_value = 0.2 +n_individuals = 6 +pft_name = "broadleaf" [[cohorts]] -dbh = 0.25 -number_of_members = 6 -pft_name = "test1" +dbh_value = 0.25 +n_individuals = 6 +pft_name = "broadleaf" [[cohorts]] -dbh = 0.3 -number_of_members = 3 -pft_name = "test1" +dbh_value = 0.3 +n_individuals = 3 +pft_name = "broadleaf" [[cohorts]] -dbh = 0.35 -number_of_members = 1 -pft_name = "test1" +dbh_value = 0.35 +n_individuals = 1 +pft_name = "broadleaf" [[cohorts]] -dbh = 0.5 -number_of_members = 1 -pft_name = "test2" +dbh_value = 0.5 +n_individuals = 1 +pft_name = "conifer" [[cohorts]] -dbh = 0.6 -number_of_members = 1 -pft_name = "test2" +dbh_value = 0.6 +n_individuals = 1 +pft_name = "conifer" diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index d90acc6d..8815e80c 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -22,65 +22,7 @@ def fixture_flora(): @pytest.mark.parametrize( - argnames="cell_id,cell_area,cohort_pfts,cohort_dbh,cohort_n,outcome", - argvalues=[ - pytest.param( - 1, - 100, - np.array(["broadleaf", "broadleaf", "conifer"]), - np.array([0.2, 0.1, 0.2]), - np.array([2, 10, 3]), - does_not_raise(), - id="correct", - ), - pytest.param( - 1, - 100, - np.array(["broadleaf", "broadleaf", "juniper"]), - np.array([0.2, 0.1, 0.2]), - np.array([2, 10, 3]), - pytest.raises(ValueError), - id="unknown_pft", - ), - pytest.param( - 1, - 100, - np.array(["broadleaf", "broadleaf", "juniper"]), - np.array([0.2, 0.1, 0.2]), - np.array([2, 10, 3, 4]), - pytest.raises(ValueError), - id="unequal_cohort_data_lengths", - ), - ], -) -def test_Community_initialisation( - fixture_flora, cell_id, cell_area, cohort_pfts, cohort_dbh, cohort_n, outcome -): - """Test happy path for initialisation. - - Test that when a new community object is instantiated, it contains the expected - properties. - """ - - from pyrealm.demography.community import Community - - with outcome: - community = Community( - cell_id=cell_id, - cell_area=cell_area, - cohort_pft_names=cohort_pfts, - cohort_dbh_values=cohort_dbh, - cohort_n_individuals=cohort_n, - flora=fixture_flora, - ) - - if isinstance(outcome, does_not_raise): - # TODO - test something here - assert community - - -@pytest.mark.parametrize( - argnames="file_data,outcome,excep_message", + argnames="args,outcome,excep_message", argvalues=[ pytest.param( { @@ -92,7 +34,7 @@ def test_Community_initialisation( }, does_not_raise(), None, - id="correct_numpy_arrays", + id="correct", ), pytest.param( { @@ -102,86 +44,110 @@ def test_Community_initialisation( "cohort_n_individuals": [2, 10, 3], "cohort_dbh_values": [0.2, 0.1, 0.2], }, - does_not_raise(), - None, - id="correct_list", + pytest.raises(ValueError), + "Cohort data not passed as numpy arrays.", + id="lists_not_arrays", ), pytest.param( { "cell_id": 1, "cell_area": 100, - "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], - "cohort_n_individuals": [2], - "cohort_dbh_values": [0.2, 0.1, 0.2], + "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), + "cohort_n_individuals": np.array([2, 10]), + "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), }, - pytest.raises(ValidationError), - {"_schema": ["Cohort arrays of unequal length."]}, + pytest.raises(ValueError), + "Cohort arrays are of unequal length", id="unequal_cohort_arrays", ), pytest.param( { "cell_area": 100, - "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], - "cohort_n_individuals": [2, 10, 3], - "cohort_dbh_values": [0.2, 0.1, 0.2], + "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), + "cohort_n_individuals": np.array([2, 10, 3]), + "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), }, - pytest.raises(ValidationError), - {"cell_id": ["Missing data for required field."]}, - id="missing_field", + pytest.raises(TypeError), + "Community.__init__() missing 1 required positional argument: 'cell_id'", + id="missing_arg", ), pytest.param( { "cell_id": 1, "cell_area": 100, "cell_elevation": 100, - "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], - "cohort_n_individuals": [2, 10, 3], - "cohort_dbh_values": [0.2, 0.1, 0.2], + "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), + "cohort_n_individuals": np.array([2, 10, 3]), + "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), }, - pytest.raises(ValidationError), - {"cell_elevation": ["Unknown field."]}, - id="extra_field", + pytest.raises(TypeError), + "Community.__init__() got an unexpected keyword argument 'cell_elevation'", + id="extra_arg", ), pytest.param( { "cell_id": 1, - "cell_area": "a", - "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], - "cohort_n_individuals": [2, 10, 3], - "cohort_dbh_values": [0.2, 0.1, 0.2], + "cell_area": "100", + "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), + "cohort_n_individuals": np.array([2, 10]), + "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), }, - pytest.raises(ValidationError), - {"cell_area": ["Not a valid number."]}, - id="wrong_type_in_simple_field", + pytest.raises(ValueError), + "Community cell area must be a positive number.", + id="cell_area_as_string", ), pytest.param( { "cell_id": 1, + "cell_area": -100, + "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), + "cohort_n_individuals": np.array([2, 10, 3]), + "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + }, + pytest.raises(ValueError), + "Community cell area must be a positive number.", + id="cell_area_negative", + ), + pytest.param( + { + "cell_id": "1", "cell_area": 100, - "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], - "cohort_n_individuals": [2, 10.2, 3], - "cohort_dbh_values": [0.2, 0.1, 0.2], + "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), + "cohort_n_individuals": np.array([2, 10, 3]), + "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), }, - pytest.raises(ValidationError), - {"cohort_n_individuals": {1: ["Not a valid integer."]}}, - id="float_in_n_individuals", + pytest.raises(ValueError), + "Community cell id must be a integer >= 0.", + id="cell_id_as_string", + ), + pytest.param( + { + "cell_id": -1, + "cell_area": 100, + "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), + "cohort_n_individuals": np.array([2, 10, 3]), + "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + }, + pytest.raises(ValueError), + "Community cell id must be a integer >= 0.", + id="cell_id_negative", ), pytest.param( { "cell_id": 1, "cell_area": 100, - "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], - "cohort_n_individuals": [2, 10, 3], - "cohort_dbh_values": [0.2, "a", 0.2], + "cohort_pft_names": np.array(["broadleaf", "broadleaf", "juniper"]), + "cohort_n_individuals": np.array([2, 10, 3]), + "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), }, - pytest.raises(ValidationError), - {"cohort_dbh_values": {1: ["Not a valid number."]}}, - id="float_in_n_individuals", + pytest.raises(ValueError), + "Plant functional types unknown in flora: juniper", + id="unknown_pft", ), ], ) -def test_Community__from_file_data(fixture_flora, file_data, outcome, excep_message): - """Test happy path for initialisation. +def test_Community__init__(fixture_flora, args, outcome, excep_message): + """Test Community initialisation. Test that when a new community object is instantiated, it contains the expected properties. @@ -190,15 +156,15 @@ def test_Community__from_file_data(fixture_flora, file_data, outcome, excep_mess from pyrealm.demography.community import Community with outcome as excep: - community = Community._from_file_data(flora=fixture_flora, file_data=file_data) + community = Community(**args, flora=fixture_flora) if isinstance(outcome, does_not_raise): # TODO - test something here assert community return - # Note that value.messages is an extension provided by marshmallow.ValidationError - assert excep.value.messages == excep_message + # Check exception message + assert str(excep.value) == excep_message @pytest.mark.parametrize( @@ -226,9 +192,10 @@ def test_Community__from_file_data(fixture_flora, file_data, outcome, excep_mess 1,100,conifer,0.5,1 1,100,conifer,0.6,1 """, - pytest.raises(ValueError), - "Missing fields in community data: cell_area", - id="missing_field", + pytest.raises(ValidationError), + "{'cell_area': ['Missing data for required field.']," + " 'cell_elevation': ['Unknown field.']}", + id="mislabelled_field", ), pytest.param( """cell_id,cell_area,cohort_pft_names,cohort_dbh_values,cohort_n_individuals @@ -274,4 +241,107 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m assert community return + # Test exception explanation + assert str(excep.value) == excep_message + + +@pytest.mark.parametrize( + argnames="file_data,outcome,excep_message", + argvalues=[ + pytest.param( + """{"cell_id":1,"cell_area":100,"cohorts":[ + {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, + {"pft_name":"broadleaf","dbh_value":0.25,"n_individuals":6}, + {"pft_name":"broadleaf","dbh_value":0.3,"n_individuals":3}, + {"pft_name":"broadleaf","dbh_value":0.35,"n_individuals":1}, + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}, + {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + does_not_raise(), + None, + id="correct", + ), + ], +) +def test_Community_from_json( + tmp_path, fixture_flora, file_data, outcome, excep_message +): + """Test that a community can be successfully imported from JSON.""" + + from pyrealm.demography.community import Community + + temp_file = tmp_path / "data.json" + temp_file.write_text(file_data, encoding="utf-8") + + with outcome as excep: + community = Community.from_json(path=temp_file, flora=fixture_flora) + + if isinstance(outcome, does_not_raise): + # TODO - test something here + assert community + return + + assert str(excep.value) == excep_message + + +@pytest.mark.parametrize( + argnames="file_data,outcome,excep_message", + argvalues=[ + pytest.param( + """cell_area = 100 +cell_id = 1 + +[[cohorts]] +dbh_value = 0.2 +n_individuals = 6 +pft_name = "broadleaf" + +[[cohorts]] +dbh_value = 0.25 +n_individuals = 6 +pft_name = "broadleaf" + +[[cohorts]] +dbh_value = 0.3 +n_individuals = 3 +pft_name = "broadleaf" + +[[cohorts]] +dbh_value = 0.35 +n_individuals = 1 +pft_name = "broadleaf" + +[[cohorts]] +dbh_value = 0.5 +n_individuals = 1 +pft_name = "conifer" + +[[cohorts]] +dbh_value = 0.6 +n_individuals = 1 +pft_name = "conifer" +""", + does_not_raise(), + None, + id="correct", + ), + ], +) +def test_Community_from_toml( + tmp_path, fixture_flora, file_data, outcome, excep_message +): + """Test that a community can be successfully imported from JSON.""" + + from pyrealm.demography.community import Community + + temp_file = tmp_path / "data.toml" + temp_file.write_text(file_data, encoding="utf-8") + + with outcome as excep: + community = Community.from_toml(path=temp_file, flora=fixture_flora) + + if isinstance(outcome, does_not_raise): + # TODO - test something here + assert community + return + assert str(excep.value) == excep_message From a5f39dd1c589576ca0e7cd225c999ff3c5a10690 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 12 Sep 2024 15:57:00 +0100 Subject: [PATCH 084/241] Removing old marshmallow schema, firming up validation and testing --- pyrealm/demography/community.py | 53 +++++----------- tests/unit/demography/test_community.py | 84 +++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 44 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 9ee7a0bd..b7d8f417 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -22,7 +22,7 @@ import numpy as np import pandas as pd -from marshmallow import Schema, fields, post_load, validates_schema +from marshmallow import Schema, fields, post_load, validate, validates_schema from marshmallow.exceptions import ValidationError from numpy.typing import NDArray @@ -37,39 +37,6 @@ from tomli import TOMLDecodeError -class CommunitySchema(Schema): - """A validation schema for community initialisation data. - - This schema can be used to validate the data being used to create a Community - instance via one of the factory methods. It does not validate the Flora argument, - which is loaded and validated separately. - """ - - cell_id = fields.Integer(required=True, strict=True) - cell_area = fields.Float(required=True) - cohort_dbh_values = fields.List(fields.Float(), required=True) - cohort_n_individuals = fields.List(fields.Integer(strict=True), required=True) - cohort_pft_names = fields.List(fields.Str(), required=True) - - @validates_schema - def validate_array_lengths(self, data: dict, **kwargs: Any) -> None: - """Schema wide validation. - - This checks that the cohort data arrays are of equal length. - - Args: - data: Data passed to the validator - kwargs: Additional keyword arguments passed by marshmallow - """ - - len_dbh = len(data["cohort_dbh_values"]) - len_n = len(data["cohort_n_individuals"]) - len_pft = len(data["cohort_pft_names"]) - - if not ((len_dbh == len_n) and (len_dbh == len_pft)): - raise ValidationError("Cohort arrays of unequal length.") - - class CohortSchema(Schema): """A validation schema for Cohort data. @@ -77,8 +44,12 @@ class CohortSchema(Schema): community data files. """ - dbh_value = fields.Float(required=True) - n_individuals = fields.Integer(strict=True, required=True) + dbh_value = fields.Float( + required=True, validate=validate.Range(min=0, min_inclusive=False) + ) + n_individuals = fields.Integer( + strict=True, required=True, validate=validate.Range(min=0, min_inclusive=False) + ) pft_name = fields.Str(required=True) @@ -132,9 +103,13 @@ class CommunityStructuredDataSchema(Schema): :class:`~pyrealm.demography.community.Community` class. """ - cell_id = fields.Integer(required=True, strict=True) - cell_area = fields.Float(required=True) - cohorts = fields.List(fields.Nested(CohortSchema), required=True) + cell_id = fields.Integer(required=True, strict=True, validate=validate.Range(min=0)) + cell_area = fields.Float( + required=True, validate=validate.Range(min=0, min_inclusive=False) + ) + cohorts = fields.List( + fields.Nested(CohortSchema), required=True, validate=validate.Length(min=1) + ) @post_load def cohort_objects_to_arrays(self, data: dict, **kwargs: Any) -> dict: diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index 8815e80c..236cc29f 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -251,15 +251,89 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m pytest.param( """{"cell_id":1,"cell_area":100,"cohorts":[ {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, - {"pft_name":"broadleaf","dbh_value":0.25,"n_individuals":6}, - {"pft_name":"broadleaf","dbh_value":0.3,"n_individuals":3}, - {"pft_name":"broadleaf","dbh_value":0.35,"n_individuals":1}, - {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}, - {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}]}""", does_not_raise(), None, id="correct", ), + pytest.param( + """{"cell_id":1,"cohorts":[ + {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, + {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + pytest.raises(ValidationError), + "{'cell_area': ['Missing data for required field.']}", + id="missing_area", + ), + pytest.param( + """{"cell_id":1,"cell_area":"a","cohorts":[ + {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, + {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + pytest.raises(ValidationError), + "{'cell_area': ['Not a valid number.']}", + id="area_as_string", + ), + pytest.param( + """{"cell_id":1.2,"cell_area":100,"cohorts":[ + {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, + {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + pytest.raises(ValidationError), + "{'cell_id': ['Not a valid integer.']}", + id="id_as_float", + ), + pytest.param( + """{"cell_id":-1,"cell_area":100,"cohorts":[ + {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, + {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + pytest.raises(ValidationError), + "{'cell_id': ['Must be greater than or equal to 0.']}", + id="id_negative", + ), + pytest.param( + """{"cell_id":1,"cell_area":0,"cohorts":[ + {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, + {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + pytest.raises(ValidationError), + "{'cell_area': ['Must be greater than 0.']}", + id="area_zero", + ), + pytest.param( + """{"cell_id":1,"cell_area":100,"cohorts":[]}""", + pytest.raises(ValidationError), + "{'cohorts': ['Shorter than minimum length 1.']}", + id="no_cohorts", + ), + pytest.param( + """{"cell_id":1,"cell_area":100,"cohorts":[ + {"pft_name":1,"dbh_value":0.2,"n_individuals":6}, + {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + pytest.raises(ValidationError), + "{'cohorts': {0: {'pft_name': ['Not a valid string.']}}}", + id="bad_cohort_name", + ), + pytest.param( + """{"cell_id":1,"cell_area":100,"cohorts":[ + {"pft_name":"broadleaf","dbh_value":0,"n_individuals":6}, + {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + pytest.raises(ValidationError), + "{'cohorts': {0: {'dbh_value': ['Must be greater than 0.']}}}", + id="dbh_zero", + ), + pytest.param( + """{"cell_id":1,"cell_area":100,"cohorts":[ + {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6.1}, + {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + pytest.raises(ValidationError), + "{'cohorts': {0: {'n_individuals': ['Not a valid integer.']}}}", + id="individuals_float", + ), + pytest.param( + """{"cell_id":1,"cell_area":100,"cohorts":[ + {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":0}, + {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + pytest.raises(ValidationError), + "{'cohorts': {0: {'n_individuals': ['Must be greater than 0.']}}}", + id="individuals_less_than_one", + ), ], ) def test_Community_from_json( From 0b7fa05bc378eb73e1083a0fc596a2b2338432d0 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 12 Sep 2024 16:41:55 +0100 Subject: [PATCH 085/241] Simplified and aligned test inputs, added meaningful test of correct behaviour --- tests/unit/demography/test_community.py | 329 ++++++++++++++++++------ 1 file changed, 254 insertions(+), 75 deletions(-) diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index 236cc29f..76b661e8 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -21,6 +21,47 @@ def fixture_flora(): ) +@pytest.fixture +def fixture_expected(fixture_flora): + """Expected results for test data. + + This fixture simply calculates the expected results directly to check that the + Community instance maintains row order and calculation as expected. + """ + + from pyrealm.demography.t_model_functions import calculate_heights + + a_hd = np.array([fixture_flora["broadleaf"].a_hd, fixture_flora["conifer"].a_hd]) + h_max = np.array([fixture_flora["broadleaf"].h_max, fixture_flora["conifer"].h_max]) + n_indiv = np.array([6, 1]) + dbh = np.array([0.2, 0.5]) + + expected = { + "n_individuals": n_indiv, + "a_hd": a_hd, + "height": calculate_heights(a_hd=a_hd, h_max=h_max, dbh=dbh), + } + + return expected + + +def check_expected(community, expected): + """Helper function to provide simple check of returned community objects.""" + + assert np.allclose( + community.cohort_data["n_individuals"], + expected["n_individuals"], + ) + assert np.allclose( + community.cohort_data["a_hd"], + expected["a_hd"], + ) + assert np.allclose( + community.cohort_data["height"], + expected["height"], + ) + + @pytest.mark.parametrize( argnames="args,outcome,excep_message", argvalues=[ @@ -28,9 +69,9 @@ def fixture_flora(): { "cell_id": 1, "cell_area": 100, - "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), - "cohort_n_individuals": np.array([2, 10, 3]), - "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + "cohort_pft_names": np.array(["broadleaf", "conifer"]), + "cohort_n_individuals": np.array([6, 1]), + "cohort_dbh_values": np.array([0.2, 0.5]), }, does_not_raise(), None, @@ -40,9 +81,9 @@ def fixture_flora(): { "cell_id": 1, "cell_area": 100, - "cohort_pft_names": ["broadleaf", "broadleaf", "conifer"], - "cohort_n_individuals": [2, 10, 3], - "cohort_dbh_values": [0.2, 0.1, 0.2], + "cohort_pft_names": ["broadleaf", "conifer"], + "cohort_n_individuals": [6, 1], + "cohort_dbh_values": [0.2, 0.5], }, pytest.raises(ValueError), "Cohort data not passed as numpy arrays.", @@ -52,9 +93,9 @@ def fixture_flora(): { "cell_id": 1, "cell_area": 100, - "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), - "cohort_n_individuals": np.array([2, 10]), - "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + "cohort_pft_names": np.array(["broadleaf", "conifer"]), + "cohort_n_individuals": np.array([6, 1]), + "cohort_dbh_values": np.array([0.2, 0.5, 0.9]), }, pytest.raises(ValueError), "Cohort arrays are of unequal length", @@ -63,9 +104,9 @@ def fixture_flora(): pytest.param( { "cell_area": 100, - "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), - "cohort_n_individuals": np.array([2, 10, 3]), - "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + "cohort_pft_names": np.array(["broadleaf", "conifer"]), + "cohort_n_individuals": np.array([6, 1]), + "cohort_dbh_values": np.array([0.2, 0.5]), }, pytest.raises(TypeError), "Community.__init__() missing 1 required positional argument: 'cell_id'", @@ -76,9 +117,9 @@ def fixture_flora(): "cell_id": 1, "cell_area": 100, "cell_elevation": 100, - "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), - "cohort_n_individuals": np.array([2, 10, 3]), - "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + "cohort_pft_names": np.array(["broadleaf", "conifer"]), + "cohort_n_individuals": np.array([6, 1]), + "cohort_dbh_values": np.array([0.2, 0.5]), }, pytest.raises(TypeError), "Community.__init__() got an unexpected keyword argument 'cell_elevation'", @@ -88,9 +129,9 @@ def fixture_flora(): { "cell_id": 1, "cell_area": "100", - "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), - "cohort_n_individuals": np.array([2, 10]), - "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + "cohort_pft_names": np.array(["broadleaf", "conifer"]), + "cohort_n_individuals": np.array([6, 1]), + "cohort_dbh_values": np.array([0.2, 0.5]), }, pytest.raises(ValueError), "Community cell area must be a positive number.", @@ -100,9 +141,9 @@ def fixture_flora(): { "cell_id": 1, "cell_area": -100, - "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), - "cohort_n_individuals": np.array([2, 10, 3]), - "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + "cohort_pft_names": np.array(["broadleaf", "conifer"]), + "cohort_n_individuals": np.array([6, 1]), + "cohort_dbh_values": np.array([0.2, 0.5]), }, pytest.raises(ValueError), "Community cell area must be a positive number.", @@ -112,9 +153,9 @@ def fixture_flora(): { "cell_id": "1", "cell_area": 100, - "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), - "cohort_n_individuals": np.array([2, 10, 3]), - "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + "cohort_pft_names": np.array(["broadleaf", "conifer"]), + "cohort_n_individuals": np.array([6, 1]), + "cohort_dbh_values": np.array([0.2, 0.5]), }, pytest.raises(ValueError), "Community cell id must be a integer >= 0.", @@ -124,9 +165,9 @@ def fixture_flora(): { "cell_id": -1, "cell_area": 100, - "cohort_pft_names": np.array(["broadleaf", "broadleaf", "conifer"]), - "cohort_n_individuals": np.array([2, 10, 3]), - "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + "cohort_pft_names": np.array(["broadleaf", "conifer"]), + "cohort_n_individuals": np.array([6, 1]), + "cohort_dbh_values": np.array([0.2, 0.5]), }, pytest.raises(ValueError), "Community cell id must be a integer >= 0.", @@ -136,9 +177,9 @@ def fixture_flora(): { "cell_id": 1, "cell_area": 100, - "cohort_pft_names": np.array(["broadleaf", "broadleaf", "juniper"]), - "cohort_n_individuals": np.array([2, 10, 3]), - "cohort_dbh_values": np.array([0.2, 0.1, 0.2]), + "cohort_pft_names": np.array(["broadleaf", "juniper"]), + "cohort_n_individuals": np.array([6, 1]), + "cohort_dbh_values": np.array([0.2, 0.5]), }, pytest.raises(ValueError), "Plant functional types unknown in flora: juniper", @@ -146,7 +187,9 @@ def fixture_flora(): ), ], ) -def test_Community__init__(fixture_flora, args, outcome, excep_message): +def test_Community__init__( + fixture_flora, fixture_expected, args, outcome, excep_message +): """Test Community initialisation. Test that when a new community object is instantiated, it contains the expected @@ -159,8 +202,8 @@ def test_Community__init__(fixture_flora, args, outcome, excep_message): community = Community(**args, flora=fixture_flora) if isinstance(outcome, does_not_raise): - # TODO - test something here - assert community + # Simple test that data is loaded and trait and t model data calculated + check_expected(community=community, expected=fixture_expected) return # Check exception message @@ -173,11 +216,7 @@ def test_Community__init__(fixture_flora, args, outcome, excep_message): pytest.param( """cell_id,cell_area,cohort_pft_names,cohort_dbh_values,cohort_n_individuals 1,100,broadleaf,0.2,6 -1,100,broadleaf,0.25,6 -1,100,broadleaf,0.3,3 -1,100,broadleaf,0.35,1 1,100,conifer,0.5,1 -1,100,conifer,0.6,1 """, does_not_raise(), None, @@ -186,11 +225,7 @@ def test_Community__init__(fixture_flora, args, outcome, excep_message): pytest.param( """cell_id,cell_elevation,cohort_pft_names,cohort_dbh_values,cohort_n_individuals 1,100,broadleaf,0.2,6 -1,100,broadleaf,0.25,6 -1,100,broadleaf,0.3,3 -1,100,broadleaf,0.35,1 1,100,conifer,0.5,1 -1,100,conifer,0.6,1 """, pytest.raises(ValidationError), "{'cell_area': ['Missing data for required field.']," @@ -200,11 +235,7 @@ def test_Community__init__(fixture_flora, args, outcome, excep_message): pytest.param( """cell_id,cell_area,cohort_pft_names,cohort_dbh_values,cohort_n_individuals 1,100,broadleaf,0.2,6 -1,100,broadleaf,0.25,6 -1,100,broadleaf,0.3,3 -1,100,broadleaf,0.35,1 11,100,conifer,0.5,1 -1,100,conifer,0.6,1 """, pytest.raises(ValueError), "Multiple cell id values fields in community data, see load_communities", @@ -213,11 +244,7 @@ def test_Community__init__(fixture_flora, args, outcome, excep_message): pytest.param( """cell_id,cell_area,cohort_pft_names,cohort_dbh_values,cohort_n_individuals 1,100,broadleaf,0.2,6 -1,100,broadleaf,0.25,6 -1,100,broadleaf,0.3,3 -1,100,broadleaf,0.35,1 1,200,conifer,0.5,1 -1,100,conifer,0.6,1 """, pytest.raises(ValueError), "Cell area varies in community data", @@ -225,7 +252,9 @@ def test_Community__init__(fixture_flora, args, outcome, excep_message): ), ], ) -def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_message): +def test_Community_from_csv( + tmp_path, fixture_flora, fixture_expected, file_data, outcome, excep_message +): """Test that a community can be successfully imported from a csv.""" from pyrealm.demography.community import Community @@ -237,8 +266,8 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m community = Community.from_csv(path=temp_file, flora=fixture_flora) if isinstance(outcome, does_not_raise): - # TODO - test something here - assert community + # Simple test that data is loaded and trait and t model data calculated + check_expected(community=community, expected=fixture_expected) return # Test exception explanation @@ -259,7 +288,7 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m pytest.param( """{"cell_id":1,"cohorts":[ {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, - {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}]}""", pytest.raises(ValidationError), "{'cell_area': ['Missing data for required field.']}", id="missing_area", @@ -267,7 +296,7 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m pytest.param( """{"cell_id":1,"cell_area":"a","cohorts":[ {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, - {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}]}""", pytest.raises(ValidationError), "{'cell_area': ['Not a valid number.']}", id="area_as_string", @@ -275,7 +304,7 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m pytest.param( """{"cell_id":1.2,"cell_area":100,"cohorts":[ {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, - {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}]}""", pytest.raises(ValidationError), "{'cell_id': ['Not a valid integer.']}", id="id_as_float", @@ -283,7 +312,7 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m pytest.param( """{"cell_id":-1,"cell_area":100,"cohorts":[ {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, - {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}]}""", pytest.raises(ValidationError), "{'cell_id': ['Must be greater than or equal to 0.']}", id="id_negative", @@ -291,7 +320,7 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m pytest.param( """{"cell_id":1,"cell_area":0,"cohorts":[ {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6}, - {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}]}""", pytest.raises(ValidationError), "{'cell_area': ['Must be greater than 0.']}", id="area_zero", @@ -305,7 +334,7 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m pytest.param( """{"cell_id":1,"cell_area":100,"cohorts":[ {"pft_name":1,"dbh_value":0.2,"n_individuals":6}, - {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}]}""", pytest.raises(ValidationError), "{'cohorts': {0: {'pft_name': ['Not a valid string.']}}}", id="bad_cohort_name", @@ -313,7 +342,7 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m pytest.param( """{"cell_id":1,"cell_area":100,"cohorts":[ {"pft_name":"broadleaf","dbh_value":0,"n_individuals":6}, - {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}]}""", pytest.raises(ValidationError), "{'cohorts': {0: {'dbh_value': ['Must be greater than 0.']}}}", id="dbh_zero", @@ -321,7 +350,7 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m pytest.param( """{"cell_id":1,"cell_area":100,"cohorts":[ {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":6.1}, - {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}]}""", pytest.raises(ValidationError), "{'cohorts': {0: {'n_individuals': ['Not a valid integer.']}}}", id="individuals_float", @@ -329,7 +358,7 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m pytest.param( """{"cell_id":1,"cell_area":100,"cohorts":[ {"pft_name":"broadleaf","dbh_value":0.2,"n_individuals":0}, - {"pft_name":"conifer","dbh_value":0.6,"n_individuals":1}]}""", + {"pft_name":"conifer","dbh_value":0.5,"n_individuals":1}]}""", pytest.raises(ValidationError), "{'cohorts': {0: {'n_individuals': ['Must be greater than 0.']}}}", id="individuals_less_than_one", @@ -337,7 +366,7 @@ def test_Community_from_csv(tmp_path, fixture_flora, file_data, outcome, excep_m ], ) def test_Community_from_json( - tmp_path, fixture_flora, file_data, outcome, excep_message + tmp_path, fixture_flora, fixture_expected, file_data, outcome, excep_message ): """Test that a community can be successfully imported from JSON.""" @@ -350,8 +379,8 @@ def test_Community_from_json( community = Community.from_json(path=temp_file, flora=fixture_flora) if isinstance(outcome, does_not_raise): - # TODO - test something here - assert community + # Simple test that data is loaded and trait and t model data calculated + check_expected(community=community, expected=fixture_expected) return assert str(excep.value) == excep_message @@ -370,38 +399,188 @@ def test_Community_from_json( pft_name = "broadleaf" [[cohorts]] -dbh_value = 0.25 +dbh_value = 0.5 +n_individuals = 1 +pft_name = "conifer" +""", + does_not_raise(), + None, + id="correct", + ), + pytest.param( + """cell_id = 1 + +[[cohorts]] +dbh_value = 0.2 n_individuals = 6 pft_name = "broadleaf" [[cohorts]] -dbh_value = 0.3 -n_individuals = 3 +dbh_value = 0.5 +n_individuals = 1 +pft_name = "conifer" +""", + pytest.raises(ValidationError), + "{'cell_area': ['Missing data for required field.']}", + id="missing_area", + ), + pytest.param( + """cell_area = "a" +cell_id = 1 + +[[cohorts]] +dbh_value = 0.2 +n_individuals = 6 pft_name = "broadleaf" [[cohorts]] -dbh_value = 0.35 +dbh_value = 0.5 n_individuals = 1 +pft_name = "conifer" +""", + pytest.raises(ValidationError), + "{'cell_area': ['Not a valid number.']}", + id="area_as_string", + ), + pytest.param( + """cell_area = 100 +cell_id = 1.2 + +[[cohorts]] +dbh_value = 0.2 +n_individuals = 6 pft_name = "broadleaf" [[cohorts]] dbh_value = 0.5 n_individuals = 1 pft_name = "conifer" +""", + pytest.raises(ValidationError), + "{'cell_id': ['Not a valid integer.']}", + id="id_as_float", + ), + pytest.param( + """cell_area = 100 +cell_id = -1 [[cohorts]] -dbh_value = 0.6 +dbh_value = 0.2 +n_individuals = 6 +pft_name = "broadleaf" + +[[cohorts]] +dbh_value = 0.5 n_individuals = 1 pft_name = "conifer" """, - does_not_raise(), - None, - id="correct", + pytest.raises(ValidationError), + "{'cell_id': ['Must be greater than or equal to 0.']}", + id="id_negative", + ), + pytest.param( + """cell_area = 0 +cell_id = 1 + +[[cohorts]] +dbh_value = 0.2 +n_individuals = 6 +pft_name = "broadleaf" + +[[cohorts]] +dbh_value = 0.5 +n_individuals = 1 +pft_name = "conifer" +""", + pytest.raises(ValidationError), + "{'cell_area': ['Must be greater than 0.']}", + id="area_zero", + ), + pytest.param( + """cell_area = 100 +cell_id = 1 +cohorts = [] +""", + pytest.raises(ValidationError), + "{'cohorts': ['Shorter than minimum length 1.']}", + id="no_cohorts", + ), + pytest.param( + """cell_area = 100 +cell_id = 1 + +[[cohorts]] +dbh_value = 0.2 +n_individuals = 6 +pft_name = 1 + +[[cohorts]] +dbh_value = 0.5 +n_individuals = 1 +pft_name = "conifer" +""", + pytest.raises(ValidationError), + "{'cohorts': {0: {'pft_name': ['Not a valid string.']}}}", + id="bad_cohort_name", + ), + pytest.param( + """cell_area = 100 +cell_id = 1 + +[[cohorts]] +dbh_value = 0 +n_individuals = 6 +pft_name = "broadleaf" + +[[cohorts]] +dbh_value = 0.5 +n_individuals = 1 +pft_name = "conifer" +""", + pytest.raises(ValidationError), + "{'cohorts': {0: {'dbh_value': ['Must be greater than 0.']}}}", + id="dbh_zero", + ), + pytest.param( + """cell_area = 100 +cell_id = 1 + +[[cohorts]] +dbh_value = 0.2 +n_individuals = 6.2 +pft_name = "broadleaf" + +[[cohorts]] +dbh_value = 0.5 +n_individuals = 1 +pft_name = "conifer" +""", + pytest.raises(ValidationError), + "{'cohorts': {0: {'n_individuals': ['Not a valid integer.']}}}", + id="individuals_float", + ), + pytest.param( + """cell_area = 100 +cell_id = 1 + +[[cohorts]] +dbh_value = 0.2 +n_individuals = -6 +pft_name = "broadleaf" + +[[cohorts]] +dbh_value = 0.5 +n_individuals = 1 +pft_name = "conifer" +""", + pytest.raises(ValidationError), + "{'cohorts': {0: {'n_individuals': ['Must be greater than 0.']}}}", + id="individuals_less_than_one", ), ], ) def test_Community_from_toml( - tmp_path, fixture_flora, file_data, outcome, excep_message + tmp_path, fixture_flora, fixture_expected, file_data, outcome, excep_message ): """Test that a community can be successfully imported from JSON.""" @@ -414,8 +593,8 @@ def test_Community_from_toml( community = Community.from_toml(path=temp_file, flora=fixture_flora) if isinstance(outcome, does_not_raise): - # TODO - test something here - assert community + # Simple test that data is loaded and trait and t model data calculated + check_expected(community=community, expected=fixture_expected) return assert str(excep.value) == excep_message From 89a6a21d620d0a08a37756b67a0b5c1ee826ea17 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 12 Sep 2024 19:18:21 +0100 Subject: [PATCH 086/241] Extending intersphinx details and whacking docs issues - some not fixed --- docs/source/conf.py | 3 +++ pyrealm/demography/community.py | 6 ++++-- pyrealm/demography/flora.py | 13 +++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 3921eba7..c1f27803 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -96,6 +96,7 @@ class MyReferenceStyle(AuthorYearReferenceStyle): ("py:class", "numpy._typing._array_like._ScalarType_co"), ("py:class", "numpy._typing._generic_alias.ScalarType"), ("py:class", "numpy.float32"), + ("py:class", "numpy.int64"), ("py:class", "numpy.timedelta64"), ("py:class", "numpy.bool_"), ("py:class", "numpy.ndarray"), @@ -152,7 +153,9 @@ class MyReferenceStyle(AuthorYearReferenceStyle): "numpy": ("https://numpy.org/doc/stable/", None), "python": ("https://docs.python.org/3/", None), "xarray": ("https://docs.xarray.dev/en/stable/", None), + "pandas": ("http://pandas.pydata.org/pandas-docs/dev/", None), "shapely": ("https://shapely.readthedocs.io/en/stable/", None), + "marshmallow": ("https://marshmallow.readthedocs.io/en/stable/", None), } # - diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index b7d8f417..69cae985 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -143,7 +143,8 @@ class CommunityCSVDataSchema(Schema): individuals. Each row is taken to represent a cohort and the cell id and area *must** be consistent across rows. - .. code-block:: csv + .. code-block:: + cell_id,cell_area,cohort_pft_names,cohort_dbh_values,cohort_n_individuals 1,100,broadleaf,0.2,6 1,100,broadleaf,0.25,6 @@ -153,7 +154,8 @@ class CommunityCSVDataSchema(Schema): 1,100,conifer,0.6,1 The input data is expected to be converted to a dictionary of lists, representing - the field, as for example by using :meth:`~pd.DataFrame.to_dict('list')`. + the field, as for example by using :meth:`~pandas.DataFrame.to_dict` with the + ``orient='list'`` argument. The schema automatically validates that the cell id and area are consistent and then post-processing is used to simplify those fields to the scalar inputs required to diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 74849c61..57b72100 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -4,10 +4,11 @@ used to parameterise the traits of different plant functional types. The ``PlantFunctionalType`` dataclass is a subclass of ``PlantFunctionalTypeStrict`` that simply adds default values to the attributes. -* The ``PlantFunctionalTypeStrict`` dataclass is used as the basis of a ``marshmallow`` - schema for validating the creation of plant functional types from data files. This - intentionally enforces a complete description of the traits in the input data. The - ``PlantFunctionalType`` is provided as a more convenient API for programmatic use. +* The ``PlantFunctionalTypeStrict`` dataclass is used as the basis of a + :mod:`~marshmallow` schema for validating the creation of plant functional types from + data files. This intentionally enforces a complete description of the traits in the + input data. The ``PlantFunctionalType`` is provided as a more convenient API for + programmatic use. * The Flora class, which is simply a dictionary of named plant functional types for use in describing a plant community in a simulation. The Flora class also defines factory methods to create instances from plant functional type data stored in JSON, TOML or @@ -146,7 +147,7 @@ class PlantFunctionalType(PlantFunctionalTypeStrict): tau_f, 4.0, years tau_r, 1.04, years par_ext, 0.5, - - yld, 0.17, - + yld, 0.6, - zeta, 0.17, kg C m-2 resp_r, 0.913, year-1 resp_s, 0.044, year-1 @@ -164,7 +165,7 @@ class PlantFunctionalType(PlantFunctionalTypeStrict): tau_f: float = 4.0 tau_r: float = 1.04 par_ext: float = 0.5 - yld: float = 0.17 + yld: float = 0.6 zeta: float = 0.17 resp_r: float = 0.913 resp_s: float = 0.044 From 81088e0d7657a3d9156f5bb0676227a629d906f0 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 13 Sep 2024 08:49:31 +0100 Subject: [PATCH 087/241] Docstring updates --- pyrealm/demography/community.py | 74 +++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 69cae985..61a93b39 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -38,10 +38,26 @@ class CohortSchema(Schema): - """A validation schema for Cohort data. + """A validation schema for Cohort data objects. This schema can be used to validate the ``cohorts`` components of JSON and TOML - community data files. + community data files, which are simple dictionaries: + + .. code-block:: toml + :caption: TOML + + dbh_value = 0.2 + n_individuals = 6 + pft_name = "broadleaf" + + .. code-block:: json + :caption: JSON + + { + "pft_name": "broadleaf", + "dbh_value": 0.2, + "n_individuals": 6 + } """ dbh_value = fields.Float( @@ -153,9 +169,9 @@ class CommunityCSVDataSchema(Schema): 1,100,conifer,0.5,1 1,100,conifer,0.6,1 - The input data is expected to be converted to a dictionary of lists, representing - the field, as for example by using :meth:`~pandas.DataFrame.to_dict` with the - ``orient='list'`` argument. + The input data is expected to be provided to this schema as a dictionary of lists of + field values keyed by field name, as for example by using + :meth:`pandas.DataFrame.to_dict` with the ``orient='list'`` argument. The schema automatically validates that the cell id and area are consistent and then post-processing is used to simplify those fields to the scalar inputs required to @@ -207,27 +223,31 @@ def make_cell_data_scalar(self, data: dict, **kwargs: Any) -> dict: @dataclass class Community: - """Class containing properties of a community. - - A community is a group of plants in a given location. A location consists of a cell - with a specified area and ID. - - A community is broken down into cohorts, ie a collection of plants with the same - diameter at breast height (DBH) and plant functional type (PFT). This is - represented inside the class as a struct of arrays, with each element in a given - array representing a property of a cohort. The properties of a given cohort are - spread across the arrays and associated positionally, e.g. a cohort that has its - pft_h_max in the third element of the pft_h_max_values array will have the number - of individuals in the cohort in the third element of the - cohort_number_of_individuals array. Care must therefore be taken to - modify all the arrays when adding and removing cohorts. - - In addition to the properties the class is initialised with, the following - properties are calculated during initialisation and exposed publicly: - geometry of cohorts calculated using the t model, and canopy factors from - Jaideep's extension to the t model. - - A method is also provided to load community data from a csv file. + """The plant community class. + + A community is a set of size-structured plant cohorts in a given location, where the + location has a specified numeric id and a known area in square meters. + + A cohort defines a number of individual plants with the same diameter at breast + height (DBH) and plant functional type (PFT). Internally, the cohort data is built + into a :class:`pandas.DataFrame` with each row representing a cohort and each column + representing a property of the cohort. The initial input data is extended to include + the plant functional type traits for each cohort (see + :class:`~pyrealm.demography.flora.PlantFunctionalType`) and then is further extended + to include the geometric and canopy predictions of the T Model for each cohort. + + Factory methods are provided to load community data from csv, TOML or JSON files. + + Args: + cell_id: An positive integer id for the community location. + cell_area: An area in square metres for the community location. + flora: A flora object containing the plant functional types for the community + cohort_dbh_values: A numpy array giving the diameter at breast height in metres + for each cohort. + cohort_n_individuals: A numpy array giving the number of individuals in each + cohort. + cohort_pft_names: A numpy array giving the name of the plant functional type in + each cohort. """ # Dataclass attributes for initialisation @@ -244,7 +264,7 @@ class Community: # Post init properties number_of_cohorts: int = field(init=False) - # Dataframe of cohort + # Dataframe of cohort data cohort_data: pd.DataFrame = field(init=False) def __post_init__( From 5df492d304b606635dfd23ba77822a090542c780 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 13 Sep 2024 09:06:47 +0100 Subject: [PATCH 088/241] Forgot to merge in @AmyOctoCat's tests for the t model functionality --- ...st_jaideeps_t_model_extension_functions.py | 52 +++++++++++ .../unit/demography/test_t_model_functions.py | 90 +++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 tests/unit/canopy_model/test_jaideeps_t_model_extension_functions.py create mode 100644 tests/unit/demography/test_t_model_functions.py diff --git a/tests/unit/canopy_model/test_jaideeps_t_model_extension_functions.py b/tests/unit/canopy_model/test_jaideeps_t_model_extension_functions.py new file mode 100644 index 00000000..dc6c3e99 --- /dev/null +++ b/tests/unit/canopy_model/test_jaideeps_t_model_extension_functions.py @@ -0,0 +1,52 @@ +"""Test the functions in jaideeps_t_model_extension_functions.py.""" + +import numpy as np +from numpy.testing import assert_array_almost_equal + +from pyrealm.canopy_model.functions.jaideep_t_model_extension_functions import ( + calculate_q_m_values, +) + + +def test_calculate_q_m_values_returns_q_m_for_valid_input(): + """Test happy path for calculating q_m. + + test that values of q_m are calculated correctly when valid arguments are + provided to the function. + """ + m_values = np.array([2, 3]) + n_values = np.array([5, 4]) + expected_q_m_values = np.array([2.9038988210485766, 2.3953681843215673]) + actual_q_m_values = calculate_q_m_values(m_values, n_values) + assert_array_almost_equal(actual_q_m_values, expected_q_m_values, decimal=8) + + +def test_calculate_q_m_values_raises_exception_for_invalid_input(): + """Test unhappy path for calculating q_m. + + Test that an exception is raised when invalid arguments are provided to the + function. + """ + + pass + + +def test_calculate_z_max_values(): + """Test happy path for calculating z_max.""" + + pass + + +def test_calculate_r_0_values(): + """Test happy path for calculating r_0.""" + pass + + +def test_calculate_projected_canopy_area_for_individuals(): + """Test happy path for calculating canopy area for individuals.""" + pass + + +def test_calculate_relative_canopy_radii(): + """Test happy path for calculating relative canopy radii for individuals.""" + pass diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py new file mode 100644 index 00000000..afda5f74 --- /dev/null +++ b/tests/unit/demography/test_t_model_functions.py @@ -0,0 +1,90 @@ +"""test the functions in t_model_functions.py.""" + +import numpy as np +from numpy.testing import assert_array_almost_equal + +from pyrealm.t_model_functions import ( + calculate_crown_areas, + calculate_crown_fractions, + calculate_foliage_masses, + calculate_heights, + calculate_stem_masses, + calculate_swd_masses, +) + + +def test_calculate_heights(): + """Tests happy path for calculation of heights of tree from diameter.""" + pft_h_max_values = np.array([25.33, 15.33]) + pft_a_hd_values = np.array([116.0, 116.0]) + diameters_at_breast_height = np.array([0.2, 0.6]) + expected_heights = np.array([15.19414157, 15.16639589]) + actual_heights = calculate_heights( + pft_h_max_values, pft_a_hd_values, diameters_at_breast_height + ) + assert_array_almost_equal(actual_heights, expected_heights, decimal=8) + + +def test_calculate_crown_areas(): + """Tests happy path for calculation of crown areas of trees.""" + pft_ca_ratio_values = np.array([2, 3]) + pft_a_hd_values = np.array([116.0, 116.0]) + diameters_at_breast_height = np.array([0.2, 0.6]) + heights = np.array([15.194142, 15.166396]) + expected_crown_areas = np.array([0.04114983, 0.1848361]) + actual_crown_areas = calculate_crown_areas( + pft_ca_ratio_values, pft_a_hd_values, diameters_at_breast_height, heights + ) + assert_array_almost_equal(actual_crown_areas, expected_crown_areas, decimal=8) + + +def test_calculate_crown_fractions(): + """Tests happy path for calculation of crown fractions of trees.""" + pft_a_hd_values = np.array([116.0, 116.0]) + diameters_at_breast_height = np.array([0.2, 0.6]) + heights = np.array([15.194142, 15.166396]) + expected_crown_fractions = np.array([0.65491991, 0.21790799]) + actual_crown_fractions = calculate_crown_fractions( + heights, pft_a_hd_values, diameters_at_breast_height + ) + assert_array_almost_equal( + actual_crown_fractions, expected_crown_fractions, decimal=8 + ) + + +def test_calculate_stem_masses(): + """Tests happy path for calculation of stem masses.""" + diameters_at_breast_height = np.array([0.2, 0.6]) + heights = np.array([15.194142, 15.166396]) + pft_rho_s_values = np.array([200.0, 200.0]) + expected_stem_masses = np.array([47.73380488, 428.8197443]) + actual_stem_masses = calculate_stem_masses( + diameters_at_breast_height, heights, pft_rho_s_values + ) + assert_array_almost_equal(actual_stem_masses, expected_stem_masses, decimal=8) + + +def test_calculate_foliage_masses(): + """Tests happy path for calculation of foliage masses.""" + crown_areas = np.array([0.04114983, 0.1848361]) + pft_lai_values = np.array([1.8, 1.8]) + pft_sla_values = np.array([14.0, 14.0]) + expected_foliage_masses = np.array([0.00529069, 0.02376464]) + actual_foliage_masses = calculate_foliage_masses( + crown_areas, pft_lai_values, pft_sla_values + ) + assert_array_almost_equal(actual_foliage_masses, expected_foliage_masses, decimal=8) + + +def test_calculate_swd_masses(): + """Tests happy path for calculation of ??? masses.""" + crown_areas = np.array([0.04114983, 0.1848361]) + pft_rho_s_values = np.array([200.0, 200.0]) + heights = np.array([15.194142, 15.166396]) + crown_fractions = np.array([0.65491991, 0.21790799]) + pft_ca_ratio_values = [390.43, 390.43] + expected_swd_masses = np.array([0.21540173, 1.27954667]) + actual_swd_masses = calculate_swd_masses( + crown_areas, pft_rho_s_values, heights, crown_fractions, pft_ca_ratio_values + ) + assert_array_almost_equal(actual_swd_masses, expected_swd_masses, decimal=8) From 2032adcbcd483645bc58b8ff77957eb6a0ce923b Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 13 Sep 2024 09:12:09 +0100 Subject: [PATCH 089/241] Fixed incorrect yield value in TModelConst and updated regression tests --- pyrealm/constants/tmodel_const.py | 2 +- pyrealm_build_data/t_model/rtmodel_output.csv | 200 +++++++++--------- .../t_model/rtmodel_test_outputs.r | 2 +- 3 files changed, 102 insertions(+), 102 deletions(-) diff --git a/pyrealm/constants/tmodel_const.py b/pyrealm/constants/tmodel_const.py index 41dead73..a4233123 100644 --- a/pyrealm/constants/tmodel_const.py +++ b/pyrealm/constants/tmodel_const.py @@ -35,7 +35,7 @@ class TModelTraits(ConstantsClass): """Fine-root turnover time (:math:`\tau_r`, 1.04, years)""" par_ext: float = 0.5 # k, PAR extinction coefficient (-) """PAR extinction coefficient (:math:`k`, 0.5, -)""" - yld: float = 0.17 # y, Yield_factor (-) + yld: float = 0.6 # y, Yield_factor (-) """Yield_factor (:math:`y`, 0.17, -)""" zeta: float = 0.17 # zeta, Ratio of fine-root mass to foliage area (kgCm-2) r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, 0.17, kg C m-2)""" diff --git a/pyrealm_build_data/t_model/rtmodel_output.csv b/pyrealm_build_data/t_model/rtmodel_output.csv index b705cb57..192908b5 100644 --- a/pyrealm_build_data/t_model/rtmodel_output.csv +++ b/pyrealm_build_data/t_model/rtmodel_output.csv @@ -1,101 +1,101 @@ "dD","D","H","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" -1.3261078333006,0.1,9.30685130731739,2.46024211324268,0.316316843131202,7.30958392378022,7.02392939699003,9.1978885806073,0.309052893467561,0.687337521113514,0.540583245523229,0.0507133024451026 -1.32871117783746,0.102652215666601,9.50029060536579,2.57798443422273,0.331455141542923,7.86255012133515,7.54118762906641,9.63808133390068,0.331812255678922,0.720232135264278,0.566520247739465,0.0517199040312726 -1.33117797524213,0.105309638022276,9.69176749651272,2.6980263063892,0.346889096535754,8.44168433502787,8.08126557669089,10.086871214885,0.355575685374399,0.753769193426402,0.592906534593003,0.0527083128736193 -1.33351711170997,0.10797199397276,9.8812773212796,2.82032581596637,0.362613319195676,9.04742961153548,8.64439989345793,10.5441015242512,0.380353595312149,0.787936985813052,0.619729263859446,0.0536786323598661 -1.33573677880796,0.11063902819618,10.0688175615767,2.94484131346525,0.378622454588389,9.68021622549394,9.23080912303363,11.0096165507556,0.40615560141348,0.822723876473295,0.646975781104036,0.0546309827131436 -1.33784453869993,0.113310501753796,10.254387644021,3.07153144993977,0.394911186420828,10.3404618729216,9.8406940662054,11.4832617067678,0.432990538913037,0.858118313421274,0.674633628301898,0.0555654991143128 -1.33984738228969,0.115986190831196,10.4379887617388,3.20035520914713,0.411474241176059,11.0285718725065,10.4742381600064,11.9648836485053,0.460866479040282,0.894108837621106,0.702690551111788,0.0564823300086018 -1.34175178114168,0.118665885595775,10.6196237126915,3.33127193601421,0.428306391773256,11.7449393734876,11.1316078669659,12.4543303824587,0.489790746146501,0.930684090939779,0.73113450494293,0.0573816355767315 -1.34356373392493,0.121349389158059,10.7992967527958,3.46424136176887,0.445402460798854,12.4899455689935,11.8129530727054,12.9514513593477,0.519769935199036,0.967832823168263,0.759953659939556,0.0582635863530963 -1.34528880802845,0.124036516625909,10.9770134623126,3.59922362605665,0.462757323350141,13.2639599138165,12.5184074902556,13.456097556807,0.550809929571247,1.00554389820046,0.78913640499461,0.0591283619756455 -1.34693217691204,0.126727094241966,11.152780624158,3.7361792963304,0.480365909528195,14.0673403457084,13.2480890696131,13.9681215518763,0.582915919062976,1.0438062994502,0.818671350892413,0.0599761500539064 -1.34849865368444,0.12942095859579,11.3266061129416,3.87506938477033,0.498223206613328,14.9004335093748,14.0021004111812,14.4873775842582,0.616092418091971,1.08260913457836,0.848547332669859,0.0608071451431647 -1.34999272133816,0.132117955903159,11.4984987936731,4.01585536296625,0.516324260952803,15.763574982432,14.7805291818641,15.0137216112089,0.650343284002018,1.12194163959478,0.878753411276606,0.0616215478141778 -1.35141856001679,0.134817941345835,11.6684684291974,4.15849917457047,0.534664179587632,16.6570895026657,15.5834485326891,15.5470113548429,0.685671735438319,1.16179318239315,0.909278874606647,0.0624195638089992 -1.35278007164389,0.137520778465868,11.8365255955194,4.3029632461093,0.553238131642625,17.5812911959984,16.4109175169342,16.0871063425527,0.722080370745106,1.20215326577153,0.940113237966488,0.0632014032745269 -1.3540809022024,0.140226338609156,12.0026816042727,4.44921049612278,0.5720413495015,18.5364838046349,17.2629815078311,16.633867941179,0.759571186344567,1.24301152998579,0.97124624403876,0.063967280066314 -1.35532446191842,0.142934500413561,12.166948431665,4.59720434278624,0.591069129786803,19.5229609149102,18.1396726149987,17.1871593855043,0.798145595059945,1.28435775487894,1.00266786239442,0.0647174111159762 -1.35651394357314,0.145645149337398,12.3293386533035,4.74690871015251,0.610316834162465,20.5410061844157,19.0410100988433,17.7468458015905,0.837804444349107,1.32618186162499,1.03436828860153,0.0654520158562425 -1.35765233913991,0.148358177224544,12.4898653843667,4.89828803314066,0.629779889975228,21.5908935680238,19.9670007822307,18.3127942254299,0.87854803441815,1.36847391412277,1.06633794297415,0.0661713156983165 -1.35874245492084,0.151073481902824,12.648542224642,5.05130726138582,0.649453790749606,22.6728875424723,20.9176394588072,18.8848736173375,0.920376136187516,1.41122412007145,1.09856746900067,0.0668755335567674 -1.35978692533676,0.153790966812666,12.8053832079987,5.20593186205372,0.669334096549764,23.7872433292083,21.8929092974061,19.4629548724745,0.96328800908587,1.45442283175684,1.13104773148727,0.0675648934176542 -1.36078822550735,0.156510540663339,12.9604027559094,5.36212782171464,0.689416434220453,24.934207115224,22.8927822420345,20.0469108278535,1.00728241864952,1.49806054657499,1.16376981444898,0.0682396199460212 -1.36174868274229,0.159232117114354,13.1136156346685,5.5198616473629,0.709696497518087,26.1140162716489,23.9172194069884,20.6366162661501,1.05235765390749,1.54212790731695,1.19672501877756,0.0688999381292793 -1.36267048705133,0.161955614479838,13.265036915994,5.67910036666032,0.730170047142041,27.3268995698889,24.9661714666941,21.2319479166135,1.09851154453454,1.58661570223683,1.22990485971311,0.0695460729533359 -1.36355570076892,0.164680955453941,13.4146819407256,5.83981152747531,0.750832910675397,28.5730773951301,26.039579039918,21.8327844533428,1.14574147775639,1.631514864923,1.26330106414353,0.0701782491086297 -1.36440626737884,0.167408066855479,13.5625662853637,6.00196319678315,0.771680982443548,29.8527619570471,27.1373730680311,22.439006491176,1.19404441499337,1.67681647399088,1.29690556775393,0.0707966907235048 -1.36522401961499,0.170136879390237,13.7087057312122,6.16552395898716,0.79271022329835,31.1661574975761,28.2594751870507,23.0504965794132,1.24341690823023,1.72251175261392,1.33071051204603,0.0714016211225926 -1.3660106869066,0.172867327429467,13.8531162359155,6.3304629137157,0.813916660334876,32.5134604956343,29.4057980932198,23.6671391935807,1.29385511610167,1.76859206790807,1.36470824124583,0.0719932626080915 -1.36676790222851,0.17559934880328,13.9958139071947,6.49674967314494,0.835296386547206,33.8948598686812,30.576245901918,24.2888207254217,1.34535481968439,1.81504893018389,1.39889129911607,0.0725718362620231 -1.36749720841148,0.178332884607737,14.1368149786099,6.66435435889352,0.856845560429167,35.3105371710362,31.7707144997275,24.9154294712867,1.39791143798801,1.86187399207896,1.43325242568866,0.0731375617677201 -1.36820006396122,0.18106787902456,14.276135787186,6.83324759853121,0.878560405525442,36.7606667888796,32.9890918895054,25.5468556190806,1.45152004313824,1.90905904758245,1.46778455393073,0.0736906572489545 -1.36887784843045,0.183804279152482,14.4137927527587,7.00340052174008,0.90043720993801,38.2454161318772,34.2312585283419,26.1829912339112,1.50617537524704,1.9565960309627,1.50248080635674,0.0742313391252575 -1.36953186738334,0.186542034849343,14.5498023589066,7.17478475616382,0.922472325792491,39.7649458213811,35.4970876583067,26.823730242571,1.56187185696549,2.00447701560754,1.53733449159815,0.0747598219821061 -1.37016335698822,0.18928109858411,14.684181135347,7.3473724229778,0.944662168668574,41.3194098751705,36.7864456299073,27.4689684169756,1.61860360771592,2.05269421278669,1.5723391009408,0.0752763184547676 -1.37077348827061,0.192021425298086,14.8169456416862,7.52113613220962,0.967003216998379,42.9089558887042,38.0991922182052,28.1186033566689,1.67636445760103,2.10123997034446,1.60748830483932,0.0757810391246956 -1.37136337105563,0.194762972274627,14.9481124524205,7.69604897783787,0.989492011436297,44.5337252128674,39.4351809315523,28.7725344704994,1.7351479609883,2.15010677133039,1.64277594941728,0.0762741924274637 -1.37193405762607,0.197505699016739,15.0776981430947,7.87208453269429,1.01212515420355,46.1938531282029,40.7942593129304,29.4306629575615,1.79494740976894,2.19928723257507,1.6781960529605,0.0767559845713095 -1.37248654611992,0.200249567131991,15.205719277534,8.04921684319259,1.03489930841048,47.8894690156234,42.1762692338887,30.0928917874881,1.8557558462911,2.24877410321746,1.71374280241065,0.0772266194654354 -1.37302178368877,0.202994540224231,15.3321923960683,8.22742042390532,1.05781119735925,49.6206965236084,43.5810471810902,30.7591256801762,1.91756607596797,2.29856026318982,1.74941054986544,0.0776862986572854 -1.37354066943674,0.205740583791608,15.4571340046776,8.40667025200847,1.08085760382966,51.387653731897,45.0084245354927,31.4292710850172,1.98037067956168,2.34863872166562,1.78519380909091,0.0781352212780784 -1.37404405715753,0.208487665130482,15.5805605649921,8.58694176161196,1.10403536935011,53.1904533116893,46.4582278441993,32.1032361597006,2.04416202514477,2.39900261547562,1.82108725205126,0.0785735839959364 -1.3745327578859,0.211235753244797,15.7024884850846,8.76821083799247,1.12734139345617,55.0292026823793,47.930279085025,32.780930748653,2.1089322797411,2.44964520749666,1.85708570546046,0.0790015809760008 -1.375007542278,0.213984818760569,15.8229341109991,8.95045381174418,1.15077263293854,56.9040041648405,49.4243959238375,33.4622663611702,2.17467342064885,2.50055988501747,1.8931841473601,0.0794194038469744 -1.3754691428341,0.216734833845125,15.9419137189638,9.13364745286129,1.17432610108217,58.8149551312955,50.9403919647372,34.1471561492936,2.24137724644844,2.55174015808548,1.92937770372699,0.0798272416735737 -1.37591825597579,0.219485772130793,16.0594435082393,9.31776896476532,1.1979988668984,60.7621481517996,52.4780769931503,34.8355148854808,2.30903538769861,2.60317965783821,1.96566164511397,0.0802252809344147 -1.37635554398887,0.222237608642744,16.1755395945575,9.50279597828918,1.22178805435147,62.7456711373731,54.0372572119161,35.5272589401144,2.37763931732431,2.65487213482248,2.00203138332666,0.0806137055048923 -1.37678163684191,0.224990319730722,16.2902180041109,9.68870654562878,1.24569084158084,64.7656074798214,55.6177354704561,36.2223062588896,2.44718036070007,2.70681145730468,2.03848246813903,0.0809926966446484 -1.37719713388994,0.227743883004406,16.4034946680528,9.87547913427236,1.26970446012073,66.8220361882818,57.2193114871183,36.9205763401179,2.5176497054332,2.75899160957474,2.07501058404989,0.0813624329892513 -1.37760260547171,0.230498277272186,16.5153854174736,10.0630926209166,1.29382619411785,68.9150320225393,58.8417820647944,37.6219902119822,2.58903841085095,2.81140669024644,2.11161154708244,0.0817230905457432 -1.37799859440824,0.233253482483129,16.625905978821,10.2515262853783,1.31805337954864,71.0446656231568,60.4849412999141,38.3264704097744,2.66133741719622,2.86405091055641,2.14828130162851,0.0820748426917308 -1.37838561740991,0.236009479671946,16.7350719697318,10.4407598045086,1.34238340343681,73.2110036384633,62.1485807849218,39.033940953144,2.73453755453656,2.91691859266399,2.18501591733921,0.0824178601777267 -1.37876416639853,0.238766250906766,16.8428988952494,10.630773246118,1.36681370307231,75.4141088484496,63.8324898043466,39.7443273233852,2.80862955139125,2.97000416795394,2.22181158606309,0.0827523111324634 -1.37913470975053,0.241523779239563,16.9494021443989,10.8215470629176,1.39134176523226,77.6540402856182,65.5364555245792,40.457556440786,2.88360404308149,3.0233021753438,2.25866461883311,0.0830783610709286 -1.37949769346672,0.244282048659064,17.054596987096,11.0130620864832,1.41596512540498,79.9308533528382,67.2602631774704,41.1735566420616,2.9594515798087,3.07680725959749,2.29557144290312,0.0833961729048838 -1.37985354227373,0.247041044045997,17.1584985713674,11.2052995212468,1.44068136701744,82.2445999382531,69.0036962378688,41.8922576578924,3.03616263446622,3.13051416964688,2.33252859883487,0.0837059069556505 -1.38020266066182,0.249800751130545,17.2611219208611,11.3982409385218,1.46548812066709,84.5953285272961,70.7665365952173,42.6135905905855,3.11372761018956,3.18441775692235,2.36953273763586,0.0840077209689594 -1.38054543386345,0.252561156451868,17.3624819326269,11.5918682705653,1.4903830633584,86.9830843118602,72.5485647193297,43.3374878918754,3.19213684765051,3.23851297369399,2.40658061794881,0.0843017701316779 -1.38088222877647,0.255322247319595,17.4625933751492,11.7861638046814,1.51536391774475,89.4079092966784,74.3495598204668,44.0638833408802,3.27138063210054,3.29279487142427,2.44366910329273,0.0845882070902399 -1.38121339483573,0.258084011777148,17.5614708866144,11.9811101773703,1.54042845137618,91.8698424029635,76.1693000038361,44.7927120222261,3.35144920016879,3.34725859913336,2.48079515935614,0.0848671819706178 -1.38153926483648,0.260846438566819,17.6591289733977,12.1766903685258,1.56557447595332,94.3689195693615,78.0075624186367,45.5239103043541,3.43233274642001,3.401899401778,2.51795585134227,0.0851388423996881 -1.38186015571264,0.263609517096492,17.7555820087538,12.3728876956838,1.59079984658792,96.9051738502698,79.8641234017721,46.2574158180184,3.51402142967797,3.45671261864476,2.55514834136645,0.085403333527851 -1.38217636927299,0.266373237407918,17.8508442316982,12.5696858083258,1.61610246107046,99.4786355115734,81.738758616354,46.9931674349878,3.59650537911958,3.51169368175845,2.59236988590549,0.0856607980527758 -1.38248819289781,0.269137590146464,17.9449297460657,12.7670686822381,1.6414802591449,102.08933212385,83.6312431851186,47.731105246959,3.67977470014522,3.56683811430633,2.6296178332989,0.085911376244154 -1.38279590019861,0.271902566532259,18.0378525197339,12.9650206139308,1.6669312217911,104.737288653097,85.5413518188771,48.4711705446891,3.76381948003059,3.62214152907876,2.6668896213018,0.0861552059693484 -1.3830997516432,0.274668158332657,18.1296263840012,13.1635262151165,1.69245337051498,107.422527549032,87.4688589401223,49.2133057973558,3.84862979336538,3.67759962692682,2.70418277468911,0.0863924227198364 -1.38339999514825,0.277434357835943,18.2202650331079,13.3625704072522,1.71804476664671,110.145068831016,89.4135388019104,49.95745463215,3.93419570728406,3.73320819523731,2.74149490291071,0.0866231596383532 -1.38369686664136,0.280201157826239,18.3097820238907,13.5621384161446,1.74370351064716,112.904930171656,91.3751656021376,50.7035618141079,4.02050728649405,3.78896310642564,2.77882369779718,0.0868475475466455 -1.3839905905945,0.282968551559522,18.398190775562,13.7622157666206,1.76942774142265,115.702126978129,93.3535135933293,51.4515732261863,4.10755459810649,3.84486031644692,2.81616693131558,0.0870657149737557 -1.38428138053052,0.285736532740711,18.4855045696039,13.9627882772643,1.79521563564826,118.536672471282,95.348357188059,52.2014358495856,4.1953277162746,3.90089586332554,2.85352245337486,0.0872777881847607 -1.38456943950432,0.288505095501772,18.5717365497708,14.163842055221,1.82106540709984,121.408577762562,97.3594710601119,52.9530977443242,4.28381672664492,3.95706586570352,2.89088818968024,0.0874838912098938 -1.3848549605603,0.291274234380781,18.6568997221912,14.3653634910691,1.84697530599459,124.317851928817,99.3866302415064,53.7065080300671,4.37301173062628,4.01336652140789,2.9282621396361,0.0876841458739879 -1.38513812716732,0.294043944301901,18.7410069555627,14.5673392537609,1.87294361834069,127.264502085018,101.429610215488,54.4616168672109,4.46290284948147,4.06979410603723,2.96564237429667,0.0878786718261775 -1.38541911363255,0.296814220556236,18.8240709814329,14.7697562856326,1.89896866529562,130.248533454953,103.488187005604,55.2183754382278,4.55348022824657,4.12634497156747,3.00302703436395,0.0880675865698054 -1.38569808549544,0.299585058783501,18.9061043945603,14.9726017974832,1.92504880253355,133.269949439938,105.562137260968,55.9767359292685,4.64473403948258,4.18301554497726,3.04041432823212,0.0882510054924827 -1.38597519990293,0.302356454954492,18.9871196533502,15.1758632637239,1.95118241962165,136.328751685595,107.651238337825,56.7366515120276,4.73665448686428,4.23980232689267,3.07780253007788,0.0884290418962548 -1.38625060596693,0.305128405354298,19.0671290803573,15.3795284175976,1.97736793940541,139.424940146728,109.755268377516,57.4980763258698,4.82923180861071,4.29670189025159,3.11518997799586,0.0886018070278293 -1.38652444510509,0.307900906566232,19.146144862854,15.5835852464676,2.00360381740298,142.558513150369,111.874006380955,58.2609654602178,4.92245628076204,4.35371087898763,3.15257507217857,0.0887694101088267 -1.38679685136575,0.310673955456442,19.2241790534559,15.7880219871773,2.02988854120851,145.729467457008,114.00723227971,59.0252749372032,5.01631822030724,4.41082600673362,3.18995627313998,0.0889319583660154 -1.38706795173803,0.313447549159173,19.301243570802,15.9928271214792,2.05622062990447,148.937798320074,116.154727003793,59.7909616945779,5.11080798816687,4.46804405554462,3.22733209998213,0.0890895570614977 -1.38733786644775,0.316221685062649,19.3773502002849,16.1979893715345,2.08259863348301,152.183499543695,118.31627254626,60.5579835688876,5.20591599203542,4.52536187464056,3.26470112870399,0.0892423095228158 -1.38760670923999,0.318996360795545,19.4525105948267,16.4034976954812,2.10902113227615,155.466563538787,120.491652024711,61.3262992789042,5.30163268908728,4.58277637916813,3.30206199055174,0.0893903171729477 -1.38787458764901,0.321771574214025,19.5267362756974,16.6093412830724,2.13548673639502,158.786981377511,122.680649739788,62.0958684093185,5.39794858855069,4.6402845489822,3.33941337040986,0.0895336795601679 -1.38814160325629,0.324547323389323,19.6000386333719,16.8155095513834,2.16199408517786,162.144742846137,124.88305123076,62.8666513946897,5.49485425415344,4.69788342744639,3.37675400523218,0.0896724943877476 -1.38840785193704,0.327323606595836,19.6724289284227,17.0219921405867,2.18854184664686,165.539836496357,127.098643328286,63.6386095036516,5.59234030644458,4.75557012025283,3.4140826825121,0.089806857543474 -1.38867342409613,0.33010042229971,19.7439182924444,17.2287789097958,2.21512871697375,168.972249695081,129.327214204448,64.4117048233729,5.69039742499572,4.81334179426093,3.45139823879129,0.0899368631289655 -1.38893840489374,0.332877769147902,19.8145177290086,17.4358599329763,2.24175341995409,172.441968672764,131.568553420137,65.1859002442707,5.78901635048604,4.87119567635505,3.48869955820618,0.0900626034887684 -1.38920287446129,0.335655645957689,19.8842381146448,17.6432254949238,2.26841470649021,175.948978570294,133.822451969871,65.9611594449738,5.88818788667432,4.92912905232084,3.52598557107124,0.0901841692392146 -1.38946690810827,0.338434051706612,19.9530901998459,17.8508660873089,2.29511135408258,179.493263484469,136.088702324138,66.7374468775354,5.98790290226207,4.98713926574019,3.56325525249861,0.0903016492970277 -1.38973057652025,0.341212985522828,20.0210846100956,18.0587724047872,2.32184216632978,183.074806512129,138.367098469337,67.5147277528916,6.08815233265083,5.04522371690463,3.60050762105311,0.0904151309076633 -1.38999394594866,0.343992446675869,20.0882318469153,18.2669353411751,2.3486059724368,186.693589792937,140.657435945397,68.292968026563,6.18892718159746,5.10337986174681,3.63774173744195,0.0905246996733709 -1.39025707839263,0.346772434567766,20.1545422889289,18.4753459856903,2.37540162673161,190.349594550879,142.959511881149,69.0721343845995,6.29021852277055,5.16160521079018,3.67495670323847,0.0906304395809657 -1.39052003177337,0.349552948724552,20.2200261929426,18.6839956192555,2.40222800818999,194.042801134496,145.273125027531,69.8521942297617,6.39201750121138,5.21989732811637,3.7121516596391,0.090732433029303 -1.39078286010134,0.352333988788098,20.284693695039,18.892875710866,2.42908401996849,197.773189055891,147.598075788694,70.6331156679401,6.49431533470253,5.27825383035032,3.74932578625284,0.0908307608564428 -1.39104561363673,0.355115554508301,20.3485548116826,19.1019779140192,2.45596858894532,201.540737028532,149.934166251074,71.4148674948069,6.59710331504726,5.33667238566284,3.7864782999226,0.0909255023665008 -1.39130833904335,0.357897645735574,20.4116194408367,19.3112940632058,2.48288066526932,205.345423003902,152.28120021052,72.1974191826987,6.7003728092629,5.39515071279032,3.8236084535776,0.0910167353561761 -1.39157107953643,0.360680262413661,20.473897363088,19.5208161704628,2.50981922191665,209.187224207002,154.638983197519,72.9807408677275,6.80411526069083,5.45368658007156,3.86071553511624,0.0911045361409513 -1.39183387502449,0.363463404572734,20.5353982427794,19.7305364219853,2.53678325425525,213.066117170762,157.007322500598,73.7648033371152,6.90832219002631,5.51227780450141,3.89779886631865,0.0911889795809593 -1.39209676224564,0.366247072322783,20.5961316291489,19.9404471747987,2.56377177961697,216.982077769369,159.386027187972,74.549578016752,7.01298519627079,5.57092225080091,3.93485780178835,0.0912701391065137 -1.39235977489851,0.369031265847274,20.656106957473,20.1505409534892,2.59078383687719,220.93508125055,161.774908127486,75.3350369589726,7.11809595760939,5.62961783050391,3.97189172792224,0.0913480867432972 -1.39262294376808,0.371815985397071,20.7153335502146,20.3608104469923,2.61781848604187,224.925102266845,164.173778004917,76.1211528305495,7.22364623221635,5.68836250105981,4.00890006190838,0.0914228931372077 +9.23535494468514,0.1,9.30685130731739,2.46024211324268,0.316316843131202,7.30958392378022,7.02392939699003,9.1978885806073,0.309052893467561,0.687337521113514,3.76476031902394,0.353180440335674 +9.41347975186052,0.11847070988937,10.6064694519639,3.3216732508429,0.427072275108373,11.6918358255143,11.0829530843886,12.418444631113,0.4876499357131,0.928002429473987,5.11540450334165,0.402164311708017 +9.56242271047402,0.137297669393091,11.8227317389103,4.29097588211766,0.551696899129414,17.5038687119995,16.341714741243,16.0422902499508,0.719035448614692,1.19880425999427,6.62787138562828,0.446337579848307 +9.69154513020616,0.156422514814039,12.9554153338523,5.35704971954974,0.68876353537068,24.8965832383358,22.8600457539045,20.0279257785112,1.0058420131718,1.49664183654837,8.28100480236048,0.485860611280906 +9.8067299345139,0.175805605074452,14.0065146815861,6.50935370650332,0.836916905121855,34.0005072801248,30.6655594427653,24.3359423049901,1.34928461548167,1.81857021981548,10.0553709356637,0.52100017161193 +9.9118179887506,0.19541906494348,14.9792591514052,7.73806437175455,0.994893990654156,44.9276887698395,39.7582456018626,28.9296136904005,1.74936280648195,2.16184494805204,11.9334707249518,0.552072706446046 +10.0093918091071,0.215242700920981,15.8775424513254,9.03413941905036,1.16153221102076,57.7736797915528,50.1151867893735,33.7751343052069,2.20506821873244,2.52393980261545,13.8997585704866,0.579412356468393 +10.1012253105873,0.235261484539195,16.7055797227729,10.389327995,1.33577074221428,72.619474012326,61.6950922673494,38.841657416978,2.71458405976337,2.90254967658711,15.9405589482595,0.603352606803862 +10.1885538666546,0.25546393516037,17.4676966162467,11.7961506682707,1.51664794306338,89.5333258349725,74.4424750457644,44.1012203403852,3.27546890201363,3.29558498140014,18.0439316139172,0.624215789412495 +10.2722432037438,0.275841042893679,18.1681979492976,13.2478625042661,1.70329660769136,108.572417149682,88.2913823468227,49.5286063877833,3.8848208232602,3.70116133071686,20.1995143511014,0.642307261965835 +10.3528989805214,0.296385529301166,18.8112859111281,14.7384072607093,1.89493807637692,129.784359269137,103.168645349644,55.1011736243075,4.53942039538435,4.11758674368246,22.3983600310141,0.65791243548126 +10.4309402999148,0.317091327262209,19.4010098996293,16.2623676083615,2.09087583536076,153.208530237407,118.996649730928,60.7986687624964,5.23585258816084,4.54334773768881,24.6327776139951,0.671295558231005 +10.5066505553506,0.337953207862039,19.9412369382857,17.8149143933709,2.2904889934334,178.877254866472,135.695650514095,66.6030374739461,5.97060862262016,4.97709515339117,26.8961824217297,0.682699582930953 +10.5802135953775,0.35896650897274,20.4356356570896,19.3917567830863,2.4932258721111,206.816838688539,153.185667373722,72.4982380038911,6.74016936444376,5.41763022654509,29.1829583714671,0.692346693223028 +10.6517401049225,0.380126936163495,20.8876692783712,20.9890943915628,2.69859785034379,237.048468789206,171.388002835312,78.4700621870874,7.54107212475373,5.86389121292604,31.4883332404618,0.70043921831005 +10.7212872876908,0.40143041637334,21.300594588579,22.6035720021614,2.90617354313504,269.588994995487,190.226427898919,84.5059661732193,8.36996282755243,6.31494073881986,33.8082670397389,0.707160761026536 +10.788873837953,0.422872990948721,21.6774648674801,24.2322371960362,3.11557335377609,304.451604634413,209.628079003584,90.5949120162889,9.22363547615769,6.76995396335422,36.1393529904729,0.712677426777046 +10.8544915107154,0.444450738624627,22.0211353971244,25.8725009974224,3.32646441395431,341.646403373464,229.524107986928,96.7272205426512,10.0990607514249,7.22820758365789,38.4787302691996,0.717139081457436 +10.9181141692032,0.466159721646058,22.3342706083702,27.5221015217334,3.53855590993715,381.180913710614,249.850123500867,102.894435445385,10.9934054340381,7.68906967893882,40.8240075270072,0.720680593366289 +10.9797049112577,0.487995949984465,22.6193522183127,29.1790705359805,3.75159478319749,423.060501631756,270.546458704653,109.089198266706,11.9040441830047,8.15199036820116,43.1731961323058,0.723423031954346 +11.0392216947139,0.50995535980698,22.8786879147386,30.8417027966632,3.96536178814241,467.28874088081,291.558296287291,115.30513376426,12.8285650366408,8.61649324392616,45.5246520968697,0.725474808061432 +11.0966217616171,0.532033803196408,23.1144202839139,32.508528007077,4.17966788662418,513.867723244362,312.835678172426,121.536745070403,13.7647698395867,9.08216753756115,47.8770256941991,0.726932748015837 +11.1518650808786,0.554227046719642,23.3285357753348,34.1782852265282,4.39435095769649,562.798322268441,334.333423749197,127.779318018207,14.7106706449647,9.548660970017,50.2292178503936,0.727883098927698 +11.2049169750738,0.576530776881399,23.5228735647065,35.8498995631448,4.60927280097576,614.080416916261,356.010977216961,134.028834004941,15.6644829975463,10.0156732401523,52.5803424692092,0.72840246558233 +11.2557500607435,0.598940610831546,23.699134223315,37.5224609864079,4.82431641253815,667.713080849277,377.832201659479,140.281890780365,16.6246168730171,10.4829501054607,54.929693937393,0.728558681142435 +11.3043456069087,0.621452110953033,23.8588881343156,39.1952051028777,5.03938351322714,723.694742271028,399.765134781884,146.535630574648,17.5896659304029,10.9502780112318,57.2767191390989,0.728411614824685 +11.3506943996244,0.644060802166851,24.0035836186046,40.867495747327,5.25439231037061,782.023318611418,421.781718844873,152.787675013381,18.5583956291744,11.4174792268967,59.6209933863983,0.728013920123719 +11.3947971885715,0.6667621909661,24.1345547479324,42.5388092506586,5.46927547508467,842.696329743805,443.857515200855,159.036066301443,19.5297306688376,11.8844074508305,61.9621997450884,0.72741172722304 +11.4366647830844,0.689551785343243,24.2530288329452,44.2087202549852,5.6839783184981,905.710992912826,465.971411958392,165.279214191096,20.5027421261692,12.3509438473973,64.3001113004591,0.726645283101856 +11.4763178583598,0.712425114909411,24.3601335804589,45.8768889547655,5.89845715132699,971.064302101036,488.105331654886,171.515848281556,21.476634592815,12.8169934824045,66.6345759662775,0.72574954261762 +11.5137865270621,0.735377750626131,24.4569039185977,47.5430496507862,6.11267781224394,1038.75309417099,510.243944383874,177.744975226784,22.4507335528904,13.2824821253373,68.965503492165,0.72475471358056 +11.5491097265677,0.758405323680255,24.5442884912449,49.2070005110274,6.3266143514178,1108.77410378004,532.374390583779,183.965840455342,23.4244731856863,13.7473533887698,71.2928543701998,0.72368675857888 +11.5823344673607,0.781503543133391,24.623155825123,50.8685944390853,6.54024785645383,1181.12400877234,554.486016631851,190.177894030974,24.3973847318015,14.2115661772028,73.6166303814841,0.722567856084471 +11.6135149834225,0.804668212068112,24.6943001741004,52.5277309569395,6.75356540874936,1255.79946750029,576.570125483616,196.380760305435,25.3690855212791,14.6750924192878,75.936866558147,0.721416823179015 +11.6427118207842,0.827895242034957,24.7584470462852,54.1843490145248,6.96655915901033,1332.797149312,598.619743838572,202.574211036269,26.3392687288971,15.1379150589799,78.253624366379,0.72024950209124 +11.6699908957385,0.851180665676526,24.8162584202463,55.8384206438972,7.1792255113582,1412.11375925615,620.62940668237,208.758141662209,27.3076938940243,15.6000262826507,80.5669859421713,0.719079112624556 +11.695422549592,0.874520647468003,24.8683376574133,57.4899453808399,7.39156440610798,1493.74605789843,642.594959540046,214.932550447731,28.274178219762,16.0614259606083,82.8770492339763,0.71791657247362 +11.719080622341,0.897911492567187,24.9152341183743,59.1389453816113,7.60357869192145,1577.69087700956,664.513378360821,221.097520226468,29.2385886478761,16.5221202828238,85.1839239259814,0.716770787371128 +11.7410415633662,0.921349653811869,24.9574474914475,60.7854611672287,7.81527357864369,1663.94513177103,686.382606629988,227.253202490747,30.2008346917195,16.982120569978,87.4877280325238,0.715648912964093 +11.7613835932232,0.944831736938601,24.995431842535,62.4295479322454,8.02665616271726,1752.50583004824,708.201409055604,233.39980359154,31.1608619984466,17.4414422422149,89.7885850687288,0.714556590285057 +11.7801859269303,0.968354504125048,25.0295993958697,64.071272359425,8.23773501764035,1843.37007919871,729.969240996173,239.53757282977,32.1186466038316,17.9001039292314,92.0866217150543,0.713498156651918 +11.7975280658584,0.991914875978908,25.0603240558164,65.7107098860491,8.44851984249203,1936.53509081381,751.68613267014,245.666792236099,33.0741898374862,18.3581267065446,94.38196590435,0.712476833795632 +11.8134891624399,1.01550993211063,25.0879446803725,67.3479423718062,8.65902116208937,2031.99818373354,773.352587109393,251.78776785207,34.0275138328133,18.8155334439505,96.6747452695209,0.711494894974698 +11.8281474594478,1.0391369104355,25.1127681174163,68.9830561222896,8.8692500728658,2129.7567856242,794.969490778912,257.900822340737,34.9786575942721,19.272348253333,98.9650858981251,0.710553812787041 +11.8415798035397,1.0627932053544,25.1350720150602,70.6161402260632,9.07921802906526,2229.80843336607,816.538035775549,264.006288769597,35.9276735741242,19.7285960240771,101.253111347416,0.7096543893328 +11.8538612311044,1.08647636496148,25.1551074176751,72.2472851670227,9.28893666433149,2332.15077246263,838.05965253416,270.104505422751,36.8746247115031,20.1843020353925,103.538941879587,0.708796870315698 +11.8650646231567,1.11018408742369,25.173101159261,73.8765816773654,9.4984176442327,2436.78155565152,859.535952003227,276.195811512602,37.819581888142,20.639491635859,105.822693882435,0.707981044596844 +11.8752604250679,1.13391421667,25.1892580658455,75.5041197998774,9.70767254569852,2543.6986408717,880.968676299715,282.280543674115,38.7626217571875,21.0941899814501,108.104479445418,0.707206330634246 +11.8845164262532,1.15766473752014,25.2037629785039,77.1299881314368,9.91671275975616,2652.89998871831,902.359656910159,288.359033136565,39.703824904047,21.5484218241846,110.384406065233,0.706471851155574 +11.8928975945279,1.18143377037264,25.2167826084184,78.754273222612,10.1255494143358,2764.38365949757,923.710779568305,294.431603478872,40.6432743010054,22.0022113443869,112.662576458682,0.705776497322344 +11.9004659596413,1.2052195655617,25.2284672351395,80.3770591109958,10.3341933142709,2878.14780997727,945.023955006398,300.498568884916,41.5810540202815,22.4555820203118,114.939088463738,0.705118983552523 +11.9072805404736,1.22902049748098,25.2389522588894,81.9984269684694,10.5426548959461,2994.19068991414,966.301094845036,306.560232824797,42.5172481731816,22.9085565295971,117.214035012502,0.704497894076989 +11.9133973104918,1.25283505856193,25.2483596173681,83.6184548449223,10.7509441943472,3112.51063842675,987.544091953677,312.616887096702,43.4519400459618,23.3611566776647,119.487504162134,0.703911722214845 +11.9188691962787,1.27666185318291,25.2567990770969,85.2372174930867,10.9590708205397,3233.106080272,1008.75480467921,318.668811172028,44.3852114058853,23.8134033487836,121.759579171935,0.703358903264433 +11.9237461042401,1.30049959157547,25.2643694088729,86.8547862610741,11.1670439478524,3355.97552207376,1029.93504440227,324.71627179362,45.3171419536999,24.2653164760464,124.030338616569,0.702837841822017 +11.9280749709458,1.32434708378395,25.271159456425,88.4712290409399,11.3748723052637,3481.11754854429,1051.08656593975,330.759522783474,46.2478089013491,24.7169150269997,126.299856526992,0.702346934259345 +11.9318998329353,1.34820323372584,25.2772491068575,90.0866102631639,11.5825641766925,3608.53081873188,1072.21106036679,336.798805022098,47.1772866561388,25.1682170021022,128.568202552003,0.701884587015119 +11.9352619122133,1.37206703339171,25.2827101709614,91.7009909283261,11.7901274050705,3738.21406232222,1093.31014988192,342.834346566941,48.1056465948044,25.6192394435739,130.835442134521,0.701449231284342 +11.9381997140573,1.39593755721614,25.287607180965,93.3144286684936,11.9975694002349,3870.16607601566,1114.38538438539,348.866362881891,49.0329569129571,26.0699984525464,133.10163669769,0.701039334623581 +11.9407491341446,1.41981395664425,25.2919981127896,94.9269778319297,12.2048971498195,4004.38571999813,1135.43823948266,354.895057153972,49.959282537237,26.5205092127289,135.366843836778,0.700653409929674 +11.9429435723781,1.44369545491254,25.2959350393887,96.5386895856977,12.4121172324468,4140.87191451933,1156.47011566282,360.920620676935,50.8846850891641,26.9707860190731,137.631117513583,0.700290022194102 +11.9448140511425,1.4675813420573,25.2994647212688,98.1496120315762,12.6192358326312,4279.6236365888,1177.48233843573,366.943233284627,51.8092228911721,27.4208423101577,139.894508250683,0.699947793385115 +11.9463893360423,1.49147097015958,25.302629139833,99.7597903314401,12.8262587568994,4420.63991679732,1198.47615924184,372.963063819736,52.7329510066408,27.8706907032171,142.157063323418,0.699625405764469 +11.9476960574774,1.51536374883167,25.3054659787496,101.369266838901,13.0331914507158,4563.91983626886,1219.45275697546,378.980270625947,53.6559213069204,28.3203430309185,144.418826947912,0.699321603905093 +11.9487588316758,1.53925914094662,25.3080090581336,102.978081234555,13.2400390158714,4709.46252374619,1240.41323998599,384.995002053579,54.5781825593838,28.7698103791476,146.679840463869,0.699035195639795 +11.9496003800507,1.56315665860998,25.3102887259348,104.586270662666,13.446806228057,4857.26715281142,1261.35864844211,391.007396970588,55.499780531453,29.2191031251943,148.940142511157,0.698765052139036 +11.9502416459605,1.58705585937008,25.3123322105577,106.193869867514,13.6534975543946,5007.33293924156,1282.28995696246,397.017585272329,56.4207581063483,29.6682309758462,151.199769199484,0.698510107287346 +11.9507019081418,1.610956342662,25.3141639383961,107.800911328006,13.8601171707436,5159.65913849779,1303.20807743181,403.025688384807,57.3411554069997,30.1172030049955,153.458754270681,0.698269356503016 +11.9509988902507,1.63485774647828,25.3158058196382,109.407425389423,14.06666897864,5314.24504334618,1324.11386193558,409.031819757225,58.2610099251653,30.5660276904461,155.717129253297,0.698041855123787 +11.9511488660899,1.65875974425878,25.317277505408,111.013440391445,14.2731566217573,5471.08998160699,1345.00810575727,415.036085340631,59.18035665332,31.0147129496812,157.974923609348,0.697826716462099 +11.9511667602222,1.68266204199096,25.3185966190244,112.618982791806,14.4795835018036,5630.19331402889,1365.89155039375,421.038584050197,60.0992282173251,31.4632661744092,160.23216487319,0.697623109616918 +11.9510662437754,1.70656437551141,25.3197789639113,114.224077285093,14.6859527937977,5791.55443228403,1386.76488655164,427.039408209385,61.0176550082721,31.9116942637547,162.488878782583,0.697430257114672 +11.95085982533,1.73046650799896,25.3208387104553,115.828746916384,14.892267460678,5955.17275707956,1407.6287570959,433.038643974783,61.9356653122196,32.3600036560057,164.745089402082,0.697247432439474 +11.9505589368557,1.75436822764962,25.3217885638921,117.433013189507,15.0985302672223,6121.04773638097,1428.48375992771,439.036371740836,62.8532854368194,32.8082003588581,167.000819238952,0.697073957502065 +11.9501740147204,1.77826934552333,25.3226399151073,119.036896169816,15.3047437932621,6289.17884374234,1449.33045077411,445.032666524105,63.770539834061,33.2562899781309,169.256089351856,0.696909200087836 +11.9497145758456,1.80216969355277,25.323402976057,120.64041458148,15.5109104461903,6459.56557673866,1470.16934587636,451.027598326976,64.68745121856,33.7042777449449,171.510919452591,0.696752571316395 +11.9491892891207,1.82606912270446,25.3240869013502,122.243585899309,15.7170324727683,6632.20745549527,1491.00092456774,457.021232480963,65.6040406809804,34.1521685413771,173.765328001152,0.696603523138593 +11.9486060422159,1.8499675012827,25.3246998973831,123.846426435221,15.9231119702428,6807.10402130943,1511.82563173442,463.013629969995,66.5203277963146,34.5999669246193,176.019332294468,0.696461545891287 +11.9479720039624,1.87386471336713,25.3252493202842,125.448951419498,16.1291508967926,6984.25483535922,1532.64388015593,469.004847734164,67.4363307268608,35.0476771496765,178.2729485491,0.696326165925379 +11.947293682477,1.89776065737506,25.3257417638004,127.05117507697,16.3351510813247,7163.65947749504,1553.45605272328,474.994938954582,68.3520663198244,35.4953031906537,180.526191978243,0.696196943318756 +11.9465769792282,1.92165524474001,25.3261831381463,128.653110698346,16.5411142326445,7345.31754510896,1574.26250453518,480.983953320044,69.2675501995478,35.9428487606825,182.779076863339,0.69607346968243 +11.9458272392406,1.94554839869847,25.3265787407367,130.25477070688,16.7470419480275,7529.22865207757,1595.06356487342,486.971937276264,70.1827968544307,36.3903173305468,185.031616620636,0.69595536606546 +11.9450492976437,1.96944005317695,25.3269333196293,131.85616672059,16.9529357212187,7715.39242777381,1615.85953906019,492.95893425849,71.0978197186482,36.837712146065,187.28382386298,0.695842280962021 +11.9442475227673,1.99333015177224,25.3272511304224,133.457309610253,17.1587969498897,7903.80851614384,1636.65071020033,498.944984908336,72.0126312488145,37.2850362442934,189.535710457149,0.695733888422098 +11.9434258559878,2.01721864681777,25.327535987279,135.058209553405,17.3646269425807,8094.47657484475,1657.43734081274,504.930127275648,72.9272429957607,37.7322924686113,191.787287577026,0.695629886265887 +11.9425878485214,2.04110549852975,25.3277913086781,136.658876084556,17.5704269251573,8287.39627443939,1678.21967435503,510.914397006251,73.8416656716215,38.1794834827512,194.038565752866,0.69552999440074 +11.9417366953606,2.06499067422679,25.3280201584364,138.259318141853,17.7761980468097,8482.56729764473,1698.99793664625,516.897827516402,74.755909212435,38.6266117838347,196.289554916939,0.695433953238604 +11.9408752665385,2.08887414761751,25.3282252824847,139.859544110396,17.9819413856223,8679.98933863027,1719.77233719249,522.880450154729,75.6699828364695,39.0736797144742,198.540264445788,0.695341522211167 +11.9400061359016,2.11275589815059,25.3284091418387,141.459561862421,18.1876579537398,8879.66210236323,1740.54307042038,528.862294352461,76.5838950984967,39.5206894739994,200.790703199337,0.695252478379422 +11.9391316075632,2.13663591042239,25.3285739421546,143.059378794547,18.393348702156,9081.58530399742,1761.3103168234,534.843387762681,77.4976539402297,39.9676431288628,203.040879557085,0.695166615133919 +11.9382537402013,2.16051417363752,25.3287216602227,144.659001862283,18.5990145251506,9285.75866830297,1782.07424402603,540.823756389335,78.4112667371455,40.4145426222808,205.290801451581,0.695083740981745 +11.9373743693555,2.18439068111792,25.3288540677147,146.258437611976,18.8046562643969,9492.18192913409,1802.83500777056,546.803424706665,79.3247403419046,40.8613897831587,207.540476399384,0.695003678416091 +11.9364951278701,2.20826542985663,25.3289727524698,147.857692210376,19.0102747127626,9700.85482893232,1823.59275283131,552.782415769751,80.2380811245776,41.3081863343504,209.789911529694,0.694926262864179 +11.9356174646233,2.23213842011237,25.3290791375723,149.456771471983,19.2158706178263,9911.77711826289,1844.34761386094,558.760751316748,81.1512950098814,41.7549339002996,212.039113610826,0.694851341709288 +11.9347426616697,2.25600965504162,25.329174498451,151.055680884333,19.4214446851286,10124.9485553818,1865.09971617314,564.738451863424,82.0643875116182,42.2016340141033,214.288089074682,0.69477877338268 +11.9338718499205,2.27987914036496,25.3292599782041,152.654425631377,19.6269975811771,10340.3689058318,1885.84917646605,570.71553679055,82.9773637645061,42.648288124043,216.536844039384,0.694708426521255 +11.9330060234746,2.3037468840648,25.3293366013341,154.253010615075,19.8325299362239,10558.0379420646,1906.59610349039,576.692024424647,83.890228553577,43.0948975996184,218.785384330193,0.694640179186923 +11.9321460527067,2.32761289611175,25.3294052860573,155.851440475352,20.038042346831,10777.9554430886,1927.34059866618,582.667932112599,84.8029863413119,43.541463737123,221.03371549886,0.694573918143752 +11.9312926962124,2.35147718821716,25.329466855335,157.449719608536,20.2435353782403,11000.1211941389,1948.08275665167,588.643276290556,85.7156412926734,43.9879877647935,223.281842841516,0.694509538189161 +11.9304466117017,2.37533977360959,25.3295220467605,159.047852184374,20.4490095665623,11224.5349863698,1968.82266586788,594.618072547588,86.6281972981868,44.4344708475659,225.529771415216,0.694446941535517 diff --git a/pyrealm_build_data/t_model/rtmodel_test_outputs.r b/pyrealm_build_data/t_model/rtmodel_test_outputs.r index c5da8342..16ce3cdd 100644 --- a/pyrealm_build_data/t_model/rtmodel_test_outputs.r +++ b/pyrealm_build_data/t_model/rtmodel_test_outputs.r @@ -98,7 +98,7 @@ tmodel_run <- tmodel(rep(7, 100), seq(100), tf = 4.0, tr = 1.04, K = 0.5, - y = 0.17, + y = 0.6, zeta = 0.17, rr = 0.913, rs = 0.044 From 2dea74a3dca492fcb1ff0bc8f177ce9e235419ef Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 13 Sep 2024 11:04:14 +0100 Subject: [PATCH 090/241] Merging in @AmyOctoCat's t model function tests --- ...st_jaideeps_t_model_extension_functions.py | 52 ------------ ...st_jaideeps_t_model_extension_functions.py | 22 ----- .../unit/demography/test_t_model_functions.py | 85 ++++++++++++++++--- 3 files changed, 72 insertions(+), 87 deletions(-) delete mode 100644 tests/unit/canopy_model/test_jaideeps_t_model_extension_functions.py delete mode 100644 tests/unit/demography/test_jaideeps_t_model_extension_functions.py diff --git a/tests/unit/canopy_model/test_jaideeps_t_model_extension_functions.py b/tests/unit/canopy_model/test_jaideeps_t_model_extension_functions.py deleted file mode 100644 index dc6c3e99..00000000 --- a/tests/unit/canopy_model/test_jaideeps_t_model_extension_functions.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Test the functions in jaideeps_t_model_extension_functions.py.""" - -import numpy as np -from numpy.testing import assert_array_almost_equal - -from pyrealm.canopy_model.functions.jaideep_t_model_extension_functions import ( - calculate_q_m_values, -) - - -def test_calculate_q_m_values_returns_q_m_for_valid_input(): - """Test happy path for calculating q_m. - - test that values of q_m are calculated correctly when valid arguments are - provided to the function. - """ - m_values = np.array([2, 3]) - n_values = np.array([5, 4]) - expected_q_m_values = np.array([2.9038988210485766, 2.3953681843215673]) - actual_q_m_values = calculate_q_m_values(m_values, n_values) - assert_array_almost_equal(actual_q_m_values, expected_q_m_values, decimal=8) - - -def test_calculate_q_m_values_raises_exception_for_invalid_input(): - """Test unhappy path for calculating q_m. - - Test that an exception is raised when invalid arguments are provided to the - function. - """ - - pass - - -def test_calculate_z_max_values(): - """Test happy path for calculating z_max.""" - - pass - - -def test_calculate_r_0_values(): - """Test happy path for calculating r_0.""" - pass - - -def test_calculate_projected_canopy_area_for_individuals(): - """Test happy path for calculating canopy area for individuals.""" - pass - - -def test_calculate_relative_canopy_radii(): - """Test happy path for calculating relative canopy radii for individuals.""" - pass diff --git a/tests/unit/demography/test_jaideeps_t_model_extension_functions.py b/tests/unit/demography/test_jaideeps_t_model_extension_functions.py deleted file mode 100644 index dd71c729..00000000 --- a/tests/unit/demography/test_jaideeps_t_model_extension_functions.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Test the functions in jaideeps_t_model_extension_functions.py.""" - - -def test_calculate_z_max_values(): - """Test happy path for calculating z_max.""" - - pass - - -def test_calculate_r_0_values(): - """Test happy path for calculating r_0.""" - pass - - -def test_calculate_projected_canopy_area_for_individuals(): - """Test happy path for calculating canopy area for individuals.""" - pass - - -def test_calculate_relative_canopy_radii(): - """Test happy path for calculating relative canopy radii for individuals.""" - pass diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index afda5f74..26c9523c 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -3,13 +3,14 @@ import numpy as np from numpy.testing import assert_array_almost_equal -from pyrealm.t_model_functions import ( +from pyrealm.demography.t_model_functions import ( + calculate_canopy_q_m, calculate_crown_areas, calculate_crown_fractions, calculate_foliage_masses, calculate_heights, + calculate_sapwood_masses, calculate_stem_masses, - calculate_swd_masses, ) @@ -20,7 +21,9 @@ def test_calculate_heights(): diameters_at_breast_height = np.array([0.2, 0.6]) expected_heights = np.array([15.19414157, 15.16639589]) actual_heights = calculate_heights( - pft_h_max_values, pft_a_hd_values, diameters_at_breast_height + h_max=pft_h_max_values, + a_hd=pft_a_hd_values, + dbh=diameters_at_breast_height, ) assert_array_almost_equal(actual_heights, expected_heights, decimal=8) @@ -33,7 +36,10 @@ def test_calculate_crown_areas(): heights = np.array([15.194142, 15.166396]) expected_crown_areas = np.array([0.04114983, 0.1848361]) actual_crown_areas = calculate_crown_areas( - pft_ca_ratio_values, pft_a_hd_values, diameters_at_breast_height, heights + ca_ratio=pft_ca_ratio_values, + a_hd=pft_a_hd_values, + dbh=diameters_at_breast_height, + height=heights, ) assert_array_almost_equal(actual_crown_areas, expected_crown_areas, decimal=8) @@ -45,7 +51,9 @@ def test_calculate_crown_fractions(): heights = np.array([15.194142, 15.166396]) expected_crown_fractions = np.array([0.65491991, 0.21790799]) actual_crown_fractions = calculate_crown_fractions( - heights, pft_a_hd_values, diameters_at_breast_height + a_hd=pft_a_hd_values, + dbh=diameters_at_breast_height, + height=heights, ) assert_array_almost_equal( actual_crown_fractions, expected_crown_fractions, decimal=8 @@ -59,7 +67,7 @@ def test_calculate_stem_masses(): pft_rho_s_values = np.array([200.0, 200.0]) expected_stem_masses = np.array([47.73380488, 428.8197443]) actual_stem_masses = calculate_stem_masses( - diameters_at_breast_height, heights, pft_rho_s_values + dbh=diameters_at_breast_height, height=heights, rho_s=pft_rho_s_values ) assert_array_almost_equal(actual_stem_masses, expected_stem_masses, decimal=8) @@ -71,20 +79,71 @@ def test_calculate_foliage_masses(): pft_sla_values = np.array([14.0, 14.0]) expected_foliage_masses = np.array([0.00529069, 0.02376464]) actual_foliage_masses = calculate_foliage_masses( - crown_areas, pft_lai_values, pft_sla_values + crown_area=crown_areas, lai=pft_lai_values, sla=pft_sla_values ) assert_array_almost_equal(actual_foliage_masses, expected_foliage_masses, decimal=8) -def test_calculate_swd_masses(): - """Tests happy path for calculation of ??? masses.""" +def test_calculate_sapwood_masses(): + """Tests happy path for calculation of sapwood masses.""" crown_areas = np.array([0.04114983, 0.1848361]) pft_rho_s_values = np.array([200.0, 200.0]) heights = np.array([15.194142, 15.166396]) crown_fractions = np.array([0.65491991, 0.21790799]) pft_ca_ratio_values = [390.43, 390.43] - expected_swd_masses = np.array([0.21540173, 1.27954667]) - actual_swd_masses = calculate_swd_masses( - crown_areas, pft_rho_s_values, heights, crown_fractions, pft_ca_ratio_values + expected_sapwood_masses = np.array([0.21540173, 1.27954667]) + actual_sapwood_masses = calculate_sapwood_masses( + crown_area=crown_areas, + rho_s=pft_rho_s_values, + height=heights, + crown_fraction=crown_fractions, + ca_ratio=pft_ca_ratio_values, ) - assert_array_almost_equal(actual_swd_masses, expected_swd_masses, decimal=8) + assert_array_almost_equal(actual_sapwood_masses, expected_sapwood_masses, decimal=8) + + +"""Test the functions in jaideeps_t_model_extension_functions.py.""" + + +def test_calculate_calculate_canopy_q_m_returns_q_m_for_valid_input(): + """Test happy path for calculating q_m. + + test that values of q_m are calculated correctly when valid arguments are + provided to the function. + """ + m_values = np.array([2, 3]) + n_values = np.array([5, 4]) + expected_q_m_values = np.array([2.9038988210485766, 2.3953681843215673]) + actual_q_m_values = calculate_canopy_q_m(m=m_values, n=n_values) + assert_array_almost_equal(actual_q_m_values, expected_q_m_values, decimal=8) + + +def test_calculate_q_m_values_raises_exception_for_invalid_input(): + """Test unhappy path for calculating q_m. + + Test that an exception is raised when invalid arguments are provided to the + function. + """ + + pass + + +def test_calculate_z_max_values(): + """Test happy path for calculating z_max.""" + + pass + + +def test_calculate_r_0_values(): + """Test happy path for calculating r_0.""" + pass + + +def test_calculate_projected_canopy_area_for_individuals(): + """Test happy path for calculating canopy area for individuals.""" + pass + + +def test_calculate_relative_canopy_radii(): + """Test happy path for calculating relative canopy radii for individuals.""" + pass From 19424c3b979e69dc582b23537ee72c923a85ab0c Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 13 Sep 2024 12:46:34 +0100 Subject: [PATCH 091/241] Expand set of tmodel regression test data --- .../t_model/pft_definitions.csv | 4 + .../t_model/rtmodel_output_alt_one.csv | 101 ++++++++++++++++++ .../t_model/rtmodel_output_alt_two.csv | 101 ++++++++++++++++++ .../t_model/rtmodel_output_default.csv | 101 ++++++++++++++++++ .../t_model/rtmodel_test_outputs.r | 41 +++---- .../test_t_model_functions_against_rtmodel.py | 97 +++++++++++++++++ 6 files changed, 427 insertions(+), 18 deletions(-) create mode 100644 pyrealm_build_data/t_model/pft_definitions.csv create mode 100644 pyrealm_build_data/t_model/rtmodel_output_alt_one.csv create mode 100644 pyrealm_build_data/t_model/rtmodel_output_alt_two.csv create mode 100644 pyrealm_build_data/t_model/rtmodel_output_default.csv create mode 100644 tests/regression/demography/test_t_model_functions_against_rtmodel.py diff --git a/pyrealm_build_data/t_model/pft_definitions.csv b/pyrealm_build_data/t_model/pft_definitions.csv new file mode 100644 index 00000000..c83124d4 --- /dev/null +++ b/pyrealm_build_data/t_model/pft_definitions.csv @@ -0,0 +1,4 @@ +name,d,a,cr,Hm,rho,L,sigma,tf,tr,K,y,zeta,rr,rs +default,0.1,116,390.43,25.33,200,1.8,14,4,1.04,0.5,0.6,0.17,0.913,0.044 +alt_one,0.04,124,351.62,15.33,400,4,10,2,0.95,0.6,0.5,0.22,0.813,0.034 +alt_two,0.6,102,406.12,45.33,100,1,21,8,2.1,0.4,0.7,0.15,0.962,0.054 diff --git a/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv b/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv new file mode 100644 index 00000000..da151d5a --- /dev/null +++ b/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv @@ -0,0 +1,101 @@ +"dD","D","H","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" +3.4076525912172,0.04,4.2375677628595,0.377501266657307,0.151000506662923,1.06501694023107,1.04242323817797,2.49321780486283,0.0354423900980509,0.270079506217303,0.516605773866592,0.152056543224708 +2.47765324608507,0.0468153051824344,4.83251153727187,0.503851463291355,0.201540585316542,1.6636750142509,1.61697621579032,2.79337509092686,0.0549771913368709,0.360475490897167,0.497047537525469,0.12441780816647 +1.70732495414315,0.0517706116746045,5.24495157701621,0.604737005461146,0.241894802184458,2.20814685154373,2.1342201820959,2.86891020806033,0.0725634861912606,0.432653043187122,0.408557697387618,0.0921643042234363 +2.15795515547366,0.0551852615828908,5.5196902975137,0.678390225802438,0.271356090320975,2.64046733189626,2.54172665080193,3.49719120139178,0.0864187061272657,0.485347503148096,0.576842315524673,0.121788557787631 +2.45769052870287,0.0595011718938382,5.85626081132705,0.776046411719903,0.310418564687961,3.25680177278109,3.11823461581907,4.19640339006913,0.106019976937848,0.555214644800888,0.747561098692953,0.145949958587722 +3.11155047340158,0.0644165529512439,6.22553858496373,0.893133082124149,0.35725323284966,4.0578105654784,3.86033133335473,5.3368149213653,0.131251265334061,0.638983132274901,1.08274112822144,0.194599241159002 +2.81001896022174,0.070639653898047,6.67248552562724,1.04973086992593,0.419892347970372,5.23003557355684,4.93318428505692,5.93706350539475,0.167728265691935,0.751019453579807,1.14067683625001,0.186152603315975 +1.71684981432575,0.0762596918184905,7.05723507979667,1.19859205856072,0.479436823424288,6.44680528083693,6.03188990209452,5.58154716852031,0.205084256671214,0.857520702376682,0.790448096270193,0.11902984777131 +3.60736429017,0.079693391447142,7.28384315380763,1.29278010594693,0.517112042378772,7.26649670027302,6.76419885349383,8.14826246827467,0.22998276101879,0.924906598998671,1.78412597929806,0.256481929185058 +4.19224398961664,0.086908120027482,7.73996134574854,1.49810037613452,0.599240150453806,9.18288995249815,8.45376241753518,10.1240774804296,0.287427922196196,1.07180093310168,2.38256224753949,0.31252795716962 +1.47061597732594,0.0952926080067153,8.2376484918832,1.74825281064621,0.699301124258484,11.7500999106489,10.6723585524035,7.713647753548,0.362860190781721,1.25076999084873,0.966018518715497,0.114905522620708 +5.19407661707193,0.0982338399613672,8.40438979686104,1.838692368757,0.735476947502799,12.7393803961334,11.5148032967029,13.8254866009506,0.391503312087898,1.31547406830351,3.57645985674181,0.411846506622017 +3.33857337208731,0.108621993195511,8.9625482269241,2.16815855828802,0.867263423315209,16.6106611208001,14.7511363160476,12.8500256064117,0.50153863474562,1.55118735894158,2.67953128580636,0.277087302273617 +2.84640463545498,0.115299139939686,9.29732928510652,2.38740470956093,0.954961883824371,19.4146794851493,17.0403896049967,13.1442354915493,0.579373246569888,1.70804482540827,2.49725058954337,0.24218649999991 +2.94436653441781,0.120991949210596,9.56882005136166,2.57843760576435,1.03137504230574,22.0034718093834,19.1167615381295,14.3592446062027,0.649969892296402,1.84471740066805,2.77286160321962,0.2552820658544 +3.50769891071221,0.126880682279431,9.83680516850189,2.77965784485076,1.1118631379403,24.8751069895891,21.3812560853348,16.6741499394811,0.726962706901384,1.98867840852003,3.53901078491926,0.309471107120787 +3.22565850441175,0.133896080100856,10.1398402885247,3.02371422640172,1.20948569056069,28.5552993574241,24.2280421651559,17.4068569179711,0.823753433615302,2.16328610613684,3.51439402852688,0.289857584530125 +2.89166380704279,0.140347397109679,10.4037324830024,3.25188594380762,1.30075437752305,32.1897629605585,26.9828483663078,17.8285416563365,0.917416844454465,2.32652927963772,3.36592562150624,0.263721660537847 +4.64046296774645,0.146130724723765,10.6288746468056,3.45915951233512,1.38366380493405,35.6525205179494,29.5588038974511,23.5533959007067,1.00499933251334,2.47482108150504,5.71245559296637,0.42822617332666 +2.98460432413264,0.155411650659258,10.9688701981729,3.79653349864332,1.51861339945733,41.6149062556785,33.8912645848012,20.9718796452611,1.15230299588324,2.71619192626938,3.99565666888108,0.279940067885416 +4.12919579076091,0.161380859307523,11.1744369710593,4.01623798817214,1.60649519526886,45.714036901557,36.7996560465635,25.5817932984707,1.25118830558316,2.87337730625787,5.81428543899414,0.390776143958367 +3.26348591200779,0.169639250889045,11.4429591930056,4.32321128487659,1.72928451395063,51.7262409142765,40.9699861852287,24.664973774709,1.39297953029778,3.0929982816521,4.90804363779251,0.312153212199737 +3.68674173027981,0.17616622271306,11.6428517191653,4.56797559195247,1.82719023678099,56.7576660482826,44.3786516195867,27.423777455336,1.50887415506595,3.26811245750648,5.82324663439364,0.355165751841699 +3.39790762104395,0.18353970617362,11.8563311883666,4.84643196102801,1.9385727844112,62.737941281254,48.3404647560288,27.9999494774111,1.64357580170498,3.46733128219788,5.65631161483904,0.329596741599332 +2.41422582702144,0.190335521415708,12.0421234937218,5.10463493794526,2.0418539751781,68.5271461897962,52.0888702482814,25.8078939226368,1.77102158844157,3.65206002000356,4.20754712819561,0.235428098793449 +2.41204568145819,0.195163973069751,12.1680594141748,5.28886812356556,2.11554724942623,72.8015289167792,54.8048155283553,26.7075157145024,1.86336372796408,3.78386781032375,4.33722710628732,0.23597930580402 +4.17945425865771,0.199988064432667,12.289064346927,5.47349418689455,2.18939767475782,77.2052528337077,57.5593429346598,34.5140604823289,1.95701765977843,3.91595668107184,7.74560965426685,0.410050490180691 +4.91674220668635,0.208346972949983,12.4878738385037,5.79451996205028,2.31780798482011,85.1496308686289,62.4226291775791,39.4478920899605,2.12236939203769,4.14563136164925,9.57915517642897,0.484331166030133 +2.42969807983625,0.218180457363355,12.7051804043308,6.173599466451,2.4694397865804,95.0019257385172,68.2772467611385,31.132043092033,2.32142638987871,4.4168400022777,5.00329536433378,0.240170428654464 +2.86538738422293,0.223039853523028,12.8063509296314,6.36135504629793,2.54454201851917,100.071455843836,71.2185622241853,33.9827542131894,2.4214311156223,4.55116785432339,6.05658914291943,0.283593847608982 +3.76176339098658,0.228770628291474,12.9206637504606,6.58304547548127,2.63321819019251,106.219739342274,74.7245899488989,39.2086818659169,2.54063605826256,4.70977405497832,8.1918137233473,0.372734091132853 +3.67060004221364,0.236294155073447,13.0629132641754,6.87439983161545,2.74975993264618,114.568671850992,79.3836202125531,40.4299763832049,2.69904308722681,4.91822061553096,8.29955458345159,0.364056683268274 +3.03264344641453,0.243635355157874,13.1936158377101,7.15889366173236,2.86355746469295,123.016774004259,83.985302538486,38.9099453056646,2.85550028630852,5.1217588813498,7.10225111379236,0.300916988838535 +4.5415877717825,0.249700642050703,13.2958981309334,7.39399417104956,2.95759766841982,130.219755069079,87.8243398148836,47.7082557432084,2.98602755370604,5.2899591897357,10.9375054920958,0.450656625657976 +4.48876498656065,0.258783817594268,13.439988031127,7.7460048232341,3.09840192929364,141.381631709377,93.6291385709334,49.5708377278209,3.18339071141174,5.5418016907346,11.2531667085995,0.445208416489848 +4.52837857308153,0.267761347567389,13.5723697006481,8.09366699412638,3.23746679765055,152.852071245955,99.4233916219363,51.8808215115506,3.38039531514584,5.79053311427777,11.7902254418306,0.448696169006381 +3.98898028803123,0.276818104713552,13.6965261323425,8.44397010555572,3.37758804222229,164.861516016638,105.317260158106,50.975434027005,3.58078684537561,6.04115397231879,10.771490526345,0.394679222579087 +2.27963652706172,0.284796065289615,13.7986074187168,8.75207457267193,3.50082982906877,175.801714223231,110.542917393979,42.8822627252245,3.7584591913953,6.2615842322724,6.34831677583185,0.225193093095027 +3.59922282064066,0.289355338343738,13.8540544352847,8.92791721644203,3.57116688657681,182.204779507247,113.541433548668,51.4611718221524,3.8604087406547,6.38738909333129,10.1958512333737,0.355181632716896 +4.70217974307538,0.29655378398502,13.9375390206237,9.20515979651754,3.68206391860701,192.53642924786,118.291023138269,59.6193444671684,4.02189478670115,6.58573952482051,13.6747403109014,0.463197943475877 +2.58869662054652,0.30595814347117,14.0395338787937,9.56657480935512,3.82662992374205,206.441307114496,124.519658777826,48.699479899716,4.23366839844609,6.84431028160503,7.78141821166302,0.254348139211556 +3.92845501174985,0.311135536712263,14.0924606297139,9.76513413978947,3.90605365591579,214.29199203952,127.957917116452,58.1423829743609,4.35056918195938,6.98636756897098,12.0187019463976,0.385396397344322 +3.47500788727324,0.318992446735763,14.1686620752899,10.065862832357,4.02634513294282,226.469394494977,133.185293229584,56.9084441288503,4.52829996980585,7.20152090478152,10.9118874022255,0.340083982145872 +4.42165708583249,0.32594246251031,14.2321474686788,10.331256478417,4.13250259136681,237.504693702123,137.816726515892,64.609660598691,4.68576870154031,7.39139413491867,14.1982363468642,0.431755237508435 +3.97068480343319,0.334785776681975,14.3079351129848,10.6680668020666,4.26722672082664,251.901548104833,143.716577620126,63.5359890523102,4.88636363908427,7.63236171287054,13.1064525865835,0.386567181266515 +4.41765892162563,0.342727146288841,14.3715237498738,10.9696579929612,4.38786319718448,265.167139458409,149.018237999104,68.3543249186624,5.06662009196953,7.84813211448416,14.9355896750248,0.428897678481159 +4.49751168772706,0.351562464132092,14.4376321668425,11.3042105642454,4.52168422569817,280.298549006447,154.917545742689,70.8972136397498,5.26719655525143,8.08748440608375,15.6038740339542,0.435281459208223 +4.18467015532518,0.360557487507546,14.5002534965219,11.6437233781525,4.65748935126101,296.104160264481,160.921432854673,70.625168461987,5.47132871705889,8.33038545366545,14.8935280612798,0.403689595274399 +3.99912383951496,0.368926827818197,14.5545658790005,11.9586253358874,4.78345013435498,311.171353204695,166.503427843995,71.0540003500767,5.66111654669582,8.55567891030731,14.5648000535661,0.384613856760586 +4.3382543607839,0.376925075497227,14.6031446545066,12.2586651846016,4.90346607384062,325.893970323044,171.832241879997,75.3430056460589,5.84229622391988,8.77033941967134,16.1420482212618,0.416008624683971 +3.32273559776104,0.385601584218794,14.6524077692294,12.5831557348832,5.03326229395328,342.220871079292,177.604935434735,69.3142725626828,6.03856780478099,9.00249293896484,12.6463827316162,0.317616192246975 +4.71943244901862,0.392247055414316,14.6878689854757,12.8309924030577,5.13239696122307,354.975231516814,182.019703142,81.70961742775,6.188669906828,9.17980520484357,18.2687902506444,0.450031569214044 +4.29822971754317,0.401685920312354,14.7350698118396,13.18197770958,5.27279108383202,373.461032437512,188.278972356481,80.4101030850047,6.40148506012036,9.43091413254194,17.0333155762924,0.408466739088663 +2.13975812068631,0.41028237974744,14.7750323864986,13.5006000978576,5.40024003914306,390.673587216186,193.966985402662,64.386911368932,6.59487750369052,9.65886933401127,8.65792475868133,0.20271844934675 +2.15613364514834,0.414561895988813,14.79391433501,13.6588535088672,5.46354140354687,399.375795319384,196.793802952757,65.2661674055522,6.69098930039373,9.77209015438394,8.81340182789697,0.203959774345169 +2.95621172099851,0.418874163279109,14.8122910197491,13.8180759443119,5.52723037772476,408.234082198569,199.638879917524,72.7728844846437,6.78772191719581,9.88600425359851,12.2068432857035,0.279218754996161 +4.21986338367759,0.424786586721106,14.8364671794282,14.0359903441167,5.61439613764669,420.525142632069,203.534006355532,84.705642954316,6.92015621608809,10.0419089317949,17.6650799827995,0.397751374938191 +4.89568691478789,0.433226313488461,14.8690346772329,14.3462821276991,5.73851285107966,438.361400311481,209.082381316197,92.3921926644656,7.1088009647507,10.2639040854411,20.8911833257224,0.460116400742799 +3.46593546913616,0.443017687318037,14.9041346627114,14.7051546859979,5.88206187439915,459.482287105371,215.501446350263,81.8526044556982,7.32704917590896,10.5206558685503,15.1151296502862,0.324672145840963 +4.34123040552854,0.44994955825631,14.9273558140644,14.9585149741582,5.98340598966328,474.712231041645,220.033938411622,91.1302980928757,7.48115390599516,10.7019199531118,19.21986099901,0.405739515401494 +2.75924387330133,0.458632019067367,14.9546633681683,15.2750548591103,6.11002194364412,494.111840722041,225.696866858762,78.4142050093078,7.67369347319789,10.9283852484019,12.4443628044286,0.257164866532715 +4.74857268552241,0.464150506813969,14.9710490197482,15.4757899744384,6.19031598977537,506.628675409696,229.287872483935,97.9441463553031,7.7957876644538,11.0719991793122,21.6657487341854,0.441804418794587 +3.95091031925792,0.473647652185014,14.9975910020453,15.8204437352563,6.3281774941025,528.50872415359,235.452688040144,92.4602979373157,8.00539139336489,11.3185782659517,18.3828297591537,0.366518804346683 +1.9697004186902,0.48154947282353,15.01817237298,16.1064475341568,6.44257901366274,547.039624351573,240.567268191126,74.9734471495096,8.17928711849829,11.5231968238372,9.31224044133609,0.182294992200624 +3.37507276957209,0.48548887366091,15.0279520235311,16.2487833073886,6.49951332295542,556.388621111865,243.112137017482,89.2822300992611,8.26581265859438,11.6250295294381,16.0824307285656,0.312002028200505 +2.12742516487558,0.492239019200054,15.0440017007336,16.4922981100648,6.5969192440259,572.578879535063,247.465096897291,78.3031501074436,8.4138132945079,11.7992497598647,10.2732224793352,0.196285281127394 +4.77111561725361,0.496493869529806,15.0536772427654,16.6455540977098,6.65822163908393,582.894903583709,250.203968853327,105.254328811888,8.50693494101313,11.9088952236655,23.2314215730573,0.439677345758567 +6.04503382925559,0.506036100764313,15.0742027331351,16.9886010691142,6.79544042764568,606.341411105408,256.332557171022,120.208477464577,8.71530694381477,12.1543247488871,29.9792723629575,0.555620897767399 +4.66427590921526,0.518126168422824,15.0980337020725,17.4219869279571,6.96879477118284,636.665507837195,264.070467003803,108.870114848915,8.97839587812929,12.4643863277376,23.6636539163409,0.427353444220947 +1.71244608997883,0.527454720241255,15.1148928884953,17.755463869484,7.10218554779362,660.534213227927,270.02068343444,79.8701308818371,9.18070323677095,12.7029690707837,8.83843785782317,0.156532123688676 +3.42414296992047,0.530879612421212,15.1207702102284,17.8777033475959,7.15108133903838,669.400272905403,272.200902075947,98.5095361772892,9.25483067058219,12.790424083004,17.7834670199142,0.312734132013411 +4.67532197179623,0.537727898361053,15.1320450879592,18.1218262263991,7.24873049055965,687.294141327024,276.553493769973,113.208297365798,9.40281878817907,12.965079355415,24.5829914043761,0.42630919383445 +3.18843457428175,0.547078542304645,15.1464651450937,18.4545192748916,7.38180770995664,712.082854488507,282.481940363429,99.0498471467853,9.6043859723566,13.2031012700284,17.0454586296706,0.290104876072618 +4.0916443402265,0.553455411453209,15.1556919880842,18.6810023208245,7.47240092832981,729.223949947645,286.515523928416,110.170571761801,9.74152781356615,13.3651363004107,22.1194885766672,0.371757370105621 +1.95331974249994,0.561638700133662,15.1668562639784,18.9711807707903,7.58847230831613,751.500889713508,291.680778761914,87.9992933363734,9.91714647790507,13.5727415706542,10.7100000789139,0.17716211789244 +5.08340155532172,0.565545339618662,15.1719309543811,19.1095320088165,7.64381280352661,762.246766091291,294.142377533173,123.75842373675,10.0008408361279,13.6717235803877,28.0588841926186,0.460677836515594 +3.90792350721405,0.575712142729305,15.1844098382668,19.4690639887022,7.78762559548087,790.548598878244,300.535979438678,112.59888618167,10.2182233009151,13.9289471400771,21.9441193929559,0.353424300634486 +2.46967229628026,0.583527989743733,15.1933291603666,19.7449666743902,7.8979866697561,812.636282448057,305.439107690562,97.5341871124819,10.3849296614791,14.1263389575258,14.0493771927678,0.223014325973234 +4.8753772986644,0.588467334336294,15.1986819223211,19.9191156107844,7.96764624431375,826.742994915549,308.532474503196,126.413616165804,10.4901041331087,14.2509320725796,27.9612308801021,0.439844675177353 +4.27821024917365,0.598218088933623,15.208641208173,20.2624390429558,8.10497561718231,854.927670561952,314.62751172276,121.46532303098,10.6973353985739,14.4965593888923,24.9285192904262,0.385289804001696 +4.79803725394281,0.60677450943197,15.2167564359228,20.56322288318,8.22528915327202,880.02826641428,319.963717585896,129.461728606572,10.8787663979205,14.7117521795423,28.3434554814418,0.431466917320751 +5.24531535000394,0.616370583939856,15.2252139112449,20.9000378631955,8.3600151452782,908.588191354735,325.935169467635,136.974446856678,11.0817957618996,14.9527230888446,31.4589778438749,0.470943513177193 +4.90104398243494,0.626861214639863,15.233738802801,21.2676581305881,8.50706325223525,940.305944501134,332.448033612529,135.06139844747,11.303233142826,15.215733332948,29.8778044253446,0.439312402893434 +2.28013837910928,0.636663302604733,15.2410762727071,21.6106196640405,8.6442478656162,970.40974480616,338.519653158533,104.280713236762,11.5096682073901,15.4611017324411,14.1105025063145,0.204086994231776 +3.80863167248694,0.641223579362952,15.2442966232462,21.7700106010397,8.70800424041589,984.569177478894,341.340014860126,124.367780277258,11.6055605052443,15.5751363844079,23.7329596210461,0.340675395796068 +4.13716150876472,0.648840842707926,15.2494177537781,22.0360225155935,8.81440900623742,1008.4386871905,346.045027096335,130.063012440891,11.7655309212754,15.7654519485562,26.0768214964022,0.369673192616678 +5.79275674057479,0.657115165725455,15.2546344921442,22.3246707493989,8.92986829975958,1034.67668800861,351.147678437689,153.161413024435,11.9390210668814,15.97196244095,36.9635432007299,0.517042397722757 +5.0903653175615,0.668700679206605,15.261376310789,22.7283145557011,9.09132582228044,1071.95636379996,358.278540320474,146.622603210829,12.1814703708961,16.2607453657308,33.0372426221192,0.45369156277112 +6.26165478478156,0.678881409841728,15.2668009815026,23.0825468803666,9.23301875214666,1105.23786140791,364.532151934983,164.499697686025,12.3940931657894,16.5141773400895,41.2400589505367,0.557417626912788 +4.43283749002881,0.691404719411291,15.272889311417,23.5177251072681,9.40709004290724,1146.847733345,372.209437285899,142.683356087229,12.6551208677206,16.8255212507439,29.7189019215063,0.394069942058171 +3.5382461357486,0.700270394391349,15.2768414279516,23.8254494703924,9.53017978815697,1176.75209331134,377.634792563457,132.218557878167,12.8395829471575,17.0456795690976,24.0174143473388,0.314253403806956 +4.30546398815621,0.707346886662846,15.279798764229,24.0708732903386,9.62834931613544,1200.88772132753,381.959789519804,144.220878960209,12.9866328436733,17.2212655868398,29.5129589350622,0.382126676457145 +5.3298811451347,0.715957814639158,15.2831763554113,24.3692870768276,9.74771483073104,1230.57579686032,387.216330726321,160.377876687715,13.1653552446949,17.4347627462455,36.9687043530275,0.4726621825116 +1.24478389836617,0.726617576929428,15.2870445074308,24.7383765108675,9.89535060434699,1267.81301432757,393.714485943257,104.550948292473,13.3862925220708,17.698824090935,8.7594076329805,0.110284136618117 +4.31842070711914,0.72910714472616,15.2879008681686,24.8245267405674,9.92981069622695,1276.58707500322,395.23072424028,148.863699423828,13.4378446241695,17.7604594112715,30.4899240444183,0.382517215662588 +1.80760653348548,0.737743986140398,15.2907415710799,25.1232599557057,10.0493039822823,1307.25340374604,400.486945574493,114.324545436226,13.6165561495328,17.9741851027101,12.9101786030993,0.159999117728906 +3.27222893921011,0.741359199207369,15.2918729599581,25.2482410637384,10.0992964254954,1320.19450331298,402.685332821539,136.174339180617,13.6913013159323,18.063601586641,23.4826704033615,0.289555169133979 +3.0910324276404,0.74790365708579,15.2938387722363,25.4743980254686,10.1897592101874,1343.77853092433,406.662416521562,134.730807522447,13.8265221617331,18.2254033233412,22.3738423318281,0.2733819634356 +5.55242634737728,0.75408572194107,15.2956025467487,25.6879279024675,10.275171160987,1366.24285167527,410.416336670436,172.209944499845,13.9541554467948,18.3781711385414,40.515241209822,0.490848952021599 +5.80374973980142,0.765190574635825,15.2985575610163,26.0712505057187,10.4285002022875,1407.05017879372,417.15265675441,178.509437646041,14.1831903296499,18.6524154618114,42.9597934199056,0.512661411469696 diff --git a/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv b/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv new file mode 100644 index 00000000..4ad51974 --- /dev/null +++ b/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv @@ -0,0 +1,101 @@ +"dD","D","H","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" +13.4468615259933,0.6,33.5798055081921,63.0047820994125,3.00022771901964,474.723316320797,378.031173825666,112.800283144307,20.413683386586,9.09159005694522,52.6093955065352,0.821741240601042 +20.1226590065085,0.626893723051987,34.2697846560544,67.1814516669976,3.19911674604751,528.882386519655,414.98734677119,160.393378634384,22.4093167256443,9.69428347554776,83.3639407310527,1.24033945985456 +21.415559932846,0.667139041065003,35.2273694324058,73.492100012986,3.49962381014219,615.705187027075,472.473726964019,183.399124821607,25.513581256057,10.6049100318739,96.0757140378924,1.33384074420015 +18.7427359837963,0.709970160930695,36.1555840437245,80.2711647605426,3.82243641716869,715.674362237756,536.232653219677,180.939134015321,28.9565632738626,11.5831290749463,90.8910762785455,1.17707371011401 +18.7503702918153,0.747455632898288,36.8976945022625,86.2439694372004,4.10685568748573,809.524421039719,593.95415246012,194.087148985833,32.0735242328465,12.445004789788,96.8406340656255,1.18375941644892 +20.8775007275776,0.784956373481919,37.5800425660006,92.24585803966,4.39265990665048,909.30209888026,653.267633149951,224.042630503815,35.2764521900974,13.3110773151229,114.357579272193,1.32291907851609 +13.5153459719739,0.826711374937074,38.275034542045,98.9494971843508,4.71188081830242,1027.26692066309,720.911579574095,177.791393926889,38.9292252970011,14.2784124437018,78.6932361026511,0.858586897937527 +14.2209716545081,0.853742066881022,38.691353117325,103.296281156986,4.91887053128505,1107.45774878866,765.485577183094,191.737565956016,41.3362211678871,14.9056533709531,85.9496039059287,0.904215472756413 +21.5328173587532,0.882184010190038,39.1029102941759,107.872899086908,5.1368047184242,1195.05345269207,812.968074988941,266.376314649445,43.9002760494028,15.5660593382409,135.120033624822,1.36964419099955 +17.1788288524123,0.925249644907544,39.6780293143474,114.802965921938,5.46680790104467,1333.91400968529,885.846401042909,241.1605697223,47.8357056563171,16.5660679825357,113.755295312689,1.09229910652615 +13.9498351415601,0.959607302612369,40.0985218676212,120.327805190942,5.72989548528294,1450.02449251351,944.70695375387,220.362858568923,51.014175502709,17.3633022890529,96.1925705638733,0.886115816554606 +19.6626251502739,0.987506972895489,40.4168514462113,124.80923927041,5.94329710811476,1547.75674606689,992.895675286195,287.092323614537,53.6163664654546,18.0099732267201,139.920802037173,1.24752890779383 +16.607403649346,1.02683222319604,40.8329273182244,131.115516973634,6.24359604636353,1690.71100346357,1061.31266362699,268.362756523188,57.3108838358573,18.9199690992954,123.295072501955,1.05141643432936 +19.0170384588928,1.06004703049473,41.1567802590317,136.430230531606,6.49667764436221,1816.14929035304,1119.46533207356,305.62993595651,60.4511279319721,19.6868822657108,146.08592092715,1.20132593194018 +15.8351765175105,1.09808110741251,41.4990803491458,142.500693916232,6.78574732934437,1965.02100583866,1186.374710968,282.198249070145,64.064234392272,20.5628501321123,126.275515061345,0.997460710502415 +19.4532945400472,1.12975146044754,41.762584593619,147.541558579008,7.02578850376229,2093.21133048073,1242.28611044939,334.753071164087,67.083449964267,21.2902469029509,159.826495296775,1.2221603924201 +10.1546824395512,1.16865804952763,42.0616178891886,153.715448150814,7.31978324527688,2255.90480319315,1311.14434038745,234.338846047754,70.8017943809223,22.1811391681625,86.4187158529375,0.635775122556258 +15.7399448585692,1.18896741440673,42.2076195866885,156.929611276793,7.47283863222824,2343.09905996866,1347.13986319975,308.933383041192,72.7455526127867,22.6449429072412,136.353048202548,0.983610284895937 +22.9624669857488,1.22044730412387,42.421141594818,161.899486446503,7.70949935459538,2481.30586536156,1402.9741616628,410.954498559338,75.7606047297912,23.3620958942304,204.323671489059,1.43065061444497 +17.9133366771062,1.26637223809537,42.7067290226697,169.122651038371,8.05345957325578,2689.54588188523,1484.45762226332,361.272117331813,80.1607116022191,24.404398544837,165.497002279203,1.11103094358604 +15.2205768333594,1.30219891144958,42.909906777722,174.734630565322,8.32069669358677,2857.40705492221,1547.99769113822,336.083557854815,83.5918753214637,25.214207190576,144.632480628587,0.940619984277925 +9.39789597168783,1.3326400651163,43.070127425594,179.487045889403,8.54700218520968,3003.73610130033,1601.93888579824,263.638972117013,86.504699833105,25.8999807218409,91.3961368394102,0.578988703070732 +15.7595964303829,1.35143585705967,43.163712686149,182.414063479943,8.68638397523539,3095.77617875419,1635.21412439553,358.206468500735,88.3015627173584,26.3223493601558,155.423351777666,0.969063758830436 +12.4666267288399,1.38295504992044,43.312031347035,187.309888078712,8.91951847993866,3253.00377635744,1690.94938859999,319.851757739313,91.3112669843994,27.0288168497581,125.799835442529,0.764118761179434 +16.8611956537359,1.40788830337812,43.4221299885645,191.171615901372,9.10341028101772,3379.92770123049,1734.97204248724,391.285824202797,93.6884902943112,27.586064174568,173.183986272428,1.03086083466067 +11.8336136412102,1.44161069468559,43.5615446488633,196.379139916053,9.35138761505014,3555.1599734372,1794.40589080271,325.713796388422,96.8979181033465,28.3375098898864,124.417826753027,0.721026249148752 +16.4944719525086,1.46527792196801,43.6532602123864,200.023387165572,9.52492319836056,3680.58271142509,1836.0373902594,403.298639247764,99.1460190740074,28.863374767992,176.221832659709,1.00263892699086 +20.0736002553168,1.49826686587303,43.7732182284202,205.088703513063,9.76612873871728,3858.75063059255,1893.94598645029,469.410316527027,102.273083268316,29.594299916935,219.193862561796,1.21623157703197 +12.2220336427015,1.53841406638366,43.9076891901282,211.231124292266,10.0586249662984,4080.81541818482,1964.21895240589,356.598563853233,106.067823429918,30.480651235374,136.952156802841,0.737640058483079 +14.889684763343,1.56285813366907,43.9838082447748,214.959416005811,10.2361626669434,4218.82809450043,2006.89179215199,406.472840247524,108.372156776207,31.0186437296385,169.427107607721,0.896555877670914 +26.3632170809837,1.59263750319575,44.0710586422218,219.48988363947,10.4518992209271,4389.82537995441,2058.75826758297,605.856136159903,111.17294644948,31.6723902091755,305.540215257397,1.58300815947022 +18.6572436260023,1.64536393735772,44.2119031767812,227.481074884896,10.832432137376,4700.27258184673,2150.25817744805,494.495278186042,116.113941582194,32.8255191058905,223.171407860479,1.11496216485438 +14.6366423184651,1.68267842460972,44.3019495879274,233.113836505562,11.1006588812172,4925.8930319761,2214.7502895579,435.848822864532,119.596515636126,33.6383266077526,178.919366338477,0.871849414001941 +22.1233868222178,1.71195170924665,44.3674849041894,237.520121779023,11.3104819894773,5106.31633543378,2265.19085135369,577.561713739933,122.320305973099,34.274153572713,274.982997609332,1.31454709365196 +18.081195088664,1.75619848289109,44.4586992687314,244.159955504509,11.6266645478338,5384.72877854538,2341.17566402404,519.238530888775,126.423485857298,35.2322815793006,230.344115277233,1.07048924905985 +21.1233094954501,1.79236087306842,44.5267902984929,249.569168548522,11.8842461213582,5617.35906982172,2403.04931115383,587.203407934436,129.764662802307,36.0128310215517,274.439184546813,1.24705538338439 +14.5831497167101,1.83460749205932,44.5996280354426,255.869479995738,12.184260952178,5894.91364977461,2475.07672104261,476.898996588971,133.654142936301,36.921965963385,193.768383470102,0.858213865107776 +18.7203782798503,1.86377379149274,44.6460225525782,260.207650770186,12.390840512866,6090.16502324923,2524.6445096648,564.995468893127,136.330803521899,37.5479640061379,252.547205968029,1.09936915412641 +12.4279654853734,1.90121454805244,44.701285632075,265.763435854776,12.6554017073703,6345.15385599393,2588.08848727998,452.668971205795,139.756778313119,38.3496637938442,170.900797895873,0.727944698832728 +19.5565743985037,1.92607047902319,44.7354843197345,269.443930715844,12.8306633674211,6517.12992117884,2630.09393107607,601.342549824469,142.025072278108,38.8807592022962,272.312291290085,1.14358357870095 +18.2798131369585,1.96518362782019,44.7855718187514,275.223395190097,13.1058759614332,6792.1033244494,2696.01473569959,587.973482396891,145.584795727778,39.7147359259309,259.508483223929,1.06623385896982 +14.1072370633568,2.00174325409411,44.8285665848949,280.612693891842,13.3625092329449,7053.93551599766,2757.43946914374,512.814336162252,148.901731333762,40.4924117285929,203.859049924271,0.821007742121497 +19.8050054494929,2.02995772822082,44.8594117103333,284.763718433597,13.5601770682665,7259.17804060626,2804.71995834678,640.069074448718,151.454877750726,41.0914045699681,290.079976904746,1.15068984893757 +14.8923041032743,2.06956773911981,44.8995399527871,290.579936270046,13.8371398223831,7551.98412999577,2870.92100052901,547.778925299972,155.029734028567,41.9306848037676,222.224274121031,0.86332819494264 +19.5770663311285,2.09935234732636,44.927444000011,294.945064798512,14.0450030856434,7775.74961094531,2920.56984247724,657.612729978153,157.710771493771,42.5605728504252,296.182745589844,1.13309433975509 +21.4541849376102,2.13850647998862,44.9613930349864,300.672989843261,14.3177614211076,8074.5956845281,2985.67250540469,711.648928170717,161.226315291853,43.3871124343825,330.41923969305,1.23924830878676 +26.0871093213351,2.18141484986384,44.9953182737374,306.937308488572,14.6160623089796,8408.2137640167,3056.81138278035,830.510175444349,165.067814670139,44.291053614901,409.551083762651,1.50372999677303 +23.6848164199906,2.23358906850651,45.0323913450531,314.537457827628,14.977974182268,8822.49551842321,3143.03651334467,795.29521835166,169.723971720612,45.3877551645266,380.427199470391,1.36203650998786 +16.7670950183068,2.28095870134649,45.0624811921284,321.422748173394,15.305845151114,9206.82377797127,3221.073709784,649.851146065802,173.937980328336,46.3813025614207,274.83800443958,0.962301413091768 +25.6444784861217,2.3144928913831,45.0819246829752,326.288965867283,15.5375698032039,9483.6176730683,3276.18342489496,871.216508598663,176.913904944328,47.0834977746489,426.33498215166,1.46984103391362 +20.6471788563113,2.36578184835534,45.1089644035136,333.719542284902,15.8914067754715,9914.53004396059,3360.26685787001,769.084490221748,181.45441032498,48.1557299517113,350.627346204693,1.18116274670519 +25.0351224620777,2.40707620606797,45.1285775142083,339.692197452844,16.1758189263259,10268.1264896237,3427.79532498861,891.346363808126,185.100947549385,49.0175840924454,432.34363765911,1.43013910201775 +16.589052798004,2.45714645099212,45.1500393373614,346.923134977597,16.5201492846475,10704.8380881859,3509.48461134532,696.809128304744,189.512169012647,50.0610083772672,292.273795925729,0.946127127099266 +19.5256765742748,2.49032455658813,45.1629852621552,351.70835002371,16.7480166677957,10999.031070097,3563.50604943847,781.550687137785,192.429326669678,50.7515149084213,348.5308666155,1.11249819111225 +22.6510255124076,2.52937590973668,45.1770348598418,357.334697146018,17.0159379593342,11350.2222270225,3626.98600261925,875.178995546822,195.857244141439,51.5633967981703,410.490814890779,1.28913415035214 +17.7795085505431,2.57467796076149,45.1918592706897,363.854048794123,17.3263832759106,11764.2955329871,3700.49310755546,762.327949969558,199.826627807995,52.504139240992,327.831991803092,1.01066341795273 +23.6382739288928,2.61023697786258,45.202481778092,368.965963198973,17.5698077713796,12094.3363135149,3758.09636899737,929.932759579562,202.937203925858,53.2417884896117,441.734188182066,1.3425112043073 +14.6879037072415,2.65751352572037,45.2153505494857,375.755609694813,17.8931242711816,12539.9774380953,3834.56018374163,703.061954104784,207.066249922048,54.2215344789615,279.332324726993,0.833267124978738 +18.2420772643019,2.68688933313485,45.2226838887766,379.970779430977,18.0938466395703,12820.8192509498,3882.00607672122,808.903277385218,209.628328142946,54.82978347189,350.674877884893,1.03423736507214 +20.7411236327924,2.72337348766345,45.231142105936,385.202277633968,18.3429656016175,13173.8237922516,3940.86673120045,889.813762333717,212.806803484824,55.5846886625815,404.013234896033,1.17503513175602 +20.7535304353342,2.76485573492904,45.2399521238852,391.145825241385,18.6259916781612,13580.8506558953,4007.70668379581,903.89922020901,216.416160924974,56.4423425823318,410.286470447816,1.17479476636573 +16.2782656924011,2.80636279579971,45.2479815902443,397.088319612941,18.9089676006162,13994.1564629241,4074.50238579423,789.033993535604,220.023128832888,57.2998445201473,326.549867626844,0.920774149952184 +15.8677724125978,2.83891932718451,45.2537752548804,401.7463634293,19.130779210919,14322.5650802822,4126.83891305294,786.426769551048,222.849301304859,57.972000242848,321.939251013151,0.897060371444283 +20.9874252218571,2.8706548720097,45.2590286749825,406.28454139152,19.3468829234057,14646.2714484777,4177.81134982449,945.815467650018,225.601812890522,58.6268593227964,430.486182672438,1.1858893827178 +14.5440089994823,2.91262972245342,45.2654251146134,412.283512671859,19.6325482224695,15079.8507503603,4245.16635261556,767.77847191294,229.23898304124,59.4925108785493,302.608706120634,0.821287613058768 +11.5553030871171,2.94171774045238,45.2695163723604,416.438565231202,19.8304078681525,15383.9457482043,4291.80243121033,685.653734092233,231.757331285358,60.0920849628625,242.786359709607,0.652249995454262 +20.7725571470686,2.96482834662662,45.2725813006302,419.738589427769,19.9875518775128,15627.6707065731,4328.83289066771,970.718255656666,233.756976096056,60.5682784544271,439.823167887548,1.17216108582138 +18.7802799922004,3.00637346092075,45.2777057384985,425.668417401557,20.2699246381694,16070.5283893029,4395.35433024181,923.23801982608,237.349133833058,61.4239526310446,403.127646753129,1.0591790632306 +15.1765800519215,3.04393402090516,45.2819438957043,431.026909006815,20.5250909050864,16476.1378619184,4455.44675843334,822.781153433119,240.5941249554,62.1971829696834,329.784065340832,0.855553794026882 +16.9905047076646,3.074287181009,45.2851165317927,435.355475456301,20.7312131169667,16807.5434911471,4503.97624362117,888.146516950586,243.214717155543,62.8217951083442,372.831296597272,0.957485368346211 +23.9863967950323,3.10826819042433,45.2884205255808,440.19970339344,20.9618906377829,17182.4080345944,4558.27404467836,1120.38385778333,246.146798412632,63.5208171996735,532.087049731212,1.35124750210528 +14.1740892972385,3.15624098401439,45.2926751278059,447.035707432521,21.2874146396439,17718.5495609514,4634.87515953927,821.368164870714,250.283258615121,64.5072525825128,319.214203104783,0.798105676951936 +16.3792023993594,3.18458916260887,45.2949816634004,451.073785144511,21.4797040545005,18039.1803095432,4680.11256533641,900.638990024917,252.726078528166,65.0899471963529,372.149525833843,0.92203008787266 +16.7504245982794,3.21734756740759,45.2974700892663,455.738809924699,21.7018480916523,18413.2221327951,4732.36349899753,922.257605978384,255.547628945867,65.7631102721341,384.454644389233,0.942659194100423 +20.9561140219608,3.25084841660415,45.2998321272217,460.508233077112,21.9289634798625,18799.6566229013,4785.77324229686,1071.67046037026,258.431755084031,66.4513380330272,485.93757258909,1.17901883337278 +16.6398109437233,3.29276064464807,45.3025472019539,466.473386359317,22.2130183980627,19288.6943827842,4852.55909838455,940.50083793403,262.038191312766,67.3121096516494,390.77334246752,0.935878514358757 +14.1920165743093,3.32604026653551,45.3045279075342,471.208590118448,22.4385042913547,19681.4232193048,4905.56391714144,867.017569903928,264.900451525637,67.9953995540921,336.624616533914,0.79801716957377 +8.56686696704997,3.35442429968413,45.3061039142605,475.246360138939,22.6307790542352,20019.4708160424,4950.75486912334,681.882668890875,267.34076293266,68.5780497680489,204.918060435658,0.481622934325769 +20.5447881096357,3.37155803361823,45.3070076642359,477.68335274274,22.7468263210828,20224.9075196344,4978.02686640466,1097.79190089247,268.813450785852,68.9297078007773,493.91564178457,1.15488505775926 +19.7743358249175,3.4126476098375,45.309038182094,483.526605390501,23.0250764471667,20721.8067623154,5043.40912167445,1084.49430714033,272.34409257042,69.7728891578492,481.137082470577,1.11129609121837 +14.2462436999226,3.45219628148734,45.3108230021309,489.149392047429,23.2928281927347,21205.7089845893,5106.31358157896,902.420475653876,275.740933405264,70.584257272444,350.61541017292,0.800443497203485 +12.8863260452843,3.48068876888719,45.312013909263,493.199518598624,23.4856913618392,21557.7600919794,5151.61779712293,861.687417286311,278.187361044638,71.1686905337815,319.743782761421,0.723924771114698 +6.51939631486714,3.50646142097775,45.3130273030537,496.86251112375,23.6601195773214,21878.6788550339,5192.58731335232,640.334490114408,280.399714921025,71.6972603551572,162.952368930743,0.366197142867173 +17.2589347907408,3.51950021360749,45.3135180383387,498.715497592797,23.7483570282284,22041.9320190259,5213.31094828266,1028.54103908023,281.518791207264,71.9646463026406,432.979861351469,0.96937957688954 +23.6900582943807,3.55401808318897,45.3147497540226,503.620391517701,23.9819234056048,22477.0203152633,5268.16222562923,1272.02286993677,284.480760183978,72.6724224960042,600.107775042359,1.33038050328461 +15.8789848370893,3.60139819977773,45.3162919598759,510.351736040043,24.3024636209544,23081.1018897938,5343.42831029794,1002.11898239759,288.545128756089,73.6437555105781,407.568020257578,0.891545050015464 +21.7267908395487,3.63315616945191,45.3172373639338,514.862877755904,24.5172798931383,23490.4558450143,5393.8630796228,1227.86650772869,291.268606299631,74.294713260177,562.551930465887,1.21972142598119 +17.9786370695621,3.67660975113101,45.3184261979905,521.034452537431,24.8111644065443,24056.3522585912,5462.85398496804,1102.13227390991,294.994115188274,75.1852715011513,471.039739664364,1.00913922933779 +16.987762780536,3.71256702527013,45.3193257501983,526.14061731285,25.0543151101357,24529.6827615086,5519.92866275932,1075.53356721071,298.076147789003,75.9220910782443,449.408065471177,0.953402315276292 +16.4142500287741,3.7465425508312,45.320111388647,530.964793140462,25.2840377685934,24981.1365397408,5573.84655336076,1063.60166972758,300.987713881481,76.6182196501686,438.189340712878,0.921113250310375 +21.4964465557266,3.77937105088875,45.3208155285705,535.62561197931,25.5059815228243,25421.2362192179,5625.93447686793,1268.97578861037,303.800461750868,77.2907758086144,578.865777485597,1.20618827543221 +12.8826339592445,3.8223639440002,45.3216624196611,541.728837213677,25.7966112958894,26003.3791771709,5694.13647003929,947.76861914691,307.483369382121,78.1714712099336,350.837381809483,0.722769823094926 +18.8887774284275,3.84812921191869,45.3221320548339,545.386100221046,25.9707666771927,26355.3938209855,5735.00247265179,1189.98839915087,309.690133523197,78.699214261897,517.857173118276,1.0596669873325 +7.8958551929425,3.88590676677555,45.3227732372576,550.748013679365,26.2260958894936,26875.7823033553,5794.91232976813,766.184569738717,312.925265807479,79.4729383739323,218.590131774251,0.442918295435595 +20.0726932657472,3.90169847716143,45.3230255238477,552.989244649189,26.3328211737709,27094.8148282414,5819.95283074247,1253.87633612637,314.277452860094,79.796348002878,557.94500411031,1.1259361666939 +17.8300780130369,3.94184386369293,45.3236279358506,558.686491611798,26.6041186481809,27655.6192389178,5883.60301322003,1176.79098785543,317.714562713882,80.6184607395825,500.688831561648,1.00005071643561 +13.3931057393873,3.977504019719,45.3241192623294,563.746797767257,26.8450856079646,28158.5646767881,5940.13359581891,1007.62762010455,320.767214174221,81.3486629178151,379.483821703075,0.751134292739026 +17.5869692681093,4.00429023119778,45.3244632438292,567.5476168633,27.0260769934905,28539.3219430734,5982.59186128348,1185.75995673528,323.059960509308,81.8971211133742,501.658348174177,0.986289290217428 +17.0933910131153,4.03946416973399,45.3248845691977,572.53831313909,27.2637291970995,29043.1764227298,6038.33943619893,1175.98835027381,326.070329554742,82.6172785859707,491.848413212339,0.958546335540944 +10.5116711811783,4.07365095176023,45.3252633236238,577.388642682624,27.4946972706012,29537.0997448489,6092.51641166153,912.720363556032,328.995886229723,83.3171811391027,305.016796201568,0.589428064750264 diff --git a/pyrealm_build_data/t_model/rtmodel_output_default.csv b/pyrealm_build_data/t_model/rtmodel_output_default.csv new file mode 100644 index 00000000..e24f234f --- /dev/null +++ b/pyrealm_build_data/t_model/rtmodel_output_default.csv @@ -0,0 +1,101 @@ +"dD","D","H","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" +10.0193765180823,0.1,9.30685130731739,2.46024211324268,0.316316843131202,7.30958392378022,7.02392939699003,9.78053256354872,0.309052893467561,0.687337521113514,4.08436398628558,0.383163162838877 +8.94826996898982,0.120038753036165,10.711819414002,3.39906751279348,0.43702296593059,12.1226083507134,11.4772945001997,12.230269204462,0.505000958008785,0.949624683589217,4.97058165919415,0.385438488085086 +10.9544242990939,0.137935292974144,11.8621158250655,4.32526414254345,0.556105389755587,17.7256775596921,16.5399186131405,17.8935142010193,0.727756418978182,1.2083836456155,7.65010363773741,0.512668700892211 +8.89695823526391,0.159844141572332,13.1478077357338,5.55552544627375,0.714281843092339,26.3837591192719,24.1508693832434,19.498706462455,1.06263825286271,1.55209158812907,7.86616538293065,0.451043603635951 +8.78531953345,0.17763805804286,14.101141616645,6.62163692287193,0.851353318654962,34.9475060802419,31.4648881117397,22.8725802145125,1.38445507691655,1.84993968023811,9.15277344984067,0.469010169526799 +8.89702030940376,0.19520869710976,14.9692825462652,7.72458615765159,0.993161077412348,44.801153176621,39.6545187783565,26.7543031566861,1.74479882624769,2.15807943155239,10.694429135877,0.49532460694634 +11.4305447761726,0.213002737728567,15.7800798895247,8.8852459918118,1.1423887703758,56.2301769103635,48.8881734052546,36.6197413642089,2.1510796298312,2.4823422547004,15.6328125882049,0.65906914403219 +9.78711084366124,0.235863827280912,16.7293370477721,10.430740604128,1.34109522053074,73.0956100787923,62.0601613634078,38.1286931965105,2.73064709998994,2.91411944850007,15.5009548647787,0.585082487301701 +12.9550108860307,0.255438048968235,17.466764507657,11.7943259622377,1.51641333800199,89.5104052127066,74.4254959534891,52.5417247468014,3.27472182195352,3.29507519867805,22.9401161424638,0.793683558309927 +10.0666892193544,0.281348070740296,18.3465579659371,13.6450022534866,1.75435743259113,114.059735900108,92.1931032079778,50.2238440564425,4.05649654115102,3.81211343957458,20.3273297143475,0.632441863735982 +10.6815066568184,0.301481449179005,18.9616518981767,15.1116482662492,1.94292620566062,135.359031780319,106.990074003523,57.6691870898778,4.70756325615503,4.22186206932818,23.6306898678065,0.681123745691776 +12.544157302508,0.322844462492642,19.5551797815225,16.6889966539019,2.14572814121596,160.08047995681,123.530399320254,71.0439872809571,5.43533757009117,4.66253850717382,30.3111481554649,0.809670208279064 +13.5319826386959,0.347932777097658,20.1819709367495,18.562394263949,2.38659354822202,191.886377777615,143.923672907495,82.9502604127476,6.3326416079298,5.18592458467355,35.9182457105518,0.882494891432708 +12.7060673483057,0.37499674237505,20.7820655871978,20.6011412101063,2.6487181555851,229.52689541987,166.925235522201,87.2872964057804,7.34471036297683,5.75550562899709,36.9538864182509,0.834692665855434 +13.8821677047812,0.400408877071661,21.2817001019339,22.5260523473027,2.89620673036749,267.980747823668,189.312536647627,101.143992252697,8.3297516124956,6.29328345268473,43.6451158269815,0.91554909305737 +10.5483374872048,0.428173212481223,21.7650541865735,24.6350993996117,3.16736992280721,313.392515782141,214.483324465877,90.6180587858546,9.43726627649858,6.88250480006471,35.841828516957,0.696897381491776 +6.94705334692583,0.449269887455633,22.0933605733743,26.2388117764855,3.37356151411956,350.240434802596,234.011736739874,74.2110644175239,10.2965164165544,7.33054675649096,24.9278172369694,0.458927358491127 +12.6207652717153,0.463163994149485,22.2928887345195,27.2945671712372,3.50930149344478,375.600196438528,247.029123566735,112.820537134461,10.8692814369363,7.6255015871659,46.8540032624812,0.833222335758677 +10.0421438869611,0.488405524692915,22.6244317279346,29.2101186032406,3.75558667755951,423.866112522073,270.936697158499,102.944858187507,11.9212146749739,8.16066451513616,39.5227530166498,0.661622046444847 +10.0321322898703,0.508489812466837,22.8621804846574,30.7308786832526,3.95111297356105,464.271519523663,290.150795681296,107.907081192623,12.766635009977,8.58553142476974,41.24378323713,0.659417300094623 +14.1800134678242,0.528554077046578,23.0788309213771,32.2461823456612,4.14593773015644,506.386992077055,309.473939920118,142.975947108045,13.6168533564852,9.00887393136613,60.7564077927271,0.92942063053023 +12.3761117194866,0.556914103982226,23.3530139023875,34.3800281064738,4.42028932797521,568.865050212554,336.941870734766,137.853536087807,14.8254423123297,9.60502349233045,56.0256967652779,0.807410956673238 +16.4759671624905,0.581666327421199,23.5648786020695,36.233826708283,4.65863486249352,626.185395983782,361.009138035379,177.543734070837,15.8844020735567,10.1229340381067,78.0260503221687,1.07002303315974 +5.99726701829118,0.61461826174618,23.8121202802534,38.6882067901583,4.9741980158775,706.478368789153,393.107074643341,99.875208236132,17.296711284307,10.8086338366209,30.0481300545573,0.386977466568459 +10.8593093925347,0.626612795782763,23.8932481986191,39.5776065302976,5.08854941103826,736.823713005514,404.792414596019,144.034713101776,17.8108662422249,11.0571125572215,55.4839538665588,0.698999748357308 +9.3465640378999,0.648331414567832,24.0292729559091,41.1825058932959,5.29489361485233,793.276599376287,425.937559948046,136.014060558755,18.741252637714,11.5054861314572,49.4205660019427,0.598943280259281 +13.6565336884694,0.667024542643632,24.1359901562896,42.5580780455452,5.47175289157009,843.409772588716,444.112388184454,179.850194719185,19.540945080116,11.8897907282083,74.2900939480301,0.871747135270118 +17.1630587427594,0.694337610020571,24.276375944231,44.558403041201,5.7289375338687,919.210795425418,470.607987945956,221.138611372785,20.7067514696221,12.4486375248447,97.1578417261582,1.0894041148584 +8.14221510584855,0.72866372750609,24.429641684122,47.0564674209637,6.05011723983819,1018.73512555144,503.77601262409,142.321483442475,22.1661445554599,13.146541755134,48.3340732530964,0.513215109519905 +10.4906009296595,0.744948157717787,24.4943436604853,48.2355161541569,6.20170921982018,1067.5980923316,519.451659677508,169.729444410608,22.8558730258103,13.4759420321161,63.6366825576248,0.659094726748587 +15.204772839994,0.765929359577106,24.5709004033259,49.7490579834027,6.39630745500892,1132.1093763317,539.586813885786,224.231904896834,23.7418198109746,13.8987923212871,94.7666238525676,0.951371343460942 +9.87318455737865,0.796338905257094,24.669583328297,51.9319727972061,6.67696793106936,1228.70482349192,568.64003896716,175.317108215791,25.020161714555,14.5086506961379,63.9095074945855,0.614243701912923 +15.0607583064829,0.816085274371851,24.7266837784768,53.3428836158617,6.85837075061079,1293.38207876613,587.420284339211,237.704950911664,25.8464925109253,14.9028281388322,99.8300298003339,0.933637989874976 +11.5706146693963,0.846206790984817,24.8044220661791,55.485651756082,7.13386951149625,1394.99293008041,615.936069221402,206.357446057704,27.1011870457417,15.5014704163107,79.4302703796194,0.713549402434661 +13.3127061818153,0.86934802032361,24.8572711028689,57.1244709970712,7.34457484248059,1475.47097039345,637.735153547186,232.788587133637,28.0603467560762,15.9593204582198,93.7995640130915,0.81786718452395 +17.4806466078772,0.89597343268724,24.9115365031328,59.0025416363156,7.58604106752629,1570.65449196802,662.700889835047,290.852681730521,29.1588391527421,16.4840120772706,126.799548025647,1.06947679555334 +13.2803100173771,0.930934725902995,24.9734470792585,61.4572036574245,7.9016404702403,1699.83526491928,695.299642872636,249.120992610039,30.593184286396,17.169790643404,99.9484227015776,0.808377482110023 +11.6203755381957,0.957495345937749,25.0142827646319,63.3140069315505,8.14037231977077,1801.15579450275,719.931075856815,234.74097082629,31.6769673376999,17.6885406285227,89.856451514715,0.704804158830193 +13.6533474488494,0.98073609701414,25.0461588337357,64.9334328677561,8.34858422585435,1892.06186407513,741.392512692035,267.530941186444,32.6212705584496,18.140972607728,108.042986986012,0.825671868210196 +10.1030440456253,1.00804279191184,25.0795241684604,66.8302881733147,8.59246562228332,2001.55307528676,766.504486397848,226.584042121815,33.7261974015053,18.6709122492843,82.0915219052653,0.608994074630574 +8.49260767209638,1.02824888000309,25.1016618497245,68.2300662271125,8.77243708634303,2084.43734983109,785.017322655642,208.799503644895,34.5407621968482,19.0619794423982,70.3387931533824,0.510769907751515 +13.8053080796145,1.04523409534728,25.1187498442437,69.404345269295,8.92341582033793,2155.33627352502,800.535616824675,287.350415212216,35.2235671402857,19.3900471726451,116.161530716003,0.828801971941598 +16.215100773981,1.07284471150651,25.1438414354828,71.3088720387312,9.16828354783687,2272.97804088535,825.680649327476,329.851539963162,36.3299485704089,19.9221300524367,139.915530550737,0.970811093559158 +13.209624453261,1.10527491305447,25.1695338398153,73.5394805320076,9.45507606840097,2414.93629647464,855.094203822381,295.003617258371,37.6241449681847,20.5453129920712,117.310605849175,0.788542786830633 +12.0514233751536,1.131694161961,25.1878198649143,75.3519901484984,9.68811301909265,2533.6032712166,878.966159575786,284.410904243807,38.6745110213346,21.0516883037072,109.500096382961,0.717824289063547 +11.7573374929648,1.1557970087113,25.2026785972082,77.0022366405034,9.90028756806472,2644.23296203881,900.679574498839,285.913962837713,39.6299012779489,21.5127308681506,109.03229088336,0.699008320367035 +11.9413299885634,1.17931168369723,25.215676975266,78.6093683186548,10.106918783827,2754.34105850597,921.806767504261,294.669317672048,40.5594977701875,21.9617281021292,112.924076483006,0.708753991733565 +11.7295851387953,1.20319434367436,25.2275211785046,80.2389863994057,10.316441108495,2868.37562970052,943.211240129407,297.229198192377,41.5012945656939,22.4170075422932,113.103565013111,0.695083669805023 +16.2356339673271,1.22665351395195,25.2379599585221,81.837287673914,10.5219369866461,2982.55144166953,964.187226546502,377.275258333103,42.4242379680461,22.8635377557627,159.522236863729,0.960720351130048 +14.6654125687904,1.2591247818866,25.2506776505847,84.0459677710847,10.8059101419966,3144.12976903235,993.147301151348,360.688872608011,43.6984812506593,23.4805943839501,147.809267392037,0.866223508474503 +11.7505133374711,1.28845560702418,25.2606477948161,86.0377444088061,11.0619957097036,3293.61843278227,1019.23860288348,318.709887284472,44.8464985268733,24.0370529574434,121.122329439296,0.693021393087743 +10.3133987768923,1.31195663369913,25.2677241432344,87.6315875664223,11.2669184013971,3415.81992802936,1040.10135886501,299.26621696313,45.7644597900604,24.4823376711319,108.203412283868,0.607600398363945 +14.4596658030464,1.33258343125291,25.2733375139929,89.0291197108457,11.4466011056802,3524.85532868421,1058.3835989497,378.017022804304,46.568878353787,24.8727774065767,154.037347417299,0.851116156184381 +10.0658223001966,1.361502762859,25.280366061387,90.986499769288,11.6982642560513,3680.5294201203,1083.97360264756,306.109028726002,47.6948385164927,25.4196263325442,109.50933346422,0.591810981213213 +12.548760707127,1.3816344074594,25.284737404992,92.3478227364118,11.8732914946815,3790.83262152093,1101.76061359785,356.57537965893,48.4774669983052,25.7999500204532,138.501630151433,0.737253638478154 +13.2466537648798,1.40673192887365,25.28965184691,94.0436049224458,12.0913206328859,3930.56897346283,1123.90653446682,376.196307421132,49.4518875165402,26.2737142560231,148.811471044972,0.777599968382503 +8.58244282916634,1.43322523640341,25.2942618696261,95.8322158335763,12.3212848928884,4080.75747826864,1147.25224676876,293.88473590934,50.4790988578256,26.7734127951529,98.1988327088463,0.503394039946095 +13.0441450835547,1.45039012206174,25.2969635748421,96.9902997709128,12.4701813991174,4179.53477855968,1162.36165152005,383.952863842133,51.1439126668823,27.0969559693981,151.007403478047,0.764717786166741 +9.20061678832784,1.47647841222885,25.3006838629285,98.7493929264495,12.6963505191149,4331.8792709798,1185.30338189343,315.01998160752,52.1533488033111,27.5884078970056,108.398717616899,0.539019855823727 +12.7745603536336,1.49487964580551,25.303053086886,99.9894611985468,12.8557878683846,4440.94367736316,1201.46998088612,390.360330132367,52.8646791589895,27.9348556907276,152.354488109287,0.74806600978791 +13.6404475098987,1.52042876651278,25.3060285083747,101.710348810902,13.077044847116,4594.58224556532,1223.89715905698,414.630209233473,53.8514749985073,28.4156338300922,165.423970551173,0.798314310610568 +9.80983528093082,1.54770966153257,25.3088438413088,103.546845465064,13.3131658455082,4761.47134316266,1247.82171379714,342.907469315653,54.9041554070739,28.9287105923386,121.07599560025,0.573806935511613 +12.8796594611724,1.56732933209443,25.3106618120152,104.866997891083,13.4828997288535,4883.30561804984,1265.01422905743,411.51638018797,55.6606260785269,29.2975321368149,160.956016647808,0.753094147141227 +11.2348478441228,1.59308865101678,25.3128136458499,106.599566481355,13.7056585476028,5045.56947711794,1287.57126420477,383.319292391107,56.6531356250097,29.7815736844279,142.682834170626,0.656628595998901 +10.542535954065,1.61555834670502,25.314494192797,108.110275604684,13.8998925777451,5189.24804488804,1307.23428839034,373.82137911933,57.5183086891749,30.2036325778853,135.759371698173,0.615948315836371 +11.1038512723045,1.63664341861315,25.315921420298,109.527425704448,14.0820975905718,5325.88466323585,1325.67523457024,390.981027405039,58.3297103210905,30.5995531384571,144.835650350445,0.64854490232151 +9.135119604379,1.65885112115776,25.3172828282139,111.019579183636,14.2739458950389,5471.69392575151,1345.08796223266,352.742649449992,59.1838703382369,31.0164279931659,120.758149667868,0.533398346648589 +15.8593151147652,1.67712136036652,25.3183035694221,112.246850984579,14.4317379837315,5593.11133999266,1361.05159050326,507.07135733533,59.8862699821434,31.3593007343696,211.935246689506,0.925813476928017 +12.4957453608961,1.70883999059605,25.319884927226,114.376867833347,14.7055972928589,5807.03450741953,1388.75162964875,440.022884357307,61.105071704545,31.9543805815447,170.119267639436,0.729198475267786 +17.6034491248596,1.73383148131784,25.3209788043078,116.054623447071,14.9213087289091,5978.38857758428,1410.56529957708,564.554555718946,62.0648731813915,32.4231085893958,243.135773969263,1.02700208778611 +13.5145570137727,1.76903837956756,25.3223221071839,118.41749146522,15.2251060455283,6223.97615880805,1441.28002930058,479.603296434683,63.4163212892254,33.0832419305702,190.425692646515,0.788201166846156 +12.5120982451255,1.79606749359511,25.323216019941,120.231034923572,15.458275918745,6415.84770932383,1464.84943407943,462.956375541357,64.4533750994948,33.5899060748777,178.978040715262,0.729577034268381 +4.18255646771085,1.82109169008536,25.3239505678901,121.909722480524,15.6741071760674,6596.0655625305,1486.66292905104,267.288486808476,65.4131688782457,34.0588944471639,60.6578964861845,0.243839387484557 +9.2567911518124,1.82945680302078,25.3241779295316,122.470809536629,15.7462469404238,6656.86203895112,1493.95325093873,392.235807908197,65.7339430413041,34.2156498267244,134.860854703067,0.539632087650388 +14.8673408331022,1.84797038532441,25.3246512008685,123.712491241835,15.9058917310931,6792.40179615179,1510.08558850969,534.379813473132,66.4437658944265,34.5625483781614,218.781005316303,0.866599809709966 +10.1509757996828,1.87770506699061,25.3253321405036,125.706461293154,16.1622593091198,7012.93458021649,1535.9889597091,425.016900818807,67.5835142272005,35.1196197431587,151.769401733536,0.591584744690471 +12.9752678727178,1.89800701858998,25.3257465653334,127.067692544789,16.3372747557586,7165.52088343135,1553.67059667347,501.048244874538,68.3615062536325,35.4999178077782,196.084450414267,0.756098462838088 +10.6905357078339,1.92395755433541,25.3262231699791,128.807451878686,16.5609580986882,7362.94038142981,1576.26703885964,449.374163692465,69.355749709824,35.9859682909636,163.757229355965,0.622882885447943 +12.7738259123397,1.94533862575108,25.3265754524711,130.240709465373,16.7452340741194,7527.60412906611,1594.88095630982,508.372392581682,70.174762077632,36.3863889290169,197.835417650949,0.744194644383146 +15.8618557810182,1.97088627757576,25.3269535633162,131.953098496041,16.9653983780624,7726.73409540663,1617.11825993344,596.129031569758,71.1532034370712,36.8647927516269,248.876604731405,0.924005229841964 +15.2220463629289,2.0026099891378,25.3273655029634,134.079218143858,17.238756618496,7977.6073212915,1644.72594043538,588.687942069479,72.3679413791566,37.4587838065948,242.670177496139,0.886631987146379 +17.2759460420879,2.03305408186365,25.3277083500902,136.119360820401,17.5010606769087,8222.11678606774,1671.21498559556,653.263073561819,73.5334593662048,38.0287547872821,279.58858014956,1.00616608482524 +6.17613701917727,2.06760597394783,25.3280437293573,138.434551664648,17.798728071169,8504.07507072289,1701.27289725376,358.84517012236,74.8560074791655,38.675568174966,101.647101618207,0.359668420532437 +11.8690203025204,2.07995824798618,25.328151319629,139.262177752044,17.9051371395485,8606.0250925273,1712.01734500145,518.648488218613,75.3287631800636,38.9067886960106,196.505087355821,0.691172480079081 +7.3906520350722,2.10369628859122,25.3283417504979,140.852600976496,18.1096201255494,8803.64902642477,1732.66387668092,399.179939836839,76.2372105739606,39.3511179556114,123.754034906694,0.430357712809791 +8.19986285685887,2.11847759266137,25.3284502853628,141.842888302737,18.2369427817805,8927.83693454277,1745.5191135434,424.827315325923,76.8028409959098,39.6277824482422,138.266774912599,0.477462385789857 +7.58759582841038,2.13487731837509,25.3285624109407,142.94156642931,18.3782013980542,9066.6378430605,1759.78102111371,410.740673593133,77.4303649290031,39.9347289458879,128.931194318995,0.441796116889666 +10.2340004348094,2.15005251003191,25.328658924508,143.958176013644,18.5089083446113,9196.02642486975,1772.97725947435,489.419303148273,78.0109994168713,40.2187472983397,175.133713696907,0.595868211224714 +9.4995959685784,2.17052051090153,25.3287789176155,145.329312922932,18.6851973758056,9371.99229720981,1790.7750036049,472.888506376047,78.7941001586156,40.601812785783,164.110813876739,0.553087305205784 +12.9794754131923,2.18951970283868,25.3288806704192,146.602011246041,18.8488300173482,9536.82019401234,1807.29452320213,578.461548028186,79.5209590208937,40.9573766978966,226.187228048555,0.755669293045033 +12.6710676399942,2.21547865366507,25.3290061315192,148.340859812062,19.0723962615508,9764.34622648712,1829.86397096677,576.25554692123,80.5140147225381,41.4431727325742,223.426787162915,0.737684160511341 +11.6675333743865,2.24082078894506,25.3291150339252,150.038327450359,19.2906421007605,9989.0490949876,1851.89563834903,552.949986895441,81.4834080873573,41.9174078464265,208.081713091626,0.679236460361238 +12.4183829002601,2.26415585569383,25.3292047271947,151.601307120759,19.4915966298119,10198.212873192,1872.18123241692,581.359346009993,82.3759742263446,42.3540699807835,223.775986117665,0.722926596069812 +15.5311202202032,2.28899262149435,25.3292902278537,153.264822255391,19.7054771471217,10423.2147847653,1893.77114331724,682.576183935073,83.3259303059585,42.8188195120666,282.933158136722,0.904106498505373 +14.0271619378482,2.32005486193476,25.3293843411985,155.345243972937,19.9729599393776,10708.0656385808,1920.77120046058,645.441401794235,84.5139328202657,43.4000435706712,258.999333351321,0.816531275314657 +10.9032003862436,2.34810918581045,25.3294585684019,157.224154166784,20.214534107158,10968.6293965923,1945.15543367696,555.676225792921,85.5868390817861,43.9249697428078,203.750165779831,0.634667052225825 +8.73516698531288,2.36991558658294,25.3295100255545,158.684584497689,20.4023037211314,11173.3248309749,1964.10835558459,492.502529756334,86.4207676457218,44.3329818477953,164.75034648912,0.508458376468196 +15.3227939054228,2.38738592055357,25.3295476994145,159.8545992327,20.5527341870614,11338.6819319955,1979.29217653433,705.398301740837,87.0888557675104,44.6598582244333,291.125526895556,0.891900509700692 +15.3130857581556,2.41803150836441,25.3296069236094,161.906945226469,20.8166072434032,11631.6745684895,2005.92603442958,714.17139753425,88.2607455149013,45.2332385434805,294.672974570022,0.891316666859769 +13.0627294568385,2.44865767988072,25.3296583626176,163.957950340179,21.0803079008801,11928.212416117,2032.54205217107,649.942139771962,89.4318502955271,45.8062442501384,254.550558465785,0.760317844681849 diff --git a/pyrealm_build_data/t_model/rtmodel_test_outputs.r b/pyrealm_build_data/t_model/rtmodel_test_outputs.r index 16ce3cdd..969e4534 100644 --- a/pyrealm_build_data/t_model/rtmodel_test_outputs.r +++ b/pyrealm_build_data/t_model/rtmodel_test_outputs.r @@ -87,21 +87,26 @@ tmodel <- function(P0, year, a, cr, Hm, rho, rr, return(output) } -tmodel_run <- tmodel(rep(7, 100), seq(100), - d = 0.1, - a = 116.0, - cr = 390.43, - Hm = 25.33, - rho = 200.0, - L = 1.8, - sigma = 14.0, - tf = 4.0, - tr = 1.04, - K = 0.5, - y = 0.6, - zeta = 0.17, - rr = 0.913, - rs = 0.044 -) - -write.csv(tmodel_run, "rtmodel_output.csv", row.names = FALSE) +# Load alternative plant functional types +pfts <- read.csv("pft_definitions.csv") + +for (pft_idx in seq_len(nrow(pfts))) { + # Get the PFT + pft <- as.list(pfts[pft_idx, ]) + + # Seperate off the name + name <- pft[["name"]] + pft[["name"]] <- NULL + + # Get GPP sequence + n_years <- 100 + pft[["P0"]] <- rnorm(n_years, mean = 7) + pft[["year"]] <- seq(n_years) + + tmodel_run <- do.call(tmodel, pft) + + write.csv(tmodel_run, + sprintf("rtmodel_output_%s.csv", name), + row.names = FALSE + ) +} diff --git a/tests/regression/demography/test_t_model_functions_against_rtmodel.py b/tests/regression/demography/test_t_model_functions_against_rtmodel.py new file mode 100644 index 00000000..1d994de3 --- /dev/null +++ b/tests/regression/demography/test_t_model_functions_against_rtmodel.py @@ -0,0 +1,97 @@ +"""Test TModel class. + +Tests the init, grow_ttree and other methods of TModel. +""" + +from importlib import resources + +import numpy as np +import pandas as pd +import pytest + +# Fixtures: inputs and expected values from the original implementation in R + + +@pytest.fixture(scope="module") +def rvalues(): + """Fixture to load test inputs from file. + + This is a time series of growth using the default trait values in R, mapped to the + internal property names used in TTree + """ + from pyrealm.demography.flora import PlantFunctionalType + + # Load the PFT definitions and rename to pyrealm attributes + pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" + pft_definitions = pd.read_csv(pfts_path) + + pft_definitions = pft_definitions.rename( + columns={ + "name": "alt_two", + "d": 0.6, + "a": 102, + "cr": 406.12, + "Hm": 45.33, + "rho": 100, + "L": 1.0, + "sigma": 21, + "tf": 8, + "tr": 2.1, + "K": 0.4, + "y": 0.7, + "zeta": 0.15, + "rr": 0.962, + "rs": 0.054, + } + ) + + datapath = resources.files("pyrealm_build_data.t_model") / "rtmodel_output.csv" + data = pd.read_csv(datapath) + + data = data.rename( + columns={ + "dD": "delta_d", + "D": "diameter", + "H": "height", + "Ac": "crown_area", + "Wf": "mass_fol", + "Ws": "mass_stm", + "Wss": "mass_swd", + "GPP": "gpp_actual", + "Rm1": "resp_swd", + "Rm2": "resp_frt", + "dWs": "delta_mass_stm", + "dWfr": "delta_mass_frt", + } + ) + + # Get the default PFT traits, which should match the settings used for the + # regression data set. + default_pft = PlantFunctionalType() + + # Fix some scaling differences: + # The R tmodel implementation rescales reported delta_d as a radial increase in + # millimetres, not diameter increase in metres + data["delta_d"] = data["delta_d"] / 500 + + # The R tmodel implementation slices off foliar respiration costs from GPP before + # doing anything - the pyrealm.tmodel implementation keeps this cost within the tree + # calculation, so proportionally inflate the GPP to make it match + data["gpp_actual"] = data["gpp_actual"] / (1 - default_pft.resp_f) + + return data + + +def test_calculate_heights(rvalues): + """Tests happy path for calculation of heights of tree from diameter.""" + + from pyrealm.demography.t_model_functions import calculate_heights + + pft_h_max_values = np.array([25.33, 15.33]) + pft_a_hd_values = np.array([116.0, 116.0]) + diameters_at_breast_height = np.array([0.2, 0.6]) + expected_heights = np.array([15.19414157, 15.16639589]) + actual_heights = calculate_heights( + pft_h_max_values, pft_a_hd_values, diameters_at_breast_height + ) + assert np.allclose(actual_heights, expected_heights, decimal=8) From e808947cd077cab8b47c3351a9ef5d973c4e6c04 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 13 Sep 2024 13:21:30 +0100 Subject: [PATCH 092/241] Regression tests for multiple PFTs for existing demography.t_model functions --- .../t_model/rtmodel_output_alt_one.csv | 202 ++++++++--------- .../t_model/rtmodel_output_alt_two.csv | 202 ++++++++--------- .../t_model/rtmodel_output_default.csv | 202 ++++++++--------- .../t_model/rtmodel_test_outputs.r | 6 +- .../test_t_model_functions_against_rtmodel.py | 203 +++++++++++++----- tests/regression/tmodel/test_tmodel.py | 1 + 6 files changed, 451 insertions(+), 365 deletions(-) diff --git a/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv b/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv index da151d5a..6e9785b0 100644 --- a/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv +++ b/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv @@ -1,101 +1,101 @@ -"dD","D","H","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" -3.4076525912172,0.04,4.2375677628595,0.377501266657307,0.151000506662923,1.06501694023107,1.04242323817797,2.49321780486283,0.0354423900980509,0.270079506217303,0.516605773866592,0.152056543224708 -2.47765324608507,0.0468153051824344,4.83251153727187,0.503851463291355,0.201540585316542,1.6636750142509,1.61697621579032,2.79337509092686,0.0549771913368709,0.360475490897167,0.497047537525469,0.12441780816647 -1.70732495414315,0.0517706116746045,5.24495157701621,0.604737005461146,0.241894802184458,2.20814685154373,2.1342201820959,2.86891020806033,0.0725634861912606,0.432653043187122,0.408557697387618,0.0921643042234363 -2.15795515547366,0.0551852615828908,5.5196902975137,0.678390225802438,0.271356090320975,2.64046733189626,2.54172665080193,3.49719120139178,0.0864187061272657,0.485347503148096,0.576842315524673,0.121788557787631 -2.45769052870287,0.0595011718938382,5.85626081132705,0.776046411719903,0.310418564687961,3.25680177278109,3.11823461581907,4.19640339006913,0.106019976937848,0.555214644800888,0.747561098692953,0.145949958587722 -3.11155047340158,0.0644165529512439,6.22553858496373,0.893133082124149,0.35725323284966,4.0578105654784,3.86033133335473,5.3368149213653,0.131251265334061,0.638983132274901,1.08274112822144,0.194599241159002 -2.81001896022174,0.070639653898047,6.67248552562724,1.04973086992593,0.419892347970372,5.23003557355684,4.93318428505692,5.93706350539475,0.167728265691935,0.751019453579807,1.14067683625001,0.186152603315975 -1.71684981432575,0.0762596918184905,7.05723507979667,1.19859205856072,0.479436823424288,6.44680528083693,6.03188990209452,5.58154716852031,0.205084256671214,0.857520702376682,0.790448096270193,0.11902984777131 -3.60736429017,0.079693391447142,7.28384315380763,1.29278010594693,0.517112042378772,7.26649670027302,6.76419885349383,8.14826246827467,0.22998276101879,0.924906598998671,1.78412597929806,0.256481929185058 -4.19224398961664,0.086908120027482,7.73996134574854,1.49810037613452,0.599240150453806,9.18288995249815,8.45376241753518,10.1240774804296,0.287427922196196,1.07180093310168,2.38256224753949,0.31252795716962 -1.47061597732594,0.0952926080067153,8.2376484918832,1.74825281064621,0.699301124258484,11.7500999106489,10.6723585524035,7.713647753548,0.362860190781721,1.25076999084873,0.966018518715497,0.114905522620708 -5.19407661707193,0.0982338399613672,8.40438979686104,1.838692368757,0.735476947502799,12.7393803961334,11.5148032967029,13.8254866009506,0.391503312087898,1.31547406830351,3.57645985674181,0.411846506622017 -3.33857337208731,0.108621993195511,8.9625482269241,2.16815855828802,0.867263423315209,16.6106611208001,14.7511363160476,12.8500256064117,0.50153863474562,1.55118735894158,2.67953128580636,0.277087302273617 -2.84640463545498,0.115299139939686,9.29732928510652,2.38740470956093,0.954961883824371,19.4146794851493,17.0403896049967,13.1442354915493,0.579373246569888,1.70804482540827,2.49725058954337,0.24218649999991 -2.94436653441781,0.120991949210596,9.56882005136166,2.57843760576435,1.03137504230574,22.0034718093834,19.1167615381295,14.3592446062027,0.649969892296402,1.84471740066805,2.77286160321962,0.2552820658544 -3.50769891071221,0.126880682279431,9.83680516850189,2.77965784485076,1.1118631379403,24.8751069895891,21.3812560853348,16.6741499394811,0.726962706901384,1.98867840852003,3.53901078491926,0.309471107120787 -3.22565850441175,0.133896080100856,10.1398402885247,3.02371422640172,1.20948569056069,28.5552993574241,24.2280421651559,17.4068569179711,0.823753433615302,2.16328610613684,3.51439402852688,0.289857584530125 -2.89166380704279,0.140347397109679,10.4037324830024,3.25188594380762,1.30075437752305,32.1897629605585,26.9828483663078,17.8285416563365,0.917416844454465,2.32652927963772,3.36592562150624,0.263721660537847 -4.64046296774645,0.146130724723765,10.6288746468056,3.45915951233512,1.38366380493405,35.6525205179494,29.5588038974511,23.5533959007067,1.00499933251334,2.47482108150504,5.71245559296637,0.42822617332666 -2.98460432413264,0.155411650659258,10.9688701981729,3.79653349864332,1.51861339945733,41.6149062556785,33.8912645848012,20.9718796452611,1.15230299588324,2.71619192626938,3.99565666888108,0.279940067885416 -4.12919579076091,0.161380859307523,11.1744369710593,4.01623798817214,1.60649519526886,45.714036901557,36.7996560465635,25.5817932984707,1.25118830558316,2.87337730625787,5.81428543899414,0.390776143958367 -3.26348591200779,0.169639250889045,11.4429591930056,4.32321128487659,1.72928451395063,51.7262409142765,40.9699861852287,24.664973774709,1.39297953029778,3.0929982816521,4.90804363779251,0.312153212199737 -3.68674173027981,0.17616622271306,11.6428517191653,4.56797559195247,1.82719023678099,56.7576660482826,44.3786516195867,27.423777455336,1.50887415506595,3.26811245750648,5.82324663439364,0.355165751841699 -3.39790762104395,0.18353970617362,11.8563311883666,4.84643196102801,1.9385727844112,62.737941281254,48.3404647560288,27.9999494774111,1.64357580170498,3.46733128219788,5.65631161483904,0.329596741599332 -2.41422582702144,0.190335521415708,12.0421234937218,5.10463493794526,2.0418539751781,68.5271461897962,52.0888702482814,25.8078939226368,1.77102158844157,3.65206002000356,4.20754712819561,0.235428098793449 -2.41204568145819,0.195163973069751,12.1680594141748,5.28886812356556,2.11554724942623,72.8015289167792,54.8048155283553,26.7075157145024,1.86336372796408,3.78386781032375,4.33722710628732,0.23597930580402 -4.17945425865771,0.199988064432667,12.289064346927,5.47349418689455,2.18939767475782,77.2052528337077,57.5593429346598,34.5140604823289,1.95701765977843,3.91595668107184,7.74560965426685,0.410050490180691 -4.91674220668635,0.208346972949983,12.4878738385037,5.79451996205028,2.31780798482011,85.1496308686289,62.4226291775791,39.4478920899605,2.12236939203769,4.14563136164925,9.57915517642897,0.484331166030133 -2.42969807983625,0.218180457363355,12.7051804043308,6.173599466451,2.4694397865804,95.0019257385172,68.2772467611385,31.132043092033,2.32142638987871,4.4168400022777,5.00329536433378,0.240170428654464 -2.86538738422293,0.223039853523028,12.8063509296314,6.36135504629793,2.54454201851917,100.071455843836,71.2185622241853,33.9827542131894,2.4214311156223,4.55116785432339,6.05658914291943,0.283593847608982 -3.76176339098658,0.228770628291474,12.9206637504606,6.58304547548127,2.63321819019251,106.219739342274,74.7245899488989,39.2086818659169,2.54063605826256,4.70977405497832,8.1918137233473,0.372734091132853 -3.67060004221364,0.236294155073447,13.0629132641754,6.87439983161545,2.74975993264618,114.568671850992,79.3836202125531,40.4299763832049,2.69904308722681,4.91822061553096,8.29955458345159,0.364056683268274 -3.03264344641453,0.243635355157874,13.1936158377101,7.15889366173236,2.86355746469295,123.016774004259,83.985302538486,38.9099453056646,2.85550028630852,5.1217588813498,7.10225111379236,0.300916988838535 -4.5415877717825,0.249700642050703,13.2958981309334,7.39399417104956,2.95759766841982,130.219755069079,87.8243398148836,47.7082557432084,2.98602755370604,5.2899591897357,10.9375054920958,0.450656625657976 -4.48876498656065,0.258783817594268,13.439988031127,7.7460048232341,3.09840192929364,141.381631709377,93.6291385709334,49.5708377278209,3.18339071141174,5.5418016907346,11.2531667085995,0.445208416489848 -4.52837857308153,0.267761347567389,13.5723697006481,8.09366699412638,3.23746679765055,152.852071245955,99.4233916219363,51.8808215115506,3.38039531514584,5.79053311427777,11.7902254418306,0.448696169006381 -3.98898028803123,0.276818104713552,13.6965261323425,8.44397010555572,3.37758804222229,164.861516016638,105.317260158106,50.975434027005,3.58078684537561,6.04115397231879,10.771490526345,0.394679222579087 -2.27963652706172,0.284796065289615,13.7986074187168,8.75207457267193,3.50082982906877,175.801714223231,110.542917393979,42.8822627252245,3.7584591913953,6.2615842322724,6.34831677583185,0.225193093095027 -3.59922282064066,0.289355338343738,13.8540544352847,8.92791721644203,3.57116688657681,182.204779507247,113.541433548668,51.4611718221524,3.8604087406547,6.38738909333129,10.1958512333737,0.355181632716896 -4.70217974307538,0.29655378398502,13.9375390206237,9.20515979651754,3.68206391860701,192.53642924786,118.291023138269,59.6193444671684,4.02189478670115,6.58573952482051,13.6747403109014,0.463197943475877 -2.58869662054652,0.30595814347117,14.0395338787937,9.56657480935512,3.82662992374205,206.441307114496,124.519658777826,48.699479899716,4.23366839844609,6.84431028160503,7.78141821166302,0.254348139211556 -3.92845501174985,0.311135536712263,14.0924606297139,9.76513413978947,3.90605365591579,214.29199203952,127.957917116452,58.1423829743609,4.35056918195938,6.98636756897098,12.0187019463976,0.385396397344322 -3.47500788727324,0.318992446735763,14.1686620752899,10.065862832357,4.02634513294282,226.469394494977,133.185293229584,56.9084441288503,4.52829996980585,7.20152090478152,10.9118874022255,0.340083982145872 -4.42165708583249,0.32594246251031,14.2321474686788,10.331256478417,4.13250259136681,237.504693702123,137.816726515892,64.609660598691,4.68576870154031,7.39139413491867,14.1982363468642,0.431755237508435 -3.97068480343319,0.334785776681975,14.3079351129848,10.6680668020666,4.26722672082664,251.901548104833,143.716577620126,63.5359890523102,4.88636363908427,7.63236171287054,13.1064525865835,0.386567181266515 -4.41765892162563,0.342727146288841,14.3715237498738,10.9696579929612,4.38786319718448,265.167139458409,149.018237999104,68.3543249186624,5.06662009196953,7.84813211448416,14.9355896750248,0.428897678481159 -4.49751168772706,0.351562464132092,14.4376321668425,11.3042105642454,4.52168422569817,280.298549006447,154.917545742689,70.8972136397498,5.26719655525143,8.08748440608375,15.6038740339542,0.435281459208223 -4.18467015532518,0.360557487507546,14.5002534965219,11.6437233781525,4.65748935126101,296.104160264481,160.921432854673,70.625168461987,5.47132871705889,8.33038545366545,14.8935280612798,0.403689595274399 -3.99912383951496,0.368926827818197,14.5545658790005,11.9586253358874,4.78345013435498,311.171353204695,166.503427843995,71.0540003500767,5.66111654669582,8.55567891030731,14.5648000535661,0.384613856760586 -4.3382543607839,0.376925075497227,14.6031446545066,12.2586651846016,4.90346607384062,325.893970323044,171.832241879997,75.3430056460589,5.84229622391988,8.77033941967134,16.1420482212618,0.416008624683971 -3.32273559776104,0.385601584218794,14.6524077692294,12.5831557348832,5.03326229395328,342.220871079292,177.604935434735,69.3142725626828,6.03856780478099,9.00249293896484,12.6463827316162,0.317616192246975 -4.71943244901862,0.392247055414316,14.6878689854757,12.8309924030577,5.13239696122307,354.975231516814,182.019703142,81.70961742775,6.188669906828,9.17980520484357,18.2687902506444,0.450031569214044 -4.29822971754317,0.401685920312354,14.7350698118396,13.18197770958,5.27279108383202,373.461032437512,188.278972356481,80.4101030850047,6.40148506012036,9.43091413254194,17.0333155762924,0.408466739088663 -2.13975812068631,0.41028237974744,14.7750323864986,13.5006000978576,5.40024003914306,390.673587216186,193.966985402662,64.386911368932,6.59487750369052,9.65886933401127,8.65792475868133,0.20271844934675 -2.15613364514834,0.414561895988813,14.79391433501,13.6588535088672,5.46354140354687,399.375795319384,196.793802952757,65.2661674055522,6.69098930039373,9.77209015438394,8.81340182789697,0.203959774345169 -2.95621172099851,0.418874163279109,14.8122910197491,13.8180759443119,5.52723037772476,408.234082198569,199.638879917524,72.7728844846437,6.78772191719581,9.88600425359851,12.2068432857035,0.279218754996161 -4.21986338367759,0.424786586721106,14.8364671794282,14.0359903441167,5.61439613764669,420.525142632069,203.534006355532,84.705642954316,6.92015621608809,10.0419089317949,17.6650799827995,0.397751374938191 -4.89568691478789,0.433226313488461,14.8690346772329,14.3462821276991,5.73851285107966,438.361400311481,209.082381316197,92.3921926644656,7.1088009647507,10.2639040854411,20.8911833257224,0.460116400742799 -3.46593546913616,0.443017687318037,14.9041346627114,14.7051546859979,5.88206187439915,459.482287105371,215.501446350263,81.8526044556982,7.32704917590896,10.5206558685503,15.1151296502862,0.324672145840963 -4.34123040552854,0.44994955825631,14.9273558140644,14.9585149741582,5.98340598966328,474.712231041645,220.033938411622,91.1302980928757,7.48115390599516,10.7019199531118,19.21986099901,0.405739515401494 -2.75924387330133,0.458632019067367,14.9546633681683,15.2750548591103,6.11002194364412,494.111840722041,225.696866858762,78.4142050093078,7.67369347319789,10.9283852484019,12.4443628044286,0.257164866532715 -4.74857268552241,0.464150506813969,14.9710490197482,15.4757899744384,6.19031598977537,506.628675409696,229.287872483935,97.9441463553031,7.7957876644538,11.0719991793122,21.6657487341854,0.441804418794587 -3.95091031925792,0.473647652185014,14.9975910020453,15.8204437352563,6.3281774941025,528.50872415359,235.452688040144,92.4602979373157,8.00539139336489,11.3185782659517,18.3828297591537,0.366518804346683 -1.9697004186902,0.48154947282353,15.01817237298,16.1064475341568,6.44257901366274,547.039624351573,240.567268191126,74.9734471495096,8.17928711849829,11.5231968238372,9.31224044133609,0.182294992200624 -3.37507276957209,0.48548887366091,15.0279520235311,16.2487833073886,6.49951332295542,556.388621111865,243.112137017482,89.2822300992611,8.26581265859438,11.6250295294381,16.0824307285656,0.312002028200505 -2.12742516487558,0.492239019200054,15.0440017007336,16.4922981100648,6.5969192440259,572.578879535063,247.465096897291,78.3031501074436,8.4138132945079,11.7992497598647,10.2732224793352,0.196285281127394 -4.77111561725361,0.496493869529806,15.0536772427654,16.6455540977098,6.65822163908393,582.894903583709,250.203968853327,105.254328811888,8.50693494101313,11.9088952236655,23.2314215730573,0.439677345758567 -6.04503382925559,0.506036100764313,15.0742027331351,16.9886010691142,6.79544042764568,606.341411105408,256.332557171022,120.208477464577,8.71530694381477,12.1543247488871,29.9792723629575,0.555620897767399 -4.66427590921526,0.518126168422824,15.0980337020725,17.4219869279571,6.96879477118284,636.665507837195,264.070467003803,108.870114848915,8.97839587812929,12.4643863277376,23.6636539163409,0.427353444220947 -1.71244608997883,0.527454720241255,15.1148928884953,17.755463869484,7.10218554779362,660.534213227927,270.02068343444,79.8701308818371,9.18070323677095,12.7029690707837,8.83843785782317,0.156532123688676 -3.42414296992047,0.530879612421212,15.1207702102284,17.8777033475959,7.15108133903838,669.400272905403,272.200902075947,98.5095361772892,9.25483067058219,12.790424083004,17.7834670199142,0.312734132013411 -4.67532197179623,0.537727898361053,15.1320450879592,18.1218262263991,7.24873049055965,687.294141327024,276.553493769973,113.208297365798,9.40281878817907,12.965079355415,24.5829914043761,0.42630919383445 -3.18843457428175,0.547078542304645,15.1464651450937,18.4545192748916,7.38180770995664,712.082854488507,282.481940363429,99.0498471467853,9.6043859723566,13.2031012700284,17.0454586296706,0.290104876072618 -4.0916443402265,0.553455411453209,15.1556919880842,18.6810023208245,7.47240092832981,729.223949947645,286.515523928416,110.170571761801,9.74152781356615,13.3651363004107,22.1194885766672,0.371757370105621 -1.95331974249994,0.561638700133662,15.1668562639784,18.9711807707903,7.58847230831613,751.500889713508,291.680778761914,87.9992933363734,9.91714647790507,13.5727415706542,10.7100000789139,0.17716211789244 -5.08340155532172,0.565545339618662,15.1719309543811,19.1095320088165,7.64381280352661,762.246766091291,294.142377533173,123.75842373675,10.0008408361279,13.6717235803877,28.0588841926186,0.460677836515594 -3.90792350721405,0.575712142729305,15.1844098382668,19.4690639887022,7.78762559548087,790.548598878244,300.535979438678,112.59888618167,10.2182233009151,13.9289471400771,21.9441193929559,0.353424300634486 -2.46967229628026,0.583527989743733,15.1933291603666,19.7449666743902,7.8979866697561,812.636282448057,305.439107690562,97.5341871124819,10.3849296614791,14.1263389575258,14.0493771927678,0.223014325973234 -4.8753772986644,0.588467334336294,15.1986819223211,19.9191156107844,7.96764624431375,826.742994915549,308.532474503196,126.413616165804,10.4901041331087,14.2509320725796,27.9612308801021,0.439844675177353 -4.27821024917365,0.598218088933623,15.208641208173,20.2624390429558,8.10497561718231,854.927670561952,314.62751172276,121.46532303098,10.6973353985739,14.4965593888923,24.9285192904262,0.385289804001696 -4.79803725394281,0.60677450943197,15.2167564359228,20.56322288318,8.22528915327202,880.02826641428,319.963717585896,129.461728606572,10.8787663979205,14.7117521795423,28.3434554814418,0.431466917320751 -5.24531535000394,0.616370583939856,15.2252139112449,20.9000378631955,8.3600151452782,908.588191354735,325.935169467635,136.974446856678,11.0817957618996,14.9527230888446,31.4589778438749,0.470943513177193 -4.90104398243494,0.626861214639863,15.233738802801,21.2676581305881,8.50706325223525,940.305944501134,332.448033612529,135.06139844747,11.303233142826,15.215733332948,29.8778044253446,0.439312402893434 -2.28013837910928,0.636663302604733,15.2410762727071,21.6106196640405,8.6442478656162,970.40974480616,338.519653158533,104.280713236762,11.5096682073901,15.4611017324411,14.1105025063145,0.204086994231776 -3.80863167248694,0.641223579362952,15.2442966232462,21.7700106010397,8.70800424041589,984.569177478894,341.340014860126,124.367780277258,11.6055605052443,15.5751363844079,23.7329596210461,0.340675395796068 -4.13716150876472,0.648840842707926,15.2494177537781,22.0360225155935,8.81440900623742,1008.4386871905,346.045027096335,130.063012440891,11.7655309212754,15.7654519485562,26.0768214964022,0.369673192616678 -5.79275674057479,0.657115165725455,15.2546344921442,22.3246707493989,8.92986829975958,1034.67668800861,351.147678437689,153.161413024435,11.9390210668814,15.97196244095,36.9635432007299,0.517042397722757 -5.0903653175615,0.668700679206605,15.261376310789,22.7283145557011,9.09132582228044,1071.95636379996,358.278540320474,146.622603210829,12.1814703708961,16.2607453657308,33.0372426221192,0.45369156277112 -6.26165478478156,0.678881409841728,15.2668009815026,23.0825468803666,9.23301875214666,1105.23786140791,364.532151934983,164.499697686025,12.3940931657894,16.5141773400895,41.2400589505367,0.557417626912788 -4.43283749002881,0.691404719411291,15.272889311417,23.5177251072681,9.40709004290724,1146.847733345,372.209437285899,142.683356087229,12.6551208677206,16.8255212507439,29.7189019215063,0.394069942058171 -3.5382461357486,0.700270394391349,15.2768414279516,23.8254494703924,9.53017978815697,1176.75209331134,377.634792563457,132.218557878167,12.8395829471575,17.0456795690976,24.0174143473388,0.314253403806956 -4.30546398815621,0.707346886662846,15.279798764229,24.0708732903386,9.62834931613544,1200.88772132753,381.959789519804,144.220878960209,12.9866328436733,17.2212655868398,29.5129589350622,0.382126676457145 -5.3298811451347,0.715957814639158,15.2831763554113,24.3692870768276,9.74771483073104,1230.57579686032,387.216330726321,160.377876687715,13.1653552446949,17.4347627462455,36.9687043530275,0.4726621825116 -1.24478389836617,0.726617576929428,15.2870445074308,24.7383765108675,9.89535060434699,1267.81301432757,393.714485943257,104.550948292473,13.3862925220708,17.698824090935,8.7594076329805,0.110284136618117 -4.31842070711914,0.72910714472616,15.2879008681686,24.8245267405674,9.92981069622695,1276.58707500322,395.23072424028,148.863699423828,13.4378446241695,17.7604594112715,30.4899240444183,0.382517215662588 -1.80760653348548,0.737743986140398,15.2907415710799,25.1232599557057,10.0493039822823,1307.25340374604,400.486945574493,114.324545436226,13.6165561495328,17.9741851027101,12.9101786030993,0.159999117728906 -3.27222893921011,0.741359199207369,15.2918729599581,25.2482410637384,10.0992964254954,1320.19450331298,402.685332821539,136.174339180617,13.6913013159323,18.063601586641,23.4826704033615,0.289555169133979 -3.0910324276404,0.74790365708579,15.2938387722363,25.4743980254686,10.1897592101874,1343.77853092433,406.662416521562,134.730807522447,13.8265221617331,18.2254033233412,22.3738423318281,0.2733819634356 -5.55242634737728,0.75408572194107,15.2956025467487,25.6879279024675,10.275171160987,1366.24285167527,410.416336670436,172.209944499845,13.9541554467948,18.3781711385414,40.515241209822,0.490848952021599 -5.80374973980142,0.765190574635825,15.2985575610163,26.0712505057187,10.4285002022875,1407.05017879372,417.15265675441,178.509437646041,14.1831903296499,18.6524154618114,42.9597934199056,0.512661411469696 +"dD","D","H","fc","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" +3.61419527788626,0.04,4.2375677628595,0.85434833928619,0.377501266657307,0.151000506662923,1.06501694023107,1.04242323817797,2.57427495945796,0.0354423900980509,0.270079506217303,0.547917987076988,0.161272907311876 +2.63582213481423,0.0472283905557725,4.86752857429837,0.831158170626178,0.511980501549784,0.204792200619914,1.70543306434933,1.65681532323452,2.91641485312791,0.0563317209899736,0.366291330028777,0.537031448881447,0.133212729374954 +2.0223383372043,0.052500034825401,5.30427913897247,0.81478888178635,0.620194239560314,0.248077695824126,2.29649461222528,2.21771759398417,3.12840123085741,0.0754023981954617,0.443711766751031,0.495860062869258,0.110248905528795 +3.99630301427157,0.0565447114998096,5.62697550702139,0.80253013111927,0.7086124576983,0.28344498307932,2.82604378944852,2.71584405130631,4.88214527137934,0.0923386977444145,0.506969696735672,1.11397328014681,0.229323758579466 +4.2217019893994,0.0645373175283527,6.23442775587003,0.779047613350402,0.896085134420728,0.358434053768291,4.07885525608091,3.8797257171921,6.26761792519107,0.131910674384531,0.641095148569966,1.47368574215049,0.264345473357082 +3.46719987885737,0.0729807215071515,6.8348837407399,0.755268364424925,1.1109155610504,0.444366224420161,5.71830497593628,5.37581525684338,6.91918868753264,0.182777718732675,0.7947934289979,1.48532285495898,0.234244177758968 +4.52469122322255,0.0799151212648662,7.2982610776457,0.736493209833092,1.29894308939059,0.519577235756236,7.32145163448969,6.8130805746893,9.22721320408101,0.231644739539436,0.929315843873604,2.24789896187047,0.322207237255168 +2.75527508964622,0.0889645037113114,7.86516608120094,0.712967038237946,1.55835508989843,0.623342035959373,9.77825357498007,8.97264359057825,8.59628300060585,0.305069882079661,1.11490956551694,1.62501387485143,0.207937958293907 +2.16979705684583,0.0944750538906038,8.19059161833534,0.699159783373791,1.72335277072833,0.689341108291332,11.4833723280803,10.4440715994928,8.6203748332246,0.355098434382757,1.23295550628988,1.40630296660708,0.168818043164358 +3.07431283587035,0.0988146480042955,8.43684994070901,0.688552899789867,1.85670718694588,0.742682874778351,12.9402556871126,11.6850599924355,10.6694458607846,0.397292039742807,1.32836258982856,2.13620539825103,0.244451596269189 +4.23100485332867,0.104963273676036,8.77129160112042,0.67391402832961,2.05041930668986,0.820167722675942,15.1795242773453,13.5654541771466,13.6876639916261,0.461225442022985,1.46695198877819,3.22441060509178,0.345913035154214 +2.7042299793535,0.113425283382693,9.20519506341289,0.65448762256395,2.32533021429281,0.930132085717125,18.6025559273069,16.3818050686804,12.5469236125034,0.556981372335134,1.66363424851365,2.31553531944851,0.228562540280565 +3.37588075128829,0.1188337433414,9.46736349476652,0.642491799518667,2.50559339573157,1.00223735829263,21.0004443835834,18.316333204339,14.8340486774496,0.622755328947526,1.7926017390422,3.09657275674885,0.290683644367646 +2.80933458522169,0.125585504843977,9.77895419215864,0.627958886701988,2.73510304682919,1.09404121873167,24.226535930895,20.873229893287,14.9071511577164,0.709689816371757,1.95680212382347,2.79278991549599,0.246949945783297 +4.23327794435142,0.13120417401442,10.0255901031469,0.616226836510612,2.92953952481571,1.17181580992628,27.1097257755016,23.1169554538833,19.198843022899,0.785976485432033,2.09590975763415,4.48104815419439,0.377843613034844 +2.49528677089278,0.139670729903123,10.3766952825391,0.59914505014854,3.22779713774433,1.29111885509773,31.7972635195878,26.6879300620075,16.7122118358412,0.907389622108256,2.3092951842278,2.88500650779462,0.22723812549853 +5.21454313363615,0.144661303444909,10.5726649560033,0.589400378913447,3.40626639131945,1.36250655652778,34.7543439338253,28.8950378840561,24.712744734852,0.982431288057907,2.43697922700559,6.33030958897154,0.479825901226051 +4.45825591570449,0.155090389712181,10.9575226802592,0.569778169705937,3.78476597991417,1.51390639196567,41.4001609797465,33.7373711008436,25.120177625202,1.14707061742868,2.70777297266979,5.9518792164748,0.417946118436792 +3.12684454571733,0.16400690154359,11.2617756833122,0.553761889193886,4.11349299747377,1.64539719898951,47.5829098962398,38.1077987290336,23.0952188646874,1.29566515678714,2.94295743011264,4.49822466080094,0.296981365148724 +0.83980983369455,0.170260590635025,11.4624458291288,0.542927044493358,4.34643508436966,1.73857403374786,52.19458447931,41.2903170231125,17.0032963824399,1.40387077878582,3.10961351676143,1.26906122218077,0.0803863578176289 +2.7528518715949,0.171940210302414,11.5146349609479,0.540071221264406,4.40929741575342,1.76371896630137,53.4718190625483,42.1606855417976,23.475574884942,1.43346330842112,3.15458774312663,4.21349381903444,0.264006797814069 +2.02196007113399,0.177445914045604,11.680820757461,0.530866928695069,4.61616292963981,1.84646517185592,57.7730430884123,45.0580144522875,22.0703980885603,1.53197249137777,3.3025876063815,3.22362492642659,0.195036874537514 +2.93072817620029,0.181489834187872,11.7982547283812,0.524256446523438,4.76882996982629,1.90753198793052,61.0438973330566,47.2277143158573,25.9462138702097,1.60574228673915,3.41181171361252,4.80934928503044,0.283772157567886 +2.55220658302714,0.187351290540272,11.9617931511234,0.514894098253604,4.99108243495948,1.99643297398379,65.952238887114,50.4318478316679,25.7462611652837,1.71468282627671,3.57082001726741,4.3605129986276,0.248331209182562 +4.2334045240652,0.192455703706327,12.0980283550311,0.506946496880732,5.1854583512764,2.07418334051056,70.3875823151747,53.2762373877248,32.9910779163514,1.81139207118264,3.70988432283719,7.48099842816608,0.413438716298905 +3.77428041150235,0.200922512754457,12.311962569824,0.494170709709006,5.50931562024479,2.20372624809792,78.0736287521434,58.0974547273159,33.1381689583558,1.97531346072874,3.94158476734793,7.03492117818929,0.370485014674553 +3.71063509624183,0.208471073577462,12.4907253747914,0.483192485747375,5.79929536759975,2.3197181470399,85.2705654276001,62.4956495287277,34.5377499283938,2.12485208397674,4.14904787779557,7.23454633453342,0.365540708428101 +4.40657037127339,0.215892343769945,12.6561481671932,0.472762068554469,6.08527987936592,2.43411195174637,92.660771071553,66.9029450925581,39.1282454029168,2.27470013314697,4.35365263689355,8.96072067347031,0.435278831471487 +5.22460777567042,0.224705484512492,12.8401235677315,0.460822680120124,6.42576208421306,2.57030483368522,101.839539178313,72.2335445021246,44.8437690444463,2.45594051307224,4.59724722552939,11.140571841934,0.517281516137811 +4.12588358939749,0.235154700063833,13.0419215563785,0.447266360044847,6.83025649549098,2.73210259819639,113.284055387619,78.6741364831034,42.3199634805667,2.67492064042552,4.88663870713407,9.27700987969847,0.409166449778424 +4.06195735877181,0.243406467242628,13.1896568529133,0.436998250834034,7.15002196320273,2.86000878528109,122.748897536845,83.8410604716865,43.883735959641,2.85059605603734,5.11541171335376,9.50263257381839,0.403048889067712 +4.78633758749704,0.251530381960172,13.3257816488355,0.427248510504041,7.46491572128936,2.98596628851574,132.432162409347,88.988550536786,49.3766535163434,3.02561071825073,5.34069930363926,11.6223985614159,0.474920741832296 +2.03198403068806,0.261103057135166,13.4751135258468,0.41619685177978,7.83585074967758,3.13434029987103,144.303286879851,95.1209581050517,37.1845032870995,3.23411257557176,5.60608106034933,5.14501621766722,0.201496184600926 +1.82127914231564,0.265167025196542,13.5350965806736,0.411642452910375,7.99323610375422,3.19729444150169,149.492797495271,97.7436825664736,36.7912609661138,3.3232852072601,5.71868083806992,4.691217155486,0.180522272256403 +3.07616600733212,0.268809583481173,13.5872094385735,0.407627839182267,8.13423628206164,3.25369451282466,154.219624991688,100.103221888547,44.2435310838741,3.4035095442106,5.81955800563818,8.04375415622991,0.304758850987011 +4.04790294034711,0.274961915495837,13.6718158143053,0.400988547627763,8.37221763733068,3.34888705493227,162.364532060208,104.105747939225,50.8915512397339,3.53959542993365,5.98981938645186,10.8506660592561,0.400641234582419 +4.69468494112271,0.283057721376532,13.7769224575599,0.392514335334539,8.68498326766391,3.47399330706556,173.389224258201,109.401867322359,56.4003054735228,3.71966348896019,6.21358442901747,12.9875600433066,0.463934948781327 +4.26504606926218,0.292447091258777,13.8905076204548,0.38304440732659,9.0470541345681,3.61882165382724,186.609008929115,115.579237480994,56.0638033139443,3.9296940743538,6.4726244100354,12.2203283900467,0.420574104743592 +3.95460165519157,0.300977183397301,13.986479975711,0.374759947180498,9.37526964293929,3.75010785717571,199.019418172765,121.217727514879,56.0918223514591,4.12140273550589,6.70744291334448,11.682877520424,0.389096601464554 +3.59592766439221,0.308886386707684,14.0697403608319,0.367337807536995,9.67891369552117,3.87156547820847,210.864512914207,126.463577269679,55.5693667490418,4.2997616271691,6.92468201432366,10.9179376090087,0.353010624547243 +4.60653890456036,0.316078242036469,14.140961621756,0.360796783555636,9.95440510013855,3.98176204005542,221.91569717693,131.245214763122,63.5649889911477,4.46233730194616,7.12177958484313,14.327396861869,0.451235551206729 +1.1348826389603,0.32529131984559,14.2263499269029,0.352695019643393,10.3064174071021,4.12256696284085,236.460341865218,137.382574830826,42.7561876155631,4.67100754424809,7.37362326973714,3.63665770107136,0.110840041192015 +4.06458077382757,0.32756108512351,14.2464275021785,0.350745401667865,10.3929787502524,4.15719150010096,240.110112758196,138.896128729079,62.6000982972905,4.7224683767887,7.43555271708058,13.1185869983298,0.39667553730703 +4.41724932120023,0.335690246671165,14.3153852537642,0.343908279782048,10.7024579259797,4.2809831703919,253.396355101432,144.32028616236,66.7741021069221,4.90688972952024,7.65696649856294,14.6208665143895,0.429909076821166 +1.79279718091315,0.344524745313566,14.385359418673,0.336727519958628,11.0378097287001,4.41512389148005,268.213995002787,150.218509514196,50.4035758976065,5.10742932348266,7.89689059230121,6.09362137305291,0.173947239217225 +3.06143683120084,0.348110339675392,14.4123632021848,0.333884755074705,11.1736197285772,4.46944789143088,274.339865383491,152.612655528483,59.9777583823456,5.18883028796843,7.99405449861327,10.5157523298448,0.296660142165985 +1.50117390397806,0.354233213337794,14.4567031891335,0.329123051288314,11.4051318186194,4.56205272744776,284.949368687038,156.700530730671,49.9659051519358,5.32781804484281,8.15968750831306,5.24827151026063,0.145148240789601 +4.05132556253422,0.35723556114575,14.4776558714492,0.326829974349181,11.5184674550801,4.60738698203202,290.22010518285,158.704576587986,68.9363905955646,5.39595560399154,8.24077235606248,14.2851022243896,0.391297328170271 +5.66403244635144,0.365338212270818,14.5317272613311,0.320774955768466,11.8237190946155,4.72948763784621,304.668331241669,164.110613998832,82.6188780371177,5.57976087596028,8.45916158905174,20.4272855438418,0.545450735644038 +3.01316544943287,0.376666277163521,14.6016215011273,0.312624249222992,12.2489705948221,4.89958823792885,325.412658538535,171.659920998718,65.1780022373135,5.83643731395643,8.76340352235954,11.2039025457643,0.288969168987441 +2.78597582479134,0.382692608062387,14.6362750499602,0.30843155504617,12.47447858356,4.98979143342402,336.705791579979,175.670551696288,64.5792347691106,5.97279875767378,8.9247409578222,10.5240536198184,0.266591712873914 +4.87271491146775,0.38826455971197,14.6668470696161,0.304640281468683,12.6825411454887,5.07301645819548,347.305884466971,179.374758697704,82.017260717091,6.09874179572193,9.07359723712844,18.6725908906924,0.465323608614364 +3.21641292436047,0.398009989534905,14.7171148114456,0.298199575112206,13.0454305221565,5.21817220886261,366.210253418252,185.84297448568,70.9130976403458,6.31866113251313,9.33322281277166,12.631265916159,0.306066553784671 +5.00151802197696,0.404442815383626,14.7481897698691,0.294076219799635,13.2842673673543,5.31370694694171,378.942088220714,190.104489975619,86.7503037018685,6.46355265917104,9.50409624529994,19.9542175912008,0.474829720056854 +2.61513448177088,0.41444585142758,14.7934109012255,0.287858354488032,13.654565431774,5.4618261727096,399.13865623935,196.717193734834,69.0842499993258,6.68838458698434,9.76902229250839,10.6866797363974,0.247389179310551 +4.38846825604944,0.419676120391122,14.8156384269194,0.284698006987983,13.8476600984633,5.53906403938533,409.891360594184,200.167600805403,85.0450639705865,6.80569842738372,9.9071699408446,18.1548785261568,0.414381058858339 +2.2485165003717,0.428453056903221,14.8508889871088,0.27952941830465,14.1709009749327,5.6683603899731,428.23170717312,205.946109419911,68.4696693246413,7.00216772027697,10.1384293935059,9.49195653615183,0.211670050142608 +2.2432449737829,0.432950089903964,14.8680035938117,0.276944750872787,14.3361407891295,5.73445631565182,437.772223990479,208.901012052733,69.2081665357538,7.10263440979291,10.2566485661748,9.56657101723573,0.210849031742982 +5.35926015710125,0.43743657985153,14.8844688464015,0.274407867592198,14.5007412980437,5.80029651921748,447.38705429855,211.844954077835,97.419304842287,7.2027284386464,10.3744103542724,23.0857016376885,0.502967503935862 +3.66062598867648,0.448155100165732,14.9214688693569,0.268510670348906,14.89298274049,5.95719309619602,470.747628295901,218.861569344914,84.6172228504012,7.44129335772707,10.6550355718562,16.1439158496426,0.342329497793288 +2.28005711417344,0.455476352143085,14.9449594711966,0.26461059094751,15.1601096057181,6.06404384228725,487.019427928689,223.640498456833,73.4548082335293,7.60377694753231,10.846148816315,10.2146522742118,0.212718141557215 +3.57967699729492,0.460036466371432,14.9589031297618,0.262232071544505,15.3261747990157,6.1304699196063,497.283608949281,226.61138658818,86.2458088504981,7.70478714399812,10.9649584982078,16.1924371444989,0.333481791282087 +5.12174135801468,0.467195820366022,14.9797829305438,0.258574019258411,15.5864149740682,6.23456598962728,513.597965625679,231.266751692435,102.110108451039,7.8630695575428,11.1511447290474,23.5166485477788,0.476073247863579 +3.47882972754835,0.477439303082051,15.0076310977229,0.253496690081571,15.957765510624,6.38310620424962,537.36373987444,237.908557622901,88.7203345796038,8.08889095917862,11.4168237569209,16.3114696293465,0.322357043071212 +2.70806295248966,0.484396962537148,15.0252724724439,0.250149281619073,16.2093475178922,6.48373900715688,553.789931798322,242.407088807024,82.6053547145053,8.2418410194388,11.5968155882008,12.8760838627386,0.250421144226177 +4.37599022139665,0.489813088442127,15.0383342290835,0.247598301895011,16.4048356762212,6.56193427048848,566.735453197475,245.901800560683,99.9214167398006,8.36066121906322,11.7366756361957,21.0309882508301,0.404026245591593 +3.47778796671728,0.498565068884921,15.0582680094727,0.243574315202804,16.7200909485027,6.6880363794011,587.947561937489,251.535833765387,92.8233751898047,8.55221834802316,11.9622218681968,17.0020572794889,0.320307770568813 +4.85561756252765,0.505520644818355,15.0731339916517,0.240460075046821,16.9700929828417,6.78803719313668,605.063882069782,256.001985399667,108.079124393239,8.70406750358867,12.1410833236443,24.0569438868774,0.446359220714667 +2.63373782532175,0.515231879943411,15.0925390549594,0.236231548114099,17.318361519981,6.9273446079924,629.343338531056,262.220780607991,87.3807825111785,8.91550654067168,12.3902485658552,13.2900797623986,0.241489912159131 +2.19034495341924,0.520499355594054,15.1024440689288,0.233994341150871,17.5068978609808,7.00275914439232,642.698824203025,265.58586110291,83.7156916857586,9.02991927749892,12.5251350056601,11.1614591468821,0.200564068891872 +1.893949536051,0.524880045500893,15.1103661356152,0.232163124623956,17.663502167006,7.06540086680241,653.905499015575,268.380166748156,81.3565113734852,9.1249256694373,12.6371759903628,9.72929011395808,0.173233354782932 +4.0167248422012,0.528667944572995,15.1169935022014,0.230600775349538,17.7987773446922,7.11951093787687,663.668583303918,270.793262941119,104.323927275728,9.20697093999804,12.7339572634866,20.7774020625898,0.367053516878844 +3.26841455257459,0.536701394257397,15.1303946061369,0.227350464607316,18.0852594721741,7.23410378886962,684.597925489792,275.901655256233,97.9628815395287,9.38065627871194,12.9389180367722,17.153844815493,0.29809549629111 +4.93448854908464,0.543238223362546,15.140674484156,0.22476734576244,18.317968525841,7.32718741033639,701.852320130267,280.049134541717,117.192654439197,9.52167057441837,13.1054074021277,26.2016060851972,0.449364964391523 +4.73524779695389,0.553107200460715,15.1552003436659,0.220968661243978,18.6686433928723,7.46745735714892,728.283018227318,286.295463460179,117.17106733652,9.73404575764607,13.3562942289966,25.5833093017526,0.430266551740257 +7.1605637480004,0.562577696054623,15.1680906909191,0.217433632512271,19.0044450652437,7.60177802609746,754.077207229724,292.272694620644,146.2912733193,9.93727161710189,13.5965401774779,39.3244040277945,0.649320187396606 +1.8825382247838,0.576898823550624,15.1858006322826,0.212283556720695,19.510981315987,7.8043925263948,793.883686235923,301.281085760271,89.6779658124455,10.2435569158492,13.9589364727097,10.5919968601291,0.170213027491961 +3.40529396917268,0.580663900000192,15.1901259730612,0.210967163468821,19.643911460874,7.8575645843496,804.508998223118,303.643564797392,107.804204477731,10.3238812031113,14.0540400155677,19.2802234833689,0.307670500751777 +2.80729730873834,0.587474487938537,15.1976230803309,0.208624338538262,19.8841232522444,7.95364930089776,823.89822853601,307.911004959653,102.141487087847,10.4689741686282,14.2258971395857,16.0741916740617,0.253314236911191 +3.28931180225444,0.593089082556014,15.2035004880304,0.206729273071539,20.0819225549833,8.03276902199332,840.046504173767,311.423345290206,108.801479617725,10.588393739867,14.3674106727373,19.0077485234132,0.296502622481705 +5.37215315424785,0.599667706160523,15.210055895409,0.204549519395285,20.3134288504572,8.12537154018288,859.15596558391,315.532359457551,134.739143572098,10.7281002215567,14.5330395367711,31.3759806980666,0.483685556198223 +5.69364842064207,0.610412012469018,15.2200398301163,0.201080998059022,20.6909592982136,8.27638371928544,890.803283679541,322.228871763402,141.04909525273,10.9557816399557,14.8031399203139,33.8288388117205,0.511693877574235 +4.19237247795697,0.621799309310302,15.2297156540814,0.197524001223396,21.0903504367334,8.43614017469335,924.93697827169,329.307413264352,125.262225169105,11.196452050988,15.0888803164565,25.3579688387214,0.376082859682845 +3.83112582458423,0.630184054266216,15.2362916032446,0.19498005154078,21.3839756691964,8.55359026767856,950.460280962115,334.507731062184,122.479151585599,11.3732628561142,15.2989515527699,23.4751224188504,0.343236731570036 +7.53560514155128,0.637846305915385,15.2419231235586,0.192709017403503,21.651978006647,8.66079120265881,974.073510736204,339.251558826025,170.583006404223,11.5345530000848,15.4906911450756,46.7175462597354,0.674370167572335 +3.37525652151053,0.652917516198487,15.2520316242566,0.188385595397222,22.1782759449131,8.87131037796525,1021.32559046479,348.560099648313,121.088712735682,11.8510433880426,15.8672257420286,21.4040499364049,0.301429486340331 +3.17738150566599,0.659668029241508,15.2561747857618,0.18650845906323,22.4136640412306,8.96546561649224,1042.83693799205,352.720315166131,119.787387632254,11.9924907156485,16.035631801658,20.3512590265734,0.28350982130395 +7.05291590223014,0.66602279225284,15.2598736606517,0.184773702484046,22.6350675775558,9.05402703102233,1063.2833132038,356.631692092436,171.758610676945,12.1254775311428,16.1940327476865,45.5965020660648,0.628814124587998 +2.77717783466472,0.680128624057301,15.2674353507162,0.181031167164102,23.1259141200635,9.25036564802539,1109.34868475497,365.297484806032,118.200889582143,12.4201144834051,16.5452039980582,18.3235118087884,0.2471915221117 +3.90877011453918,0.68568297972663,15.2701840222934,0.179597057214651,23.3189722705212,9.32758890820847,1127.74493853369,368.703815393531,134.432513628376,12.53592972338,16.6833255212217,25.9944058905176,0.347696638782448 +2.04632912417107,0.693500519955708,15.273849310733,0.17761515755847,23.5904952519697,9.4361981007879,1153.88349336412,373.492668007137,110.599973501744,12.6987507122427,16.8775839230692,13.7595981208754,0.181874028543112 +5.39361726544622,0.69759317820405,15.275677711591,0.176594257421178,23.7325540015589,9.49302160062356,1167.68261409078,375.99728503748,157.132665011288,12.7839076912743,16.9792184348753,36.4752480793978,0.47917106667856 +2.01159278058089,0.708380412734943,15.2802166920773,0.173956749442865,24.106703316468,9.64268132658721,1204.43253465662,382.591063779503,112.532835604944,13.0080961685031,17.2468998207339,13.8086404042661,0.178518826091763 +3.24272336527191,0.712403598296105,15.2818106836296,0.17299240070335,24.2461442917626,9.69845771670506,1218.27940068484,385.047475541401,130.397275836017,13.0916141684076,17.3466614720987,22.3830198191459,0.287665128939845 +1.22807840044806,0.718889045026649,15.2842734809767,0.171459380081815,24.4708148588027,9.78832594352106,1240.76178254007,389.004181418551,103.179274884822,13.2261421682307,17.5073997825818,8.55212261392499,0.108878696323 +3.06924173777533,0.721345201827545,15.2851729719422,0.170885622660239,24.5558669076722,9.82234676306886,1249.32816082707,390.501690277517,129.594570386947,13.2770574694356,17.568249420425,21.4449191911359,0.272051935081801 +2.4712809976844,0.727483685303095,15.2873443892178,0.16946776661466,24.7683498467462,9.90733993869848,1270.86214251068,394.242036402654,122.177075285995,13.4042292376902,17.7202682143561,17.410373685769,0.218931719606793 +6.24824272188956,0.732426247298464,15.2890160779638,0.168342569934592,24.9393541528058,9.9757416611223,1288.33027640702,397.251383076148,177.257864740946,13.506547024589,17.8426115350834,44.3114630457955,0.553301683260023 +4.09674871424538,0.744922732742243,15.2929562615094,0.16556118777248,25.3714004483227,10.1485601793291,1333.0111407072,404.851304473221,148.869716693407,13.7649443520895,18.151714736748,29.5379055429178,0.362414333361263 +4.64710260130901,0.753116230170734,15.2953317434718,0.163785408682753,25.654447957117,10.2617791828468,1362.70795770396,409.827819050208,158.633180012678,13.9341458477071,18.3542182464398,33.8665527941661,0.410845360767617 diff --git a/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv b/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv index 4ad51974..650163fd 100644 --- a/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv +++ b/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv @@ -1,101 +1,101 @@ -"dD","D","H","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" -13.4468615259933,0.6,33.5798055081921,63.0047820994125,3.00022771901964,474.723316320797,378.031173825666,112.800283144307,20.413683386586,9.09159005694522,52.6093955065352,0.821741240601042 -20.1226590065085,0.626893723051987,34.2697846560544,67.1814516669976,3.19911674604751,528.882386519655,414.98734677119,160.393378634384,22.4093167256443,9.69428347554776,83.3639407310527,1.24033945985456 -21.415559932846,0.667139041065003,35.2273694324058,73.492100012986,3.49962381014219,615.705187027075,472.473726964019,183.399124821607,25.513581256057,10.6049100318739,96.0757140378924,1.33384074420015 -18.7427359837963,0.709970160930695,36.1555840437245,80.2711647605426,3.82243641716869,715.674362237756,536.232653219677,180.939134015321,28.9565632738626,11.5831290749463,90.8910762785455,1.17707371011401 -18.7503702918153,0.747455632898288,36.8976945022625,86.2439694372004,4.10685568748573,809.524421039719,593.95415246012,194.087148985833,32.0735242328465,12.445004789788,96.8406340656255,1.18375941644892 -20.8775007275776,0.784956373481919,37.5800425660006,92.24585803966,4.39265990665048,909.30209888026,653.267633149951,224.042630503815,35.2764521900974,13.3110773151229,114.357579272193,1.32291907851609 -13.5153459719739,0.826711374937074,38.275034542045,98.9494971843508,4.71188081830242,1027.26692066309,720.911579574095,177.791393926889,38.9292252970011,14.2784124437018,78.6932361026511,0.858586897937527 -14.2209716545081,0.853742066881022,38.691353117325,103.296281156986,4.91887053128505,1107.45774878866,765.485577183094,191.737565956016,41.3362211678871,14.9056533709531,85.9496039059287,0.904215472756413 -21.5328173587532,0.882184010190038,39.1029102941759,107.872899086908,5.1368047184242,1195.05345269207,812.968074988941,266.376314649445,43.9002760494028,15.5660593382409,135.120033624822,1.36964419099955 -17.1788288524123,0.925249644907544,39.6780293143474,114.802965921938,5.46680790104467,1333.91400968529,885.846401042909,241.1605697223,47.8357056563171,16.5660679825357,113.755295312689,1.09229910652615 -13.9498351415601,0.959607302612369,40.0985218676212,120.327805190942,5.72989548528294,1450.02449251351,944.70695375387,220.362858568923,51.014175502709,17.3633022890529,96.1925705638733,0.886115816554606 -19.6626251502739,0.987506972895489,40.4168514462113,124.80923927041,5.94329710811476,1547.75674606689,992.895675286195,287.092323614537,53.6163664654546,18.0099732267201,139.920802037173,1.24752890779383 -16.607403649346,1.02683222319604,40.8329273182244,131.115516973634,6.24359604636353,1690.71100346357,1061.31266362699,268.362756523188,57.3108838358573,18.9199690992954,123.295072501955,1.05141643432936 -19.0170384588928,1.06004703049473,41.1567802590317,136.430230531606,6.49667764436221,1816.14929035304,1119.46533207356,305.62993595651,60.4511279319721,19.6868822657108,146.08592092715,1.20132593194018 -15.8351765175105,1.09808110741251,41.4990803491458,142.500693916232,6.78574732934437,1965.02100583866,1186.374710968,282.198249070145,64.064234392272,20.5628501321123,126.275515061345,0.997460710502415 -19.4532945400472,1.12975146044754,41.762584593619,147.541558579008,7.02578850376229,2093.21133048073,1242.28611044939,334.753071164087,67.083449964267,21.2902469029509,159.826495296775,1.2221603924201 -10.1546824395512,1.16865804952763,42.0616178891886,153.715448150814,7.31978324527688,2255.90480319315,1311.14434038745,234.338846047754,70.8017943809223,22.1811391681625,86.4187158529375,0.635775122556258 -15.7399448585692,1.18896741440673,42.2076195866885,156.929611276793,7.47283863222824,2343.09905996866,1347.13986319975,308.933383041192,72.7455526127867,22.6449429072412,136.353048202548,0.983610284895937 -22.9624669857488,1.22044730412387,42.421141594818,161.899486446503,7.70949935459538,2481.30586536156,1402.9741616628,410.954498559338,75.7606047297912,23.3620958942304,204.323671489059,1.43065061444497 -17.9133366771062,1.26637223809537,42.7067290226697,169.122651038371,8.05345957325578,2689.54588188523,1484.45762226332,361.272117331813,80.1607116022191,24.404398544837,165.497002279203,1.11103094358604 -15.2205768333594,1.30219891144958,42.909906777722,174.734630565322,8.32069669358677,2857.40705492221,1547.99769113822,336.083557854815,83.5918753214637,25.214207190576,144.632480628587,0.940619984277925 -9.39789597168783,1.3326400651163,43.070127425594,179.487045889403,8.54700218520968,3003.73610130033,1601.93888579824,263.638972117013,86.504699833105,25.8999807218409,91.3961368394102,0.578988703070732 -15.7595964303829,1.35143585705967,43.163712686149,182.414063479943,8.68638397523539,3095.77617875419,1635.21412439553,358.206468500735,88.3015627173584,26.3223493601558,155.423351777666,0.969063758830436 -12.4666267288399,1.38295504992044,43.312031347035,187.309888078712,8.91951847993866,3253.00377635744,1690.94938859999,319.851757739313,91.3112669843994,27.0288168497581,125.799835442529,0.764118761179434 -16.8611956537359,1.40788830337812,43.4221299885645,191.171615901372,9.10341028101772,3379.92770123049,1734.97204248724,391.285824202797,93.6884902943112,27.586064174568,173.183986272428,1.03086083466067 -11.8336136412102,1.44161069468559,43.5615446488633,196.379139916053,9.35138761505014,3555.1599734372,1794.40589080271,325.713796388422,96.8979181033465,28.3375098898864,124.417826753027,0.721026249148752 -16.4944719525086,1.46527792196801,43.6532602123864,200.023387165572,9.52492319836056,3680.58271142509,1836.0373902594,403.298639247764,99.1460190740074,28.863374767992,176.221832659709,1.00263892699086 -20.0736002553168,1.49826686587303,43.7732182284202,205.088703513063,9.76612873871728,3858.75063059255,1893.94598645029,469.410316527027,102.273083268316,29.594299916935,219.193862561796,1.21623157703197 -12.2220336427015,1.53841406638366,43.9076891901282,211.231124292266,10.0586249662984,4080.81541818482,1964.21895240589,356.598563853233,106.067823429918,30.480651235374,136.952156802841,0.737640058483079 -14.889684763343,1.56285813366907,43.9838082447748,214.959416005811,10.2361626669434,4218.82809450043,2006.89179215199,406.472840247524,108.372156776207,31.0186437296385,169.427107607721,0.896555877670914 -26.3632170809837,1.59263750319575,44.0710586422218,219.48988363947,10.4518992209271,4389.82537995441,2058.75826758297,605.856136159903,111.17294644948,31.6723902091755,305.540215257397,1.58300815947022 -18.6572436260023,1.64536393735772,44.2119031767812,227.481074884896,10.832432137376,4700.27258184673,2150.25817744805,494.495278186042,116.113941582194,32.8255191058905,223.171407860479,1.11496216485438 -14.6366423184651,1.68267842460972,44.3019495879274,233.113836505562,11.1006588812172,4925.8930319761,2214.7502895579,435.848822864532,119.596515636126,33.6383266077526,178.919366338477,0.871849414001941 -22.1233868222178,1.71195170924665,44.3674849041894,237.520121779023,11.3104819894773,5106.31633543378,2265.19085135369,577.561713739933,122.320305973099,34.274153572713,274.982997609332,1.31454709365196 -18.081195088664,1.75619848289109,44.4586992687314,244.159955504509,11.6266645478338,5384.72877854538,2341.17566402404,519.238530888775,126.423485857298,35.2322815793006,230.344115277233,1.07048924905985 -21.1233094954501,1.79236087306842,44.5267902984929,249.569168548522,11.8842461213582,5617.35906982172,2403.04931115383,587.203407934436,129.764662802307,36.0128310215517,274.439184546813,1.24705538338439 -14.5831497167101,1.83460749205932,44.5996280354426,255.869479995738,12.184260952178,5894.91364977461,2475.07672104261,476.898996588971,133.654142936301,36.921965963385,193.768383470102,0.858213865107776 -18.7203782798503,1.86377379149274,44.6460225525782,260.207650770186,12.390840512866,6090.16502324923,2524.6445096648,564.995468893127,136.330803521899,37.5479640061379,252.547205968029,1.09936915412641 -12.4279654853734,1.90121454805244,44.701285632075,265.763435854776,12.6554017073703,6345.15385599393,2588.08848727998,452.668971205795,139.756778313119,38.3496637938442,170.900797895873,0.727944698832728 -19.5565743985037,1.92607047902319,44.7354843197345,269.443930715844,12.8306633674211,6517.12992117884,2630.09393107607,601.342549824469,142.025072278108,38.8807592022962,272.312291290085,1.14358357870095 -18.2798131369585,1.96518362782019,44.7855718187514,275.223395190097,13.1058759614332,6792.1033244494,2696.01473569959,587.973482396891,145.584795727778,39.7147359259309,259.508483223929,1.06623385896982 -14.1072370633568,2.00174325409411,44.8285665848949,280.612693891842,13.3625092329449,7053.93551599766,2757.43946914374,512.814336162252,148.901731333762,40.4924117285929,203.859049924271,0.821007742121497 -19.8050054494929,2.02995772822082,44.8594117103333,284.763718433597,13.5601770682665,7259.17804060626,2804.71995834678,640.069074448718,151.454877750726,41.0914045699681,290.079976904746,1.15068984893757 -14.8923041032743,2.06956773911981,44.8995399527871,290.579936270046,13.8371398223831,7551.98412999577,2870.92100052901,547.778925299972,155.029734028567,41.9306848037676,222.224274121031,0.86332819494264 -19.5770663311285,2.09935234732636,44.927444000011,294.945064798512,14.0450030856434,7775.74961094531,2920.56984247724,657.612729978153,157.710771493771,42.5605728504252,296.182745589844,1.13309433975509 -21.4541849376102,2.13850647998862,44.9613930349864,300.672989843261,14.3177614211076,8074.5956845281,2985.67250540469,711.648928170717,161.226315291853,43.3871124343825,330.41923969305,1.23924830878676 -26.0871093213351,2.18141484986384,44.9953182737374,306.937308488572,14.6160623089796,8408.2137640167,3056.81138278035,830.510175444349,165.067814670139,44.291053614901,409.551083762651,1.50372999677303 -23.6848164199906,2.23358906850651,45.0323913450531,314.537457827628,14.977974182268,8822.49551842321,3143.03651334467,795.29521835166,169.723971720612,45.3877551645266,380.427199470391,1.36203650998786 -16.7670950183068,2.28095870134649,45.0624811921284,321.422748173394,15.305845151114,9206.82377797127,3221.073709784,649.851146065802,173.937980328336,46.3813025614207,274.83800443958,0.962301413091768 -25.6444784861217,2.3144928913831,45.0819246829752,326.288965867283,15.5375698032039,9483.6176730683,3276.18342489496,871.216508598663,176.913904944328,47.0834977746489,426.33498215166,1.46984103391362 -20.6471788563113,2.36578184835534,45.1089644035136,333.719542284902,15.8914067754715,9914.53004396059,3360.26685787001,769.084490221748,181.45441032498,48.1557299517113,350.627346204693,1.18116274670519 -25.0351224620777,2.40707620606797,45.1285775142083,339.692197452844,16.1758189263259,10268.1264896237,3427.79532498861,891.346363808126,185.100947549385,49.0175840924454,432.34363765911,1.43013910201775 -16.589052798004,2.45714645099212,45.1500393373614,346.923134977597,16.5201492846475,10704.8380881859,3509.48461134532,696.809128304744,189.512169012647,50.0610083772672,292.273795925729,0.946127127099266 -19.5256765742748,2.49032455658813,45.1629852621552,351.70835002371,16.7480166677957,10999.031070097,3563.50604943847,781.550687137785,192.429326669678,50.7515149084213,348.5308666155,1.11249819111225 -22.6510255124076,2.52937590973668,45.1770348598418,357.334697146018,17.0159379593342,11350.2222270225,3626.98600261925,875.178995546822,195.857244141439,51.5633967981703,410.490814890779,1.28913415035214 -17.7795085505431,2.57467796076149,45.1918592706897,363.854048794123,17.3263832759106,11764.2955329871,3700.49310755546,762.327949969558,199.826627807995,52.504139240992,327.831991803092,1.01066341795273 -23.6382739288928,2.61023697786258,45.202481778092,368.965963198973,17.5698077713796,12094.3363135149,3758.09636899737,929.932759579562,202.937203925858,53.2417884896117,441.734188182066,1.3425112043073 -14.6879037072415,2.65751352572037,45.2153505494857,375.755609694813,17.8931242711816,12539.9774380953,3834.56018374163,703.061954104784,207.066249922048,54.2215344789615,279.332324726993,0.833267124978738 -18.2420772643019,2.68688933313485,45.2226838887766,379.970779430977,18.0938466395703,12820.8192509498,3882.00607672122,808.903277385218,209.628328142946,54.82978347189,350.674877884893,1.03423736507214 -20.7411236327924,2.72337348766345,45.231142105936,385.202277633968,18.3429656016175,13173.8237922516,3940.86673120045,889.813762333717,212.806803484824,55.5846886625815,404.013234896033,1.17503513175602 -20.7535304353342,2.76485573492904,45.2399521238852,391.145825241385,18.6259916781612,13580.8506558953,4007.70668379581,903.89922020901,216.416160924974,56.4423425823318,410.286470447816,1.17479476636573 -16.2782656924011,2.80636279579971,45.2479815902443,397.088319612941,18.9089676006162,13994.1564629241,4074.50238579423,789.033993535604,220.023128832888,57.2998445201473,326.549867626844,0.920774149952184 -15.8677724125978,2.83891932718451,45.2537752548804,401.7463634293,19.130779210919,14322.5650802822,4126.83891305294,786.426769551048,222.849301304859,57.972000242848,321.939251013151,0.897060371444283 -20.9874252218571,2.8706548720097,45.2590286749825,406.28454139152,19.3468829234057,14646.2714484777,4177.81134982449,945.815467650018,225.601812890522,58.6268593227964,430.486182672438,1.1858893827178 -14.5440089994823,2.91262972245342,45.2654251146134,412.283512671859,19.6325482224695,15079.8507503603,4245.16635261556,767.77847191294,229.23898304124,59.4925108785493,302.608706120634,0.821287613058768 -11.5553030871171,2.94171774045238,45.2695163723604,416.438565231202,19.8304078681525,15383.9457482043,4291.80243121033,685.653734092233,231.757331285358,60.0920849628625,242.786359709607,0.652249995454262 -20.7725571470686,2.96482834662662,45.2725813006302,419.738589427769,19.9875518775128,15627.6707065731,4328.83289066771,970.718255656666,233.756976096056,60.5682784544271,439.823167887548,1.17216108582138 -18.7802799922004,3.00637346092075,45.2777057384985,425.668417401557,20.2699246381694,16070.5283893029,4395.35433024181,923.23801982608,237.349133833058,61.4239526310446,403.127646753129,1.0591790632306 -15.1765800519215,3.04393402090516,45.2819438957043,431.026909006815,20.5250909050864,16476.1378619184,4455.44675843334,822.781153433119,240.5941249554,62.1971829696834,329.784065340832,0.855553794026882 -16.9905047076646,3.074287181009,45.2851165317927,435.355475456301,20.7312131169667,16807.5434911471,4503.97624362117,888.146516950586,243.214717155543,62.8217951083442,372.831296597272,0.957485368346211 -23.9863967950323,3.10826819042433,45.2884205255808,440.19970339344,20.9618906377829,17182.4080345944,4558.27404467836,1120.38385778333,246.146798412632,63.5208171996735,532.087049731212,1.35124750210528 -14.1740892972385,3.15624098401439,45.2926751278059,447.035707432521,21.2874146396439,17718.5495609514,4634.87515953927,821.368164870714,250.283258615121,64.5072525825128,319.214203104783,0.798105676951936 -16.3792023993594,3.18458916260887,45.2949816634004,451.073785144511,21.4797040545005,18039.1803095432,4680.11256533641,900.638990024917,252.726078528166,65.0899471963529,372.149525833843,0.92203008787266 -16.7504245982794,3.21734756740759,45.2974700892663,455.738809924699,21.7018480916523,18413.2221327951,4732.36349899753,922.257605978384,255.547628945867,65.7631102721341,384.454644389233,0.942659194100423 -20.9561140219608,3.25084841660415,45.2998321272217,460.508233077112,21.9289634798625,18799.6566229013,4785.77324229686,1071.67046037026,258.431755084031,66.4513380330272,485.93757258909,1.17901883337278 -16.6398109437233,3.29276064464807,45.3025472019539,466.473386359317,22.2130183980627,19288.6943827842,4852.55909838455,940.50083793403,262.038191312766,67.3121096516494,390.77334246752,0.935878514358757 -14.1920165743093,3.32604026653551,45.3045279075342,471.208590118448,22.4385042913547,19681.4232193048,4905.56391714144,867.017569903928,264.900451525637,67.9953995540921,336.624616533914,0.79801716957377 -8.56686696704997,3.35442429968413,45.3061039142605,475.246360138939,22.6307790542352,20019.4708160424,4950.75486912334,681.882668890875,267.34076293266,68.5780497680489,204.918060435658,0.481622934325769 -20.5447881096357,3.37155803361823,45.3070076642359,477.68335274274,22.7468263210828,20224.9075196344,4978.02686640466,1097.79190089247,268.813450785852,68.9297078007773,493.91564178457,1.15488505775926 -19.7743358249175,3.4126476098375,45.309038182094,483.526605390501,23.0250764471667,20721.8067623154,5043.40912167445,1084.49430714033,272.34409257042,69.7728891578492,481.137082470577,1.11129609121837 -14.2462436999226,3.45219628148734,45.3108230021309,489.149392047429,23.2928281927347,21205.7089845893,5106.31358157896,902.420475653876,275.740933405264,70.584257272444,350.61541017292,0.800443497203485 -12.8863260452843,3.48068876888719,45.312013909263,493.199518598624,23.4856913618392,21557.7600919794,5151.61779712293,861.687417286311,278.187361044638,71.1686905337815,319.743782761421,0.723924771114698 -6.51939631486714,3.50646142097775,45.3130273030537,496.86251112375,23.6601195773214,21878.6788550339,5192.58731335232,640.334490114408,280.399714921025,71.6972603551572,162.952368930743,0.366197142867173 -17.2589347907408,3.51950021360749,45.3135180383387,498.715497592797,23.7483570282284,22041.9320190259,5213.31094828266,1028.54103908023,281.518791207264,71.9646463026406,432.979861351469,0.96937957688954 -23.6900582943807,3.55401808318897,45.3147497540226,503.620391517701,23.9819234056048,22477.0203152633,5268.16222562923,1272.02286993677,284.480760183978,72.6724224960042,600.107775042359,1.33038050328461 -15.8789848370893,3.60139819977773,45.3162919598759,510.351736040043,24.3024636209544,23081.1018897938,5343.42831029794,1002.11898239759,288.545128756089,73.6437555105781,407.568020257578,0.891545050015464 -21.7267908395487,3.63315616945191,45.3172373639338,514.862877755904,24.5172798931383,23490.4558450143,5393.8630796228,1227.86650772869,291.268606299631,74.294713260177,562.551930465887,1.21972142598119 -17.9786370695621,3.67660975113101,45.3184261979905,521.034452537431,24.8111644065443,24056.3522585912,5462.85398496804,1102.13227390991,294.994115188274,75.1852715011513,471.039739664364,1.00913922933779 -16.987762780536,3.71256702527013,45.3193257501983,526.14061731285,25.0543151101357,24529.6827615086,5519.92866275932,1075.53356721071,298.076147789003,75.9220910782443,449.408065471177,0.953402315276292 -16.4142500287741,3.7465425508312,45.320111388647,530.964793140462,25.2840377685934,24981.1365397408,5573.84655336076,1063.60166972758,300.987713881481,76.6182196501686,438.189340712878,0.921113250310375 -21.4964465557266,3.77937105088875,45.3208155285705,535.62561197931,25.5059815228243,25421.2362192179,5625.93447686793,1268.97578861037,303.800461750868,77.2907758086144,578.865777485597,1.20618827543221 -12.8826339592445,3.8223639440002,45.3216624196611,541.728837213677,25.7966112958894,26003.3791771709,5694.13647003929,947.76861914691,307.483369382121,78.1714712099336,350.837381809483,0.722769823094926 -18.8887774284275,3.84812921191869,45.3221320548339,545.386100221046,25.9707666771927,26355.3938209855,5735.00247265179,1189.98839915087,309.690133523197,78.699214261897,517.857173118276,1.0596669873325 -7.8958551929425,3.88590676677555,45.3227732372576,550.748013679365,26.2260958894936,26875.7823033553,5794.91232976813,766.184569738717,312.925265807479,79.4729383739323,218.590131774251,0.442918295435595 -20.0726932657472,3.90169847716143,45.3230255238477,552.989244649189,26.3328211737709,27094.8148282414,5819.95283074247,1253.87633612637,314.277452860094,79.796348002878,557.94500411031,1.1259361666939 -17.8300780130369,3.94184386369293,45.3236279358506,558.686491611798,26.6041186481809,27655.6192389178,5883.60301322003,1176.79098785543,317.714562713882,80.6184607395825,500.688831561648,1.00005071643561 -13.3931057393873,3.977504019719,45.3241192623294,563.746797767257,26.8450856079646,28158.5646767881,5940.13359581891,1007.62762010455,320.767214174221,81.3486629178151,379.483821703075,0.751134292739026 -17.5869692681093,4.00429023119778,45.3244632438292,567.5476168633,27.0260769934905,28539.3219430734,5982.59186128348,1185.75995673528,323.059960509308,81.8971211133742,501.658348174177,0.986289290217428 -17.0933910131153,4.03946416973399,45.3248845691977,572.53831313909,27.2637291970995,29043.1764227298,6038.33943619893,1175.98835027381,326.070329554742,82.6172785859707,491.848413212339,0.958546335540944 -10.5116711811783,4.07365095176023,45.3252633236238,577.388642682624,27.4946972706012,29537.0997448489,6092.51641166153,912.720363556032,328.995886229723,83.3171811391027,305.016796201568,0.589428064750264 +"dD","D","H","fc","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" +13.8622301137606,0.6,33.5798055081921,0.5486896324868,63.0047820994125,3.00022771901964,474.723316320797,378.031173825666,115.15809469658,20.413683386586,9.09159005694522,54.2344803096022,0.847124524124768 +12.3430477961087,0.627724460227521,34.2904401617441,0.535554701465037,67.311024216857,3.20528686746938,530.604647281172,416.148218432024,113.887792896694,22.4720037953293,9.71298079449247,51.2223767918793,0.760997863293316 +14.741406831811,0.652410555819739,34.8869428416076,0.524254012043932,71.1750826285497,3.38928964897856,583.129157916036,451.147060188797,135.641872760139,24.361941250195,10.2705644232997,64.2840089316746,0.914952349386033 +19.0298305764337,0.68189336948336,35.5572669876616,0.511224587806007,75.8208986257463,3.61051898217839,649.263806288655,494.153771682077,173.075647784032,26.6843036708321,10.9409556716952,87.7591875111139,1.18899105189968 +14.5390796191973,0.719953030636228,36.3593725147542,0.495121794409489,81.8586599690667,3.89803142709841,740.090098186756,551.439650143114,154.41727833873,29.7777411077281,11.8122046335363,71.7303215643756,0.914510184815394 +12.4868007833764,0.749031189874622,36.9275363205345,0.483337242431468,86.4956612797278,4.11884101332037,813.598284362919,596.416028780328,147.741160175046,32.2064655541377,12.4813239226647,64.6557730970838,0.788469745041307 +18.7146970224615,0.774004791441375,37.3866887484073,0.473558004101625,90.4908648031101,4.3090888001481,879.557399267045,635.795828114243,203.095710309553,34.3329747181691,13.0578317910888,100.806392629914,1.18477073005195 +11.0687390245441,0.811434185486298,38.0282949227206,0.459466001654279,96.4948734575568,4.59499397416937,983.271247766531,695.982001096573,153.257224474973,37.583028059215,13.9242102399254,63.0554934884997,0.702631626557789 +9.99188887606772,0.833571663535386,38.3831042523623,0.451436823145604,100.052311256533,4.76439577412064,1047.33560235106,732.169740094757,149.857216821208,39.5371659651169,14.4375485143178,58.7406793651936,0.634929141101866 +21.0347270968238,0.853555441287522,38.6885647087163,0.44437611859738,103.266258153473,4.91744086445107,1106.89385008451,765.175907836751,251.116914597184,41.3194990231846,14.9013210515461,127.098974369283,1.33745039170142 +12.4552306793704,0.89562489548117,39.2884242360783,0.430069141343528,110.036015249726,5.23981024998697,1237.59005405231,835.594587822926,187.882810260862,45.122107742438,15.8781970005355,79.5108190198485,0.792243186444809 +18.3054962030954,0.92053535683991,39.6177544851137,0.421938554354454,114.044518881976,5.43069137533217,1318.3498980886,877.81664182726,250.306637699218,47.4020986586721,16.4566240746691,120.524625308205,1.1640416829933 +13.99074330282,0.957146349246101,40.0694719255813,0.410426222034006,119.932269840562,5.71106046859817,1441.55162168061,940.472257149687,220.049926562394,50.7855018860831,17.306226537993,96.2014724504743,0.888792984876516 +17.867254884771,0.985127835851741,40.3904786114689,0.401963146319784,124.427299986266,5.92510952315553,1539.30282541457,988.774127891341,267.880193507252,53.3938029061324,17.9548593880182,126.810022542905,1.13374633113883 +17.1528686872216,1.02086234562128,40.7721096122263,0.391557751679517,130.159075566422,6.19805121744864,1668.61997895163,1050.8935763278,272.250549032331,56.7482531217014,18.7819546042346,126.546064086742,1.08634159938043 +8.40531118471655,1.05516808299573,41.1107124063486,0.381973456700806,135.650292925283,6.4595377583468,1797.45563792297,1110.90521954064,187.104802373592,59.9888818551946,19.5743372691183,64.251205485062,0.531153932119961 +17.1989737308038,1.07197870536516,41.2673331587757,0.377415797170373,138.336457305956,6.58745034790269,1862.252673296,1140.42288546501,289.392443613045,61.5828358151107,19.9619507892495,133.70321301562,1.08554007511778 +21.3583204606377,1.10637665282677,41.5699263597697,0.368363067499233,143.822338130835,6.84868276813502,1998.22848670555,1201.0048298891,348.675981024856,64.8542608140114,20.7535633922796,171.674133706531,1.34446656824501 +19.5748171221695,1.14909329374804,41.9145166078147,0.357609460994775,150.613478554897,7.17207040737606,2173.37630403091,1276.49865749724,342.918367238594,68.9309275048512,21.7335249554717,163.695402992472,1.22772294033201 +21.0780833878178,1.18824292799238,42.202525286213,0.348203417127093,156.815058383416,7.46738373254361,2339.96197933298,1345.85537404615,375.210164626101,72.6761901984923,22.6284129247269,182.482107234984,1.31728725164999 +17.7663534548161,1.23039909476802,42.4855562554794,0.338528419843126,163.467491738421,7.78416627325813,2525.76650911221,1420.63088247799,347.672222114619,76.7140676538113,23.5883590578541,159.403745216442,1.1058413715811 +17.961493344503,1.26593180167765,42.7041279286451,0.330719174851472,169.053534234523,8.05016829688203,2687.51169699785,1483.67624590715,361.76877889196,80.1185172789863,24.3944249900416,165.883495383381,1.11406677023811 +14.3120378766119,1.30185478836666,42.9080320918417,0.323128958046347,174.680822711912,8.31813441485294,2855.77226919378,1547.38761743079,323.5717911128,83.5589313412627,25.2064427173289,135.963019708148,0.884503805661616 +18.1731030033039,1.33047886411988,43.0591107644497,0.317290380278803,179.150128345169,8.5309584926271,2993.23560096724,1598.11116153556,385.624346457602,86.2980027229201,25.8513635202079,176.449817507664,1.11986109194861 +22.9719408671974,1.36682507012649,43.2374435268256,0.310132228644101,184.806410104996,8.80030524309504,3172.09193268759,1662.43773722587,466.200039283889,89.7716378101969,26.6675649781509,229.121751040306,1.41033848654288 +21.1877155552395,1.41276895186088,43.4429680914385,0.301472828459206,191.926400481102,9.13935240386198,3405.03561551955,1743.58182433392,456.869049183795,94.1534185140318,27.694979589423,218.368272566596,1.29473553336646 +21.3947491682205,1.45514438297136,43.6145877259405,0.293849876560021,198.464094002247,9.45067114296413,3626.63485966028,1818.22065164125,474.936971946587,98.1839151886275,28.6383687645242,227.02111729222,1.30182369586748 +13.5347755477253,1.4979338813078,43.7720513408712,0.286486448833888,205.037657315724,9.76369796741544,3856.93281436455,1893.36219492829,366.752832565086,102.241558526128,29.586933950659,147.760948839182,0.82008002557811 +17.6368277176128,1.52500343240325,43.8641151913114,0.281993034163311,209.181985873333,9.96104694634917,4005.99959842948,1940.77058947476,439.554692813675,104.801611831637,30.1849605615219,195.945168293155,1.06581471338907 +16.0998553950522,1.56027708783848,43.9759671112557,0.276320748297705,214.566154295934,10.217435918854,4204.15526766759,2002.39013629592,425.484991663169,108.12906735998,30.9618960649033,182.902826056308,0.969660342354264 +19.7920696016182,1.59247679862858,44.0706033117677,0.271316190429117,219.465468602171,10.4507366001034,4388.89417150213,2058.47873031032,496.44298931256,111.157851436757,31.6688671192933,229.360488483547,1.18845407084183 +18.910940018121,1.63206093783182,44.1779281560208,0.265380374388152,225.468461861729,10.7365934219871,4621.02130778959,2127.2132488823,494.56484095972,114.869515439644,32.5350990466475,224.433731201404,1.13146301926763 +13.058600363945,1.66988281786806,44.2719194793058,0.259921487677705,231.184352075674,11.0087786702702,4847.97341717905,2192.65981808391,404.796489837738,118.403630176531,33.3599020045198,158.455094818293,0.778710202198632 +16.4399539926589,1.69600001859595,44.3323089161026,0.256267968634485,235.120388473342,11.1962089749211,5007.62664837409,2237.72139202606,471.440412873777,120.836955169407,33.9278720567033,202.500915622791,0.978154746329385 +14.6935227174881,1.72887992658127,44.4034588491079,0.251797722467204,240.063271497205,11.4315843570098,5212.02332592542,2294.29801799267,449.711735355037,123.892092971604,34.6411300770467,184.376783621595,0.871850412733737 +14.3134058999187,1.75826697201624,44.4627452648874,0.2479198405251,244.46977858479,11.6414180278471,5397.91194829848,2344.72034374724,450.915248203151,126.614898562351,35.2769890497852,182.551769046062,0.847279072396818 +17.7282741340238,1.78689378381608,44.5168483017949,0.244244897590513,248.75237433569,11.8453511588424,5581.89639562363,2393.7082158636,522.22473090368,129.260243656635,35.89496761664,229.65290364097,1.04706446719514 +17.426218288193,1.82235033208413,44.579203545209,0.239828208360615,254.043602367246,12.0973143984403,5813.74436127936,2454.20734256136,527.384303365834,132.527196498313,36.6584918215935,230.054436965634,1.02645766904937 +18.2064133954421,1.85720276866052,44.6358342019639,0.235626515882232,259.231077663008,12.3443370315718,6045.91707699399,2513.48831295304,553.005342952225,135.728368899464,37.4070445067721,244.779715595074,1.06968741081317 +23.839848701127,1.8936155954514,44.6904428721149,0.231378320836545,264.637001610767,12.6017619814651,6293.00660459123,2575.228657951,675.024612239864,139.062347529354,38.1871193324337,326.567639198958,1.39709934581536 +17.6836621503451,1.94129529285365,44.7555065240246,0.226024076471507,271.695324740703,12.9378726067001,6623.53087892323,2655.77935176076,568.565940068146,143.412084995081,39.2056353600834,248.106675837022,1.03303497617712 +17.6678815991345,1.97666261715434,44.7994541353125,0.222197926367538,276.916834439728,13.1865159257013,6873.8128852517,2715.32060925138,579.000089319932,146.627312899575,39.9590992096528,252.231682960526,1.02980270770222 +22.0848145576271,2.01199838035261,44.8400050444356,0.218493164251684,282.12226810841,13.4343937194481,7128.21502789123,2774.63678313316,681.726731080317,149.83038628919,40.7102432880436,320.714882897189,1.28449836086555 +17.1607536499745,2.05616800946787,44.8863632385484,0.214020635796945,288.613807824222,13.7435146582963,7452.32010629431,2848.54830006801,592.332894593995,153.821608203672,41.6469724690352,254.47623666154,0.995571763629735 +13.589198638998,2.09048951676782,44.9193353056355,0.210661491827151,293.646887760904,13.9831851314716,7708.84289502583,2905.80762285427,525.379036774768,156.913611634131,42.3732459038984,204.754955431424,0.786894195652328 +18.5038809032059,2.11766791404581,44.9436973374468,0.208070623716749,297.625913069181,14.1726625271039,7914.88111180313,2951.04650827356,640.021209303065,159.356511446772,42.9474192558828,282.301558720724,1.06995969301946 +23.0820377816011,2.15467567585222,44.9745631575913,0.204637335781827,303.035110322382,14.4302433486848,8199.56206002718,3012.50460704382,753.353385282024,162.675248780366,43.7279664195197,358.083759706918,1.33221390896508 +22.0173409128457,2.20083975141543,45.0096318616306,0.200501149763597,309.769011281346,14.7509052991117,8561.34877450423,3088.94823729255,745.601959520132,166.803204813798,44.6996683278982,348.63114292654,1.26799642730904 +20.1827821888325,2.24487443324112,45.0398536510714,0.196700174459217,316.179065567773,15.0561459794177,8913.35007672046,3161.6489711205,718.335669264893,170.729044440507,45.6246391614296,325.761072424495,1.16008032302053 +15.6225202249188,2.28523999761878,45.0650459939897,0.193333819148988,322.044378382595,15.3354465896474,9241.94410984372,3228.11563297323,624.158576944563,174.318244180554,46.4710038006084,256.541973253869,0.896456312334238 +12.3265626073557,2.31648503806862,45.0830342314669,0.190802238916924,326.57784909235,15.5513261472548,9500.18412305232,3279.45390194279,554.323124116062,177.090510704911,47.1251836240261,205.097839853446,0.706456008253428 +17.4908153612346,2.34113816328333,45.0963612480451,0.188848823892679,330.151011684642,15.7214767468877,9706.33945340721,3319.89587129263,684.878510478008,179.274377049802,47.6407909860939,294.025445424348,1.00149457143817 +17.7866771557451,2.3761197940058,45.1140468101674,0.186141531115577,335.215587522134,15.9626470248635,10002.4948368221,3377.18626896615,702.579214027836,182.368058524172,48.3716092794439,303.331231474001,1.01714946754942 +17.2737066128449,2.41169314831729,45.130659236927,0.18346340777557,340.359450706087,16.207592890766,10308.0297244357,3435.33638380422,700.604359823726,185.508164725428,49.1138687368883,298.863676245484,0.986613760008242 +21.6794728704231,2.44624056154298,45.1455684592484,0.180932169674432,345.349137752292,16.4451970358234,10608.9728409931,3491.70883907044,821.630601185485,188.552277309804,49.8338805776558,380.310793656884,1.23687146852062 +25.5303472256792,2.48959950728383,45.162712558406,0.177848561768132,351.60382829312,16.7430394425295,10992.5609675861,3562.32639373487,934.882681257224,192.365625261683,50.7364324226973,455.584345101233,1.45465230564751 +17.2364814260224,2.54066020173518,45.1808699820247,0.174344331998275,358.959342448633,17.0933020213635,11452.6936583803,3645.30899176331,737.903791870481,196.846685555219,51.7978331153378,313.724201012065,0.980674443166633 +13.4362788790797,2.57513316458723,45.1920006935769,0.172052784074257,363.919517139682,17.3295008161753,11768.4925906568,3701.2310225572,647.687461932444,199.866475218089,52.5135863232562,247.790974717023,0.763766730461611 +11.0522829326299,2.60200572234539,45.2000979171098,0.170306395204308,367.783050014908,17.5134785721385,12017.5449711272,3744.76942845789,590.98586531518,202.217549136726,53.0710941171512,205.900824006448,0.627828756738567 +14.1247240522206,2.62411028821065,45.2064010527437,0.168895344190442,370.959164444858,17.6647221164218,12224.2996543422,3780.5486571601,678.86361054017,204.149627486645,53.529407429393,265.322096560959,0.801932936748392 +18.6562257626199,2.65235973631509,45.214013234342,0.167124629997668,375.015804448515,17.8578954499293,12491.0168990086,3826.23103446205,809.597329974785,206.616475860951,54.1147805819207,354.128652749181,1.05851861702313 +22.5267379863495,2.68967218784033,45.2233537901538,0.164840241734053,380.369955794064,18.1128550378126,12847.5807767795,3886.49825471613,927.886737916347,209.870905754671,54.8873846210834,433.479442501871,1.27708134009851 +15.1534176531533,2.73472566381303,45.2336353791277,0.162161426057828,386.829286147238,18.4204421974875,13284.6131176518,3959.16707033183,736.996721183661,213.795021797919,55.8194659910465,296.376060174737,0.858284630632356 +14.0777837052047,2.76503249911934,45.2399879331865,0.160406539020383,391.171141807038,18.6271972289066,13582.5979785575,4007.99131824584,714.868918660774,216.431531185275,56.4459957627555,278.327880454584,0.796898247363505 +14.0803936170745,2.79318806652974,45.2455137286492,0.158809023009697,395.202595985809,18.8191712374195,13862.3150604319,4053.30959802796,722.387032787648,218.87871829351,57.0277346007522,281.158615675783,0.796636988780348 +17.8880670636792,2.82134885376389,45.2507012297171,0.157241925325788,399.232777177171,19.0110846274843,14144.8640431309,4098.59922129468,839.831023832703,221.324357949912,57.6092897466657,360.723579247162,1.01157152846378 +20.467214690467,2.85712498789125,45.2568347632555,0.155294031707995,404.350051679647,19.2547643656975,14507.8327740473,4156.08536250491,926.087170716903,224.428609575265,58.3477124573731,417.871860328847,1.15674165588026 +26.2003700636307,2.89805941727219,45.2632729003871,0.153122318614318,410.201577502252,19.5334084524882,14928.6456657332,4221.79401478515,1109.5629758553,227.976876798398,59.192087633575,542.454190786086,1.47982847495024 +25.3758576553513,2.95046015739945,45.2706945725985,0.150427497837571,417.687039112513,19.8898590053578,15475.9227138147,4305.81279473136,1104.90053306619,232.513890915494,60.2722397439356,534.726867609411,1.43219319161204 +9.71812013501909,3.00121187271015,45.2770948297807,0.147904614999951,424.931861532264,20.2348505491554,16015.1772737359,4387.09284081576,643.479165528653,236.903013404051,61.3176676191057,208.251184981355,0.54812203011442 +22.3493381090295,3.02064811298019,45.2793587575036,0.146960276514414,427.705160673543,20.3669124130259,16224.0929064123,4418.19738661931,1037.92963798767,238.582658877443,61.7178546851923,481.98390424159,1.26025018476479 +23.8138323781506,3.06534678919825,45.2842044513033,0.144832809880669,434.080667162182,20.6705079601039,16709.5924225032,4489.68496410294,1099.35444992056,242.442988061559,62.6378402715028,521.059819765733,1.34213991034561 +17.7855258196004,3.11297445395455,45.2888585236117,0.142631564590616,440.870478424095,20.9938323059093,17234.6462569397,4565.79155899649,924.799728784541,246.55274418581,63.6176100365969,395.123704632441,1.00188006395059 +24.8579862557682,3.14854550559375,45.2920231782769,0.141030022318368,445.939335641178,21.2352064591037,17631.9991236642,4622.59139170113,1163.08947800341,249.619935151861,64.349046133022,558.477347380212,1.39978982671127 +24.7640432852839,3.19826147810529,45.2960425980544,0.138850075905493,453.020979496039,21.5724275950495,18194.8332813654,4701.92352221739,1178.55683407801,253.903870199739,65.3709273412785,565.048363270423,1.39386746351611 +15.4619949824824,3.24778956467585,45.29962376784,0.136743452635781,460.072806512802,21.908228881562,18764.2082781331,4780.89760252996,888.378459991682,258.168470536618,66.3885059797973,358.204232958237,0.869933541911998 +15.5528620904625,3.27871355464082,45.3016656068653,0.135459828721314,464.47434744726,22.1178260689172,19124.1000878244,4830.17954811246,900.025951012955,260.829695598073,67.0236483366397,363.704521311151,0.874836281627671 +3.11889991605433,3.30981927882174,45.3035810027037,0.134192449047122,468.900720856844,22.3286057550878,19489.5126891104,4879.73126747861,488.425183153754,263.505488443845,67.6623740196426,73.620744420921,0.175395710247566 +20.226388472652,3.31605707865385,45.3039492316169,0.133941109721838,469.78824578751,22.3708688470243,19563.202140627,4889.66584146031,1068.71720924893,264.041955438857,67.7904438671377,478.32929597724,1.13740910639664 +20.5806262265707,3.35650985559916,45.3062157921895,0.132333466996077,475.54301072491,22.6449052726147,20044.4215786546,4954.07475593205,1094.06019760273,267.520036820331,68.6208564476045,492.588530153777,1.15701181257903 +15.4401979441994,3.3976711080523,45.3083197394437,0.130736377655587,481.397001641567,22.9236667448365,20540.0036646824,5019.58160058033,929.33063964506,271.057406431338,69.4655873368781,374.046593751798,0.867799901633693 +16.8410846595,3.4285515039407,45.3097750660989,0.129563018239515,485.787875345831,23.1327559688491,20915.7358123876,5068.70813866827,986.949471149616,273.710239488086,70.0991904124035,411.660937226189,0.946363198819623 +17.4309851927292,3.4622336732597,45.3112512751713,0.128306750959391,490.57624930866,23.3607737766028,21329.4026624033,5122.27481022873,1017.64089998857,276.602839752351,70.7901527752396,430.232948871332,0.979328964374832 +14.9387775764299,3.49709564364515,45.3126658154117,0.127031647683697,495.531435515654,23.596735024555,21761.7851979667,5177.70007285466,939.084743081589,279.595803934152,71.5051861449089,372.404776231477,0.839156455391221 +13.3146509149991,3.52697319879801,45.3137928727833,0.125958675119277,499.777455734343,23.7989264635401,22135.7692993851,5225.18735521629,888.783429761942,282.16011718168,72.1178868624656,334.732727636296,0.747814862909469 +17.9064466008416,3.55360250062801,45.3147354863974,0.125017390812064,503.561343045068,23.9791115735746,22471.7569292554,5267.5019271755,1062.13533025414,284.445104067477,72.6639018014033,453.54678301764,1.00558774498618 +16.3369138372681,3.5894153938297,45.315917317838,0.123773275157344,508.649455426729,24.2214026393681,22927.5739815723,5324.39545625949,1015.50463482071,287.517354638012,73.398116418077,417.935333241437,0.917302104826116 +20.2580644059831,3.62208922150423,45.3169155525312,0.122659453878561,513.290910168085,24.4424242937183,23347.3995700807,5376.28895889567,1169.80408537483,290.319603780366,74.0678783372546,522.935364629226,1.13731817352528 +27.9189470878385,3.6626053503162,45.3180556744596,0.121305633826133,519.045561024057,24.7164552868599,23873.2422663483,5440.62145330767,1469.31523260668,293.793558478614,74.8982744557714,728.704972021103,1.56716790835334 +13.1034536015564,3.71844324449187,45.3194659610883,0.119487769639283,526.975018539001,25.0940485018572,24607.4710880574,5529.25475988537,929.919985182333,298.57975703381,76.0424951751778,347.195195044354,0.735389221469768 +15.7962237995095,3.74465015169499,45.3200691910724,0.118653114666247,530.696105787215,25.2712431327245,24955.8834593327,5570.84366033158,1039.44927952478,300.825557657906,76.5794480650952,421.478784605852,0.88643696471676 +15.6178164304204,3.77624259929401,45.3207506460711,0.117662219278092,535.1814707556,25.4848319407429,25379.131409245,5620.97105772275,1041.48219841753,303.532437117029,77.2266862300331,420.216960361518,0.876340284099832 +19.8847180049077,3.80747823215485,45.3213784200082,0.116698563279869,539.615761506731,25.6959886431777,25801.0781416556,5670.52410714768,1215.93172181949,306.208301785975,77.8665543854213,539.428162332898,1.11566207560313 +14.8327790378881,3.84724766816466,45.3221164323365,0.115494117652893,545.260973193474,25.9648082473083,26343.3109402761,5733.60434739868,1030.5666101268,309.614634759529,78.6811584318183,406.564632480026,0.83212597291591 +22.1086796378837,3.87691322624044,45.3226254997542,0.114611661327988,549.471571667648,26.1653129365547,26751.4364684607,5780.65075350545,1326.31283164028,312.155140689294,79.2887477916416,610.649412285726,1.2402144039108 +22.5186193919238,3.92113058551621,45.3233239148366,0.11332096781777,555.747023754411,26.4641439883053,27365.5543399252,5850.76356029454,1358.00013128666,315.941232255905,80.1942955277615,629.037909625347,1.26307884575114 +18.3850964029363,3.96616782430005,45.3239673250247,0.112035758575595,562.138191174964,26.7684852940459,27998.1913570046,5922.16360337146,1206.59710377609,319.796834582059,81.1165409865473,519.448693827549,1.03112731486815 +21.7488720454584,4.00293801710593,45.3244463714553,0.111007793642649,567.355749751468,27.0169404643556,28520.0396176236,5980.44859019624,1355.22464641988,322.944223870597,81.8694346891368,620.165468418322,1.21969482920334 +19.4727269712519,4.04643576119684,45.324964190011,0.109815753973142,573.527447537192,27.3108308351044,29143.5636415011,6049.38802900245,1276.20974842257,326.666953566132,82.7600106796168,561.275890024485,1.09195879224165 +13.8043770941534,4.08538121513935,45.3253867127611,0.108769907384142,579.052835919799,27.5739445676095,29707.5323796995,6111.10446158128,1052.54681169547,329.999640925389,83.557324223227,401.711185579119,0.774047081311369 diff --git a/pyrealm_build_data/t_model/rtmodel_output_default.csv b/pyrealm_build_data/t_model/rtmodel_output_default.csv index e24f234f..69035adb 100644 --- a/pyrealm_build_data/t_model/rtmodel_output_default.csv +++ b/pyrealm_build_data/t_model/rtmodel_output_default.csv @@ -1,101 +1,101 @@ -"dD","D","H","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" -10.0193765180823,0.1,9.30685130731739,2.46024211324268,0.316316843131202,7.30958392378022,7.02392939699003,9.78053256354872,0.309052893467561,0.687337521113514,4.08436398628558,0.383163162838877 -8.94826996898982,0.120038753036165,10.711819414002,3.39906751279348,0.43702296593059,12.1226083507134,11.4772945001997,12.230269204462,0.505000958008785,0.949624683589217,4.97058165919415,0.385438488085086 -10.9544242990939,0.137935292974144,11.8621158250655,4.32526414254345,0.556105389755587,17.7256775596921,16.5399186131405,17.8935142010193,0.727756418978182,1.2083836456155,7.65010363773741,0.512668700892211 -8.89695823526391,0.159844141572332,13.1478077357338,5.55552544627375,0.714281843092339,26.3837591192719,24.1508693832434,19.498706462455,1.06263825286271,1.55209158812907,7.86616538293065,0.451043603635951 -8.78531953345,0.17763805804286,14.101141616645,6.62163692287193,0.851353318654962,34.9475060802419,31.4648881117397,22.8725802145125,1.38445507691655,1.84993968023811,9.15277344984067,0.469010169526799 -8.89702030940376,0.19520869710976,14.9692825462652,7.72458615765159,0.993161077412348,44.801153176621,39.6545187783565,26.7543031566861,1.74479882624769,2.15807943155239,10.694429135877,0.49532460694634 -11.4305447761726,0.213002737728567,15.7800798895247,8.8852459918118,1.1423887703758,56.2301769103635,48.8881734052546,36.6197413642089,2.1510796298312,2.4823422547004,15.6328125882049,0.65906914403219 -9.78711084366124,0.235863827280912,16.7293370477721,10.430740604128,1.34109522053074,73.0956100787923,62.0601613634078,38.1286931965105,2.73064709998994,2.91411944850007,15.5009548647787,0.585082487301701 -12.9550108860307,0.255438048968235,17.466764507657,11.7943259622377,1.51641333800199,89.5104052127066,74.4254959534891,52.5417247468014,3.27472182195352,3.29507519867805,22.9401161424638,0.793683558309927 -10.0666892193544,0.281348070740296,18.3465579659371,13.6450022534866,1.75435743259113,114.059735900108,92.1931032079778,50.2238440564425,4.05649654115102,3.81211343957458,20.3273297143475,0.632441863735982 -10.6815066568184,0.301481449179005,18.9616518981767,15.1116482662492,1.94292620566062,135.359031780319,106.990074003523,57.6691870898778,4.70756325615503,4.22186206932818,23.6306898678065,0.681123745691776 -12.544157302508,0.322844462492642,19.5551797815225,16.6889966539019,2.14572814121596,160.08047995681,123.530399320254,71.0439872809571,5.43533757009117,4.66253850717382,30.3111481554649,0.809670208279064 -13.5319826386959,0.347932777097658,20.1819709367495,18.562394263949,2.38659354822202,191.886377777615,143.923672907495,82.9502604127476,6.3326416079298,5.18592458467355,35.9182457105518,0.882494891432708 -12.7060673483057,0.37499674237505,20.7820655871978,20.6011412101063,2.6487181555851,229.52689541987,166.925235522201,87.2872964057804,7.34471036297683,5.75550562899709,36.9538864182509,0.834692665855434 -13.8821677047812,0.400408877071661,21.2817001019339,22.5260523473027,2.89620673036749,267.980747823668,189.312536647627,101.143992252697,8.3297516124956,6.29328345268473,43.6451158269815,0.91554909305737 -10.5483374872048,0.428173212481223,21.7650541865735,24.6350993996117,3.16736992280721,313.392515782141,214.483324465877,90.6180587858546,9.43726627649858,6.88250480006471,35.841828516957,0.696897381491776 -6.94705334692583,0.449269887455633,22.0933605733743,26.2388117764855,3.37356151411956,350.240434802596,234.011736739874,74.2110644175239,10.2965164165544,7.33054675649096,24.9278172369694,0.458927358491127 -12.6207652717153,0.463163994149485,22.2928887345195,27.2945671712372,3.50930149344478,375.600196438528,247.029123566735,112.820537134461,10.8692814369363,7.6255015871659,46.8540032624812,0.833222335758677 -10.0421438869611,0.488405524692915,22.6244317279346,29.2101186032406,3.75558667755951,423.866112522073,270.936697158499,102.944858187507,11.9212146749739,8.16066451513616,39.5227530166498,0.661622046444847 -10.0321322898703,0.508489812466837,22.8621804846574,30.7308786832526,3.95111297356105,464.271519523663,290.150795681296,107.907081192623,12.766635009977,8.58553142476974,41.24378323713,0.659417300094623 -14.1800134678242,0.528554077046578,23.0788309213771,32.2461823456612,4.14593773015644,506.386992077055,309.473939920118,142.975947108045,13.6168533564852,9.00887393136613,60.7564077927271,0.92942063053023 -12.3761117194866,0.556914103982226,23.3530139023875,34.3800281064738,4.42028932797521,568.865050212554,336.941870734766,137.853536087807,14.8254423123297,9.60502349233045,56.0256967652779,0.807410956673238 -16.4759671624905,0.581666327421199,23.5648786020695,36.233826708283,4.65863486249352,626.185395983782,361.009138035379,177.543734070837,15.8844020735567,10.1229340381067,78.0260503221687,1.07002303315974 -5.99726701829118,0.61461826174618,23.8121202802534,38.6882067901583,4.9741980158775,706.478368789153,393.107074643341,99.875208236132,17.296711284307,10.8086338366209,30.0481300545573,0.386977466568459 -10.8593093925347,0.626612795782763,23.8932481986191,39.5776065302976,5.08854941103826,736.823713005514,404.792414596019,144.034713101776,17.8108662422249,11.0571125572215,55.4839538665588,0.698999748357308 -9.3465640378999,0.648331414567832,24.0292729559091,41.1825058932959,5.29489361485233,793.276599376287,425.937559948046,136.014060558755,18.741252637714,11.5054861314572,49.4205660019427,0.598943280259281 -13.6565336884694,0.667024542643632,24.1359901562896,42.5580780455452,5.47175289157009,843.409772588716,444.112388184454,179.850194719185,19.540945080116,11.8897907282083,74.2900939480301,0.871747135270118 -17.1630587427594,0.694337610020571,24.276375944231,44.558403041201,5.7289375338687,919.210795425418,470.607987945956,221.138611372785,20.7067514696221,12.4486375248447,97.1578417261582,1.0894041148584 -8.14221510584855,0.72866372750609,24.429641684122,47.0564674209637,6.05011723983819,1018.73512555144,503.77601262409,142.321483442475,22.1661445554599,13.146541755134,48.3340732530964,0.513215109519905 -10.4906009296595,0.744948157717787,24.4943436604853,48.2355161541569,6.20170921982018,1067.5980923316,519.451659677508,169.729444410608,22.8558730258103,13.4759420321161,63.6366825576248,0.659094726748587 -15.204772839994,0.765929359577106,24.5709004033259,49.7490579834027,6.39630745500892,1132.1093763317,539.586813885786,224.231904896834,23.7418198109746,13.8987923212871,94.7666238525676,0.951371343460942 -9.87318455737865,0.796338905257094,24.669583328297,51.9319727972061,6.67696793106936,1228.70482349192,568.64003896716,175.317108215791,25.020161714555,14.5086506961379,63.9095074945855,0.614243701912923 -15.0607583064829,0.816085274371851,24.7266837784768,53.3428836158617,6.85837075061079,1293.38207876613,587.420284339211,237.704950911664,25.8464925109253,14.9028281388322,99.8300298003339,0.933637989874976 -11.5706146693963,0.846206790984817,24.8044220661791,55.485651756082,7.13386951149625,1394.99293008041,615.936069221402,206.357446057704,27.1011870457417,15.5014704163107,79.4302703796194,0.713549402434661 -13.3127061818153,0.86934802032361,24.8572711028689,57.1244709970712,7.34457484248059,1475.47097039345,637.735153547186,232.788587133637,28.0603467560762,15.9593204582198,93.7995640130915,0.81786718452395 -17.4806466078772,0.89597343268724,24.9115365031328,59.0025416363156,7.58604106752629,1570.65449196802,662.700889835047,290.852681730521,29.1588391527421,16.4840120772706,126.799548025647,1.06947679555334 -13.2803100173771,0.930934725902995,24.9734470792585,61.4572036574245,7.9016404702403,1699.83526491928,695.299642872636,249.120992610039,30.593184286396,17.169790643404,99.9484227015776,0.808377482110023 -11.6203755381957,0.957495345937749,25.0142827646319,63.3140069315505,8.14037231977077,1801.15579450275,719.931075856815,234.74097082629,31.6769673376999,17.6885406285227,89.856451514715,0.704804158830193 -13.6533474488494,0.98073609701414,25.0461588337357,64.9334328677561,8.34858422585435,1892.06186407513,741.392512692035,267.530941186444,32.6212705584496,18.140972607728,108.042986986012,0.825671868210196 -10.1030440456253,1.00804279191184,25.0795241684604,66.8302881733147,8.59246562228332,2001.55307528676,766.504486397848,226.584042121815,33.7261974015053,18.6709122492843,82.0915219052653,0.608994074630574 -8.49260767209638,1.02824888000309,25.1016618497245,68.2300662271125,8.77243708634303,2084.43734983109,785.017322655642,208.799503644895,34.5407621968482,19.0619794423982,70.3387931533824,0.510769907751515 -13.8053080796145,1.04523409534728,25.1187498442437,69.404345269295,8.92341582033793,2155.33627352502,800.535616824675,287.350415212216,35.2235671402857,19.3900471726451,116.161530716003,0.828801971941598 -16.215100773981,1.07284471150651,25.1438414354828,71.3088720387312,9.16828354783687,2272.97804088535,825.680649327476,329.851539963162,36.3299485704089,19.9221300524367,139.915530550737,0.970811093559158 -13.209624453261,1.10527491305447,25.1695338398153,73.5394805320076,9.45507606840097,2414.93629647464,855.094203822381,295.003617258371,37.6241449681847,20.5453129920712,117.310605849175,0.788542786830633 -12.0514233751536,1.131694161961,25.1878198649143,75.3519901484984,9.68811301909265,2533.6032712166,878.966159575786,284.410904243807,38.6745110213346,21.0516883037072,109.500096382961,0.717824289063547 -11.7573374929648,1.1557970087113,25.2026785972082,77.0022366405034,9.90028756806472,2644.23296203881,900.679574498839,285.913962837713,39.6299012779489,21.5127308681506,109.03229088336,0.699008320367035 -11.9413299885634,1.17931168369723,25.215676975266,78.6093683186548,10.106918783827,2754.34105850597,921.806767504261,294.669317672048,40.5594977701875,21.9617281021292,112.924076483006,0.708753991733565 -11.7295851387953,1.20319434367436,25.2275211785046,80.2389863994057,10.316441108495,2868.37562970052,943.211240129407,297.229198192377,41.5012945656939,22.4170075422932,113.103565013111,0.695083669805023 -16.2356339673271,1.22665351395195,25.2379599585221,81.837287673914,10.5219369866461,2982.55144166953,964.187226546502,377.275258333103,42.4242379680461,22.8635377557627,159.522236863729,0.960720351130048 -14.6654125687904,1.2591247818866,25.2506776505847,84.0459677710847,10.8059101419966,3144.12976903235,993.147301151348,360.688872608011,43.6984812506593,23.4805943839501,147.809267392037,0.866223508474503 -11.7505133374711,1.28845560702418,25.2606477948161,86.0377444088061,11.0619957097036,3293.61843278227,1019.23860288348,318.709887284472,44.8464985268733,24.0370529574434,121.122329439296,0.693021393087743 -10.3133987768923,1.31195663369913,25.2677241432344,87.6315875664223,11.2669184013971,3415.81992802936,1040.10135886501,299.26621696313,45.7644597900604,24.4823376711319,108.203412283868,0.607600398363945 -14.4596658030464,1.33258343125291,25.2733375139929,89.0291197108457,11.4466011056802,3524.85532868421,1058.3835989497,378.017022804304,46.568878353787,24.8727774065767,154.037347417299,0.851116156184381 -10.0658223001966,1.361502762859,25.280366061387,90.986499769288,11.6982642560513,3680.5294201203,1083.97360264756,306.109028726002,47.6948385164927,25.4196263325442,109.50933346422,0.591810981213213 -12.548760707127,1.3816344074594,25.284737404992,92.3478227364118,11.8732914946815,3790.83262152093,1101.76061359785,356.57537965893,48.4774669983052,25.7999500204532,138.501630151433,0.737253638478154 -13.2466537648798,1.40673192887365,25.28965184691,94.0436049224458,12.0913206328859,3930.56897346283,1123.90653446682,376.196307421132,49.4518875165402,26.2737142560231,148.811471044972,0.777599968382503 -8.58244282916634,1.43322523640341,25.2942618696261,95.8322158335763,12.3212848928884,4080.75747826864,1147.25224676876,293.88473590934,50.4790988578256,26.7734127951529,98.1988327088463,0.503394039946095 -13.0441450835547,1.45039012206174,25.2969635748421,96.9902997709128,12.4701813991174,4179.53477855968,1162.36165152005,383.952863842133,51.1439126668823,27.0969559693981,151.007403478047,0.764717786166741 -9.20061678832784,1.47647841222885,25.3006838629285,98.7493929264495,12.6963505191149,4331.8792709798,1185.30338189343,315.01998160752,52.1533488033111,27.5884078970056,108.398717616899,0.539019855823727 -12.7745603536336,1.49487964580551,25.303053086886,99.9894611985468,12.8557878683846,4440.94367736316,1201.46998088612,390.360330132367,52.8646791589895,27.9348556907276,152.354488109287,0.74806600978791 -13.6404475098987,1.52042876651278,25.3060285083747,101.710348810902,13.077044847116,4594.58224556532,1223.89715905698,414.630209233473,53.8514749985073,28.4156338300922,165.423970551173,0.798314310610568 -9.80983528093082,1.54770966153257,25.3088438413088,103.546845465064,13.3131658455082,4761.47134316266,1247.82171379714,342.907469315653,54.9041554070739,28.9287105923386,121.07599560025,0.573806935511613 -12.8796594611724,1.56732933209443,25.3106618120152,104.866997891083,13.4828997288535,4883.30561804984,1265.01422905743,411.51638018797,55.6606260785269,29.2975321368149,160.956016647808,0.753094147141227 -11.2348478441228,1.59308865101678,25.3128136458499,106.599566481355,13.7056585476028,5045.56947711794,1287.57126420477,383.319292391107,56.6531356250097,29.7815736844279,142.682834170626,0.656628595998901 -10.542535954065,1.61555834670502,25.314494192797,108.110275604684,13.8998925777451,5189.24804488804,1307.23428839034,373.82137911933,57.5183086891749,30.2036325778853,135.759371698173,0.615948315836371 -11.1038512723045,1.63664341861315,25.315921420298,109.527425704448,14.0820975905718,5325.88466323585,1325.67523457024,390.981027405039,58.3297103210905,30.5995531384571,144.835650350445,0.64854490232151 -9.135119604379,1.65885112115776,25.3172828282139,111.019579183636,14.2739458950389,5471.69392575151,1345.08796223266,352.742649449992,59.1838703382369,31.0164279931659,120.758149667868,0.533398346648589 -15.8593151147652,1.67712136036652,25.3183035694221,112.246850984579,14.4317379837315,5593.11133999266,1361.05159050326,507.07135733533,59.8862699821434,31.3593007343696,211.935246689506,0.925813476928017 -12.4957453608961,1.70883999059605,25.319884927226,114.376867833347,14.7055972928589,5807.03450741953,1388.75162964875,440.022884357307,61.105071704545,31.9543805815447,170.119267639436,0.729198475267786 -17.6034491248596,1.73383148131784,25.3209788043078,116.054623447071,14.9213087289091,5978.38857758428,1410.56529957708,564.554555718946,62.0648731813915,32.4231085893958,243.135773969263,1.02700208778611 -13.5145570137727,1.76903837956756,25.3223221071839,118.41749146522,15.2251060455283,6223.97615880805,1441.28002930058,479.603296434683,63.4163212892254,33.0832419305702,190.425692646515,0.788201166846156 -12.5120982451255,1.79606749359511,25.323216019941,120.231034923572,15.458275918745,6415.84770932383,1464.84943407943,462.956375541357,64.4533750994948,33.5899060748777,178.978040715262,0.729577034268381 -4.18255646771085,1.82109169008536,25.3239505678901,121.909722480524,15.6741071760674,6596.0655625305,1486.66292905104,267.288486808476,65.4131688782457,34.0588944471639,60.6578964861845,0.243839387484557 -9.2567911518124,1.82945680302078,25.3241779295316,122.470809536629,15.7462469404238,6656.86203895112,1493.95325093873,392.235807908197,65.7339430413041,34.2156498267244,134.860854703067,0.539632087650388 -14.8673408331022,1.84797038532441,25.3246512008685,123.712491241835,15.9058917310931,6792.40179615179,1510.08558850969,534.379813473132,66.4437658944265,34.5625483781614,218.781005316303,0.866599809709966 -10.1509757996828,1.87770506699061,25.3253321405036,125.706461293154,16.1622593091198,7012.93458021649,1535.9889597091,425.016900818807,67.5835142272005,35.1196197431587,151.769401733536,0.591584744690471 -12.9752678727178,1.89800701858998,25.3257465653334,127.067692544789,16.3372747557586,7165.52088343135,1553.67059667347,501.048244874538,68.3615062536325,35.4999178077782,196.084450414267,0.756098462838088 -10.6905357078339,1.92395755433541,25.3262231699791,128.807451878686,16.5609580986882,7362.94038142981,1576.26703885964,449.374163692465,69.355749709824,35.9859682909636,163.757229355965,0.622882885447943 -12.7738259123397,1.94533862575108,25.3265754524711,130.240709465373,16.7452340741194,7527.60412906611,1594.88095630982,508.372392581682,70.174762077632,36.3863889290169,197.835417650949,0.744194644383146 -15.8618557810182,1.97088627757576,25.3269535633162,131.953098496041,16.9653983780624,7726.73409540663,1617.11825993344,596.129031569758,71.1532034370712,36.8647927516269,248.876604731405,0.924005229841964 -15.2220463629289,2.0026099891378,25.3273655029634,134.079218143858,17.238756618496,7977.6073212915,1644.72594043538,588.687942069479,72.3679413791566,37.4587838065948,242.670177496139,0.886631987146379 -17.2759460420879,2.03305408186365,25.3277083500902,136.119360820401,17.5010606769087,8222.11678606774,1671.21498559556,653.263073561819,73.5334593662048,38.0287547872821,279.58858014956,1.00616608482524 -6.17613701917727,2.06760597394783,25.3280437293573,138.434551664648,17.798728071169,8504.07507072289,1701.27289725376,358.84517012236,74.8560074791655,38.675568174966,101.647101618207,0.359668420532437 -11.8690203025204,2.07995824798618,25.328151319629,139.262177752044,17.9051371395485,8606.0250925273,1712.01734500145,518.648488218613,75.3287631800636,38.9067886960106,196.505087355821,0.691172480079081 -7.3906520350722,2.10369628859122,25.3283417504979,140.852600976496,18.1096201255494,8803.64902642477,1732.66387668092,399.179939836839,76.2372105739606,39.3511179556114,123.754034906694,0.430357712809791 -8.19986285685887,2.11847759266137,25.3284502853628,141.842888302737,18.2369427817805,8927.83693454277,1745.5191135434,424.827315325923,76.8028409959098,39.6277824482422,138.266774912599,0.477462385789857 -7.58759582841038,2.13487731837509,25.3285624109407,142.94156642931,18.3782013980542,9066.6378430605,1759.78102111371,410.740673593133,77.4303649290031,39.9347289458879,128.931194318995,0.441796116889666 -10.2340004348094,2.15005251003191,25.328658924508,143.958176013644,18.5089083446113,9196.02642486975,1772.97725947435,489.419303148273,78.0109994168713,40.2187472983397,175.133713696907,0.595868211224714 -9.4995959685784,2.17052051090153,25.3287789176155,145.329312922932,18.6851973758056,9371.99229720981,1790.7750036049,472.888506376047,78.7941001586156,40.601812785783,164.110813876739,0.553087305205784 -12.9794754131923,2.18951970283868,25.3288806704192,146.602011246041,18.8488300173482,9536.82019401234,1807.29452320213,578.461548028186,79.5209590208937,40.9573766978966,226.187228048555,0.755669293045033 -12.6710676399942,2.21547865366507,25.3290061315192,148.340859812062,19.0723962615508,9764.34622648712,1829.86397096677,576.25554692123,80.5140147225381,41.4431727325742,223.426787162915,0.737684160511341 -11.6675333743865,2.24082078894506,25.3291150339252,150.038327450359,19.2906421007605,9989.0490949876,1851.89563834903,552.949986895441,81.4834080873573,41.9174078464265,208.081713091626,0.679236460361238 -12.4183829002601,2.26415585569383,25.3292047271947,151.601307120759,19.4915966298119,10198.212873192,1872.18123241692,581.359346009993,82.3759742263446,42.3540699807835,223.775986117665,0.722926596069812 -15.5311202202032,2.28899262149435,25.3292902278537,153.264822255391,19.7054771471217,10423.2147847653,1893.77114331724,682.576183935073,83.3259303059585,42.8188195120666,282.933158136722,0.904106498505373 -14.0271619378482,2.32005486193476,25.3293843411985,155.345243972937,19.9729599393776,10708.0656385808,1920.77120046058,645.441401794235,84.5139328202657,43.4000435706712,258.999333351321,0.816531275314657 -10.9032003862436,2.34810918581045,25.3294585684019,157.224154166784,20.214534107158,10968.6293965923,1945.15543367696,555.676225792921,85.5868390817861,43.9249697428078,203.750165779831,0.634667052225825 -8.73516698531288,2.36991558658294,25.3295100255545,158.684584497689,20.4023037211314,11173.3248309749,1964.10835558459,492.502529756334,86.4207676457218,44.3329818477953,164.75034648912,0.508458376468196 -15.3227939054228,2.38738592055357,25.3295476994145,159.8545992327,20.5527341870614,11338.6819319955,1979.29217653433,705.398301740837,87.0888557675104,44.6598582244333,291.125526895556,0.891900509700692 -15.3130857581556,2.41803150836441,25.3296069236094,161.906945226469,20.8166072434032,11631.6745684895,2005.92603442958,714.17139753425,88.2607455149013,45.2332385434805,294.672974570022,0.891316666859769 -13.0627294568385,2.44865767988072,25.3296583626176,163.957950340179,21.0803079008801,11928.212416117,2032.54205217107,649.942139771962,89.4318502955271,45.8062442501384,254.550558465785,0.760317844681849 +"dD","D","H","fc","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" +9.15158015400302,0.1,9.30685130731739,0.802314767872188,2.46024211324268,0.316316843131202,7.30958392378022,7.02392939699003,9.13563152114705,0.309052893467561,0.687337521113514,3.73060981700386,0.349976706679594 +7.51068608859801,0.118303160308006,10.5951677269446,0.772064352133008,3.31344110400063,0.426013856228652,11.6463653600737,11.0412824125802,10.5344545786858,0.485816426153529,0.925702548753488,4.0717530576517,0.320588515727445 +11.0223864066205,0.133324532485202,11.5747150651166,0.748414598299783,4.07939210586527,0.524493270754106,16.1592175957903,15.1364164543581,17.0051191375024,0.666002323991757,1.13969240775243,7.28243545071491,0.505813197748838 +12.2109860328466,0.155369305298443,12.8955857508128,0.7155135466808,5.29640723899734,0.680966645013944,24.4490170178718,22.470295918228,23.5706604699857,0.988693020402033,1.4796996616166,10.3227454787767,0.610007556660469 +8.14343951151115,0.179791277364136,14.2113227388961,0.681409046743642,6.75426651300729,0.868405694529509,36.0795921593221,32.4175065017063,22.1196280496285,1.42637028607508,1.88699346987095,8.64216534018665,0.437178780678676 +7.98837001728421,0.196078156387159,15.0104541268837,0.659943305237754,7.78033181838295,1.00032837664924,45.3254518882641,40.0840820976028,25.0226173827984,1.76369961229452,2.17365354275619,9.66629191655132,0.445571510141509 +12.0258637885806,0.212054896421727,15.7385365812519,0.639820356817988,8.82241993281344,1.13431113421887,55.5841333977515,48.373238491983,37.7793762157135,2.12842249364725,2.46479003598956,16.3400771342304,0.692215890552332 +6.5560471764814,0.236106623998888,16.7388948076693,0.611168017497777,10.4474433390386,1.34324271501924,73.288022651745,62.2075837425506,29.3234723190146,2.73713368467223,2.91878582517392,10.3987028384482,0.392058878157929 +9.06119771562442,0.249218718351851,17.2395860558773,0.59633209798285,11.3574952749362,1.46024939249179,84.0965213401603,70.3931802925398,39.2099313720491,3.09729993287175,3.17303431492111,15.5058348811442,0.551136474007312 +12.5411592420971,0.2673411137831,17.8839217661859,0.57668548313431,12.6387343989382,1.62498013700633,100.388542478402,82.3993995200503,54.7252358201368,3.62557357888221,3.53098433890655,23.6382736008367,0.777983562017604 +9.03418038499667,0.292423432267294,18.691926724088,0.551040995915459,14.4491171748091,1.85774363676117,125.536001523663,100.232439393555,49.2645559252196,4.41022733331644,4.03676545806381,19.2022322133608,0.572494896702917 +10.4795840004484,0.310491793037287,19.2190833187389,0.533610731307969,15.7745822821954,2.0281605791394,145.520038705201,113.866672689204,59.2632249984158,5.01013359832497,4.40707124883518,24.0872447367328,0.671959730051301 +11.9753726313239,0.331450961038184,19.7783608026811,0.514414288719766,17.3294448640194,2.22807148251678,170.654891764143,130.415580444168,71.161547545663,5.73828553954339,4.84146564722001,29.9171641677866,0.776039884241294 +7.80628339083056,0.355401706300832,20.3550784533437,0.49373655540199,19.1234992007906,2.45873561153022,201.930387670726,150.175089079034,58.6532690356622,6.6077039194775,5.34268495971847,21.2700220352415,0.510300275523062 +4.00892322682109,0.371014273082493,20.6983597468974,0.480936041265026,20.3002609801303,2.61003355458818,223.772671728003,163.482184102033,43.5295413559335,7.19321610048947,5.67144631210684,11.510326592636,0.263130980950176 +9.14103200731802,0.379032119536135,20.8653405365414,0.474560376400669,20.9062704384995,2.68794905637851,235.433027053355,170.433076459398,70.595634068793,7.4990553642135,5.84075202256713,26.9292656571604,0.600975055086163 +12.9288890666292,0.397314183550771,21.2239178805536,0.460504096984337,22.2912641636173,2.86601967817936,263.138003967915,186.550153984087,95.1139417044901,8.20820677529982,6.22768879950307,40.2791656157786,0.852381340501473 +8.559841502641,0.42317196168403,21.6824623192037,0.441706435062423,24.2549597310002,3.11849482255717,304.952537262096,209.901361085315,77.9748046952907,9.23565988775386,6.77630213972738,28.6960853671925,0.565441068540363 +11.7119920410932,0.440291644689312,21.9575081629571,0.429917001053558,25.5563348496366,3.28581448066756,334.313429185402,225.663361404898,100.7266565802,9.92918790181549,7.13987771762177,41.0798038839857,0.773837010777129 +8.1661974411302,0.463715628771498,22.3005515182373,0.414577645975007,27.3364685680675,3.51468881589439,376.624832725536,247.548221416205,84.8922502025986,10.892121742313,7.63720791560956,30.3567355628113,0.539114385185502 +9.11610386981603,0.480048023653758,22.5188727324862,0.404393318263312,28.5763269029229,3.67409917323295,407.573463450989,262.987869861956,94.780184305758,11.5714662739261,7.9835970574848,35.207422127762,0.601091017101131 +9.45349393230877,0.498280231393391,22.7440569444025,0.393492344396193,29.9582654351054,3.85177698451356,443.511750184483,280.365271509347,101.411722320694,12.3360719464113,8.36968028072889,38.0238284659624,0.622165860251205 +10.5041723806732,0.517187219258008,22.9585424533782,0.382682444685352,31.3882548353777,4.03563276454856,482.313882472608,298.5132431413,113.42139399129,13.1345826982172,8.76918785939815,43.9766410856273,0.689634418416019 +12.2128888837326,0.538195564019354,23.1760658641222,0.371228758836905,32.9727297581712,4.23935096890772,527.241789610679,318.795022049385,131.404128395006,14.026980970173,9.21185529437835,53.3384664764177,0.799279419243195 +12.1856528195232,0.562621341786819,23.4040161433267,0.358604881954002,34.8082078848516,4.47534101376664,581.85219182514,342.485358372075,137.973101490197,15.0693557683713,9.72464750245409,55.7527969074137,0.794180989263487 +9.11472071104903,0.586992647425866,23.6074128455832,0.34670311561101,36.6316203311612,4.70977975686359,638.856913795495,366.194815094084,119.878012477321,16.1125718641397,10.2340688248792,43.5718796187963,0.591348686762172 +10.3759087481066,0.605222088847964,23.7453799177281,0.338225512232287,37.9899713077899,4.88442488243013,683.122428005091,383.952053387605,134.587064757615,16.8938903490546,10.6135622040277,51.1780688104701,0.670773810696265 +6.93901957870437,0.625973906344177,23.889038357084,0.328991326554911,39.530287298616,5.08246550982206,735.192400601846,404.170081441633,110.103496654093,17.7834835834319,11.0438926049128,35.4173150493713,0.446714012837032 +12.284388351516,0.639851945501586,23.9777694004383,0.323051152813844,40.5567687846253,5.21444170088039,771.005808870131,417.684886042966,159.920476132293,18.3781349858905,11.330668949511,64.1017594282772,0.788584187622587 +12.075607039426,0.664420722204618,24.1216671677035,0.312972488167058,42.3667902401924,5.4471587451676,836.341293135801,441.582513969378,164.654513698263,19.4296306146526,11.8363491237245,65.4344699422069,0.771247465222399 +11.917199932589,0.68857193628347,24.2481853160583,0.303579145904651,44.1370836450472,5.67476789722035,902.958437900666,465.021784167154,169.575365139389,20.4609585033548,12.330930154586,66.9075758011336,0.757330040945065 +10.7311762351148,0.712406336148648,24.3600501700355,0.294776199823816,45.8755226084278,5.89828147822643,971.009785550148,488.087188105459,164.221879519707,21.4758362766402,12.8166117552973,62.306468003344,0.67863021382006 +14.4672595446774,0.733868688618878,24.4508492070951,0.287221932327531,47.4337410742638,6.09862385240534,1034.23813067158,508.790786508429,207.095718270781,22.3867946063709,13.2519437138457,86.4821252694631,0.910940614000552 +15.7103757812118,0.762803207708232,24.5599546892029,0.277560116660781,49.5239349849306,6.36736306949107,1122.38657631876,536.591264630236,228.57167037994,23.6100156437304,13.8358979082199,97.528547825802,0.983600017668455 +8.91259981408415,0.794223959270656,24.6631557853775,0.267699569449094,51.7805552706752,6.65749996337253,1221.86857668617,566.624543312778,164.393628364537,24.9314799057622,14.4663479704107,57.5429740486748,0.554698645013589 +15.3828383288123,0.812049158898824,24.7154286300117,0.262378253310204,53.0549049004546,6.82134491577274,1280.03743164846,583.587188895696,240.078103118852,25.6778363114106,14.8223732212792,101.476722856044,0.954291586384592 +10.9117224578962,0.842814835556449,24.7961941944862,0.253626639876271,55.2449103869321,7.10291704974841,1383.37286768916,612.732927587703,197.929333821628,26.9602488138589,15.4342125740803,74.6171403957344,0.673301322809818 +13.1758830355601,0.864638280472241,24.8469643034311,0.247731303333039,56.79143836478,7.301756361186,1458.9222106752,633.306180185225,229.891395155748,27.8654719281499,15.8662784674755,92.3504829403427,0.810076229643654 +11.8938985413645,0.890990046543361,24.9018766615094,0.240935744863909,58.6516187772485,7.54092241421767,1552.62889407201,658.037439405553,221.478220299491,28.9536473338443,16.3859719507501,85.8125908564757,0.728228239448258 +6.52221762717001,0.91477784362609,24.9460647481528,0.235086894386527,60.3243644889098,7.75598972000269,1639.54447137064,680.260020566022,160.705315769748,29.931440904905,16.8533003021826,48.2661399785982,0.397923162068421 +13.0691103920329,0.92782227888043,24.9683285219099,0.231988621415194,61.2391761388802,7.87360836071317,1688.14188140885,692.405779619886,245.616465036947,30.465854303275,17.1088785513281,98.0423188814217,0.795868435405181 +11.2901444723039,0.953960499664496,25.0091303412222,0.226000920680948,63.0672733715652,8.10864943348696,1787.51319409109,716.65948741528,229.587914041282,31.5330174462723,17.6196087000012,86.992585520139,0.685092501091739 +10.1856883712762,0.976540788609104,25.0406527764937,0.221053435624073,64.6414525528343,8.31104389965013,1875.49669495756,737.524539905611,220.483611468645,32.4510797558469,18.0593997313058,80.2703253073748,0.616288597793446 +14.7168490949802,0.996912165351656,25.0664255962766,0.216759192374532,66.0578413751149,8.49315103394334,1956.57311664364,756.281714675988,286.324948042341,33.2763954457435,18.4551076076968,118.308276055709,0.888253697621887 +13.7225114301121,1.02634586354162,25.0996631956801,0.210822116155523,68.0983678516983,8.75550443807549,2076.56365197065,783.276212189851,280.994170628441,34.4641533363534,19.0251858136718,113.451905799841,0.825481821325105 +10.816437840661,1.05379088640184,25.1268678501801,0.20555399798773,69.995136832937,8.99937473566333,2191.47799228847,808.338819910207,247.162954379706,35.5669080760491,19.5551013381123,91.7312013870843,0.648798955558408 +12.8623291298772,1.07542376208316,25.1460272006553,0.20157272342343,71.4865078533874,9.19112243829267,2284.11790815506,828.024454441548,281.978663498967,36.4330759954281,19.9717575910637,111.243097728695,0.769889413893804 +14.1478121549792,1.10114842034292,25.1664726000935,0.197023712691922,73.2560134541069,9.41863030124231,2396.6463246909,851.358473848795,307.829786744212,37.459772849347,20.4661185267815,125.188655249443,0.844851206715583 +10.8555957019155,1.12944404465288,25.1863471916489,0.192239432944515,75.1977729008894,9.66828508725721,2523.39075014522,876.935986311119,265.650564786315,38.5851833976892,21.0086033975047,98.4447835735337,0.646713384255583 +11.0993368301995,1.15115523605671,25.1999431256371,0.188715546096349,76.6846653632697,9.85945697527753,2622.75200951499,896.502626426457,274.565808596585,39.4461155627641,21.4240084398596,102.5294412184,0.660117216118531 +13.568084538822,1.17335390971711,25.2125148532172,0.185237603229543,78.2024329806775,10.0545985260871,2726.24007799684,916.458962697381,318.850786637231,40.3241943586847,21.8480393212757,127.678279472747,0.805640658471192 +16.4971864488835,1.20049007879475,25.2262441571925,0.18114903728575,80.0545909876401,10.2927331269823,2855.35181726442,940.790170804074,373.482727025559,41.3947675153792,22.3654915209449,158.727996995137,0.977776629910409 +10.3348974886028,1.23348445169252,25.2407946428701,0.17640518854336,82.3022628132546,10.5817195045613,3016.20089036043,970.286449748543,281.632774748363,42.6926037889359,22.9934415802414,102.095441461473,0.611308192921989 +6.95304413788432,1.25415424666972,25.248851343592,0.173553222947393,83.7081321589271,10.7624741347192,3119.12954784146,988.719540153709,229.455338382896,43.5036597667632,23.3862105462968,69.8083579179077,0.410796274322147 +9.00973354518552,1.26806033494549,25.2538580690473,0.17168400194332,84.6530726309822,10.8839664811263,3189.31527331777,1001.10248684552,267.025327496874,44.0485094212028,23.6502061254985,91.4355195447515,0.531917327108769 +15.6877482156484,1.28607980203586,25.2598891148891,0.169318936848877,85.8765186648459,11.0412666854802,3281.38475792988,1017.12745792761,386.026693623099,44.7536081488149,23.9920100315473,161.415476431828,0.92533801682606 +13.6259336297694,1.31745529846716,25.2692727571396,0.165347969304656,88.0042618444706,11.3148336657177,3444.72376670439,1044.97758045118,359.011793969757,45.9790135398519,24.5864546655845,143.542966257681,0.802559126396787 +10.4723127635367,1.3447071657267,25.2763977458718,0.162042700538525,89.8499775229471,11.5521399672361,3589.71938616316,1069.11738122691,309.634996111116,47.0411647739842,25.1021070204059,112.554260725533,0.616110870749928 +10.7110453834933,1.36565179125377,25.2813002370154,0.15958844327547,91.2671434529,11.7343470153729,3703.13244395458,1087.64116184824,318.844086272799,47.8562111213227,25.4980320035843,116.877068597587,0.629648713663442 +11.3625258593164,1.38707388202076,25.2858509844599,0.157152028330603,92.7154779261424,11.9205614476469,3820.90855602521,1106.56299766795,335.959626395463,48.6887718973897,25.9026647920498,125.893592208284,0.667434863611444 +15.1570929677971,1.40979893373939,25.2902145956771,0.154645521516862,94.250739226678,12.1179521862872,3947.81462317105,1126.61077887524,413.049910726614,49.5708742705106,26.3315830236708,170.637857867346,0.889658642307582 +11.7737995457054,1.44011311967498,25.2953715779612,0.151421124567691,96.2969968268858,12.381042449171,4120.25560223883,1153.31678235808,356.765644416924,50.7459384237553,26.9032623795017,135.350623899051,0.690442205868936 +10.6219765176094,1.4636607187664,25.2989115183682,0.14900588778343,97.8852662736601,12.5852485208992,4256.69518892669,1174.0349326372,340.078070003847,51.657537036037,27.3469899210026,124.074461350785,0.62249515501688 +11.1679845453287,1.48490467180161,25.3017935791659,0.146890850508661,99.3173115066653,12.7693686222855,4381.65658946667,1192.707863827,355.870036811486,52.4791460083879,27.7470718541091,132.317597916604,0.654142334679536 +9.05093328369608,1.50724064089227,25.3045361205648,0.144729744438387,100.822171964241,12.9628506811167,4514.9552826765,1212.32323945806,318.611163539509,53.3422225361547,28.1674967590257,108.825304996237,0.529863667525806 +8.57305196232164,1.52534250745966,25.306561908206,0.143023626092595,102.04120838124,13.1195839347308,4624.4253638677,1228.20804389168,312.726293160373,54.0411539312337,28.508068715134,104.300993008223,0.501690081248363 +11.9963730923388,1.54248861138431,25.3083319004076,0.141443686127259,103.195452656216,13.2679867700849,4729.3051288036,1243.24472597693,386.785898128011,54.7027679429848,28.8305391721882,147.569504732543,0.701775766483526 +10.0140419718713,1.56648135756898,25.3105865692215,0.139289695820095,104.809949965981,13.4755649956262,4878.00850198396,1264.27137669996,351.360290163172,55.6279405747982,29.281594201596,125.077703880855,0.585545900775574 +8.59974324691289,1.58650944151273,25.3122879442408,0.137540548527464,106.157122036104,13.6487728332133,5003.87676708123,1281.81155980696,325.92479736763,56.3997086315064,29.6579644402025,108.770716793029,0.502672900212778 +13.8494174687163,1.60370892800655,25.3136295215744,0.136072662776004,107.313668039312,13.7974716050544,5113.23078495148,1296.86645369772,441.846265145894,57.0621239626999,29.9810779494869,177.048186089522,0.809300853256342 +12.5502020049628,1.63140776294399,25.3155797795604,0.133772660445432,109.175571881749,14.0368592419391,5291.79252543124,1321.09704226708,421.209198483345,58.1282698597514,30.5012529211793,163.18270189656,0.733076218427733 +13.048208318553,1.65650816695391,25.3171456424203,0.131753805922635,110.862174878597,14.2537081986768,5456.2188814255,1343.04034688599,438.713921061775,59.0937752629835,30.9724526932327,172.244219779408,0.761906041132742 +15.4289611814367,1.68260458359102,25.3185936180167,0.12971778409193,112.615123807065,14.4790873466227,5629.80814126343,1365.84136148515,499.072579656001,60.0970199053464,31.4621880589703,206.852784346406,0.900632327178097 +13.220831045457,1.71346250595389,25.3200968030889,0.12738924593908,114.687223857574,14.7455002102595,5838.54261380009,1392.78709571411,457.784235647098,61.282632211421,32.0410872268813,180.473950750123,0.771473826034513 +14.6744254829537,1.7399041680448,25.3212262289061,0.125458882745886,116.462238883666,14.9737164278999,6020.39895576884,1415.86438762986,498.58810242852,62.298033055714,32.5369873748407,203.385575584845,0.856070373880828 +12.3771664239417,1.76925301901071,25.3223296504764,0.123383113052303,118.431894474234,15.2269578609729,6225.48842919364,1441.46723092982,452.837371241796,63.4245581609122,33.0872658144224,174.420416953411,0.721864528611161 +8.30551838108739,1.7940073518586,25.3231517134587,0.121684580493169,120.092821456216,15.4405056157992,6401.12156682518,1463.05330026531,361.84128377361,64.3743452116736,33.5512922727946,118.669957989799,0.484300143581058 +12.8703977351198,1.81061838862077,25.3236533481343,0.120570606054503,121.207183476956,15.5837807327514,6520.33778331882,1477.53423877282,475.366821932463,65.0115065060042,33.8626205054249,185.586400489081,0.750388449631874 +17.5024069731262,1.83635918409101,25.324359085768,0.118883844884963,122.933760626036,15.8057692233475,6707.23629890486,1499.96823680202,595.493209833851,65.9986024192889,34.3449881761808,255.947163965479,1.02027031828359 +9.82761584378681,1.87136399803726,25.3251946020614,0.116663911109864,125.281266238125,16.1075913734733,6965.61092818679,1530.46560258242,415.51140787359,67.3404865136264,35.000829599075,146.440793652955,0.57276022476205 +14.8268683831841,1.89101922972484,25.3256082501731,0.115453193506121,126.599182937103,16.277037806199,7112.81734768733,1547.58508394251,545.841667553417,68.0937436934704,35.369026530602,223.244677061804,0.864026904682818 +16.670401818256,1.9206729664912,25.3261659297282,0.113673186661467,128.587260671192,16.5326478005818,7337.8051756096,1573.40726014861,601.589581347018,69.2299194465387,35.9244517117962,254.922321501423,0.971314041079683 +15.4149286674,1.95401377012772,25.326708836671,0.1117360072921,130.822200648551,16.8199972262423,7594.93180715081,1602.43247915913,579.381729102403,70.5070290830019,36.548844772791,239.800566299458,0.898030812662004 +12.3928009689304,1.98484362746252,25.3271421939176,0.11000233453419,132.888548814085,17.0856705618109,7836.61776914167,1629.26539899861,508.667229941956,71.6876775559387,37.1261369905814,195.818848176034,0.721883481245894 +10.4851561842095,2.00962922940038,25.3274488421256,0.108646944934399,134.549614711054,17.2992361771355,8033.65552576276,1650.83371474498,463.998402237256,72.6366834487793,37.5902022587448,167.7387542842,0.610709953218915 +9.90626867627027,2.0305995417688,25.3276824450438,0.107525923035169,135.954882592171,17.4799134761363,8202.26698408822,1669.0794885972,453.215628575713,73.4394974982769,37.9828031888356,160.126954689734,0.576953988619449 +10.9382513143009,2.05041207912134,25.3278834651907,0.106487776383637,137.282482455137,17.6506048870891,8363.17306360221,1686.31597978949,485.836872094783,74.1979031107376,38.3537053833514,178.528755623175,0.637020900784014 +9.04501767607766,2.07228858174994,25.3280852334845,0.105364457576292,138.748298487551,17.8390669483994,8542.65187213743,1705.34606875546,438.815304844657,75.0352270252404,38.763222134855,149.199596343449,0.526731736736262 +10.9586459149586,2.09037861710209,25.3282374678955,0.104453266473771,139.960342461799,17.9949011736599,8692.50119776504,1721.08088500557,495.924803941091,75.7275589402453,39.1018405562926,182.339736167713,0.638141981266525 +16.1117280957809,2.11229590893201,25.3284057870944,0.103370140910424,141.428744554095,18.1836957283836,8875.79478757591,1740.1430221228,646.049923998231,76.5662929734034,39.512079796034,270.886150621575,0.938167882112159 +8.9056789119109,2.14451936512357,25.3286245083767,0.101817784828689,143.587505562741,18.4612507152095,9148.74307999231,1768.16575809573,450.235234089833,77.7992933562119,40.1151901291074,152.010742424316,0.518533045937227 +11.0637760928849,2.1623307229474,25.3287322505919,0.100979529992379,144.780690949288,18.6146602649085,9301.38395896497,1783.65379992591,516.112133491727,78.4807671967398,40.4485398760302,190.412930019335,0.644166698040669 +11.2436003389495,2.18445827513316,25.3288544223834,0.0999571361843007,146.262965496525,18.8052384209818,9492.76952530043,1802.89377898382,526.649487980533,79.327326275288,40.8626547744882,195.484718190378,0.654611514815008 +12.8576696941051,2.20694547581106,25.3289665241632,0.098939082131522,147.769276390515,18.9989069644948,9689.25886209949,1822.44516393894,579.507225035631,80.1875872133133,41.2834848994294,225.845139885379,0.748557266175009 +13.0768279219054,2.23266081519927,25.3290813379501,0.0977999649470258,149.491762344538,19.2203694442977,9916.41789767204,1844.80176301094,592.800561589888,81.1712775724812,41.7647095802923,232.367287855927,0.761288216970229 +13.8119631621991,2.25881447104309,25.3291850340405,0.0966679849966022,151.243545911318,19.4455987600266,10150.1443992872,1867.53796550784,621.871547307728,82.1716704823448,42.2541193696122,248.301491908762,0.804058020017973 +14.6807566864776,2.28643839736748,25.3292818767622,0.0955004423033468,153.093747765929,19.6834818556194,10399.9623752052,1891.55087809784,655.939600902199,83.2282386363049,42.7710250633497,267.143833652667,0.854607035364916 +11.2579410178118,2.31579991074044,25.3293722269738,0.0942899497129994,155.060268605205,19.9363202492406,10668.8196395403,1917.07278416288,558.921876984561,84.3512025031665,43.3204277223849,207.487230268737,0.655335615519299 +10.1683384595739,2.33831579277606,25.3294337327887,0.0933822488930768,156.568256895287,20.1302044579654,10877.3145553614,1936.64334876507,530.483213501824,85.212307345663,43.7417264748914,189.225861670154,0.59189636069528 +9.34236926109352,2.35865246969521,25.3294840895293,0.0925772763334125,157.93026806652,20.3053201799811,11067.3625363081,1954.3191524587,509.20213624864,85.9900427081828,44.1222424318881,175.365828917953,0.543807444159576 diff --git a/pyrealm_build_data/t_model/rtmodel_test_outputs.r b/pyrealm_build_data/t_model/rtmodel_test_outputs.r index 969e4534..70e9cb4a 100644 --- a/pyrealm_build_data/t_model/rtmodel_test_outputs.r +++ b/pyrealm_build_data/t_model/rtmodel_test_outputs.r @@ -12,9 +12,9 @@ tmodel <- function(P0, year, a, cr, Hm, rho, rr, P0 <- P0 * (1 - 0.1) aa <- length(year) # simulate years output <- matrix() - output <- matrix(NA, nrow = aa, ncol = 12, byrow = T) + output <- matrix(NA, nrow = aa, ncol = 13, byrow = T) colnames(output) <- c( - "dD", "D", "H", "Ac", "Wf", "Ws", "Wss", + "dD", "D", "H", "fc", "Ac", "Wf", "Ws", "Wss", "GPP", "Rm1", "Rm2", "dWs", "dWfr" ) # you can decide which index you want output dD <- 0 @@ -80,7 +80,7 @@ tmodel <- function(P0, year, a, cr, Hm, rho, rr, a * d * (1 - H / Hm) + H )) * (1 / sigma + zeta) * dD output[i, ] <- c( - dD / 2 * 1000, d, H, Ac, Wf, Ws, Wss, GPP, Rm1, Rm2, dWs, dWfr + dD / 2 * 1000, d, H, fc, Ac, Wf, Ws, Wss, GPP, Rm1, Rm2, dWs, dWfr ) } diff --git a/tests/regression/demography/test_t_model_functions_against_rtmodel.py b/tests/regression/demography/test_t_model_functions_against_rtmodel.py index 1d994de3..218b3a07 100644 --- a/tests/regression/demography/test_t_model_functions_against_rtmodel.py +++ b/tests/regression/demography/test_t_model_functions_against_rtmodel.py @@ -5,9 +5,9 @@ from importlib import resources -import numpy as np import pandas as pd import pytest +from numpy.testing import assert_array_almost_equal # Fixtures: inputs and expected values from the original implementation in R @@ -16,8 +16,8 @@ def rvalues(): """Fixture to load test inputs from file. - This is a time series of growth using the default trait values in R, mapped to the - internal property names used in TTree + The regression test inputs consist of time series of growth from an initial DBH + using a small set of different plant functional type definitions. """ from pyrealm.demography.flora import PlantFunctionalType @@ -25,73 +25,158 @@ def rvalues(): pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" pft_definitions = pd.read_csv(pfts_path) + # Map the PFT trait args from the R implementation to pyrealm pft_definitions = pft_definitions.rename( columns={ - "name": "alt_two", - "d": 0.6, - "a": 102, - "cr": 406.12, - "Hm": 45.33, - "rho": 100, - "L": 1.0, - "sigma": 21, - "tf": 8, - "tr": 2.1, - "K": 0.4, - "y": 0.7, - "zeta": 0.15, - "rr": 0.962, - "rs": 0.054, + "a": "a_hd", + "cr": "ca_ratio", + "Hm": "h_max", + "rho": "rho_s", + "L": "lai", + "sigma": "sla", + "tf": "tau_f", + "tr": "tau_r", + "K": "par_ext", + "y": "yld", + "rr": "resp_r", + "rs": "resp_s", } ) - datapath = resources.files("pyrealm_build_data.t_model") / "rtmodel_output.csv" - data = pd.read_csv(datapath) + # Convert to dicts for creating PFT instances + pft_definitions = pft_definitions.to_dict(orient="records") + + return_value = [] + + # Loop over the PFT definitions + for pft_args in pft_definitions: + # Record the starting DBH and create the PFT instances + dbh_init = pft_args.pop("d") + pft = PlantFunctionalType(**pft_args) + + # Load the appropriate output file and then remap the field names + datapath = ( + resources.files("pyrealm_build_data.t_model") + / f"rtmodel_output_{pft.name}.csv" + ) + data = pd.read_csv(datapath) + + data = data.rename( + columns={ + "dD": "delta_d", + "D": "diameter", + "H": "height", + "fc": "crown_fraction", + "Ac": "crown_area", + "Wf": "mass_fol", + "Ws": "mass_stm", + "Wss": "mass_swd", + "GPP": "gpp_actual", + "Rm1": "resp_swd", + "Rm2": "resp_frt", + "dWs": "delta_mass_stm", + "dWfr": "delta_mass_frt", + } + ) + + # Fix some scaling differences: + # The R tmodel implementation rescales reported delta_d as a radial increase in + # millimetres, not diameter increase in metres + data["delta_d"] = data["delta_d"] / 500 + + # The R tmodel implementation slices off foliar respiration costs from GPP + # before doing anything - the pyrealm.tmodel implementation keeps this cost + # within the tree calculation, so proportionally inflate the GPP to make it + # match + data["gpp_actual"] = data["gpp_actual"] / (1 - pft.resp_f) + + # Add a tuple of the inputs and outputs to the return list. + return_value.append((pft, dbh_init, data)) + + return return_value - data = data.rename( - columns={ - "dD": "delta_d", - "D": "diameter", - "H": "height", - "Ac": "crown_area", - "Wf": "mass_fol", - "Ws": "mass_stm", - "Wss": "mass_swd", - "GPP": "gpp_actual", - "Rm1": "resp_swd", - "Rm2": "resp_frt", - "dWs": "delta_mass_stm", - "dWfr": "delta_mass_frt", - } - ) - # Get the default PFT traits, which should match the settings used for the - # regression data set. - default_pft = PlantFunctionalType() +def test_calculate_heights(rvalues): + """Test calculation of heights of tree from diameter.""" - # Fix some scaling differences: - # The R tmodel implementation rescales reported delta_d as a radial increase in - # millimetres, not diameter increase in metres - data["delta_d"] = data["delta_d"] / 500 + from pyrealm.demography.t_model_functions import calculate_heights - # The R tmodel implementation slices off foliar respiration costs from GPP before - # doing anything - the pyrealm.tmodel implementation keeps this cost within the tree - # calculation, so proportionally inflate the GPP to make it match - data["gpp_actual"] = data["gpp_actual"] / (1 - default_pft.resp_f) + for pft, _, data in rvalues: + actual_heights = calculate_heights( + h_max=pft.h_max, a_hd=pft.a_hd, dbh=data["diameter"] + ) - return data + assert_array_almost_equal(actual_heights, data["height"], decimal=8) -def test_calculate_heights(rvalues): - """Tests happy path for calculation of heights of tree from diameter.""" +def test_calculate_crown_areas(rvalues): + """Tests calculation of crown areas of trees.""" + from pyrealm.demography.t_model_functions import calculate_crown_areas - from pyrealm.demography.t_model_functions import calculate_heights + for pft, _, data in rvalues: + actual_crown_areas = calculate_crown_areas( + ca_ratio=pft.ca_ratio, + a_hd=pft.a_hd, + dbh=data["diameter"], + height=data["height"], + ) - pft_h_max_values = np.array([25.33, 15.33]) - pft_a_hd_values = np.array([116.0, 116.0]) - diameters_at_breast_height = np.array([0.2, 0.6]) - expected_heights = np.array([15.19414157, 15.16639589]) - actual_heights = calculate_heights( - pft_h_max_values, pft_a_hd_values, diameters_at_breast_height - ) - assert np.allclose(actual_heights, expected_heights, decimal=8) + assert_array_almost_equal(actual_crown_areas, data["crown_area"], decimal=8) + + +def test_calculate_crown_fractions(rvalues): + """Tests calculation of crown fractions of trees.""" + + from pyrealm.demography.t_model_functions import calculate_crown_fractions + + for pft, _, data in rvalues: + actual_crown_fractions = calculate_crown_fractions( + a_hd=pft.a_hd, + dbh=data["diameter"], + height=data["height"], + ) + assert_array_almost_equal( + actual_crown_fractions, data["crown_fraction"], decimal=8 + ) + + +def test_calculate_stem_masses(rvalues): + """Tests happy path for calculation of stem masses of trees.""" + + from pyrealm.demography.t_model_functions import calculate_stem_masses + + for pft, _, data in rvalues: + actual_stem_masses = calculate_stem_masses( + dbh=data["diameter"], + height=data["height"], + rho_s=pft.rho_s, + ) + assert_array_almost_equal(actual_stem_masses, data["mass_stm"], decimal=8) + + +def test_calculate_foliage_masses(rvalues): + """Tests calculation of foliage masses of trees.""" + + from pyrealm.demography.t_model_functions import calculate_foliage_masses + + for pft, _, data in rvalues: + actual_foliage_masses = calculate_foliage_masses( + crown_area=data["crown_area"], lai=pft.lai, sla=pft.sla + ) + assert_array_almost_equal(actual_foliage_masses, data["mass_fol"], decimal=8) + + +def test_calculate_sapwood_masses(rvalues): + """Tests calculation of sapwood masses of trees.""" + + from pyrealm.demography.t_model_functions import calculate_sapwood_masses + + for pft, _, data in rvalues: + actual_sapwood_masses = calculate_sapwood_masses( + crown_area=data["crown_area"], + height=data["height"], + crown_fraction=data["crown_fraction"], + ca_ratio=pft.ca_ratio, + rho_s=pft.rho_s, + ) + assert_array_almost_equal(actual_sapwood_masses, data["mass_swd"], decimal=8) diff --git a/tests/regression/tmodel/test_tmodel.py b/tests/regression/tmodel/test_tmodel.py index 6c7d2f3d..8aa1e33a 100644 --- a/tests/regression/tmodel/test_tmodel.py +++ b/tests/regression/tmodel/test_tmodel.py @@ -32,6 +32,7 @@ def rvalues(): ("dD", "delta_d"), ("D", "diameter"), ("H", "height"), + ("fc", "crown_fraction"), ("Ac", "crown_area"), ("Wf", "mass_fol"), ("Ws", "mass_stm"), From 0e60479bab80389eda9790825a20f996329e3cdf Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 13 Sep 2024 17:30:43 +0100 Subject: [PATCH 093/241] First draft of T Model growth functions and regression tests --- pyrealm/demography/t_model_functions.py | 102 +++++++++ .../t_model/rtmodel_output_alt_one.csv | 202 +++++++++--------- .../t_model/rtmodel_output_alt_two.csv | 202 +++++++++--------- .../t_model/rtmodel_output_default.csv | 202 +++++++++--------- .../t_model/rtmodel_test_outputs.r | 8 +- .../test_t_model_functions_against_rtmodel.py | 179 +++++++++++++++- tests/regression/tmodel/test_tmodel.py | 1 + 7 files changed, 581 insertions(+), 315 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 9c2fd903..82f64d24 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -145,6 +145,108 @@ def calculate_sapwood_masses( return crown_area * rho_s * height * (1 - crown_fraction / 2) / ca_ratio +def calculate_whole_crown_gpp( + potential_gpp: Series, crown_area: Series, par_ext: Series, lai: Series +) -> Series: + r"""Calculate whole crown gross primary productivity. + + Given an estimate of potential gross primary productivity (GPP) per metre squared + (:math:`P_0`), this function scales the GPP up to the whole crown, given the crown + area (:math:`A_c`) and leaf area index (:math:`L`) and the extinction coefficient + (:math:`k`) :cite:p:`{Equation 12, }Li:2014bc`:. + + .. math:: + + P = P_0 A_c (1 - e^{-kL}) + + Args: + potential_gpp: Potential GPP per metre squared + crown_area: The crown area in metres squared + par_ext: The extinction coefficient + lai: The leaf area index + """ + + return potential_gpp * crown_area * (1 - np.exp(-(par_ext * lai))) + + +def calculate_sapwood_respiration(resp_s: Series, sapwood_mass: Series) -> Series: + """TODO docstring.""" + return sapwood_mass * resp_s + + +def calculate_foliar_respiration(resp_f: Series, whole_crown_gpp: Series) -> Series: + """TODO docstring.""" + return whole_crown_gpp * resp_f + + +def calculate_fine_root_respiration( + zeta: Series, sla: Series, resp_r: Series, foliage_mass: Series +) -> Series: + """TODO docstring.""" + + return zeta * sla * foliage_mass * resp_r + + +def calculate_net_primary_productivity( + yld: Series, + whole_crown_gpp: Series, + foliar_respiration: Series, + fine_root_respiration: Series, + sapwood_respiration: Series, +) -> Series: + """TODO docstring.""" + + return yld * ( + whole_crown_gpp + - foliar_respiration + - fine_root_respiration + - sapwood_respiration + ) + + +def calculate_foliage_and_fine_root_turnover( + lai: Series, + sla: Series, + tau_f: Series, + zeta: Series, + tau_r: Series, + crown_area: Series, +) -> Series: + """TODO docstring.""" + + return crown_area * lai * ((1 / (sla * tau_f)) + (zeta / tau_r)) + + +def calculate_growth_increments( + rho_s: Series, + a_hd: Series, + h_max: Series, + lai: Series, + ca_ratio: Series, + sla: Series, + zeta: Series, + npp: Series, + turnover: Series, + dbh: Series, + height: Series, +) -> tuple[Series, Series, Series]: + """TODO docstring.""" + # relative increments - these are used to calculate delta_d and + # then scaled by delta_d to give actual increments + dSdD = np.pi / 8 * rho_s * dbh * (a_hd * dbh * (1 - (height / h_max)) + 2 * height) + + dFdD = ( + lai + * ((np.pi * ca_ratio) / (4 * a_hd)) + * (a_hd * dbh * (1 - height / h_max) + height) + * (1 / sla + zeta) + ) + + delta_d = (npp - turnover) / (dSdD + dFdD) + + return (delta_d, dSdD * delta_d, dFdD * delta_d) + + def calculate_canopy_q_m(m: float, n: float) -> float: """Calculate a q_m value. diff --git a/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv b/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv index 6e9785b0..2df8e17c 100644 --- a/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv +++ b/pyrealm_build_data/t_model/rtmodel_output_alt_one.csv @@ -1,101 +1,101 @@ -"dD","D","H","fc","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" -3.61419527788626,0.04,4.2375677628595,0.85434833928619,0.377501266657307,0.151000506662923,1.06501694023107,1.04242323817797,2.57427495945796,0.0354423900980509,0.270079506217303,0.547917987076988,0.161272907311876 -2.63582213481423,0.0472283905557725,4.86752857429837,0.831158170626178,0.511980501549784,0.204792200619914,1.70543306434933,1.65681532323452,2.91641485312791,0.0563317209899736,0.366291330028777,0.537031448881447,0.133212729374954 -2.0223383372043,0.052500034825401,5.30427913897247,0.81478888178635,0.620194239560314,0.248077695824126,2.29649461222528,2.21771759398417,3.12840123085741,0.0754023981954617,0.443711766751031,0.495860062869258,0.110248905528795 -3.99630301427157,0.0565447114998096,5.62697550702139,0.80253013111927,0.7086124576983,0.28344498307932,2.82604378944852,2.71584405130631,4.88214527137934,0.0923386977444145,0.506969696735672,1.11397328014681,0.229323758579466 -4.2217019893994,0.0645373175283527,6.23442775587003,0.779047613350402,0.896085134420728,0.358434053768291,4.07885525608091,3.8797257171921,6.26761792519107,0.131910674384531,0.641095148569966,1.47368574215049,0.264345473357082 -3.46719987885737,0.0729807215071515,6.8348837407399,0.755268364424925,1.1109155610504,0.444366224420161,5.71830497593628,5.37581525684338,6.91918868753264,0.182777718732675,0.7947934289979,1.48532285495898,0.234244177758968 -4.52469122322255,0.0799151212648662,7.2982610776457,0.736493209833092,1.29894308939059,0.519577235756236,7.32145163448969,6.8130805746893,9.22721320408101,0.231644739539436,0.929315843873604,2.24789896187047,0.322207237255168 -2.75527508964622,0.0889645037113114,7.86516608120094,0.712967038237946,1.55835508989843,0.623342035959373,9.77825357498007,8.97264359057825,8.59628300060585,0.305069882079661,1.11490956551694,1.62501387485143,0.207937958293907 -2.16979705684583,0.0944750538906038,8.19059161833534,0.699159783373791,1.72335277072833,0.689341108291332,11.4833723280803,10.4440715994928,8.6203748332246,0.355098434382757,1.23295550628988,1.40630296660708,0.168818043164358 -3.07431283587035,0.0988146480042955,8.43684994070901,0.688552899789867,1.85670718694588,0.742682874778351,12.9402556871126,11.6850599924355,10.6694458607846,0.397292039742807,1.32836258982856,2.13620539825103,0.244451596269189 -4.23100485332867,0.104963273676036,8.77129160112042,0.67391402832961,2.05041930668986,0.820167722675942,15.1795242773453,13.5654541771466,13.6876639916261,0.461225442022985,1.46695198877819,3.22441060509178,0.345913035154214 -2.7042299793535,0.113425283382693,9.20519506341289,0.65448762256395,2.32533021429281,0.930132085717125,18.6025559273069,16.3818050686804,12.5469236125034,0.556981372335134,1.66363424851365,2.31553531944851,0.228562540280565 -3.37588075128829,0.1188337433414,9.46736349476652,0.642491799518667,2.50559339573157,1.00223735829263,21.0004443835834,18.316333204339,14.8340486774496,0.622755328947526,1.7926017390422,3.09657275674885,0.290683644367646 -2.80933458522169,0.125585504843977,9.77895419215864,0.627958886701988,2.73510304682919,1.09404121873167,24.226535930895,20.873229893287,14.9071511577164,0.709689816371757,1.95680212382347,2.79278991549599,0.246949945783297 -4.23327794435142,0.13120417401442,10.0255901031469,0.616226836510612,2.92953952481571,1.17181580992628,27.1097257755016,23.1169554538833,19.198843022899,0.785976485432033,2.09590975763415,4.48104815419439,0.377843613034844 -2.49528677089278,0.139670729903123,10.3766952825391,0.59914505014854,3.22779713774433,1.29111885509773,31.7972635195878,26.6879300620075,16.7122118358412,0.907389622108256,2.3092951842278,2.88500650779462,0.22723812549853 -5.21454313363615,0.144661303444909,10.5726649560033,0.589400378913447,3.40626639131945,1.36250655652778,34.7543439338253,28.8950378840561,24.712744734852,0.982431288057907,2.43697922700559,6.33030958897154,0.479825901226051 -4.45825591570449,0.155090389712181,10.9575226802592,0.569778169705937,3.78476597991417,1.51390639196567,41.4001609797465,33.7373711008436,25.120177625202,1.14707061742868,2.70777297266979,5.9518792164748,0.417946118436792 -3.12684454571733,0.16400690154359,11.2617756833122,0.553761889193886,4.11349299747377,1.64539719898951,47.5829098962398,38.1077987290336,23.0952188646874,1.29566515678714,2.94295743011264,4.49822466080094,0.296981365148724 -0.83980983369455,0.170260590635025,11.4624458291288,0.542927044493358,4.34643508436966,1.73857403374786,52.19458447931,41.2903170231125,17.0032963824399,1.40387077878582,3.10961351676143,1.26906122218077,0.0803863578176289 -2.7528518715949,0.171940210302414,11.5146349609479,0.540071221264406,4.40929741575342,1.76371896630137,53.4718190625483,42.1606855417976,23.475574884942,1.43346330842112,3.15458774312663,4.21349381903444,0.264006797814069 -2.02196007113399,0.177445914045604,11.680820757461,0.530866928695069,4.61616292963981,1.84646517185592,57.7730430884123,45.0580144522875,22.0703980885603,1.53197249137777,3.3025876063815,3.22362492642659,0.195036874537514 -2.93072817620029,0.181489834187872,11.7982547283812,0.524256446523438,4.76882996982629,1.90753198793052,61.0438973330566,47.2277143158573,25.9462138702097,1.60574228673915,3.41181171361252,4.80934928503044,0.283772157567886 -2.55220658302714,0.187351290540272,11.9617931511234,0.514894098253604,4.99108243495948,1.99643297398379,65.952238887114,50.4318478316679,25.7462611652837,1.71468282627671,3.57082001726741,4.3605129986276,0.248331209182562 -4.2334045240652,0.192455703706327,12.0980283550311,0.506946496880732,5.1854583512764,2.07418334051056,70.3875823151747,53.2762373877248,32.9910779163514,1.81139207118264,3.70988432283719,7.48099842816608,0.413438716298905 -3.77428041150235,0.200922512754457,12.311962569824,0.494170709709006,5.50931562024479,2.20372624809792,78.0736287521434,58.0974547273159,33.1381689583558,1.97531346072874,3.94158476734793,7.03492117818929,0.370485014674553 -3.71063509624183,0.208471073577462,12.4907253747914,0.483192485747375,5.79929536759975,2.3197181470399,85.2705654276001,62.4956495287277,34.5377499283938,2.12485208397674,4.14904787779557,7.23454633453342,0.365540708428101 -4.40657037127339,0.215892343769945,12.6561481671932,0.472762068554469,6.08527987936592,2.43411195174637,92.660771071553,66.9029450925581,39.1282454029168,2.27470013314697,4.35365263689355,8.96072067347031,0.435278831471487 -5.22460777567042,0.224705484512492,12.8401235677315,0.460822680120124,6.42576208421306,2.57030483368522,101.839539178313,72.2335445021246,44.8437690444463,2.45594051307224,4.59724722552939,11.140571841934,0.517281516137811 -4.12588358939749,0.235154700063833,13.0419215563785,0.447266360044847,6.83025649549098,2.73210259819639,113.284055387619,78.6741364831034,42.3199634805667,2.67492064042552,4.88663870713407,9.27700987969847,0.409166449778424 -4.06195735877181,0.243406467242628,13.1896568529133,0.436998250834034,7.15002196320273,2.86000878528109,122.748897536845,83.8410604716865,43.883735959641,2.85059605603734,5.11541171335376,9.50263257381839,0.403048889067712 -4.78633758749704,0.251530381960172,13.3257816488355,0.427248510504041,7.46491572128936,2.98596628851574,132.432162409347,88.988550536786,49.3766535163434,3.02561071825073,5.34069930363926,11.6223985614159,0.474920741832296 -2.03198403068806,0.261103057135166,13.4751135258468,0.41619685177978,7.83585074967758,3.13434029987103,144.303286879851,95.1209581050517,37.1845032870995,3.23411257557176,5.60608106034933,5.14501621766722,0.201496184600926 -1.82127914231564,0.265167025196542,13.5350965806736,0.411642452910375,7.99323610375422,3.19729444150169,149.492797495271,97.7436825664736,36.7912609661138,3.3232852072601,5.71868083806992,4.691217155486,0.180522272256403 -3.07616600733212,0.268809583481173,13.5872094385735,0.407627839182267,8.13423628206164,3.25369451282466,154.219624991688,100.103221888547,44.2435310838741,3.4035095442106,5.81955800563818,8.04375415622991,0.304758850987011 -4.04790294034711,0.274961915495837,13.6718158143053,0.400988547627763,8.37221763733068,3.34888705493227,162.364532060208,104.105747939225,50.8915512397339,3.53959542993365,5.98981938645186,10.8506660592561,0.400641234582419 -4.69468494112271,0.283057721376532,13.7769224575599,0.392514335334539,8.68498326766391,3.47399330706556,173.389224258201,109.401867322359,56.4003054735228,3.71966348896019,6.21358442901747,12.9875600433066,0.463934948781327 -4.26504606926218,0.292447091258777,13.8905076204548,0.38304440732659,9.0470541345681,3.61882165382724,186.609008929115,115.579237480994,56.0638033139443,3.9296940743538,6.4726244100354,12.2203283900467,0.420574104743592 -3.95460165519157,0.300977183397301,13.986479975711,0.374759947180498,9.37526964293929,3.75010785717571,199.019418172765,121.217727514879,56.0918223514591,4.12140273550589,6.70744291334448,11.682877520424,0.389096601464554 -3.59592766439221,0.308886386707684,14.0697403608319,0.367337807536995,9.67891369552117,3.87156547820847,210.864512914207,126.463577269679,55.5693667490418,4.2997616271691,6.92468201432366,10.9179376090087,0.353010624547243 -4.60653890456036,0.316078242036469,14.140961621756,0.360796783555636,9.95440510013855,3.98176204005542,221.91569717693,131.245214763122,63.5649889911477,4.46233730194616,7.12177958484313,14.327396861869,0.451235551206729 -1.1348826389603,0.32529131984559,14.2263499269029,0.352695019643393,10.3064174071021,4.12256696284085,236.460341865218,137.382574830826,42.7561876155631,4.67100754424809,7.37362326973714,3.63665770107136,0.110840041192015 -4.06458077382757,0.32756108512351,14.2464275021785,0.350745401667865,10.3929787502524,4.15719150010096,240.110112758196,138.896128729079,62.6000982972905,4.7224683767887,7.43555271708058,13.1185869983298,0.39667553730703 -4.41724932120023,0.335690246671165,14.3153852537642,0.343908279782048,10.7024579259797,4.2809831703919,253.396355101432,144.32028616236,66.7741021069221,4.90688972952024,7.65696649856294,14.6208665143895,0.429909076821166 -1.79279718091315,0.344524745313566,14.385359418673,0.336727519958628,11.0378097287001,4.41512389148005,268.213995002787,150.218509514196,50.4035758976065,5.10742932348266,7.89689059230121,6.09362137305291,0.173947239217225 -3.06143683120084,0.348110339675392,14.4123632021848,0.333884755074705,11.1736197285772,4.46944789143088,274.339865383491,152.612655528483,59.9777583823456,5.18883028796843,7.99405449861327,10.5157523298448,0.296660142165985 -1.50117390397806,0.354233213337794,14.4567031891335,0.329123051288314,11.4051318186194,4.56205272744776,284.949368687038,156.700530730671,49.9659051519358,5.32781804484281,8.15968750831306,5.24827151026063,0.145148240789601 -4.05132556253422,0.35723556114575,14.4776558714492,0.326829974349181,11.5184674550801,4.60738698203202,290.22010518285,158.704576587986,68.9363905955646,5.39595560399154,8.24077235606248,14.2851022243896,0.391297328170271 -5.66403244635144,0.365338212270818,14.5317272613311,0.320774955768466,11.8237190946155,4.72948763784621,304.668331241669,164.110613998832,82.6188780371177,5.57976087596028,8.45916158905174,20.4272855438418,0.545450735644038 -3.01316544943287,0.376666277163521,14.6016215011273,0.312624249222992,12.2489705948221,4.89958823792885,325.412658538535,171.659920998718,65.1780022373135,5.83643731395643,8.76340352235954,11.2039025457643,0.288969168987441 -2.78597582479134,0.382692608062387,14.6362750499602,0.30843155504617,12.47447858356,4.98979143342402,336.705791579979,175.670551696288,64.5792347691106,5.97279875767378,8.9247409578222,10.5240536198184,0.266591712873914 -4.87271491146775,0.38826455971197,14.6668470696161,0.304640281468683,12.6825411454887,5.07301645819548,347.305884466971,179.374758697704,82.017260717091,6.09874179572193,9.07359723712844,18.6725908906924,0.465323608614364 -3.21641292436047,0.398009989534905,14.7171148114456,0.298199575112206,13.0454305221565,5.21817220886261,366.210253418252,185.84297448568,70.9130976403458,6.31866113251313,9.33322281277166,12.631265916159,0.306066553784671 -5.00151802197696,0.404442815383626,14.7481897698691,0.294076219799635,13.2842673673543,5.31370694694171,378.942088220714,190.104489975619,86.7503037018685,6.46355265917104,9.50409624529994,19.9542175912008,0.474829720056854 -2.61513448177088,0.41444585142758,14.7934109012255,0.287858354488032,13.654565431774,5.4618261727096,399.13865623935,196.717193734834,69.0842499993258,6.68838458698434,9.76902229250839,10.6866797363974,0.247389179310551 -4.38846825604944,0.419676120391122,14.8156384269194,0.284698006987983,13.8476600984633,5.53906403938533,409.891360594184,200.167600805403,85.0450639705865,6.80569842738372,9.9071699408446,18.1548785261568,0.414381058858339 -2.2485165003717,0.428453056903221,14.8508889871088,0.27952941830465,14.1709009749327,5.6683603899731,428.23170717312,205.946109419911,68.4696693246413,7.00216772027697,10.1384293935059,9.49195653615183,0.211670050142608 -2.2432449737829,0.432950089903964,14.8680035938117,0.276944750872787,14.3361407891295,5.73445631565182,437.772223990479,208.901012052733,69.2081665357538,7.10263440979291,10.2566485661748,9.56657101723573,0.210849031742982 -5.35926015710125,0.43743657985153,14.8844688464015,0.274407867592198,14.5007412980437,5.80029651921748,447.38705429855,211.844954077835,97.419304842287,7.2027284386464,10.3744103542724,23.0857016376885,0.502967503935862 -3.66062598867648,0.448155100165732,14.9214688693569,0.268510670348906,14.89298274049,5.95719309619602,470.747628295901,218.861569344914,84.6172228504012,7.44129335772707,10.6550355718562,16.1439158496426,0.342329497793288 -2.28005711417344,0.455476352143085,14.9449594711966,0.26461059094751,15.1601096057181,6.06404384228725,487.019427928689,223.640498456833,73.4548082335293,7.60377694753231,10.846148816315,10.2146522742118,0.212718141557215 -3.57967699729492,0.460036466371432,14.9589031297618,0.262232071544505,15.3261747990157,6.1304699196063,497.283608949281,226.61138658818,86.2458088504981,7.70478714399812,10.9649584982078,16.1924371444989,0.333481791282087 -5.12174135801468,0.467195820366022,14.9797829305438,0.258574019258411,15.5864149740682,6.23456598962728,513.597965625679,231.266751692435,102.110108451039,7.8630695575428,11.1511447290474,23.5166485477788,0.476073247863579 -3.47882972754835,0.477439303082051,15.0076310977229,0.253496690081571,15.957765510624,6.38310620424962,537.36373987444,237.908557622901,88.7203345796038,8.08889095917862,11.4168237569209,16.3114696293465,0.322357043071212 -2.70806295248966,0.484396962537148,15.0252724724439,0.250149281619073,16.2093475178922,6.48373900715688,553.789931798322,242.407088807024,82.6053547145053,8.2418410194388,11.5968155882008,12.8760838627386,0.250421144226177 -4.37599022139665,0.489813088442127,15.0383342290835,0.247598301895011,16.4048356762212,6.56193427048848,566.735453197475,245.901800560683,99.9214167398006,8.36066121906322,11.7366756361957,21.0309882508301,0.404026245591593 -3.47778796671728,0.498565068884921,15.0582680094727,0.243574315202804,16.7200909485027,6.6880363794011,587.947561937489,251.535833765387,92.8233751898047,8.55221834802316,11.9622218681968,17.0020572794889,0.320307770568813 -4.85561756252765,0.505520644818355,15.0731339916517,0.240460075046821,16.9700929828417,6.78803719313668,605.063882069782,256.001985399667,108.079124393239,8.70406750358867,12.1410833236443,24.0569438868774,0.446359220714667 -2.63373782532175,0.515231879943411,15.0925390549594,0.236231548114099,17.318361519981,6.9273446079924,629.343338531056,262.220780607991,87.3807825111785,8.91550654067168,12.3902485658552,13.2900797623986,0.241489912159131 -2.19034495341924,0.520499355594054,15.1024440689288,0.233994341150871,17.5068978609808,7.00275914439232,642.698824203025,265.58586110291,83.7156916857586,9.02991927749892,12.5251350056601,11.1614591468821,0.200564068891872 -1.893949536051,0.524880045500893,15.1103661356152,0.232163124623956,17.663502167006,7.06540086680241,653.905499015575,268.380166748156,81.3565113734852,9.1249256694373,12.6371759903628,9.72929011395808,0.173233354782932 -4.0167248422012,0.528667944572995,15.1169935022014,0.230600775349538,17.7987773446922,7.11951093787687,663.668583303918,270.793262941119,104.323927275728,9.20697093999804,12.7339572634866,20.7774020625898,0.367053516878844 -3.26841455257459,0.536701394257397,15.1303946061369,0.227350464607316,18.0852594721741,7.23410378886962,684.597925489792,275.901655256233,97.9628815395287,9.38065627871194,12.9389180367722,17.153844815493,0.29809549629111 -4.93448854908464,0.543238223362546,15.140674484156,0.22476734576244,18.317968525841,7.32718741033639,701.852320130267,280.049134541717,117.192654439197,9.52167057441837,13.1054074021277,26.2016060851972,0.449364964391523 -4.73524779695389,0.553107200460715,15.1552003436659,0.220968661243978,18.6686433928723,7.46745735714892,728.283018227318,286.295463460179,117.17106733652,9.73404575764607,13.3562942289966,25.5833093017526,0.430266551740257 -7.1605637480004,0.562577696054623,15.1680906909191,0.217433632512271,19.0044450652437,7.60177802609746,754.077207229724,292.272694620644,146.2912733193,9.93727161710189,13.5965401774779,39.3244040277945,0.649320187396606 -1.8825382247838,0.576898823550624,15.1858006322826,0.212283556720695,19.510981315987,7.8043925263948,793.883686235923,301.281085760271,89.6779658124455,10.2435569158492,13.9589364727097,10.5919968601291,0.170213027491961 -3.40529396917268,0.580663900000192,15.1901259730612,0.210967163468821,19.643911460874,7.8575645843496,804.508998223118,303.643564797392,107.804204477731,10.3238812031113,14.0540400155677,19.2802234833689,0.307670500751777 -2.80729730873834,0.587474487938537,15.1976230803309,0.208624338538262,19.8841232522444,7.95364930089776,823.89822853601,307.911004959653,102.141487087847,10.4689741686282,14.2258971395857,16.0741916740617,0.253314236911191 -3.28931180225444,0.593089082556014,15.2035004880304,0.206729273071539,20.0819225549833,8.03276902199332,840.046504173767,311.423345290206,108.801479617725,10.588393739867,14.3674106727373,19.0077485234132,0.296502622481705 -5.37215315424785,0.599667706160523,15.210055895409,0.204549519395285,20.3134288504572,8.12537154018288,859.15596558391,315.532359457551,134.739143572098,10.7281002215567,14.5330395367711,31.3759806980666,0.483685556198223 -5.69364842064207,0.610412012469018,15.2200398301163,0.201080998059022,20.6909592982136,8.27638371928544,890.803283679541,322.228871763402,141.04909525273,10.9557816399557,14.8031399203139,33.8288388117205,0.511693877574235 -4.19237247795697,0.621799309310302,15.2297156540814,0.197524001223396,21.0903504367334,8.43614017469335,924.93697827169,329.307413264352,125.262225169105,11.196452050988,15.0888803164565,25.3579688387214,0.376082859682845 -3.83112582458423,0.630184054266216,15.2362916032446,0.19498005154078,21.3839756691964,8.55359026767856,950.460280962115,334.507731062184,122.479151585599,11.3732628561142,15.2989515527699,23.4751224188504,0.343236731570036 -7.53560514155128,0.637846305915385,15.2419231235586,0.192709017403503,21.651978006647,8.66079120265881,974.073510736204,339.251558826025,170.583006404223,11.5345530000848,15.4906911450756,46.7175462597354,0.674370167572335 -3.37525652151053,0.652917516198487,15.2520316242566,0.188385595397222,22.1782759449131,8.87131037796525,1021.32559046479,348.560099648313,121.088712735682,11.8510433880426,15.8672257420286,21.4040499364049,0.301429486340331 -3.17738150566599,0.659668029241508,15.2561747857618,0.18650845906323,22.4136640412306,8.96546561649224,1042.83693799205,352.720315166131,119.787387632254,11.9924907156485,16.035631801658,20.3512590265734,0.28350982130395 -7.05291590223014,0.66602279225284,15.2598736606517,0.184773702484046,22.6350675775558,9.05402703102233,1063.2833132038,356.631692092436,171.758610676945,12.1254775311428,16.1940327476865,45.5965020660648,0.628814124587998 -2.77717783466472,0.680128624057301,15.2674353507162,0.181031167164102,23.1259141200635,9.25036564802539,1109.34868475497,365.297484806032,118.200889582143,12.4201144834051,16.5452039980582,18.3235118087884,0.2471915221117 -3.90877011453918,0.68568297972663,15.2701840222934,0.179597057214651,23.3189722705212,9.32758890820847,1127.74493853369,368.703815393531,134.432513628376,12.53592972338,16.6833255212217,25.9944058905176,0.347696638782448 -2.04632912417107,0.693500519955708,15.273849310733,0.17761515755847,23.5904952519697,9.4361981007879,1153.88349336412,373.492668007137,110.599973501744,12.6987507122427,16.8775839230692,13.7595981208754,0.181874028543112 -5.39361726544622,0.69759317820405,15.275677711591,0.176594257421178,23.7325540015589,9.49302160062356,1167.68261409078,375.99728503748,157.132665011288,12.7839076912743,16.9792184348753,36.4752480793978,0.47917106667856 -2.01159278058089,0.708380412734943,15.2802166920773,0.173956749442865,24.106703316468,9.64268132658721,1204.43253465662,382.591063779503,112.532835604944,13.0080961685031,17.2468998207339,13.8086404042661,0.178518826091763 -3.24272336527191,0.712403598296105,15.2818106836296,0.17299240070335,24.2461442917626,9.69845771670506,1218.27940068484,385.047475541401,130.397275836017,13.0916141684076,17.3466614720987,22.3830198191459,0.287665128939845 -1.22807840044806,0.718889045026649,15.2842734809767,0.171459380081815,24.4708148588027,9.78832594352106,1240.76178254007,389.004181418551,103.179274884822,13.2261421682307,17.5073997825818,8.55212261392499,0.108878696323 -3.06924173777533,0.721345201827545,15.2851729719422,0.170885622660239,24.5558669076722,9.82234676306886,1249.32816082707,390.501690277517,129.594570386947,13.2770574694356,17.568249420425,21.4449191911359,0.272051935081801 -2.4712809976844,0.727483685303095,15.2873443892178,0.16946776661466,24.7683498467462,9.90733993869848,1270.86214251068,394.242036402654,122.177075285995,13.4042292376902,17.7202682143561,17.410373685769,0.218931719606793 -6.24824272188956,0.732426247298464,15.2890160779638,0.168342569934592,24.9393541528058,9.9757416611223,1288.33027640702,397.251383076148,177.257864740946,13.506547024589,17.8426115350834,44.3114630457955,0.553301683260023 -4.09674871424538,0.744922732742243,15.2929562615094,0.16556118777248,25.3714004483227,10.1485601793291,1333.0111407072,404.851304473221,148.869716693407,13.7649443520895,18.151714736748,29.5379055429178,0.362414333361263 -4.64710260130901,0.753116230170734,15.2953317434718,0.163785408682753,25.654447957117,10.2617791828468,1362.70795770396,409.827819050208,158.633180012678,13.9341458477071,18.3542182464398,33.8665527941661,0.410845360767617 +"P0","dD","D","H","fc","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","NPP","turnover","dWs","dWfr" +7.49554772192574,3.61065392785234,0.04,4.2375677628595,0.85434833928619,0.377501266657307,0.151000506662923,1.06501694023107,1.04242323817797,2.5728851656008,0.0354423900980509,0.270079506217303,1.13368163464272,0.42518563718244,0.547381112549485,0.161114884910798 +7.08599881624794,3.38755026387756,0.0472213078557047,4.86692916274892,0.831180467338634,0.511840683012919,0.204736273205168,1.70471163286376,1.65612729233048,3.2978773047212,0.0563083279392362,0.366191298254763,1.4376888392636,0.576494242972445,0.6900087497602,0.171185846530957 +6.35441155201201,2.79790820356479,0.0539964083834598,5.42489641651488,0.810223604848407,0.652376170769326,0.26095046830773,2.48451185764506,2.39503196394162,3.76939842353647,0.081431086774015,0.466736007615206,1.61061566457362,0.734781581813872,0.720285077549637,0.155549005210115 +5.77593157999703,2.29241120672,0.0595922247905894,5.86323566020654,0.793461877219925,0.778159664033028,0.311263865613211,3.27066773057914,3.1311475990825,4.08685633908433,0.106459018368805,0.55672655003579,1.71183538533987,0.876453516331937,0.699108609666685,0.136273259341245 +8.33987285919221,4.85691339032518,0.0641770472040294,6.20788347303686,0.78008538218186,0.887288909826318,0.354915563930527,4.01626994991319,3.82203333893048,6.72857502874762,0.129949133523636,0.634801977646141,2.98191195878892,0.999367508962274,1.67951212075214,0.303032329074508 +5.72975308173827,2.33118006371596,0.0738908739846797,6.89719483287688,0.752766017984117,1.13502404877275,0.454009619509099,5.91526190246491,5.55369363714836,5.91343171974879,0.188825583663044,0.812041605453975,2.45628226531588,1.2783955075651,1.01922771023309,0.158659047517701 +6.2657770763125,2.90848200486772,0.0785532341121116,7.20929498679816,0.740128351902204,1.26124260254576,0.504497041018302,6.98780558177195,6.51589619635768,7.1857513935746,0.221540470676161,0.902343407565335,3.03093375766655,1.42055745760417,1.40526579674485,0.205110503317538 +6.99889959249982,3.7141526111863,0.0843701981218471,7.58253873483704,0.724776132892248,1.42477233009401,0.569908932037605,8.47837560281049,7.83615410675804,9.06721370301643,0.266429239629773,1.01933911584246,3.8907226737721,1.6047435717901,2.01345046738777,0.272528634594234 +5.35906670175618,2.00948647245774,0.0917985033442197,8.03433914797226,0.705818235423524,1.64258376793897,0.657033507175587,10.6350916943143,9.71469990449124,8.00415159891184,0.330299796752702,1.17517013093425,3.24934083561244,1.85006803336284,1.24515927139619,0.154113530853421 +6.7339708545309,3.50841693125576,0.0958174762891352,8.26769531337178,0.695853875376714,1.764293999459,0.705717599783598,11.9232265565485,10.8202700920997,10.8029111869906,0.36788918313139,1.26224649897294,4.58638775244311,1.98715218886434,2.3243704214175,0.274865142161265 +5.20657779130872,1.86859022630884,0.102834310151647,8.65736875115767,0.678931864527832,1.98273978469815,0.79309591387926,14.3807610876729,12.8983239604302,9.38678128610371,0.438543014654628,1.41853135156444,3.76485345994232,2.23319112592318,1.38029995740751,0.151362376611625 +7.7135752048239,4.6541230076348,0.106571490604264,8.85605742826326,0.670158759766913,2.10195410960806,0.840781643843226,15.7994650177428,14.0805583698836,14.7427182085259,0.478738984576041,1.50382204817799,6.38007858788593,2.36746410240066,3.62953443806943,0.383080047415842 +5.00211904801865,1.65965683079547,0.115879736619534,9.32559398076352,0.649003917894614,2.40672111599011,0.962688446396043,19.6703179117587,17.2469691749055,10.9465788109412,0.586396951946786,1.72186455522396,4.31915865188523,2.71072799379938,1.46693381851576,0.141496839570078 +6.00248775076181,2.79965176697874,0.119199050281125,9.48466121777122,0.641693060378643,2.51788786024386,1.00715514409754,21.1683637820799,18.4506874667532,13.7425169930029,0.627323373869608,1.80139769073286,5.6568979642002,2.83593685311676,2.57960784223324,0.241353268850204 +6.55514448244711,3.45092930924139,0.124798353815082,9.74349770320583,0.629628452448352,2.70810506612105,1.08324202644842,23.8370483601978,20.5671992672918,16.1415930625443,0.699284775087922,1.93748668850564,6.75241079947536,3.05018149552581,3.39956982159194,0.302659482357608 +7.18895695430233,4.21444280798718,0.131700212433565,10.0468304180054,0.615206494010232,2.94684513518015,1.17873805407206,27.3729686358531,23.319961505257,19.2629063175042,0.792878691178739,2.10829088351328,8.18086837140611,3.31907820488711,4.48514962191931,0.376640544599687 +7.2606968482581,4.34072848861625,0.14012909804954,10.3950261981069,0.598240177116599,3.24411081403222,1.29764432561289,32.0628496504997,26.8875544593077,21.4176886637257,0.914176851616461,2.32096664079121,9.09127258565901,3.65389323264682,5.04168854884585,0.39569080416634 +5.20241097246857,1.92655029061938,0.148810555026772,10.7296815309437,0.581475485728199,3.5560047638444,1.42240190553776,37.3227969288469,30.7852324702318,16.8215343724606,1.04669790398788,2.54410804824483,6.61536421011394,4.00518431296158,2.4315022956229,0.178677601529461 +6.23606547081245,3.170931796341,0.152663655608011,10.8708467164419,0.5742566449875,3.69607517161585,1.47843006864634,39.7973875436604,32.5838163780909,20.9580116657696,1.10784975685509,2.64432002078084,8.60292094406686,4.16294782487259,4.14389284974421,0.296080269450059 +4.67703748513476,1.30032350754141,0.159005519200693,11.0938223098119,0.562661657279793,3.92857610292046,1.57143044116818,44.058071263053,35.6313119284455,16.7072371599917,1.21146460556715,2.81066048707341,6.34255603367555,4.42481729486831,1.79510047838872,0.122638260418522 +7.18040640219089,4.34319526832161,0.161606166215776,11.1820033525403,0.558007460377776,4.02456838754282,1.60982735501713,45.8728106508254,36.9112173982758,26.2764658800844,1.25498139154138,2.87933720718363,11.0710736406797,4.53293492070612,6.12698025562813,0.411158464345466 +6.97283473021944,4.12408693641248,0.170292556752419,11.4634457132701,0.542872481404793,4.34763033608228,1.73905213443291,52.2187399081297,41.3068212495623,27.5651651244913,1.40443192248512,3.1104686476467,11.5251322771797,4.89680469432425,6.23355651778481,0.394771065070671 +5.57430249516482,2.41596964764401,0.178540730625244,11.7129939774782,0.52906487231141,4.6574370475189,1.86297481900756,58.6492431885744,45.6420202222313,23.6067468123993,1.55182868755587,3.33211676127692,9.36140068178324,5.24574488510023,3.88236473697906,0.233291059703955 +6.87219974333148,4.04568241298336,0.183372669920532,11.851634712428,0.521221070376491,4.84010330924281,1.93604132369713,62.5989935992691,48.2494724037077,30.2446819398938,1.64048206172606,3.46280351156468,12.5706981833015,5.45148477988401,6.72683846978225,0.392374933635247 +6.551618602613,3.66762266841177,0.191464034746498,12.0719993980702,0.508475829334236,5.14764012566635,2.05905605026654,69.5141946063924,52.7198425268872,30.665877830475,1.79247464591416,3.68282765150673,12.595287766527,5.79786835206631,6.43947900138394,0.357940413076782 +8.10479390458318,5.66565175194636,0.198799280083322,12.2596824694285,0.497327791982356,5.42794945763765,2.17117978305506,76.1077203338098,56.8768711278062,40.0015101308951,1.93381361834541,3.88337215997228,17.0921621762887,6.11358517860241,10.4230816277748,0.55549536991145 +6.18408442042872,3.24343458596136,0.210130583587215,12.5285831628013,0.480829393158744,5.86317683170863,2.34527073268345,86.8961170558696,63.4743011155386,32.9690944307129,2.15812623792831,4.19475123247762,13.3081084801535,6.60378864202972,6.38458886308816,0.3197309750356 +6.23580676582209,3.32377437659101,0.216617452759137,12.6717849414995,0.471761682831625,6.1132619304899,2.44530477219596,93.3995018494875,67.3377046289707,34.6628501141491,2.28948195738501,4.37367211554969,13.9998480206072,6.88546343749915,6.78598949127018,0.32839509183787 +3.3279466719316,-0.464249369128925,0.223265001512319,12.8109427106352,0.462741824371095,6.37005972585542,2.54802389034217,100.309546042038,71.355561979679,19.2760692997857,2.42608910730909,4.557395530266,6.1462923311053,7.17469884912136,-0.9824563417916,-0.0459501762244662 +6.67747861451358,3.91240430483846,0.222336502774062,12.791952456892,0.46398547077648,6.33416500562717,2.53366600225087,99.3295010652287,70.7909856167037,38.4592220101489,2.40689351096793,4.5317150116259,15.7603067437776,7.13427005896955,8.2388810435577,0.387155641250312 +5.36289499732994,2.20211185134877,0.230161311383739,12.9476141218965,0.453665484832205,6.63687803566206,2.65475121426482,107.739330226129,75.5811438397416,32.3639667886737,2.56975889055122,4.74828802183406,12.5229599381442,7.47522052437726,4.82949459875284,0.218244815014085 +6.75433456765573,4.04527818179217,0.234565535086436,13.0309914948291,0.4480139891336,6.80743382616914,2.72297353046766,112.622649674141,78.307817150387,41.8085026377729,2.66246578311316,4.87031045659445,17.1378631990326,7.66732020421156,9.06939551437222,0.401147480448848 +5.06424265808234,1.81465382950048,0.24265609145002,13.1766263730268,0.437916539727146,7.12093784980933,2.84837513992373,121.872720161289,83.3685190854907,32.7906721299447,2.83452964890668,5.09460377526759,12.4307693528852,8.02042473610103,4.23028967741247,0.180054939371691 +6.42306065245781,3.63231366107183,0.246285399109021,13.238922870693,0.43350319348187,7.26161272521444,2.90464509008578,126.139138466167,85.6587387337746,42.4105322428931,2.91239711694834,5.19524820812742,17.1514434589087,8.17886906945205,8.6121370675439,0.360437321912728 +5.0340492653364,1.77879551704734,0.253550026431165,13.358257229889,0.424878208070108,7.54319314480357,3.01727725792143,134.895356256072,90.276683552331,34.5279906761785,3.06940724077925,5.39670210351827,13.0309406659405,8.49601754204192,4.35843754320852,0.176485580690032 +6.81449196847425,4.18261741574216,0.25710761746526,13.4141881663647,0.420753526838383,7.68105904850526,3.0724236194021,139.288146382358,92.5532853847666,47.5941093468675,3.14681170308206,5.4953368856626,19.4759803790614,8.65129808621119,10.4097852809364,0.414897011913835 +5.98245408442601,3.07220822206233,0.265472852296744,13.5395312324696,0.411302952671544,8.00507693538821,3.20203077415528,149.886920684066,97.941477898273,43.5455219527452,3.33001024854128,5.72715224265414,17.2441797307749,9.01624454827935,7.92343417125971,0.304501011235845 +7.83262355085145,5.60789750415318,0.271617268740869,13.6263431418686,0.404576132278857,8.24287027202539,3.29714810881016,157.911570914187,101.927247645222,58.7062494020637,3.46552641993756,5.89727910741785,24.6717219373541,9.28407493796544,14.8322992417785,0.555347757610214 +7.38672788528102,5.03143700949309,0.282833063749175,13.7740976524124,0.392745569447481,8.67631081249967,3.47052432499987,173.078606776226,109.254495690446,58.2754744871514,3.71465285347515,6.20737980769476,24.1767209129907,9.77226586249962,13.907218427454,0.497236623037079 +7.18290247616099,4.77651246317387,0.292895937768161,13.8957243535589,0.382601049464071,9.06434244907842,3.62573697963137,187.252560236874,115.875355165027,59.2017972088435,3.93976207561091,6.48499316176867,24.3885209857319,10.2093120215936,13.7082515947005,0.470957369437847 +5.53497045587379,2.49683999195698,0.302448962694509,14.0023794891102,0.373360233173681,9.43182444828823,3.77272977931529,201.199047020638,122.192728883623,47.4689507383995,4.15455278204319,6.74790448328333,18.2832467365365,10.623212799651,7.41446743075709,0.245566506128466 +7.13212333202592,4.74103260845525,0.307442642678423,14.054936735668,0.368674504648594,9.62353799757707,3.84941519903083,208.678151574156,125.504908160801,62.4097188705728,4.26716687746725,6.88506402498654,25.6287439840595,10.839142797271,14.3239789862833,0.465622200505186 +5.69657018653438,2.73660490087346,0.316924707895333,14.1490749477971,0.360039593899634,9.9867898585003,3.99471594340012,223.233887083183,131.808600120106,51.729464238817,4.48149240408361,7.14494893636546,20.0515114491839,11.2482791037846,8.53523790494435,0.267994440455052 +6.50193147440236,3.88239647354101,0.32239791769708,14.2002155751928,0.355206597982672,10.1959789793603,4.07839159174413,231.845820252996,135.453942540026,60.2795408637502,4.60543404636088,7.29461120099355,24.1897478081979,11.4838921135953,12.3263171922538,0.379538502348794 +7.41263388855764,5.19112664856163,0.330162710644162,14.2689917414792,0.348532739568545,10.4921157675851,4.19684630703402,244.32573084299,140.631547243974,70.7186954883545,4.78147260629512,7.50647930476105,29.2153717886492,11.8174356540168,16.8917581428071,0.50617799182525 +7.16696829889936,4.86350822307832,0.340544963941286,14.3544554431176,0.339930845268513,10.8868678073294,4.35474712293177,261.490263696711,147.561233638435,70.9474922630505,5.01708194370679,7.78890070407576,29.070754807634,12.2620511093079,16.3361585145046,0.472545183821431 +7.2094684163364,4.94451615189935,0.350271980387442,14.4282685290147,0.332190442802598,11.2554115674708,4.50216462698831,278.064078935726,154.055951575887,73.7841774265725,5.23790235358015,8.05257165183129,30.2468517105805,12.6771477654671,17.0909388474489,0.478765097664555 +5.68878302556488,2.76246573740402,0.360161012691241,14.4975882515111,0.324621572481555,11.6287819105309,4.65151276421238,295.399010174927,160.656881256254,60.1522963909355,5.46233396271264,8.31969573007026,23.1851333490763,13.097680678177,9.82092285210033,0.266529818799025 +5.89121188037656,3.06065351919607,0.365685944166049,14.5339694116652,0.320519376282107,11.8367990658652,4.73471962634609,305.295676722477,164.342519585556,63.4070479647673,5.58764566590889,8.46851952368262,24.6754413875879,13.3319736847114,11.0487618098663,0.294705893010187 +6.28626755207343,3.64158141155067,0.371807251204441,14.5724238162145,0.316076532999988,12.066780553253,4.8267122213012,316.437089494701,168.423226758122,68.9735997007119,5.72638970977613,8.63305747901933,27.3070762559582,13.5910054652429,13.366212601255,0.349858189460316 +7.40658762005926,5.28764597861629,0.379090414027543,14.6157645448772,0.310926007487322,12.3397427665913,4.93589710663653,329.933960584255,173.273738453659,83.1041836508507,5.89130710742441,8.8283455649301,34.1922654892481,13.8984471160555,19.7871720056766,0.506646367515954 +7.26273558931264,5.09625056256649,0.389665705984775,14.6743204655469,0.303699535934052,12.7347947795468,5.0939179118187,349.995328476521,180.305575701047,84.0989939109844,6.1303895738356,9.11098157707893,34.4288113800349,14.3434004359106,19.5989895246071,0.486421419517219 +6.87768770725305,4.54538602272207,0.399858207109908,14.7262091163153,0.297004660217925,13.1141076228891,5.24564304915566,369.847654672612,187.068038436844,82.012454870514,6.36031330685271,9.38235715771981,33.1348922029707,14.7706264805172,17.9320262474063,0.432239475047225 +6.25249711590599,3.63181843408895,0.408948979155352,14.7690143896017,0.291246489967656,13.4512426730981,5.38049706923923,387.980275855902,193.085547178073,76.4741263371155,6.56490860405448,9.62355705804129,30.1428303375099,15.1503470107526,14.6482449952643,0.344238331492962 +5.40785979714781,2.38378677271132,0.41621261602353,14.8010246850072,0.286783960176011,13.7198318571151,5.48793274284606,402.756112549317,197.883293371931,67.4641151905997,6.72803197464567,9.81571650385446,25.4601833560498,15.4528632495928,9.78195687050845,0.225363235948482 +6.51606717278862,4.03555716784701,0.420980189568953,14.8210355232272,0.283919488345541,13.8957494007782,5.5582997603113,412.592893976931,201.027099703529,82.331521688079,6.83492138991999,9.94157495129278,32.7775126734331,15.651001956666,16.7456271206353,0.380883596131786 +6.81072797432145,4.48403889908773,0.429051303904647,14.8532018285054,0.279183129438466,14.192897761008,5.67715910440321,429.49529607399,206.339435424981,87.8948086817728,7.01554080444935,10.1541667741356,35.3625505515939,15.985684846609,18.9548356425842,0.422030062400648 +6.28010110327007,3.6995795894813,0.438019381702822,14.886564190121,0.274081335283369,14.5221048492058,5.80884193968232,448.643114724425,212.227077647555,82.9267833378028,7.21572064001688,10.3896946933158,32.660684002235,16.3564759880528,15.9570699138556,0.347138100326614 +7.42053823875698,5.41879423743201,0.445418540881785,14.9123251050803,0.269994792074025,14.7929714786627,5.91718859146507,464.731191425483,217.072405885199,99.8135365428054,7.38046180009678,10.5834835146944,40.9247956140071,16.6615573496516,23.7560348384023,0.507203425953108 +6.78755133002097,4.47953479755171,0.456256129356649,14.9473804311299,0.264201142335562,15.18852378674,6.07540951469599,488.76757700008,224.148830880891,93.7405093192867,7.62106024995029,10.8664774579852,37.6264858056756,17.1070741598019,20.1015973590173,0.417814286856415 +5.51037714419897,2.55777459723717,0.465215198951752,14.9741270295109,0.259576835021232,15.5144782136282,6.20579128545127,509.060242608168,229.979946228433,77.7350915225599,7.81931817176674,11.0996782931581,29.4080475288175,17.4742017774549,11.6959508430542,0.237894908308447 +6.53341105025317,4.10874991554916,0.470330748146227,14.9885519230022,0.257000885462646,15.700186612128,6.28007464485118,520.818374324197,233.301796888001,93.2703085460434,7.93226109419202,11.2325415097808,37.0527529710353,17.6833680789231,18.9878386973057,0.381546194806504 +7.35868664298159,5.3681610873227,0.478548247977325,15.0105097969767,0.252957771498207,15.9978985594018,6.39915942376073,539.966455001518,238.626246299909,107.043885434628,8.11329237419692,11.4455365453385,43.7425282575464,18.0186857458526,25.2265797462809,0.497262765412957 +6.0316230754951,3.36004670521656,0.48928457015197,15.0370846790265,0.247845158677226,16.3857729014802,6.55430916059209,565.46608582439,245.561052363696,89.866896069447,8.34907578036568,11.723037364635,34.8973914622232,18.4555547416672,16.1315635528532,0.31027316770276 +5.42943672524085,2.44528069453826,0.496004663562403,15.0525816542392,0.24473920600328,16.6279426295475,6.65117705181901,581.704453172888,249.88925809508,82.0903126808989,8.49623477523273,11.8962952748835,30.8488913153913,18.728314330122,11.8952038476299,0.225373137639491 +6.07859555209321,3.43801375532007,0.50089522495148,15.0633416413604,0.242522898148294,16.8038959419706,6.72155837678824,593.656170582682,253.033143584953,92.877784605587,8.60312688188842,12.0221793127234,36.1262392054876,18.9264933241142,16.8833044486598,0.316441432713569 +6.59488898103451,4.23143433893329,0.50777125246212,15.0777678087915,0.23946787277579,17.0508850458357,6.82035401833429,610.651104976192,257.444938832627,102.247578544478,8.75312792030932,12.1988851971927,40.6477827134882,19.2046810516255,21.0543558773463,0.388745784516374 +6.44038096704321,4.00048657237704,0.516234121139987,15.0944563316087,0.235802868428029,17.3542539179589,6.94170156718356,631.87440669065,262.861487108082,101.628641825705,8.9372905616748,12.4159274230645,40.1377119204829,19.5463702023326,20.22462828527,0.366713432880225 +6.08965058184416,3.46675245243097,0.524235094284741,15.1092173499408,0.232431075950571,17.6404567340137,7.05618269360548,652.249909503733,267.969013642916,97.678912458599,9.11094646385916,12.6206883657828,37.9736388144786,19.868724953047,17.7877704505183,0.317143410913272 +5.5636508442556,2.66095981736198,0.531168599189603,15.1212587202954,0.22957990179981,17.8880130512878,7.15520522051512,670.150903536486,272.384759609614,90.4941669921769,9.26108182672687,12.7978000574133,34.2176425540184,20.1475515419768,13.8270770031237,0.24301400891783 +7.01090558635489,4.8909224496964,0.536490518824327,15.1300538464317,0.227434705733596,18.0777464421399,7.23109857685597,684.044654127675,275.767722402038,115.243655517091,9.3761025616693,12.9335429145646,46.4670050204287,20.3612512558839,25.6596553225768,0.446098441967952 +5.95807993135232,3.27355597302444,0.546272363723719,15.1452644130134,0.22358668907325,18.4258637511101,7.37034550044405,709.929456786471,281.971464616411,99.8235009201741,9.58702979695798,13.1825999620942,38.526935580561,20.7533412775661,17.4756902433374,0.29790405965746 +5.71913647020711,2.90682293927807,0.552819475669768,15.1547930544999,0.221077726815051,18.6584305673575,7.463372226943,727.505961879502,286.113611863246,97.0295878934718,9.72786280335035,13.3489875651103,36.9763687625056,21.0152849548132,15.6969397179134,0.264144089779039 +6.68411895887111,4.40092226410899,0.558633121548324,15.1628414276841,0.218893177899297,18.8646625321069,7.54586501284276,743.282372641521,289.785083647431,114.654690770338,9.85269284401266,13.4965341619706,45.6527318821773,21.2475672730046,24.0057549924555,0.399409616717252 +6.84917101948242,4.66138698484383,0.567434966076542,15.1743286140087,0.215661045178526,19.1764116874361,7.67056467497442,767.470250782624,295.332072163432,119.427398303836,10.0412904535567,13.7195719776593,47.8332679363103,21.5986952690069,25.8123039888752,0.422268678428167 +7.48997215015155,5.66086761637489,0.57675774004623,15.1856359803041,0.212333182183145,19.5059983115286,7.80239932461144,793.486833760507,301.192513237355,132.845547010564,10.2405454500701,13.955371432,54.3248150642468,21.9699138877217,31.843049639437,0.511851537088072 +7.10381833493448,5.06839671246445,0.58807947527898,15.1982692936373,0.208418577767519,19.9054464864502,7.96217859458008,825.631125131241,308.289714279991,128.576732949039,10.4818502855197,14.2411526342659,51.9268650146265,22.4198186742123,29.0497550333653,0.457291307048847 +5.43845659824591,2.48118256809504,0.598216268703909,15.2086394213556,0.205026717477764,20.2623750087988,8.1049500035195,854.922367460624,314.626375333314,100.19928721262,10.6972967613327,14.496513576295,37.5027384374959,22.821832904647,14.4574535291694,0.223452003679477 +5.95859577092069,3.29230975306861,0.603178633840099,15.21341426256,0.203403797506841,20.4368711304243,8.17474845216971,869.43769810791,317.722521945667,110.727870238116,10.8025657461527,14.6213550815507,42.6519747052062,23.0183706416358,19.3373592453172,0.296244818253236 +4.7356759676816,1.38680947509147,0.609763253346236,15.2194612834219,0.201287287027848,20.6681828257366,8.26727313029464,888.876970406358,321.825020050617,88.9985414997134,10.942050681721,14.786844720845,31.6348230485737,23.278900656356,8.23127501265384,0.124647379563903 +5.59063918752794,2.72061149549533,0.612536872296419,15.2219136091298,0.200408127849253,20.765541242261,8.30621649690439,897.126330029877,323.551156961245,105.56096114453,11.0007393366823,14.8564988263632,39.8518614907423,23.3885569781255,16.2188860620114,0.244418450605366 +6.36631446572492,3.93254541736741,0.61797809528741,15.2265675935955,0.198704292085372,20.9564088142651,8.38256352570605,913.414822128932,326.934172368727,121.311944809644,11.1157618605367,14.9930531220778,47.6015649135147,23.6035341381723,23.6450433413048,0.352987434037641 +7.38612001543715,5.52886448979596,0.625843186122144,15.2329428632823,0.196289288015978,21.232009855481,8.49280394219241,937.205322945592,331.816693083621,142.595586400059,11.2817675648431,15.1902291310053,58.0617948521054,23.9139479424891,33.652181942224,0.495664967392212 +5.18193144907903,2.08462756429157,0.636900915101736,15.2412470181734,0.192986506205585,21.6189272720202,8.64757090880809,971.14510313428,338.666675132512,101.864866477985,11.5146669545054,15.4670453274941,37.4415770979925,24.3497391379596,12.9052568304116,0.186581129621218 +6.32218351314554,3.87031908744509,0.641070170230319,15.2441902093951,0.191768426494613,21.7646503178376,8.70586012713504,984.09125900016,341.245181139771,125.117312747972,11.6023361587522,15.5713014233937,48.9718375829132,24.5138693053539,24.1117675697844,0.346200707774918 +5.61183338577813,2.7590473842904,0.64881080840521,15.2493981748366,0.189545266425647,22.0349741953983,8.81398967815932,1008.34403514711,346.026490001672,112.438729833003,11.7649006600569,15.7647019383558,42.4545636172954,24.8183393569223,17.389690497614,0.246533762759127 +7.57161989144796,5.8330723566409,0.65432890317379,15.2529166735537,0.187990155917028,22.2275076303486,8.89100305213944,1025.80540658585,349.43036715012,153.030567135017,11.8806324831041,15.9024480590566,62.623743296428,25.0351928047084,37.0677209060573,0.520829585662331 +5.93950412000593,3.27558365937069,0.665995047887072,15.2598579213945,0.184781209296159,22.6341013283293,9.05364053133173,1063.1936325335,356.614625549939,122.239639370745,12.1248972686979,16.1933414543399,46.9607003238537,25.4931457066446,21.175513662546,0.29204095466312 +7.53210296905252,5.77887893408135,0.672546215205814,15.2634780243207,0.183024693216948,22.8621676194293,9.14486704777173,1084.47026544404,360.642048755087,156.578550850343,12.2618296576729,16.3565092016445,63.9801059955126,25.7500203713572,37.7152656886097,0.514819935545742 +6.41625622548012,4.02823792749009,0.684103973073976,15.2694151449183,0.180002528217692,23.264101358431,9.30564054337242,1122.50040213469,367.735785929765,135.727108241786,12.503016721612,16.6440686758759,53.290011422149,26.2027246879171,26.7289005716234,0.358386162608547 +5.52427553963096,2.62586430212311,0.692160448928956,15.273237357374,0.177951902917416,23.543967321616,9.41758692864639,1149.38238488789,372.672211369886,118.264280711273,12.6708551865761,16.8442959805769,44.3745647720598,26.5179421411885,17.6232075453297,0.233415085541558 +6.22179039268345,3.72468424062592,0.697412177533203,15.2755981220999,0.176639168923064,23.726272626598,9.49050905063918,1167.07066759598,375.886551540165,134.228120335686,12.7801427523656,16.9747244879732,52.2366265476738,26.7232754846945,25.1824425033701,0.330908559609169 +6.37132286911498,3.96151643343558,0.704861546014454,15.2787793456806,0.174808745294554,23.9846973565391,9.59387894261563,1192.38408882768,380.441343792199,138.951254712618,12.9350056889348,17.1596118767623,54.4283185734606,27.0143433384177,27.0622897867807,0.351685448262156 +6.87780808885136,4.76148782572525,0.712784578881326,15.2819589573353,0.172901614521543,24.2593460691752,9.7037384276701,1219.59460992539,385.280012028103,151.714733913382,13.0995204089555,17.3561065517307,60.6295534763478,27.3236845200184,32.88348791259,0.422381043739328 +5.44125529061371,2.49682575096735,0.722307554532776,15.2855205597451,0.170661827252321,24.5891862465546,9.83567449862182,1252.69234868709,391.088290430448,121.658336871062,13.2970018746352,17.592087408235,45.3846237940959,27.6951887198035,17.4681400318898,0.221295042402561 +6.16230460270366,3.63522754428419,0.727301206034711,15.2872813820759,0.16950958729597,24.7620349894143,9.90481399576573,1270.21943066246,394.130892687583,138.748440635149,13.4004503513778,17.7157503128266,53.8161199854723,27.8898709880772,25.6041977407638,0.322051256631316 +6.26601053832213,3.79989777828915,0.734571661123279,15.2897211626399,0.167858643955803,25.0135596967836,10.0054238787134,1295.94861500313,398.557026593786,142.516529508522,13.5509389041887,17.8957011494669,55.5349447274332,28.1731672374299,27.0253445852755,0.336432904727765 +6.52210848807147,4.20552573690953,0.742171456679858,15.2921226380485,0.166165875218883,25.2763165577554,10.1105266231022,1323.11058768964,403.17912141265,149.899581576864,13.7080901280301,18.0836879180805,59.0539017653767,28.4691144387351,30.2126699162645,0.372117410377132 +4.59312498536532,1.15698891165422,0.750582508153677,15.2946139021842,0.164330582129995,25.5669382869945,10.2267753147978,1353.49069250473,408.289432966216,106.77893937783,13.8818407208513,18.2916103280474,37.3027441644655,28.7964462811412,8.40399040699216,0.102307476332168 +6.26097339518806,3.79414222615425,0.752896485976985,15.2952700676471,0.163832551294727,25.6468590873164,10.2587436349266,1361.90736039773,409.694416686921,146.007330349787,13.9296101673553,18.3487888654297,56.8644656585008,28.8864623404512,27.6425618120644,0.33544150598521 diff --git a/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv b/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv index 650163fd..c0c3572f 100644 --- a/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv +++ b/pyrealm_build_data/t_model/rtmodel_output_alt_two.csv @@ -1,101 +1,101 @@ -"dD","D","H","fc","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" -13.8622301137606,0.6,33.5798055081921,0.5486896324868,63.0047820994125,3.00022771901964,474.723316320797,378.031173825666,115.15809469658,20.413683386586,9.09159005694522,54.2344803096022,0.847124524124768 -12.3430477961087,0.627724460227521,34.2904401617441,0.535554701465037,67.311024216857,3.20528686746938,530.604647281172,416.148218432024,113.887792896694,22.4720037953293,9.71298079449247,51.2223767918793,0.760997863293316 -14.741406831811,0.652410555819739,34.8869428416076,0.524254012043932,71.1750826285497,3.38928964897856,583.129157916036,451.147060188797,135.641872760139,24.361941250195,10.2705644232997,64.2840089316746,0.914952349386033 -19.0298305764337,0.68189336948336,35.5572669876616,0.511224587806007,75.8208986257463,3.61051898217839,649.263806288655,494.153771682077,173.075647784032,26.6843036708321,10.9409556716952,87.7591875111139,1.18899105189968 -14.5390796191973,0.719953030636228,36.3593725147542,0.495121794409489,81.8586599690667,3.89803142709841,740.090098186756,551.439650143114,154.41727833873,29.7777411077281,11.8122046335363,71.7303215643756,0.914510184815394 -12.4868007833764,0.749031189874622,36.9275363205345,0.483337242431468,86.4956612797278,4.11884101332037,813.598284362919,596.416028780328,147.741160175046,32.2064655541377,12.4813239226647,64.6557730970838,0.788469745041307 -18.7146970224615,0.774004791441375,37.3866887484073,0.473558004101625,90.4908648031101,4.3090888001481,879.557399267045,635.795828114243,203.095710309553,34.3329747181691,13.0578317910888,100.806392629914,1.18477073005195 -11.0687390245441,0.811434185486298,38.0282949227206,0.459466001654279,96.4948734575568,4.59499397416937,983.271247766531,695.982001096573,153.257224474973,37.583028059215,13.9242102399254,63.0554934884997,0.702631626557789 -9.99188887606772,0.833571663535386,38.3831042523623,0.451436823145604,100.052311256533,4.76439577412064,1047.33560235106,732.169740094757,149.857216821208,39.5371659651169,14.4375485143178,58.7406793651936,0.634929141101866 -21.0347270968238,0.853555441287522,38.6885647087163,0.44437611859738,103.266258153473,4.91744086445107,1106.89385008451,765.175907836751,251.116914597184,41.3194990231846,14.9013210515461,127.098974369283,1.33745039170142 -12.4552306793704,0.89562489548117,39.2884242360783,0.430069141343528,110.036015249726,5.23981024998697,1237.59005405231,835.594587822926,187.882810260862,45.122107742438,15.8781970005355,79.5108190198485,0.792243186444809 -18.3054962030954,0.92053535683991,39.6177544851137,0.421938554354454,114.044518881976,5.43069137533217,1318.3498980886,877.81664182726,250.306637699218,47.4020986586721,16.4566240746691,120.524625308205,1.1640416829933 -13.99074330282,0.957146349246101,40.0694719255813,0.410426222034006,119.932269840562,5.71106046859817,1441.55162168061,940.472257149687,220.049926562394,50.7855018860831,17.306226537993,96.2014724504743,0.888792984876516 -17.867254884771,0.985127835851741,40.3904786114689,0.401963146319784,124.427299986266,5.92510952315553,1539.30282541457,988.774127891341,267.880193507252,53.3938029061324,17.9548593880182,126.810022542905,1.13374633113883 -17.1528686872216,1.02086234562128,40.7721096122263,0.391557751679517,130.159075566422,6.19805121744864,1668.61997895163,1050.8935763278,272.250549032331,56.7482531217014,18.7819546042346,126.546064086742,1.08634159938043 -8.40531118471655,1.05516808299573,41.1107124063486,0.381973456700806,135.650292925283,6.4595377583468,1797.45563792297,1110.90521954064,187.104802373592,59.9888818551946,19.5743372691183,64.251205485062,0.531153932119961 -17.1989737308038,1.07197870536516,41.2673331587757,0.377415797170373,138.336457305956,6.58745034790269,1862.252673296,1140.42288546501,289.392443613045,61.5828358151107,19.9619507892495,133.70321301562,1.08554007511778 -21.3583204606377,1.10637665282677,41.5699263597697,0.368363067499233,143.822338130835,6.84868276813502,1998.22848670555,1201.0048298891,348.675981024856,64.8542608140114,20.7535633922796,171.674133706531,1.34446656824501 -19.5748171221695,1.14909329374804,41.9145166078147,0.357609460994775,150.613478554897,7.17207040737606,2173.37630403091,1276.49865749724,342.918367238594,68.9309275048512,21.7335249554717,163.695402992472,1.22772294033201 -21.0780833878178,1.18824292799238,42.202525286213,0.348203417127093,156.815058383416,7.46738373254361,2339.96197933298,1345.85537404615,375.210164626101,72.6761901984923,22.6284129247269,182.482107234984,1.31728725164999 -17.7663534548161,1.23039909476802,42.4855562554794,0.338528419843126,163.467491738421,7.78416627325813,2525.76650911221,1420.63088247799,347.672222114619,76.7140676538113,23.5883590578541,159.403745216442,1.1058413715811 -17.961493344503,1.26593180167765,42.7041279286451,0.330719174851472,169.053534234523,8.05016829688203,2687.51169699785,1483.67624590715,361.76877889196,80.1185172789863,24.3944249900416,165.883495383381,1.11406677023811 -14.3120378766119,1.30185478836666,42.9080320918417,0.323128958046347,174.680822711912,8.31813441485294,2855.77226919378,1547.38761743079,323.5717911128,83.5589313412627,25.2064427173289,135.963019708148,0.884503805661616 -18.1731030033039,1.33047886411988,43.0591107644497,0.317290380278803,179.150128345169,8.5309584926271,2993.23560096724,1598.11116153556,385.624346457602,86.2980027229201,25.8513635202079,176.449817507664,1.11986109194861 -22.9719408671974,1.36682507012649,43.2374435268256,0.310132228644101,184.806410104996,8.80030524309504,3172.09193268759,1662.43773722587,466.200039283889,89.7716378101969,26.6675649781509,229.121751040306,1.41033848654288 -21.1877155552395,1.41276895186088,43.4429680914385,0.301472828459206,191.926400481102,9.13935240386198,3405.03561551955,1743.58182433392,456.869049183795,94.1534185140318,27.694979589423,218.368272566596,1.29473553336646 -21.3947491682205,1.45514438297136,43.6145877259405,0.293849876560021,198.464094002247,9.45067114296413,3626.63485966028,1818.22065164125,474.936971946587,98.1839151886275,28.6383687645242,227.02111729222,1.30182369586748 -13.5347755477253,1.4979338813078,43.7720513408712,0.286486448833888,205.037657315724,9.76369796741544,3856.93281436455,1893.36219492829,366.752832565086,102.241558526128,29.586933950659,147.760948839182,0.82008002557811 -17.6368277176128,1.52500343240325,43.8641151913114,0.281993034163311,209.181985873333,9.96104694634917,4005.99959842948,1940.77058947476,439.554692813675,104.801611831637,30.1849605615219,195.945168293155,1.06581471338907 -16.0998553950522,1.56027708783848,43.9759671112557,0.276320748297705,214.566154295934,10.217435918854,4204.15526766759,2002.39013629592,425.484991663169,108.12906735998,30.9618960649033,182.902826056308,0.969660342354264 -19.7920696016182,1.59247679862858,44.0706033117677,0.271316190429117,219.465468602171,10.4507366001034,4388.89417150213,2058.47873031032,496.44298931256,111.157851436757,31.6688671192933,229.360488483547,1.18845407084183 -18.910940018121,1.63206093783182,44.1779281560208,0.265380374388152,225.468461861729,10.7365934219871,4621.02130778959,2127.2132488823,494.56484095972,114.869515439644,32.5350990466475,224.433731201404,1.13146301926763 -13.058600363945,1.66988281786806,44.2719194793058,0.259921487677705,231.184352075674,11.0087786702702,4847.97341717905,2192.65981808391,404.796489837738,118.403630176531,33.3599020045198,158.455094818293,0.778710202198632 -16.4399539926589,1.69600001859595,44.3323089161026,0.256267968634485,235.120388473342,11.1962089749211,5007.62664837409,2237.72139202606,471.440412873777,120.836955169407,33.9278720567033,202.500915622791,0.978154746329385 -14.6935227174881,1.72887992658127,44.4034588491079,0.251797722467204,240.063271497205,11.4315843570098,5212.02332592542,2294.29801799267,449.711735355037,123.892092971604,34.6411300770467,184.376783621595,0.871850412733737 -14.3134058999187,1.75826697201624,44.4627452648874,0.2479198405251,244.46977858479,11.6414180278471,5397.91194829848,2344.72034374724,450.915248203151,126.614898562351,35.2769890497852,182.551769046062,0.847279072396818 -17.7282741340238,1.78689378381608,44.5168483017949,0.244244897590513,248.75237433569,11.8453511588424,5581.89639562363,2393.7082158636,522.22473090368,129.260243656635,35.89496761664,229.65290364097,1.04706446719514 -17.426218288193,1.82235033208413,44.579203545209,0.239828208360615,254.043602367246,12.0973143984403,5813.74436127936,2454.20734256136,527.384303365834,132.527196498313,36.6584918215935,230.054436965634,1.02645766904937 -18.2064133954421,1.85720276866052,44.6358342019639,0.235626515882232,259.231077663008,12.3443370315718,6045.91707699399,2513.48831295304,553.005342952225,135.728368899464,37.4070445067721,244.779715595074,1.06968741081317 -23.839848701127,1.8936155954514,44.6904428721149,0.231378320836545,264.637001610767,12.6017619814651,6293.00660459123,2575.228657951,675.024612239864,139.062347529354,38.1871193324337,326.567639198958,1.39709934581536 -17.6836621503451,1.94129529285365,44.7555065240246,0.226024076471507,271.695324740703,12.9378726067001,6623.53087892323,2655.77935176076,568.565940068146,143.412084995081,39.2056353600834,248.106675837022,1.03303497617712 -17.6678815991345,1.97666261715434,44.7994541353125,0.222197926367538,276.916834439728,13.1865159257013,6873.8128852517,2715.32060925138,579.000089319932,146.627312899575,39.9590992096528,252.231682960526,1.02980270770222 -22.0848145576271,2.01199838035261,44.8400050444356,0.218493164251684,282.12226810841,13.4343937194481,7128.21502789123,2774.63678313316,681.726731080317,149.83038628919,40.7102432880436,320.714882897189,1.28449836086555 -17.1607536499745,2.05616800946787,44.8863632385484,0.214020635796945,288.613807824222,13.7435146582963,7452.32010629431,2848.54830006801,592.332894593995,153.821608203672,41.6469724690352,254.47623666154,0.995571763629735 -13.589198638998,2.09048951676782,44.9193353056355,0.210661491827151,293.646887760904,13.9831851314716,7708.84289502583,2905.80762285427,525.379036774768,156.913611634131,42.3732459038984,204.754955431424,0.786894195652328 -18.5038809032059,2.11766791404581,44.9436973374468,0.208070623716749,297.625913069181,14.1726625271039,7914.88111180313,2951.04650827356,640.021209303065,159.356511446772,42.9474192558828,282.301558720724,1.06995969301946 -23.0820377816011,2.15467567585222,44.9745631575913,0.204637335781827,303.035110322382,14.4302433486848,8199.56206002718,3012.50460704382,753.353385282024,162.675248780366,43.7279664195197,358.083759706918,1.33221390896508 -22.0173409128457,2.20083975141543,45.0096318616306,0.200501149763597,309.769011281346,14.7509052991117,8561.34877450423,3088.94823729255,745.601959520132,166.803204813798,44.6996683278982,348.63114292654,1.26799642730904 -20.1827821888325,2.24487443324112,45.0398536510714,0.196700174459217,316.179065567773,15.0561459794177,8913.35007672046,3161.6489711205,718.335669264893,170.729044440507,45.6246391614296,325.761072424495,1.16008032302053 -15.6225202249188,2.28523999761878,45.0650459939897,0.193333819148988,322.044378382595,15.3354465896474,9241.94410984372,3228.11563297323,624.158576944563,174.318244180554,46.4710038006084,256.541973253869,0.896456312334238 -12.3265626073557,2.31648503806862,45.0830342314669,0.190802238916924,326.57784909235,15.5513261472548,9500.18412305232,3279.45390194279,554.323124116062,177.090510704911,47.1251836240261,205.097839853446,0.706456008253428 -17.4908153612346,2.34113816328333,45.0963612480451,0.188848823892679,330.151011684642,15.7214767468877,9706.33945340721,3319.89587129263,684.878510478008,179.274377049802,47.6407909860939,294.025445424348,1.00149457143817 -17.7866771557451,2.3761197940058,45.1140468101674,0.186141531115577,335.215587522134,15.9626470248635,10002.4948368221,3377.18626896615,702.579214027836,182.368058524172,48.3716092794439,303.331231474001,1.01714946754942 -17.2737066128449,2.41169314831729,45.130659236927,0.18346340777557,340.359450706087,16.207592890766,10308.0297244357,3435.33638380422,700.604359823726,185.508164725428,49.1138687368883,298.863676245484,0.986613760008242 -21.6794728704231,2.44624056154298,45.1455684592484,0.180932169674432,345.349137752292,16.4451970358234,10608.9728409931,3491.70883907044,821.630601185485,188.552277309804,49.8338805776558,380.310793656884,1.23687146852062 -25.5303472256792,2.48959950728383,45.162712558406,0.177848561768132,351.60382829312,16.7430394425295,10992.5609675861,3562.32639373487,934.882681257224,192.365625261683,50.7364324226973,455.584345101233,1.45465230564751 -17.2364814260224,2.54066020173518,45.1808699820247,0.174344331998275,358.959342448633,17.0933020213635,11452.6936583803,3645.30899176331,737.903791870481,196.846685555219,51.7978331153378,313.724201012065,0.980674443166633 -13.4362788790797,2.57513316458723,45.1920006935769,0.172052784074257,363.919517139682,17.3295008161753,11768.4925906568,3701.2310225572,647.687461932444,199.866475218089,52.5135863232562,247.790974717023,0.763766730461611 -11.0522829326299,2.60200572234539,45.2000979171098,0.170306395204308,367.783050014908,17.5134785721385,12017.5449711272,3744.76942845789,590.98586531518,202.217549136726,53.0710941171512,205.900824006448,0.627828756738567 -14.1247240522206,2.62411028821065,45.2064010527437,0.168895344190442,370.959164444858,17.6647221164218,12224.2996543422,3780.5486571601,678.86361054017,204.149627486645,53.529407429393,265.322096560959,0.801932936748392 -18.6562257626199,2.65235973631509,45.214013234342,0.167124629997668,375.015804448515,17.8578954499293,12491.0168990086,3826.23103446205,809.597329974785,206.616475860951,54.1147805819207,354.128652749181,1.05851861702313 -22.5267379863495,2.68967218784033,45.2233537901538,0.164840241734053,380.369955794064,18.1128550378126,12847.5807767795,3886.49825471613,927.886737916347,209.870905754671,54.8873846210834,433.479442501871,1.27708134009851 -15.1534176531533,2.73472566381303,45.2336353791277,0.162161426057828,386.829286147238,18.4204421974875,13284.6131176518,3959.16707033183,736.996721183661,213.795021797919,55.8194659910465,296.376060174737,0.858284630632356 -14.0777837052047,2.76503249911934,45.2399879331865,0.160406539020383,391.171141807038,18.6271972289066,13582.5979785575,4007.99131824584,714.868918660774,216.431531185275,56.4459957627555,278.327880454584,0.796898247363505 -14.0803936170745,2.79318806652974,45.2455137286492,0.158809023009697,395.202595985809,18.8191712374195,13862.3150604319,4053.30959802796,722.387032787648,218.87871829351,57.0277346007522,281.158615675783,0.796636988780348 -17.8880670636792,2.82134885376389,45.2507012297171,0.157241925325788,399.232777177171,19.0110846274843,14144.8640431309,4098.59922129468,839.831023832703,221.324357949912,57.6092897466657,360.723579247162,1.01157152846378 -20.467214690467,2.85712498789125,45.2568347632555,0.155294031707995,404.350051679647,19.2547643656975,14507.8327740473,4156.08536250491,926.087170716903,224.428609575265,58.3477124573731,417.871860328847,1.15674165588026 -26.2003700636307,2.89805941727219,45.2632729003871,0.153122318614318,410.201577502252,19.5334084524882,14928.6456657332,4221.79401478515,1109.5629758553,227.976876798398,59.192087633575,542.454190786086,1.47982847495024 -25.3758576553513,2.95046015739945,45.2706945725985,0.150427497837571,417.687039112513,19.8898590053578,15475.9227138147,4305.81279473136,1104.90053306619,232.513890915494,60.2722397439356,534.726867609411,1.43219319161204 -9.71812013501909,3.00121187271015,45.2770948297807,0.147904614999951,424.931861532264,20.2348505491554,16015.1772737359,4387.09284081576,643.479165528653,236.903013404051,61.3176676191057,208.251184981355,0.54812203011442 -22.3493381090295,3.02064811298019,45.2793587575036,0.146960276514414,427.705160673543,20.3669124130259,16224.0929064123,4418.19738661931,1037.92963798767,238.582658877443,61.7178546851923,481.98390424159,1.26025018476479 -23.8138323781506,3.06534678919825,45.2842044513033,0.144832809880669,434.080667162182,20.6705079601039,16709.5924225032,4489.68496410294,1099.35444992056,242.442988061559,62.6378402715028,521.059819765733,1.34213991034561 -17.7855258196004,3.11297445395455,45.2888585236117,0.142631564590616,440.870478424095,20.9938323059093,17234.6462569397,4565.79155899649,924.799728784541,246.55274418581,63.6176100365969,395.123704632441,1.00188006395059 -24.8579862557682,3.14854550559375,45.2920231782769,0.141030022318368,445.939335641178,21.2352064591037,17631.9991236642,4622.59139170113,1163.08947800341,249.619935151861,64.349046133022,558.477347380212,1.39978982671127 -24.7640432852839,3.19826147810529,45.2960425980544,0.138850075905493,453.020979496039,21.5724275950495,18194.8332813654,4701.92352221739,1178.55683407801,253.903870199739,65.3709273412785,565.048363270423,1.39386746351611 -15.4619949824824,3.24778956467585,45.29962376784,0.136743452635781,460.072806512802,21.908228881562,18764.2082781331,4780.89760252996,888.378459991682,258.168470536618,66.3885059797973,358.204232958237,0.869933541911998 -15.5528620904625,3.27871355464082,45.3016656068653,0.135459828721314,464.47434744726,22.1178260689172,19124.1000878244,4830.17954811246,900.025951012955,260.829695598073,67.0236483366397,363.704521311151,0.874836281627671 -3.11889991605433,3.30981927882174,45.3035810027037,0.134192449047122,468.900720856844,22.3286057550878,19489.5126891104,4879.73126747861,488.425183153754,263.505488443845,67.6623740196426,73.620744420921,0.175395710247566 -20.226388472652,3.31605707865385,45.3039492316169,0.133941109721838,469.78824578751,22.3708688470243,19563.202140627,4889.66584146031,1068.71720924893,264.041955438857,67.7904438671377,478.32929597724,1.13740910639664 -20.5806262265707,3.35650985559916,45.3062157921895,0.132333466996077,475.54301072491,22.6449052726147,20044.4215786546,4954.07475593205,1094.06019760273,267.520036820331,68.6208564476045,492.588530153777,1.15701181257903 -15.4401979441994,3.3976711080523,45.3083197394437,0.130736377655587,481.397001641567,22.9236667448365,20540.0036646824,5019.58160058033,929.33063964506,271.057406431338,69.4655873368781,374.046593751798,0.867799901633693 -16.8410846595,3.4285515039407,45.3097750660989,0.129563018239515,485.787875345831,23.1327559688491,20915.7358123876,5068.70813866827,986.949471149616,273.710239488086,70.0991904124035,411.660937226189,0.946363198819623 -17.4309851927292,3.4622336732597,45.3112512751713,0.128306750959391,490.57624930866,23.3607737766028,21329.4026624033,5122.27481022873,1017.64089998857,276.602839752351,70.7901527752396,430.232948871332,0.979328964374832 -14.9387775764299,3.49709564364515,45.3126658154117,0.127031647683697,495.531435515654,23.596735024555,21761.7851979667,5177.70007285466,939.084743081589,279.595803934152,71.5051861449089,372.404776231477,0.839156455391221 -13.3146509149991,3.52697319879801,45.3137928727833,0.125958675119277,499.777455734343,23.7989264635401,22135.7692993851,5225.18735521629,888.783429761942,282.16011718168,72.1178868624656,334.732727636296,0.747814862909469 -17.9064466008416,3.55360250062801,45.3147354863974,0.125017390812064,503.561343045068,23.9791115735746,22471.7569292554,5267.5019271755,1062.13533025414,284.445104067477,72.6639018014033,453.54678301764,1.00558774498618 -16.3369138372681,3.5894153938297,45.315917317838,0.123773275157344,508.649455426729,24.2214026393681,22927.5739815723,5324.39545625949,1015.50463482071,287.517354638012,73.398116418077,417.935333241437,0.917302104826116 -20.2580644059831,3.62208922150423,45.3169155525312,0.122659453878561,513.290910168085,24.4424242937183,23347.3995700807,5376.28895889567,1169.80408537483,290.319603780366,74.0678783372546,522.935364629226,1.13731817352528 -27.9189470878385,3.6626053503162,45.3180556744596,0.121305633826133,519.045561024057,24.7164552868599,23873.2422663483,5440.62145330767,1469.31523260668,293.793558478614,74.8982744557714,728.704972021103,1.56716790835334 -13.1034536015564,3.71844324449187,45.3194659610883,0.119487769639283,526.975018539001,25.0940485018572,24607.4710880574,5529.25475988537,929.919985182333,298.57975703381,76.0424951751778,347.195195044354,0.735389221469768 -15.7962237995095,3.74465015169499,45.3200691910724,0.118653114666247,530.696105787215,25.2712431327245,24955.8834593327,5570.84366033158,1039.44927952478,300.825557657906,76.5794480650952,421.478784605852,0.88643696471676 -15.6178164304204,3.77624259929401,45.3207506460711,0.117662219278092,535.1814707556,25.4848319407429,25379.131409245,5620.97105772275,1041.48219841753,303.532437117029,77.2266862300331,420.216960361518,0.876340284099832 -19.8847180049077,3.80747823215485,45.3213784200082,0.116698563279869,539.615761506731,25.6959886431777,25801.0781416556,5670.52410714768,1215.93172181949,306.208301785975,77.8665543854213,539.428162332898,1.11566207560313 -14.8327790378881,3.84724766816466,45.3221164323365,0.115494117652893,545.260973193474,25.9648082473083,26343.3109402761,5733.60434739868,1030.5666101268,309.614634759529,78.6811584318183,406.564632480026,0.83212597291591 -22.1086796378837,3.87691322624044,45.3226254997542,0.114611661327988,549.471571667648,26.1653129365547,26751.4364684607,5780.65075350545,1326.31283164028,312.155140689294,79.2887477916416,610.649412285726,1.2402144039108 -22.5186193919238,3.92113058551621,45.3233239148366,0.11332096781777,555.747023754411,26.4641439883053,27365.5543399252,5850.76356029454,1358.00013128666,315.941232255905,80.1942955277615,629.037909625347,1.26307884575114 -18.3850964029363,3.96616782430005,45.3239673250247,0.112035758575595,562.138191174964,26.7684852940459,27998.1913570046,5922.16360337146,1206.59710377609,319.796834582059,81.1165409865473,519.448693827549,1.03112731486815 -21.7488720454584,4.00293801710593,45.3244463714553,0.111007793642649,567.355749751468,27.0169404643556,28520.0396176236,5980.44859019624,1355.22464641988,322.944223870597,81.8694346891368,620.165468418322,1.21969482920334 -19.4727269712519,4.04643576119684,45.324964190011,0.109815753973142,573.527447537192,27.3108308351044,29143.5636415011,6049.38802900245,1276.20974842257,326.666953566132,82.7600106796168,561.275890024485,1.09195879224165 -13.8043770941534,4.08538121513935,45.3253867127611,0.108769907384142,579.052835919799,27.5739445676095,29707.5323796995,6111.10446158128,1052.54681169547,329.999640925389,83.557324223227,401.711185579119,0.774047081311369 +"P0","dD","D","H","fc","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","NPP","turnover","dWs","dWfr" +6.35655068662902,16.835303518986,0.6,33.5798055081921,0.5486896324868,63.0047820994125,3.00022771901964,474.723316320797,378.031173825666,132.034543775879,20.413683386586,9.09159005694522,71.7704892326437,4.87537004340692,65.8663093682354,1.02880982100131 +7.13108220488591,19.7257772815307,0.633670607037972,34.4371636650361,0.53279929330503,68.2393724823584,3.24949392773135,543.018199996085,424.490087682034,160.429048692085,22.9224647348299,9.84694144920431,89.3617497556353,5.28042763256345,82.8630719450124,1.21825017805949 +5.68973531883509,14.4078013668277,0.673122161601033,35.3624697907967,0.51504897636607,74.4355781444888,3.54455134021375,629.202230939793,481.228026215354,139.625638029282,25.9863134156291,10.7410539262497,72.028789481182,5.75989592784735,65.3703381708136,0.898555382521024 +6.34338332379691,16.8735034760227,0.701937764334689,35.9882560124074,0.502645757593257,78.9957081325044,3.76170038726212,696.334484557976,524.088321303909,165.202643927455,28.3007693504111,11.3990806835204,87.8519557254665,6.11276312930094,80.6809456917827,1.05824690438292 +6.82157260138089,18.7175214261303,0.735684771286734,36.671369163506,0.488691952212603,84.3651296826657,4.01738712774598,779.418200998115,575.650286764188,189.73175545329,31.0851154852662,12.1738882132087,102.530926228371,6.52825408258723,94.8227217275054,1.17995041827822 +6.49513893518327,17.5159193351451,0.773119814138995,37.3708551125743,0.473899291902444,90.3491198943974,4.30233904259035,877.175572195236,634.389202391507,193.46611586452,34.2570169291414,13.0373780007615,102.320204654232,6.99130094420933,94.2201128636027,1.10879084642025 +5.7168514614097,14.5444931490249,0.808151652809285,37.9741630954396,0.460675561731252,95.9677171151123,4.56989129119582,973.943644575127,690.651829104107,180.873362790928,37.2951987716218,13.8481415797107,90.8110157077167,7.42607334819321,82.4618466576922,0.923095701831287 +5.92255487489471,15.3534846411711,0.837240639107335,38.4402203547041,0.450127344320133,100.642231168364,4.79248719849352,1058.14785363293,738.206334780354,196.508748788989,39.8631420781391,14.5226739575949,99.4860529272782,7.78779169755197,90.7225021210206,0.975759108705611 +5.27038873009927,12.8155185553124,0.867947608389677,38.9002005936207,0.439398083406561,105.581891651649,5.02770912626899,1150.79707174324,789.13088719111,183.452919862248,42.6130679083199,15.2354669653329,87.9230694920164,8.17002733018711,78.9379814089491,0.81506075288018 +5.51071504973643,13.7607315849322,0.893578645500302,39.2605422578485,0.430748070106606,109.706702726415,5.22412870125785,1231.06714962407,832.142597763695,199.312096872264,44.9357002792395,15.8306772034217,96.9820035727222,8.489209139544,87.6175057369409,0.875288696237326 +7.54939356974498,21.8379826335328,0.921100108670166,39.6250089109782,0.421757066211035,114.13538117188,5.4350181510419,1320.20971930144,878.777941100713,284.06969259199,47.4540088194385,16.4697355031023,154.102163788614,8.83190449544308,143.881601824553,1.38865746861797 +3.54221042306307,5.9116133834398,0.964776073937232,40.1590145834713,0.408090374425407,121.158436226282,5.76944934410868,1467.89835067594,953.60988111201,141.488309228851,51.4949335800485,17.4831623474525,50.7571493109447,9.3753551841766,41.0063519626561,0.375442164111961 +7.29415483194559,20.916852879811,0.976599300704111,40.2947707483121,0.404512650948504,123.057810977306,5.85989576082411,1509.18122217015,974.017738882873,295.921625566882,52.5969578996751,17.7572421240253,157.897197880227,9.52233061133918,147.047099808253,1.32776746063497 +7.17736583844178,20.5112043555143,1.01843300646373,40.7471260686322,0.392251258147014,129.769770340942,6.1795128733782,1659.67021697482,1046.65685999763,307.065595932367,56.5194704398719,18.725777860198,162.274243342608,10.0417084192396,150.933313610098,1.29922131327072 +5.76446240966604,14.8272686734008,1.05945541517476,41.1512210344006,0.380802568655488,136.335670487032,6.49217478509676,1813.87761827228,1118.42703749844,259.096084943575,60.3950600249158,19.6732372512787,125.319451367166,10.5497840257822,113.832974304093,0.936693037291075 +6.36927494971677,17.3106971417459,1.08910995252156,41.4209613472776,0.372862129673559,141.070429358923,6.71763949328203,1929.40550568451,1170.56663822599,296.22282951795,63.2105984642033,20.3564629564925,148.859037668078,10.9161641765833,136.851699398189,1.09117409330488 +6.95286247425414,19.737288045205,1.12373134680506,41.7139306914477,0.363930494580269,146.584381245028,6.98020863071561,2068.5498552177,1231.64682064661,336.003559558579,66.5089283149171,21.1521262136575,173.839753521003,11.3428390249129,161.256276721843,1.24063777424695 +6.71087914115067,18.7837853425537,1.16320592289547,42.0212737978631,0.354170542308262,152.851570429624,7.27864621093446,2232.76136472673,1301.48622622309,338.175284062209,70.2802562160468,22.0564816129947,172.086982363217,11.8278000927685,159.082563114587,1.17661915586128 +5.26790583513827,12.8217774398287,1.20077349358057,42.2894755031074,0.345279691155205,158.795239440075,7.56167806857502,2394.49739873623,1368.07529779283,275.783337197164,73.8760660808128,22.9141530512029,125.295182645604,12.2877268614344,112.207098935612,0.800356848557437 +6.566805124161,18.2452312612906,1.22641704846023,42.45995476458,0.339422928637567,162.840262311779,7.75429820532283,2507.93208106471,1413.56565374962,352.540050645842,76.3325453024793,23.4978498515898,176.896758844241,12.6007345836496,163.159934682234,1.13608957835805 +8.11858373412842,24.7856194736716,1.26290751098281,42.6861975232612,0.331371956332191,168.578856245147,8.02756458310224,2673.56315645358,1478.31075911811,451.2070929712,79.8287809923777,24.3259289561747,242.936668115853,13.0447924475411,228.35407629729,1.5377993710223 +6.32417644520231,17.2937672380548,1.31247874993015,42.9652442879322,0.320940727762809,176.34114366281,8.39719731727666,2906.442478476,1566.2193770555,367.663207992101,84.5758463609971,25.4460270305435,180.348934220393,13.6454456405746,165.635860843253,1.06762773656446 +6.89856807347317,19.7522663348444,1.34706628440626,43.1423081277759,0.313988858655682,181.734102172055,8.65400486533596,3074.26424945922,1627.48079736818,413.32143144565,87.8839630578819,26.2242309434276,209.449266211039,14.0627579061709,194.171392334029,1.21511597083878 +6.03159946079517,16.0961124951909,1.38657081707595,43.3283830803526,0.306358726279144,187.870514608345,8.94621498134978,3271.27066389088,1697.33733062078,373.580035953626,91.6562158535224,27.1097152579842,178.369873389484,14.5375993446934,162.846055704211,0.986218340578911 +6.27778355366965,17.16394965416,1.41876304206634,43.4682489283618,0.300373840157663,192.852866922323,9.18346985344396,3435.98900015818,1754.15222481637,399.139747487371,94.7242201400838,27.8286686968912,193.610801055277,14.9231385118464,177.639446545627,1.04821599780381 +5.21642398919964,12.6295350892241,1.45309094137466,43.6066431804808,0.294211530358945,198.147929509786,9.43561569094218,3615.74781654769,1814.60873076404,340.764985119025,97.9888714612581,28.5927462282621,149.928357200653,15.332875497781,133.826844371798,0.768637331074376 +6.55619745125751,18.3952474726764,1.4783500115531,43.7018621458236,0.28981609600727,202.032528356817,9.62059658841985,3750.71760123868,1859.00125544414,436.682576845345,100.386067793984,29.1532938418887,215.000250646631,15.6334694561822,198.250050522648,1.11673066780092 +5.95993711759831,15.8446647777074,1.51514050649846,43.831218806325,0.283615829417466,207.673242246988,9.88920201176133,3951.38412628242,1923.50897853032,408.051296175994,103.869484840637,29.9672488562403,191.950193735382,16.0699532691122,174.921813282923,0.958427183346458 +7.88728680824511,24.2027307591939,1.54682983605387,43.9343698891377,0.278459276205203,212.51570473929,10.1197954637757,4128.09200944503,1978.92055295692,552.600411492272,106.861709859674,30.6660161938795,290.550879807103,16.4446676286355,272.646671641155,1.4595405373132 +8.22107522410296,25.7072772267459,1.59523529757226,44.0783962757447,0.270894921028856,219.884503251135,10.4706906310064,4404.89105922953,2063.27644923343,595.958180736472,111.416928258605,31.7293338191387,316.96834306111,17.0148722753854,298.410219153645,1.54325163207887 +6.71112521928238,19.1710920243701,1.64664985202575,44.2151337370525,0.263250686095259,227.675495035516,10.8416902397865,4707.9663229381,2152.48431418609,503.737372517346,116.234152966049,32.8535739336249,248.254751932371,17.617746639653,229.491465821617,1.14553947110074 +6.89023800746259,19.9768655220641,1.68499203607449,44.307287719967,0.257796573767286,233.462485651133,11.1172612214825,4940.0433077071,2218.74177696372,530.327160420632,119.812055956041,33.6886366794585,263.778527449593,18.0655494849091,244.52326743596,1.18971052872406 +7.76112979407141,23.8257082048812,1.72494576711862,44.3952202221123,0.252325183421029,239.472554550054,11.403454978574,5187.36719071263,2287.53747083644,612.735770347909,123.527023425168,34.5558896215728,318.257000110818,18.5306143401828,298.312213249772,1.41417252086328 +6.25057765826422,17.2060348063112,1.77259718352838,44.4902641325584,0.246067783575567,246.614794291817,11.7435616329437,5489.65408713765,2369.2590183527,508.196678582562,127.939986991046,35.5865148163092,241.269123742645,19.0832876535335,221.16848274385,1.0173533452615 +6.33509757957589,17.5901874825674,1.807009253141,44.5528335501106,0.2417212225262,251.755979211332,11.9883799624444,5712.8914070696,2428.05480451117,525.80612819557,131.114959443603,36.3283878001953,250.85394666624,19.4811174389722,230.33551895005,1.03731027721754 +6.91488450802403,20.1676572445543,1.84218962810614,44.611983259479,0.23741984984819,256.998122430973,12.2380058300463,5945.38635251638,2487.97483178667,585.878312920607,134.35064091648,37.0848290667893,290.109990056137,19.8867594738253,269.037028203938,1.18620237837325 +6.73931160907614,19.4063394208941,1.88252494259525,44.6742813871782,0.232657289656351,262.99191750131,12.5234246429195,6217.25870783403,2556.44454689767,584.319634666906,138.048005532474,37.9497336954391,285.825326807295,20.3505650447443,264.336610146147,1.13815161640412 +6.41850196835536,17.9941058688319,1.92133762143704,44.7291190646737,0.228237229236096,268.743592668877,12.7973139366132,6484.21794810845,2622.10248553891,568.675264496823,141.593534219101,38.779700422119,271.811420898922,20.7956351469964,249.96323890132,1.05254685060572 +5.9747730511708,16.0271629327293,1.9573258331747,44.7758599940221,0.224274881631349,274.063469333169,13.0506413968176,6736.4342881956,2682.78859787909,539.8400553594,144.870584285471,39.5473586247763,248.795478714407,21.2072922698286,226.652882028925,0.935304415653804 +6.29052913054772,17.440380296325,1.98938015904016,44.81442136322,0.220851238609122,278.791586051485,13.2757898119755,6964.87366780908,2736.68836173961,578.175096180058,147.781171533939,40.2296258672293,273.115009145223,21.5731584444602,250.526102621197,1.01574807956627 +4.17096572859796,7.97717281003217,2.02426091963281,44.8533405216791,0.217234165961791,283.926135389712,13.5202921614148,7217.51442345122,2795.18201798864,390.422226158856,150.939828971386,40.9705413367354,138.958299095514,21.9704747622991,116.524189610447,0.463634722767683 +6.15546298136901,16.8462038310592,2.04021526525287,44.870149040139,0.215616180044425,286.271156105999,13.6319598145714,7334.48092119112,2821.88302721456,580.939433132436,152.381683469586,41.3089278260956,271.074175285728,22.1519346986785,247.944036579181,0.978204007868186 +5.53160467339546,14.0578181245679,2.07390767291499,44.9037231810738,0.212272024428086,291.216419156258,13.8674485312504,7584.39729009076,2878.1622487121,531.079494435307,155.420761430453,42.022529284248,233.545342604424,22.5346038632819,210.195980356762,0.81475838438002 +6.17813954317543,16.9563256202662,2.10202330916413,44.9298561483692,0.209554662808895,295.336172908816,14.0636272813722,7795.96658479674,2925.01679558825,601.543304178555,157.950906961766,42.6170097507421,280.682771226233,22.8533943322298,256.84810536124,0.981271532763193 +6.51403900947682,18.4679409616795,2.13593596040466,44.9592547996009,0.20636246404865,300.297294056826,14.2998711455631,8054.81267817332,2981.40402741659,644.90287751107,160.995817480496,43.3328995323999,308.401912348722,23.2372906115401,284.097729376452,1.06689236072995 +6.86291678564618,20.0416701610014,2.17287184232802,44.9888223907982,0.202987989255609,305.69112101664,14.5567200484114,8341.28067926819,3042.66442419336,691.646364411991,164.303878906441,44.1112287627012,338.261879719994,23.6546700786686,313.45148829777,1.15572134355548 +7.20938440964792,21.6085180966257,2.21295518265002,45.0182476750904,0.199441621242011,311.533885607013,14.8349469336673,8657.52409706048,3108.9712915556,740.450474524136,167.884449744002,44.954339693092,369.328179560929,24.1067887672093,343.977621249849,1.24376954387103 +3.97341754215652,7.03601011376401,2.25617221884327,45.047136751416,0.19574684588065,317.821685360371,15.1343659695415,9004.74818030553,3180.26872423213,416.332459384523,171.734511108535,45.8616691975015,139.115395354941,24.5933447005049,114.117823915111,0.404226739324899 +7.13383296888305,21.2801954245244,2.2702442390708,45.0559531200315,0.194571589693512,319.86656803368,15.2317413349371,9119.21030750524,3203.44248475708,752.288335723568,172.985894176882,46.15674576726,373.201987045598,24.7515796692728,347.228553178835,1.22185419748985 +6.92558427196119,20.3477154671804,2.31280462991985,45.0809804853805,0.191097160217468,326.044131954048,15.5259110454309,9469.58910544113,3273.41153767995,744.432538328134,176.764223034717,47.0481682409691,364.434102936714,25.2296054488251,338.038170027688,1.16632746020092 +5.98116495848585,16.0856209308686,2.35350006085421,45.1027706607433,0.18788358387602,331.941477216838,15.8067370103256,9810.50887134914,3340.15380441796,654.545503139953,180.36830543857,47.8991551623898,298.394629777295,25.6859476417792,271.788064812345,0.920617323171306 +6.76020282743031,19.6086783694707,2.38567130271595,45.1186386568537,0.185415146743585,336.597341080319,16.0284448133485,10084.0986596268,3392.81029004832,750.175624001763,183.211755662609,48.57099631789,362.875010414885,26.0462228216913,335.70781873478,1.12096885841351 +6.98394235850872,20.6244892697195,2.42488865945489,45.1364910713637,0.182488633703364,342.265940129128,16.2983781013871,10422.4851358161,3456.87948730217,788.055620023974,186.671492314317,49.3889751606332,386.396606784316,26.484864414754,358.73425522049,1.17748714907222 +6.39636687443202,17.9661078570463,2.46613763799433,45.153643656391,0.179504490797617,348.220391796921,16.581923418901,10784.1845121894,3524.13259158699,734.311122041638,190.303159945698,50.2482025362957,345.631831691751,26.9456255557141,317.661824371769,1.02438176426843 +5.84200665420692,15.4533805220618,2.50206985370842,45.1673414534366,0.176980299897139,353.401221445891,16.8286295926615,11104.0977210229,3582.61024585722,680.648096630438,193.46095327629,50.995796254642,305.333942969654,27.3465230880749,277.107246431186,0.880173450393775 +6.2836225399326,17.4554820025052,2.53297661475254,45.178269204059,0.174863125582469,357.853159774589,17.0406266559328,11382.8715518668,3632.83364916657,741.323019591853,196.173017054995,51.6382109554732,345.458254106969,27.6910183158908,316.773893180662,0.993342610416491 +6.00254251622773,16.1791962737994,2.56788757875755,45.1897323439739,0.172529590186322,362.877351133635,17.2798738635064,11701.7729666142,3689.48383779641,718.104500330102,199.232127241006,52.3632017685835,326.556419924359,28.0797950281979,297.556769066329,0.919855829832415 +5.48632635655899,13.8332850570005,2.60024597130515,45.1995825200622,0.170419709078126,367.530125444867,17.5014345449936,12001.1585563592,3741.91972483299,664.763432944698,202.063665140982,53.0345971016942,286.765619491415,28.4398311356147,257.539949859031,0.785838496769284 +5.98282483199965,16.0870617142201,2.62791254141915,45.2074540172635,0.16865490251941,371.505325637876,17.6907297922798,12260.0361289365,3786.70009122841,732.763574124157,204.481804926334,53.6082184895455,332.271485495794,28.7474359124547,302.610786523461,0.913263059878558 +5.67376778856309,14.6803433141496,2.66008666484759,45.216012450468,0.166646540343402,376.124941256098,17.9107114883856,12564.456802952,3838.7181130582,703.552047310903,207.290778105143,54.274829023255,309.390508127754,29.1049061686267,279.452811578228,0.83279038089901 +7.23983492388136,21.8010048553562,2.68944735147589,45.2232998221572,0.164853825559235,380.337705844235,18.1113193259159,12845.4176150175,3886.13533211973,907.800854792479,209.851307934465,54.8827309533231,450.146771133284,29.4308939046134,419.47993311435,1.23594411432029 +7.19416734632511,21.5939865396093,2.73304936118661,45.2332712094154,0.16225958064549,386.58905930592,18.4090028240914,13268.2251700154,3956.46519606721,916.901400001209,213.649120587629,55.7848012578442,453.227234709015,29.9146295891486,422.089488417331,1.22311670253499 +7.71327345412673,23.9579940520286,2.77623733426582,45.2422290128025,0.159767055704081,392.775754113549,18.7036073387404,13693.581783903,4026.0307999566,998.794035973248,217.405663197656,56.6775413185852,507.297582019904,30.3933619254532,475.548315776747,1.35590431770482 +6.80656009478807,19.827899339243,2.82415332236988,45.2512000704367,0.157087511100336,399.634026818359,19.0301917532552,14173.1547308991,4103.10754590426,896.773328632942,221.56780747883,57.6671900698892,432.276831758956,30.9240615990397,400.23155416945,1.12121599046593 +6.11124360426312,16.6571270208839,2.86380912104837,45.2579269639261,0.154935314316819,405.305794116742,19.300275910321,14576.1449646088,4166.81954852107,816.591676673849,225.008255620138,58.4856260910458,373.168456473866,31.3629483542717,340.864200217104,0.941307902489831 +3.79517182518576,6.09387324258163,2.89712337509014,45.2631322083338,0.153171315359365,410.067812162191,19.52703867439,14918.9572646865,4220.29221854287,513.073595811533,227.895779801315,59.1727852950041,158.20352150065,31.7314378458838,126.127889560651,0.344194094114684 +6.75580856504265,19.593196066452,2.9093111215753,45.2649411031417,0.152535742599936,411.809360416058,19.6099695436218,15045.3459971411,4239.84368489309,917.204315665611,228.951558984227,59.4240907080371,440.180066181343,31.8662005083854,407.207401499563,1.10646417339446 +7.12178801931342,21.2608631993522,2.9484975137082,45.2704320844559,0.150526755905484,417.406773816314,19.8765130388721,15455.2508063923,4302.66775625397,980.033849843101,232.344058837714,60.2317974616941,481.220595480585,32.2993336881672,447.721283627338,1.19997816508017 +6.07003962232015,16.4591993293844,2.99101924010691,45.2758674223354,0.148404613119201,423.477239449775,20.1655828309417,15906.1501817255,4370.77620250144,847.45010956666,236.021914935078,61.1077656526025,385.224300285286,32.7690721002802,351.526776981725,0.928451203281309 +5.54665398447338,14.067105193669,3.02393763876568,45.2797322189483,0.146801619726597,428.174468784217,20.389260418296,16259.582758266,4423.46052692835,782.968666968331,238.866868454131,61.7855758455625,337.621355868047,33.1325481797311,303.695613045291,0.793194643024647 +5.86597948901178,15.5221706635119,3.05207184915301,45.2828158652527,0.145458297540648,432.18756336936,20.5803601604457,16564.6711024812,4468.46047772982,835.805734311123,241.29686579741,62.3646653941986,372.50094218366,33.4430852607243,338.182902323171,0.874954599764613 +6.7499940313267,19.5565900892202,3.08311619048004,45.2859994205356,0.144003780281376,436.614279928182,20.7911561870563,16904.5504598418,4518.08717743242,971.614226873017,243.97670758135,63.0034405936366,465.243855088621,33.7856288039664,430.356236524133,1.10198976052177 +4.95578199961377,11.3572336135693,3.12222937065848,45.2897064391146,0.142211438393329,442.189471225733,21.0566414869396,17337.6008759241,4580.5730615585,722.458878072075,247.350945324159,63.8079406978732,287.90999443503,34.2170424162769,253.053245078117,0.639706940636047 +5.40021742033823,13.385024112179,3.14494383788562,45.2917141503446,0.141190570047573,445.426179880509,21.2107704705004,17591.5631591783,4616.8417710472,793.011573138408,249.309455636549,64.2749977567575,335.598983821571,34.4675020145632,300.377725406286,0.753756400722016 +6.58267371063366,18.7856729442145,3.17171388610997,45.2939522903354,0.140005804978906,449.239886657007,21.3923755550956,17893.2039106494,4659.56895356473,974.929425243584,251.616723492495,64.8253156446061,460.941170274538,34.7626102770303,425.120939985495,1.05762001201283 +7.09688481611084,21.1330741785539,3.2092852319984,45.2968745594126,0.138375673516531,454.590799663377,21.6471809363513,18320.8136851332,4719.50609477267,1063.60639375948,254.853329117724,65.5974523914252,520.208928575234,35.1766690215708,483.842877793987,1.18938175967629 +6.00549081825657,16.1402872667318,3.25155138035551,45.299879808582,0.136586022104633,460.608298241624,21.9337284876964,18807.8077773782,4786.8936987993,911.95373435524,258.492259735162,66.4657774362663,410.896988028668,35.6423087925066,374.346610274293,0.908068961868347 +6.63004332644053,18.9930692401189,3.28383195488897,45.3019900690392,0.135249660652814,465.202770302401,22.1525128715429,19183.9933649456,4838.33454848362,1016.83666985043,261.270065618115,67.1287597546364,481.906491134372,35.9978334162572,444.840353488577,1.06830422953752 +7.03790275965857,20.8552715515222,3.32181809336921,45.3042847544534,0.13370980648881,470.607898295183,22.4098999188182,19631.3812182136,4898.84040228464,1091.93054450784,264.53738172337,67.9087197239948,531.63911014233,36.4160873680796,494.050296398511,1.17272637573945 +6.57187958564459,18.7201939408957,3.36352863647226,45.3065884754135,0.132058408880057,476.541336259031,22.6924445837634,20128.5043778859,4965.24701319008,1032.48254092468,268.123338712264,68.7649148221782,486.916001173167,36.8752224486155,448.988405561593,1.05237316295895 +6.93192037451195,20.3641803183908,3.40096902435405,45.3084800300816,0.130610064786759,481.865969670376,22.9459985557322,20579.9697315333,5024.82888213394,1101.21562000948,271.340759635233,69.5332594234352,532.239120665571,37.2872476530648,493.807348709585,1.14452430292195 +6.52173301086289,18.4837635132064,3.44169738499083,45.3103645660747,0.129069819557333,487.656846023613,23.221754572553,21076.7093170367,5089.6168501749,1048.50349363573,274.839309909445,70.3688828812073,492.306710591551,37.7353511803986,453.532765137113,1.03859427404007 +6.19871053404299,17.0020106898569,3.47866491201724,45.3119318135848,0.127702620648729,492.911853214509,23.4719930102147,21532.6587198931,5148.40017366273,1007.31003158377,278.013609377787,71.1271804188536,460.718469250994,38.1419886415989,421.621335888138,0.95514472125739 +5.87875751164983,15.5341971118263,3.51266893339696,45.313262728466,0.126470123496346,497.744696231241,23.7021283919639,21956.3254436974,5202.45371484505,964.683229486764,280.932500601632,71.8245596661681,428.348318453275,38.5159586369413,388.959824301031,0.87253551530208 +8.17929699338317,26.0623755622101,3.54373732762061,45.3143928517009,0.125364470437864,502.159607008619,23.9123622385056,22346.9932366706,5251.82700351647,1354.09861695217,283.59865818989,72.4616312913437,698.626829229653,38.8575886375717,658.305567262923,1.46367332915894 +6.55839019372951,18.6374499195066,3.59586207874503,45.3161201281912,0.123551926576211,509.565283829833,24.2650135157063,23010.1079777408,5334.63523678276,1101.76665618125,288.070302786269,73.5302704566448,518.116258056832,39.4306469630228,477.639164508722,1.04644658508762 +7.24811997637199,21.7923233454413,3.63313697858404,45.3172368127978,0.122287334069287,514.860151912496,24.5171500910712,23490.2073998688,5393.83260601876,1230.2891525949,291.266960725013,74.2943199209732,605.309510364241,39.8403688979908,564.24574101589,1.22340045036009 +8.03699004194803,25.4013998703621,3.67672162527492,45.3184291111587,0.120840893029529,521.050340388634,24.8119209708873,24057.8178303337,5463.03158153594,1380.59296179942,295.003705402941,75.1875641180799,707.281184594878,40.3193715776919,665.5360353748,1.42577764238673 +7.11338809285134,21.1673409346634,3.72752442501565,45.3196790309455,0.119197227992113,528.264480335371,25.1554514445415,24727.926824395,5543.66679390356,1238.85493414199,299.358006870792,76.2285645123941,604.28785393116,40.8776085973799,562.22233190051,1.18791343327027 +4.85641341910418,10.8253008736848,3.76985910688498,45.3206168303881,0.117861108399375,534.275203776522,25.4416763703106,25293.3257090335,5610.84312643952,855.407807754916,302.985528827734,77.0959119049521,332.728456915561,41.3427241017546,290.778296508048,0.607436305758698 +8.72776629424277,28.5571272388092,3.79150970863235,45.3210629980414,0.117189241538273,537.348878899509,25.5880418523576,25584.9350080715,5645.19219982634,1546.15132341851,304.840378790622,77.5394432251991,814.640050981885,41.580568010081,771.457169390548,1.60231358125677 +7.08212721842806,21.0137481632612,3.84862396310996,45.3221408091233,0.115452878242716,545.456325476452,25.9741107369739,26362.1763365477,5735.78714379241,1273.55072442599,309.73250576479,78.709347766252,619.576209626466,42.2079299475826,576.189402607949,1.17887707093413 +7.44958519491443,22.693764202764,3.89065145943649,45.3228499822522,0.114207523116714,551.421410794345,26.2581624187783,26941.4986580933,5802.43604046759,1354.27935218712,313.33154618525,79.5701095776239,672.964387496975,42.6695139305148,629.021880534232,1.27299303222823 +6.70427322967278,19.2748610851536,3.93603898784201,45.3235441584314,0.112892294388858,557.86272219105,26.5648915329072,27574.1752794224,5874.40005824038,1233.0241649991,317.217603144981,80.4995908121685,584.714879729363,43.1679487409741,540.465831799904,1.08109918848486 +4.45253939481135,8.95290783235091,3.97458871001232,45.3240805582976,0.111798669845848,563.333118763592,26.8253866077901,28117.2781799724,5935.51235495549,826.923998621286,320.517667167596,81.2889690375863,297.582153691272,43.5912532376589,253.488785703707,0.502114749905634 +6.00821693030311,16.0801242511131,3.99249452567702,45.3243143179729,0.111297841454115,565.873894554828,26.9463759311823,28371.3359937748,5963.89522745312,1120.87660520206,322.050342282469,81.6556029842617,502.01946195473,43.7878608881713,457.329795967968,0.901805098590442 +6.16295446882276,16.7862927535604,4.02465477417925,45.324711232619,0.110409448506277,570.43710410723,27.1636716241538,28830.5016091602,6014.86864952416,1159.01556021033,324.802907074304,82.3140741226733,526.329005309348,44.1409663892499,481.246688302997,0.94135061710152 +6.96034105030208,20.4377488087948,4.05822735968637,45.3250960483594,0.109496991509851,575.200420224076,27.3904962011465,29313.7491912436,6068.07482476288,1319.90372856316,327.676040537195,83.0014206383341,636.458387171345,44.509556326863,590.802780892225,1.14604995225686 +5.09456892523212,11.8827887757836,4.09910285730396,45.3255269759339,0.108406138366831,580.99950886989,27.6666432795186,29907.5184900864,6132.84728283027,975.833556626277,331.173753272834,83.8382291299251,392.575101956462,44.9582953292176,346.950522815231,0.666283812013103 +5.96027384301668,15.8484812556505,4.12286843485553,45.3257598941941,0.107781803388225,584.371002276896,27.8271905846141,30255.4719630029,6170.50335019394,1148.2789719047,333.207180910473,84.3247356285561,511.522938755967,45.2191846999979,465.415141656656,0.888612399312921 diff --git a/pyrealm_build_data/t_model/rtmodel_output_default.csv b/pyrealm_build_data/t_model/rtmodel_output_default.csv index 69035adb..cd1a9ee3 100644 --- a/pyrealm_build_data/t_model/rtmodel_output_default.csv +++ b/pyrealm_build_data/t_model/rtmodel_output_default.csv @@ -1,101 +1,101 @@ -"dD","D","H","fc","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" -9.15158015400302,0.1,9.30685130731739,0.802314767872188,2.46024211324268,0.316316843131202,7.30958392378022,7.02392939699003,9.13563152114705,0.309052893467561,0.687337521113514,3.73060981700386,0.349976706679594 -7.51068608859801,0.118303160308006,10.5951677269446,0.772064352133008,3.31344110400063,0.426013856228652,11.6463653600737,11.0412824125802,10.5344545786858,0.485816426153529,0.925702548753488,4.0717530576517,0.320588515727445 -11.0223864066205,0.133324532485202,11.5747150651166,0.748414598299783,4.07939210586527,0.524493270754106,16.1592175957903,15.1364164543581,17.0051191375024,0.666002323991757,1.13969240775243,7.28243545071491,0.505813197748838 -12.2109860328466,0.155369305298443,12.8955857508128,0.7155135466808,5.29640723899734,0.680966645013944,24.4490170178718,22.470295918228,23.5706604699857,0.988693020402033,1.4796996616166,10.3227454787767,0.610007556660469 -8.14343951151115,0.179791277364136,14.2113227388961,0.681409046743642,6.75426651300729,0.868405694529509,36.0795921593221,32.4175065017063,22.1196280496285,1.42637028607508,1.88699346987095,8.64216534018665,0.437178780678676 -7.98837001728421,0.196078156387159,15.0104541268837,0.659943305237754,7.78033181838295,1.00032837664924,45.3254518882641,40.0840820976028,25.0226173827984,1.76369961229452,2.17365354275619,9.66629191655132,0.445571510141509 -12.0258637885806,0.212054896421727,15.7385365812519,0.639820356817988,8.82241993281344,1.13431113421887,55.5841333977515,48.373238491983,37.7793762157135,2.12842249364725,2.46479003598956,16.3400771342304,0.692215890552332 -6.5560471764814,0.236106623998888,16.7388948076693,0.611168017497777,10.4474433390386,1.34324271501924,73.288022651745,62.2075837425506,29.3234723190146,2.73713368467223,2.91878582517392,10.3987028384482,0.392058878157929 -9.06119771562442,0.249218718351851,17.2395860558773,0.59633209798285,11.3574952749362,1.46024939249179,84.0965213401603,70.3931802925398,39.2099313720491,3.09729993287175,3.17303431492111,15.5058348811442,0.551136474007312 -12.5411592420971,0.2673411137831,17.8839217661859,0.57668548313431,12.6387343989382,1.62498013700633,100.388542478402,82.3993995200503,54.7252358201368,3.62557357888221,3.53098433890655,23.6382736008367,0.777983562017604 -9.03418038499667,0.292423432267294,18.691926724088,0.551040995915459,14.4491171748091,1.85774363676117,125.536001523663,100.232439393555,49.2645559252196,4.41022733331644,4.03676545806381,19.2022322133608,0.572494896702917 -10.4795840004484,0.310491793037287,19.2190833187389,0.533610731307969,15.7745822821954,2.0281605791394,145.520038705201,113.866672689204,59.2632249984158,5.01013359832497,4.40707124883518,24.0872447367328,0.671959730051301 -11.9753726313239,0.331450961038184,19.7783608026811,0.514414288719766,17.3294448640194,2.22807148251678,170.654891764143,130.415580444168,71.161547545663,5.73828553954339,4.84146564722001,29.9171641677866,0.776039884241294 -7.80628339083056,0.355401706300832,20.3550784533437,0.49373655540199,19.1234992007906,2.45873561153022,201.930387670726,150.175089079034,58.6532690356622,6.6077039194775,5.34268495971847,21.2700220352415,0.510300275523062 -4.00892322682109,0.371014273082493,20.6983597468974,0.480936041265026,20.3002609801303,2.61003355458818,223.772671728003,163.482184102033,43.5295413559335,7.19321610048947,5.67144631210684,11.510326592636,0.263130980950176 -9.14103200731802,0.379032119536135,20.8653405365414,0.474560376400669,20.9062704384995,2.68794905637851,235.433027053355,170.433076459398,70.595634068793,7.4990553642135,5.84075202256713,26.9292656571604,0.600975055086163 -12.9288890666292,0.397314183550771,21.2239178805536,0.460504096984337,22.2912641636173,2.86601967817936,263.138003967915,186.550153984087,95.1139417044901,8.20820677529982,6.22768879950307,40.2791656157786,0.852381340501473 -8.559841502641,0.42317196168403,21.6824623192037,0.441706435062423,24.2549597310002,3.11849482255717,304.952537262096,209.901361085315,77.9748046952907,9.23565988775386,6.77630213972738,28.6960853671925,0.565441068540363 -11.7119920410932,0.440291644689312,21.9575081629571,0.429917001053558,25.5563348496366,3.28581448066756,334.313429185402,225.663361404898,100.7266565802,9.92918790181549,7.13987771762177,41.0798038839857,0.773837010777129 -8.1661974411302,0.463715628771498,22.3005515182373,0.414577645975007,27.3364685680675,3.51468881589439,376.624832725536,247.548221416205,84.8922502025986,10.892121742313,7.63720791560956,30.3567355628113,0.539114385185502 -9.11610386981603,0.480048023653758,22.5188727324862,0.404393318263312,28.5763269029229,3.67409917323295,407.573463450989,262.987869861956,94.780184305758,11.5714662739261,7.9835970574848,35.207422127762,0.601091017101131 -9.45349393230877,0.498280231393391,22.7440569444025,0.393492344396193,29.9582654351054,3.85177698451356,443.511750184483,280.365271509347,101.411722320694,12.3360719464113,8.36968028072889,38.0238284659624,0.622165860251205 -10.5041723806732,0.517187219258008,22.9585424533782,0.382682444685352,31.3882548353777,4.03563276454856,482.313882472608,298.5132431413,113.42139399129,13.1345826982172,8.76918785939815,43.9766410856273,0.689634418416019 -12.2128888837326,0.538195564019354,23.1760658641222,0.371228758836905,32.9727297581712,4.23935096890772,527.241789610679,318.795022049385,131.404128395006,14.026980970173,9.21185529437835,53.3384664764177,0.799279419243195 -12.1856528195232,0.562621341786819,23.4040161433267,0.358604881954002,34.8082078848516,4.47534101376664,581.85219182514,342.485358372075,137.973101490197,15.0693557683713,9.72464750245409,55.7527969074137,0.794180989263487 -9.11472071104903,0.586992647425866,23.6074128455832,0.34670311561101,36.6316203311612,4.70977975686359,638.856913795495,366.194815094084,119.878012477321,16.1125718641397,10.2340688248792,43.5718796187963,0.591348686762172 -10.3759087481066,0.605222088847964,23.7453799177281,0.338225512232287,37.9899713077899,4.88442488243013,683.122428005091,383.952053387605,134.587064757615,16.8938903490546,10.6135622040277,51.1780688104701,0.670773810696265 -6.93901957870437,0.625973906344177,23.889038357084,0.328991326554911,39.530287298616,5.08246550982206,735.192400601846,404.170081441633,110.103496654093,17.7834835834319,11.0438926049128,35.4173150493713,0.446714012837032 -12.284388351516,0.639851945501586,23.9777694004383,0.323051152813844,40.5567687846253,5.21444170088039,771.005808870131,417.684886042966,159.920476132293,18.3781349858905,11.330668949511,64.1017594282772,0.788584187622587 -12.075607039426,0.664420722204618,24.1216671677035,0.312972488167058,42.3667902401924,5.4471587451676,836.341293135801,441.582513969378,164.654513698263,19.4296306146526,11.8363491237245,65.4344699422069,0.771247465222399 -11.917199932589,0.68857193628347,24.2481853160583,0.303579145904651,44.1370836450472,5.67476789722035,902.958437900666,465.021784167154,169.575365139389,20.4609585033548,12.330930154586,66.9075758011336,0.757330040945065 -10.7311762351148,0.712406336148648,24.3600501700355,0.294776199823816,45.8755226084278,5.89828147822643,971.009785550148,488.087188105459,164.221879519707,21.4758362766402,12.8166117552973,62.306468003344,0.67863021382006 -14.4672595446774,0.733868688618878,24.4508492070951,0.287221932327531,47.4337410742638,6.09862385240534,1034.23813067158,508.790786508429,207.095718270781,22.3867946063709,13.2519437138457,86.4821252694631,0.910940614000552 -15.7103757812118,0.762803207708232,24.5599546892029,0.277560116660781,49.5239349849306,6.36736306949107,1122.38657631876,536.591264630236,228.57167037994,23.6100156437304,13.8358979082199,97.528547825802,0.983600017668455 -8.91259981408415,0.794223959270656,24.6631557853775,0.267699569449094,51.7805552706752,6.65749996337253,1221.86857668617,566.624543312778,164.393628364537,24.9314799057622,14.4663479704107,57.5429740486748,0.554698645013589 -15.3828383288123,0.812049158898824,24.7154286300117,0.262378253310204,53.0549049004546,6.82134491577274,1280.03743164846,583.587188895696,240.078103118852,25.6778363114106,14.8223732212792,101.476722856044,0.954291586384592 -10.9117224578962,0.842814835556449,24.7961941944862,0.253626639876271,55.2449103869321,7.10291704974841,1383.37286768916,612.732927587703,197.929333821628,26.9602488138589,15.4342125740803,74.6171403957344,0.673301322809818 -13.1758830355601,0.864638280472241,24.8469643034311,0.247731303333039,56.79143836478,7.301756361186,1458.9222106752,633.306180185225,229.891395155748,27.8654719281499,15.8662784674755,92.3504829403427,0.810076229643654 -11.8938985413645,0.890990046543361,24.9018766615094,0.240935744863909,58.6516187772485,7.54092241421767,1552.62889407201,658.037439405553,221.478220299491,28.9536473338443,16.3859719507501,85.8125908564757,0.728228239448258 -6.52221762717001,0.91477784362609,24.9460647481528,0.235086894386527,60.3243644889098,7.75598972000269,1639.54447137064,680.260020566022,160.705315769748,29.931440904905,16.8533003021826,48.2661399785982,0.397923162068421 -13.0691103920329,0.92782227888043,24.9683285219099,0.231988621415194,61.2391761388802,7.87360836071317,1688.14188140885,692.405779619886,245.616465036947,30.465854303275,17.1088785513281,98.0423188814217,0.795868435405181 -11.2901444723039,0.953960499664496,25.0091303412222,0.226000920680948,63.0672733715652,8.10864943348696,1787.51319409109,716.65948741528,229.587914041282,31.5330174462723,17.6196087000012,86.992585520139,0.685092501091739 -10.1856883712762,0.976540788609104,25.0406527764937,0.221053435624073,64.6414525528343,8.31104389965013,1875.49669495756,737.524539905611,220.483611468645,32.4510797558469,18.0593997313058,80.2703253073748,0.616288597793446 -14.7168490949802,0.996912165351656,25.0664255962766,0.216759192374532,66.0578413751149,8.49315103394334,1956.57311664364,756.281714675988,286.324948042341,33.2763954457435,18.4551076076968,118.308276055709,0.888253697621887 -13.7225114301121,1.02634586354162,25.0996631956801,0.210822116155523,68.0983678516983,8.75550443807549,2076.56365197065,783.276212189851,280.994170628441,34.4641533363534,19.0251858136718,113.451905799841,0.825481821325105 -10.816437840661,1.05379088640184,25.1268678501801,0.20555399798773,69.995136832937,8.99937473566333,2191.47799228847,808.338819910207,247.162954379706,35.5669080760491,19.5551013381123,91.7312013870843,0.648798955558408 -12.8623291298772,1.07542376208316,25.1460272006553,0.20157272342343,71.4865078533874,9.19112243829267,2284.11790815506,828.024454441548,281.978663498967,36.4330759954281,19.9717575910637,111.243097728695,0.769889413893804 -14.1478121549792,1.10114842034292,25.1664726000935,0.197023712691922,73.2560134541069,9.41863030124231,2396.6463246909,851.358473848795,307.829786744212,37.459772849347,20.4661185267815,125.188655249443,0.844851206715583 -10.8555957019155,1.12944404465288,25.1863471916489,0.192239432944515,75.1977729008894,9.66828508725721,2523.39075014522,876.935986311119,265.650564786315,38.5851833976892,21.0086033975047,98.4447835735337,0.646713384255583 -11.0993368301995,1.15115523605671,25.1999431256371,0.188715546096349,76.6846653632697,9.85945697527753,2622.75200951499,896.502626426457,274.565808596585,39.4461155627641,21.4240084398596,102.5294412184,0.660117216118531 -13.568084538822,1.17335390971711,25.2125148532172,0.185237603229543,78.2024329806775,10.0545985260871,2726.24007799684,916.458962697381,318.850786637231,40.3241943586847,21.8480393212757,127.678279472747,0.805640658471192 -16.4971864488835,1.20049007879475,25.2262441571925,0.18114903728575,80.0545909876401,10.2927331269823,2855.35181726442,940.790170804074,373.482727025559,41.3947675153792,22.3654915209449,158.727996995137,0.977776629910409 -10.3348974886028,1.23348445169252,25.2407946428701,0.17640518854336,82.3022628132546,10.5817195045613,3016.20089036043,970.286449748543,281.632774748363,42.6926037889359,22.9934415802414,102.095441461473,0.611308192921989 -6.95304413788432,1.25415424666972,25.248851343592,0.173553222947393,83.7081321589271,10.7624741347192,3119.12954784146,988.719540153709,229.455338382896,43.5036597667632,23.3862105462968,69.8083579179077,0.410796274322147 -9.00973354518552,1.26806033494549,25.2538580690473,0.17168400194332,84.6530726309822,10.8839664811263,3189.31527331777,1001.10248684552,267.025327496874,44.0485094212028,23.6502061254985,91.4355195447515,0.531917327108769 -15.6877482156484,1.28607980203586,25.2598891148891,0.169318936848877,85.8765186648459,11.0412666854802,3281.38475792988,1017.12745792761,386.026693623099,44.7536081488149,23.9920100315473,161.415476431828,0.92533801682606 -13.6259336297694,1.31745529846716,25.2692727571396,0.165347969304656,88.0042618444706,11.3148336657177,3444.72376670439,1044.97758045118,359.011793969757,45.9790135398519,24.5864546655845,143.542966257681,0.802559126396787 -10.4723127635367,1.3447071657267,25.2763977458718,0.162042700538525,89.8499775229471,11.5521399672361,3589.71938616316,1069.11738122691,309.634996111116,47.0411647739842,25.1021070204059,112.554260725533,0.616110870749928 -10.7110453834933,1.36565179125377,25.2813002370154,0.15958844327547,91.2671434529,11.7343470153729,3703.13244395458,1087.64116184824,318.844086272799,47.8562111213227,25.4980320035843,116.877068597587,0.629648713663442 -11.3625258593164,1.38707388202076,25.2858509844599,0.157152028330603,92.7154779261424,11.9205614476469,3820.90855602521,1106.56299766795,335.959626395463,48.6887718973897,25.9026647920498,125.893592208284,0.667434863611444 -15.1570929677971,1.40979893373939,25.2902145956771,0.154645521516862,94.250739226678,12.1179521862872,3947.81462317105,1126.61077887524,413.049910726614,49.5708742705106,26.3315830236708,170.637857867346,0.889658642307582 -11.7737995457054,1.44011311967498,25.2953715779612,0.151421124567691,96.2969968268858,12.381042449171,4120.25560223883,1153.31678235808,356.765644416924,50.7459384237553,26.9032623795017,135.350623899051,0.690442205868936 -10.6219765176094,1.4636607187664,25.2989115183682,0.14900588778343,97.8852662736601,12.5852485208992,4256.69518892669,1174.0349326372,340.078070003847,51.657537036037,27.3469899210026,124.074461350785,0.62249515501688 -11.1679845453287,1.48490467180161,25.3017935791659,0.146890850508661,99.3173115066653,12.7693686222855,4381.65658946667,1192.707863827,355.870036811486,52.4791460083879,27.7470718541091,132.317597916604,0.654142334679536 -9.05093328369608,1.50724064089227,25.3045361205648,0.144729744438387,100.822171964241,12.9628506811167,4514.9552826765,1212.32323945806,318.611163539509,53.3422225361547,28.1674967590257,108.825304996237,0.529863667525806 -8.57305196232164,1.52534250745966,25.306561908206,0.143023626092595,102.04120838124,13.1195839347308,4624.4253638677,1228.20804389168,312.726293160373,54.0411539312337,28.508068715134,104.300993008223,0.501690081248363 -11.9963730923388,1.54248861138431,25.3083319004076,0.141443686127259,103.195452656216,13.2679867700849,4729.3051288036,1243.24472597693,386.785898128011,54.7027679429848,28.8305391721882,147.569504732543,0.701775766483526 -10.0140419718713,1.56648135756898,25.3105865692215,0.139289695820095,104.809949965981,13.4755649956262,4878.00850198396,1264.27137669996,351.360290163172,55.6279405747982,29.281594201596,125.077703880855,0.585545900775574 -8.59974324691289,1.58650944151273,25.3122879442408,0.137540548527464,106.157122036104,13.6487728332133,5003.87676708123,1281.81155980696,325.92479736763,56.3997086315064,29.6579644402025,108.770716793029,0.502672900212778 -13.8494174687163,1.60370892800655,25.3136295215744,0.136072662776004,107.313668039312,13.7974716050544,5113.23078495148,1296.86645369772,441.846265145894,57.0621239626999,29.9810779494869,177.048186089522,0.809300853256342 -12.5502020049628,1.63140776294399,25.3155797795604,0.133772660445432,109.175571881749,14.0368592419391,5291.79252543124,1321.09704226708,421.209198483345,58.1282698597514,30.5012529211793,163.18270189656,0.733076218427733 -13.048208318553,1.65650816695391,25.3171456424203,0.131753805922635,110.862174878597,14.2537081986768,5456.2188814255,1343.04034688599,438.713921061775,59.0937752629835,30.9724526932327,172.244219779408,0.761906041132742 -15.4289611814367,1.68260458359102,25.3185936180167,0.12971778409193,112.615123807065,14.4790873466227,5629.80814126343,1365.84136148515,499.072579656001,60.0970199053464,31.4621880589703,206.852784346406,0.900632327178097 -13.220831045457,1.71346250595389,25.3200968030889,0.12738924593908,114.687223857574,14.7455002102595,5838.54261380009,1392.78709571411,457.784235647098,61.282632211421,32.0410872268813,180.473950750123,0.771473826034513 -14.6744254829537,1.7399041680448,25.3212262289061,0.125458882745886,116.462238883666,14.9737164278999,6020.39895576884,1415.86438762986,498.58810242852,62.298033055714,32.5369873748407,203.385575584845,0.856070373880828 -12.3771664239417,1.76925301901071,25.3223296504764,0.123383113052303,118.431894474234,15.2269578609729,6225.48842919364,1441.46723092982,452.837371241796,63.4245581609122,33.0872658144224,174.420416953411,0.721864528611161 -8.30551838108739,1.7940073518586,25.3231517134587,0.121684580493169,120.092821456216,15.4405056157992,6401.12156682518,1463.05330026531,361.84128377361,64.3743452116736,33.5512922727946,118.669957989799,0.484300143581058 -12.8703977351198,1.81061838862077,25.3236533481343,0.120570606054503,121.207183476956,15.5837807327514,6520.33778331882,1477.53423877282,475.366821932463,65.0115065060042,33.8626205054249,185.586400489081,0.750388449631874 -17.5024069731262,1.83635918409101,25.324359085768,0.118883844884963,122.933760626036,15.8057692233475,6707.23629890486,1499.96823680202,595.493209833851,65.9986024192889,34.3449881761808,255.947163965479,1.02027031828359 -9.82761584378681,1.87136399803726,25.3251946020614,0.116663911109864,125.281266238125,16.1075913734733,6965.61092818679,1530.46560258242,415.51140787359,67.3404865136264,35.000829599075,146.440793652955,0.57276022476205 -14.8268683831841,1.89101922972484,25.3256082501731,0.115453193506121,126.599182937103,16.277037806199,7112.81734768733,1547.58508394251,545.841667553417,68.0937436934704,35.369026530602,223.244677061804,0.864026904682818 -16.670401818256,1.9206729664912,25.3261659297282,0.113673186661467,128.587260671192,16.5326478005818,7337.8051756096,1573.40726014861,601.589581347018,69.2299194465387,35.9244517117962,254.922321501423,0.971314041079683 -15.4149286674,1.95401377012772,25.326708836671,0.1117360072921,130.822200648551,16.8199972262423,7594.93180715081,1602.43247915913,579.381729102403,70.5070290830019,36.548844772791,239.800566299458,0.898030812662004 -12.3928009689304,1.98484362746252,25.3271421939176,0.11000233453419,132.888548814085,17.0856705618109,7836.61776914167,1629.26539899861,508.667229941956,71.6876775559387,37.1261369905814,195.818848176034,0.721883481245894 -10.4851561842095,2.00962922940038,25.3274488421256,0.108646944934399,134.549614711054,17.2992361771355,8033.65552576276,1650.83371474498,463.998402237256,72.6366834487793,37.5902022587448,167.7387542842,0.610709953218915 -9.90626867627027,2.0305995417688,25.3276824450438,0.107525923035169,135.954882592171,17.4799134761363,8202.26698408822,1669.0794885972,453.215628575713,73.4394974982769,37.9828031888356,160.126954689734,0.576953988619449 -10.9382513143009,2.05041207912134,25.3278834651907,0.106487776383637,137.282482455137,17.6506048870891,8363.17306360221,1686.31597978949,485.836872094783,74.1979031107376,38.3537053833514,178.528755623175,0.637020900784014 -9.04501767607766,2.07228858174994,25.3280852334845,0.105364457576292,138.748298487551,17.8390669483994,8542.65187213743,1705.34606875546,438.815304844657,75.0352270252404,38.763222134855,149.199596343449,0.526731736736262 -10.9586459149586,2.09037861710209,25.3282374678955,0.104453266473771,139.960342461799,17.9949011736599,8692.50119776504,1721.08088500557,495.924803941091,75.7275589402453,39.1018405562926,182.339736167713,0.638141981266525 -16.1117280957809,2.11229590893201,25.3284057870944,0.103370140910424,141.428744554095,18.1836957283836,8875.79478757591,1740.1430221228,646.049923998231,76.5662929734034,39.512079796034,270.886150621575,0.938167882112159 -8.9056789119109,2.14451936512357,25.3286245083767,0.101817784828689,143.587505562741,18.4612507152095,9148.74307999231,1768.16575809573,450.235234089833,77.7992933562119,40.1151901291074,152.010742424316,0.518533045937227 -11.0637760928849,2.1623307229474,25.3287322505919,0.100979529992379,144.780690949288,18.6146602649085,9301.38395896497,1783.65379992591,516.112133491727,78.4807671967398,40.4485398760302,190.412930019335,0.644166698040669 -11.2436003389495,2.18445827513316,25.3288544223834,0.0999571361843007,146.262965496525,18.8052384209818,9492.76952530043,1802.89377898382,526.649487980533,79.327326275288,40.8626547744882,195.484718190378,0.654611514815008 -12.8576696941051,2.20694547581106,25.3289665241632,0.098939082131522,147.769276390515,18.9989069644948,9689.25886209949,1822.44516393894,579.507225035631,80.1875872133133,41.2834848994294,225.845139885379,0.748557266175009 -13.0768279219054,2.23266081519927,25.3290813379501,0.0977999649470258,149.491762344538,19.2203694442977,9916.41789767204,1844.80176301094,592.800561589888,81.1712775724812,41.7647095802923,232.367287855927,0.761288216970229 -13.8119631621991,2.25881447104309,25.3291850340405,0.0966679849966022,151.243545911318,19.4455987600266,10150.1443992872,1867.53796550784,621.871547307728,82.1716704823448,42.2541193696122,248.301491908762,0.804058020017973 -14.6807566864776,2.28643839736748,25.3292818767622,0.0955004423033468,153.093747765929,19.6834818556194,10399.9623752052,1891.55087809784,655.939600902199,83.2282386363049,42.7710250633497,267.143833652667,0.854607035364916 -11.2579410178118,2.31579991074044,25.3293722269738,0.0942899497129994,155.060268605205,19.9363202492406,10668.8196395403,1917.07278416288,558.921876984561,84.3512025031665,43.3204277223849,207.487230268737,0.655335615519299 -10.1683384595739,2.33831579277606,25.3294337327887,0.0933822488930768,156.568256895287,20.1302044579654,10877.3145553614,1936.64334876507,530.483213501824,85.212307345663,43.7417264748914,189.225861670154,0.59189636069528 -9.34236926109352,2.35865246969521,25.3294840895293,0.0925772763334125,157.93026806652,20.3053201799811,11067.3625363081,1954.3191524587,509.20213624864,85.9900427081828,44.1222424318881,175.365828917953,0.543807444159576 +"P0","dD","D","H","fc","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","NPP","turnover","dWs","dWfr" +4.51106303704964,5.72082393359394,0.1,9.30685130731739,0.802314767872188,2.46024211324268,0.316316843131202,7.30958392378022,7.02392939699003,6.58607225315533,0.309052893467561,0.687337521113514,3.35380910314455,0.802958140256128,2.33207397726619,0.21877698562223 +5.97110627505664,8.6929386396106,0.111441647867188,10.1248091609468,0.78321560444251,2.98269910764054,0.383489885268069,9.87578844430614,9.41167108368952,10.5690022872038,0.414113527682339,0.833300511294398,5.59295294893623,0.973474324142022,4.2622737554349,0.357204869359314 +5.25390354483296,7.35980997202353,0.128827525146409,11.2884979167956,0.755386995932424,3.84432321182986,0.494270127235268,14.714427387286,13.8339819471833,11.9859299715181,0.608695205676066,1.0740193302746,6.18192926134046,1.25468570759722,4.59627922625282,0.330964327490419 +7.63967042579342,12.3929814949625,0.143547145090456,12.203827416069,0.732897952745216,4.63090305851931,0.595401821809626,19.7503618922646,18.3413018765605,20.9947186968882,0.807017282568661,1.29377243468301,11.3363573877819,1.51140462459367,9.23177046186931,0.593182301318965 +7.71699608166882,12.7874695919036,0.168333108080381,13.6123109007824,0.697114840351732,6.05726361568862,0.778791036302823,30.294293282628,27.5151123895342,27.7392363688944,1.2106649451395,1.69226619442386,14.9017831375987,1.97693109215332,12.2595328430996,0.665319202345687 +6.01901695548704,9.29027847129306,0.193908047264188,14.9073859055712,0.662746849730949,7.641390601414,0.982464505896085,44.0233453035783,39.0161437719263,27.2940330622924,1.71671032596476,2.13483642344184,14.0654917877315,2.49394836112083,11.0557901290904,0.515753297520265 +5.57841317193794,8.39526198552196,0.212488604206775,15.7575681097,0.639286539158482,8.85115425595513,1.13800554719423,55.8792234106354,48.608542913433,29.3008577450493,2.13877588819105,2.47281777372023,14.8135584498828,2.88878331210843,11.4411615218979,0.483613615876442 +8.01927620601824,13.9399372941946,0.229279128177818,16.466034426473,0.61910813151697,9.97995570326781,1.28313716184872,67.9841925508349,58.1211400212724,47.4934296366508,2.55733016093599,2.78818006446755,25.2887516467484,3.25719433392367,21.2060999245331,0.825457388291601 +7.68167675640505,13.3667115340709,0.257159002766208,17.5284926258235,0.587604141502991,11.9157498143985,1.53202497613695,91.0411882744544,75.5577820568457,54.318422770399,3.32454241050121,3.32899835164703,28.5989292049505,3.88898647788611,23.8894701117357,0.820472615328629 +6.75770324410776,11.3740809984188,0.28389242583435,18.4274568090356,0.559568948759071,13.829111578154,1.77802863147695,116.644131812233,94.0175601742685,55.457864681776,4.13677264766782,3.86354953448152,28.474525499776,4.51345729528764,23.2449971797851,0.7160710247033 +5.88395141813509,9.40520998148822,0.306640587831187,19.1103503539067,0.537255686756445,15.4907826638096,1.99167205677552,141.129501685707,110.909116971031,54.0894027143435,4.88000114672537,4.32778387904981,26.928970613141,5.05578291335325,21.2714967954537,0.601690904334045 +7.15238142037183,12.5064101411726,0.325451007794163,19.623702893677,0.519801286461809,16.8826902929905,2.17063160909878,163.245824894383,125.602838803376,71.657568350019,5.52652490734855,4.7166522486751,36.8486347163972,5.51006485386613,30.5303209504517,0.808248912079418 +5.65325234718398,8.97673686620753,0.350463828076509,20.2412976301482,0.497894307795414,18.7523898927688,2.4110215576417,195.260606075031,146.033430046453,62.9107325889391,6.42547092204394,5.23900518346196,30.7477538900599,6.12028549247508,24.0415556328468,0.585912764738114 +4.81650198985384,6.96634722675687,0.368417301808924,20.6429469785234,0.483029539047884,20.1041996066089,2.58482566370686,220.060255870452,161.24729133011,57.462997696379,7.09488081852485,5.61667107769518,26.8508674800954,6.56148053094818,19.8324137063037,0.456973242843529 +4.9810364184385,7.39349338498421,0.382349996262438,20.9326655027677,0.47196028434386,21.1573220493712,2.72022712063345,240.345832224479,173.331179314501,62.5388888219956,7.62657188983804,5.91089031950924,29.400855967589,6.90519192160798,22.0092870281885,0.486377017792504 +4.85000881520764,7.09029711951091,0.397136983032406,21.2205844482112,0.460637212461473,22.2778228415111,2.86429150819428,262.862047693503,186.392266743879,64.1187460870282,8.20125973673066,6.22393358981569,29.8161316562891,7.27089382849318,22.0777955025634,0.467442325232521 +6.16120250835905,10.4040779299032,0.411317577271428,21.4789721858788,0.450171749417732,23.3542453052975,3.00268868210967,285.402593388161,199.122219971633,85.388830971158,8.76137767875185,6.5246623449034,42.0616745685017,7.62220973150917,33.7526333789555,0.686831458036974 +5.27742123144169,8.22314302748046,0.432125733131234,21.8290019379091,0.435477539893979,24.9355574549192,3.2060002442039,320.143006778215,218.118038027627,78.0927269318696,9.5971936732156,6.96644617064042,36.9174522528082,8.1383083122099,28.2358288528599,0.543315087738353 +6.15592523474636,10.4985292838236,0.448572019186195,22.0829999772956,0.424392697977056,26.1857685404575,3.36674166948739,348.989461850704,233.360959006413,95.6595664075622,10.2678821962822,7.31572764329594,46.8455739407904,8.54634423792954,37.605675321911,0.693554380949977 +5.74789423499379,9.50397932532652,0.469569077753842,22.3806806297179,0.410880765196953,27.7809986057734,3.57184267788516,387.580707361033,253.066376229662,94.7602870423251,11.1349205541051,7.76139982848377,45.5183799958417,9.06698525924694,35.8242025594346,0.627192177160214 +5.97149900968766,10.127444252378,0.488577036404495,22.626555972576,0.399233902682805,29.2231197701014,3.7572582561559,424.203685476345,271.100132171089,103.557054529396,11.9284058155279,8.1642967551314,50.078611175242,9.53765557331882,39.8737252978456,0.667230304077618 +8.25030987196153,16.1460181633719,0.508831924909251,22.8660438421624,0.387399174373746,30.7567509890235,3.95443941287446,464.975014708175,290.479297408328,150.584566718388,12.7810890859664,8.59275957781142,77.5264308327664,10.0381923557582,66.426999476072,1.06123900093615 +4.56905157566767,6.53044383909058,0.541123961235995,23.2047588901903,0.369676893365644,33.1931828444188,4.26769493713957,533.654863629614,321.629933984687,90.0004550662801,14.1517170953262,9.27344503670805,39.9451757605475,10.8333794558158,28.684610651208,0.427185653523675 +4.12963609467907,5.37159546507656,0.554184848914176,23.3281489610887,0.362883851511289,34.1751162835838,4.39394352217505,562.703294288887,334.292468684623,83.7512949529029,14.7088686221234,9.54777563707506,35.6967904162226,11.1538566332136,24.1923267618891,0.350607021119938 +6.04893594380307,10.5065691068827,0.564928039844329,23.4242544580923,0.357449469391972,34.9811418246988,4.49757537746128,587.140341258371,344.727013163015,125.569080313727,15.1679885791726,9.77296144070071,60.3768781763123,11.4169221120171,48.2754909928686,0.684465071426604 +6.2945563317988,11.2119143099175,0.585941178058095,23.5990981439794,0.347202942649357,36.5531239580325,4.69968736603275,636.346013263859,365.170979005729,136.539833968137,16.0675230762521,10.2121386651472,66.1561033360424,11.9299756214677,53.4985695396343,0.727558174940365 +5.85813704977592,10.0791854485343,0.60836500667793,23.7680242384741,0.336799057189977,38.223669731759,4.91447182265473,690.893988327619,387.014292057569,132.880622603493,17.028628850533,10.6788524023194,63.1038848103846,12.475197703662,49.977504041231,0.651183065491647 +6.43461919416815,11.6859713482861,0.628523377574999,23.9057643733421,0.327886253694149,39.7190765803332,5.10673841747141,741.71213977051,406.653405978572,151.667224724812,17.8927498630572,11.0966361768603,73.6067032109369,12.9632590597351,59.8915269360905,0.751917215111277 +6.28452517962829,11.3237478293486,0.651895320271571,24.0503299277295,0.318042519963313,41.4451747166932,5.3286653207177,802.724737262861,429.404750928107,154.566791560146,18.8938090408367,11.5788700220003,74.4564674983851,13.5266119679757,60.2047463930205,0.725109137389003 +7.59957366756298,14.9941305432507,0.674542815930268,24.1764006186561,0.308975563582457,43.1098228057425,5.54269150359546,863.97378973908,451.413542754418,194.417437077668,19.8621958811944,12.0439360758227,97.5067830723904,14.0699092014346,82.4812350477476,0.955638823208184 +6.21149543939323,11.2170247835436,0.704531077016769,24.3244303347851,0.29763536598408,45.3020552806785,5.82454996465866,948.271872695356,480.474110520995,166.987446250236,21.1408608629238,12.6563976002054,79.9141126722639,14.7853960641335,64.4182194524633,0.71049715566715 +5.98687350548693,10.6261296950352,0.726965126583856,24.4226106406831,0.289614644779187,46.9332616048406,6.03427649205094,1013.6992438523,502.138603793136,166.744134266329,22.094098566898,13.1121207606372,78.9227489632764,15.3177787875139,62.9349616566192,0.670008519143344 +6.92465618391747,13.2853474280481,0.748217385973927,24.5067615780156,0.28235802853255,48.4717605396713,6.23208349795774,1077.53503057845,522.593715329677,199.185057712276,22.9941234745058,13.5419435160523,97.5893944330305,15.8199042640466,80.9353472990772,0.834142869906787 +6.28550492489152,11.5320441521732,0.774788080830023,24.6010799659635,0.273724236105251,50.386266173729,6.47823422233659,1159.87160371805,548.06660688132,187.941242744462,24.1149307027781,14.0768142710841,89.8496986623596,16.4447484105467,72.6846052773606,0.720344974452333 +4.49737721088138,6.50288924449187,0.797852169134369,24.6741442384487,0.266600942148725,52.040277312624,6.69089279733737,1233.60704449013,570.081669389506,138.889259921149,25.0835934531383,14.5389085950463,59.5600547237784,16.9845740240103,42.1710267562616,0.404453943506581 +6.82253612162997,13.1036095636866,0.810857947623353,24.7120668519223,0.262727965721625,52.9698716803164,6.81041207318354,1276.11116119216,582.455350270129,214.459115874962,25.6280354118857,14.7986168103034,104.419478191664,17.2879691088505,86.318438316377,0.813070766436323 +8.09628414307588,16.7700500435536,0.837065166750726,24.7819519266607,0.255222084367016,54.8365158033353,7.05040917471453,1363.77878759673,607.29868093099,263.46646295392,26.7211419609636,15.3201161121042,132.855122928511,17.8971925204292,113.922131204272,1.03579920381027 +5.94274261303538,10.6687102897861,0.870605266837834,24.859985077216,0.246162324472608,57.2133301069855,7.35599958518385,1479.90325457544,638.916795471999,201.768745702622,28.1123390007679,15.9841457386294,94.6033565779349,18.6729220239282,75.2751334635219,0.655301090484798 +7.21579747724692,14.3420120748679,0.891942687417406,24.9037403525511,0.240696425746769,58.7187229758241,7.54955009689167,1556.06724033549,658.929249251983,251.437867184224,28.9928869670873,16.4047193875398,123.624156497758,19.1642425536481,103.581922842076,0.877991102033989 +6.83611765295107,13.2848079689127,0.920626711567142,24.9562120191458,0.233688373455423,60.7347587986915,7.8087547026889,1661.25266690492,685.709434020288,246.386317319173,30.1712150968927,16.9679554436608,119.548288067172,19.8222234760565,98.9162352222531,0.809829368862466 +6.12998078400691,11.272077756155,0.947196327504967,24.9990352555523,0.227522973177596,62.5948102769921,8.04790417847041,1761.54256388277,710.39355173062,227.7021793191,31.2573162761473,17.4876129055655,107.374350082432,20.429295222271,86.2604434409872,0.684611419174225 +6.53607583312854,12.4650018762403,0.969740483017277,25.0315000481816,0.222522208052401,64.167848082737,8.2501518963519,1848.79096362887,731.249115522337,248.88819847553,32.1749610829828,17.9270850616589,119.271691398533,20.9426932753548,97.5741549713976,0.754843151780884 +7.1035131367631,14.132376749895,0.994670486769758,25.0637058368613,0.217224128494856,65.9021509660703,8.47313369563761,1947.57248452963,754.220688890985,277.806577621007,33.1857103112033,18.4116111325988,135.725553706323,21.5087239966185,113.363626467799,0.853203241904944 +6.68824176082497,12.948309708761,1.02293524026955,25.0960372946064,0.211494472547868,67.8622671252646,8.72514863039116,2062.48744336608,780.154506268251,269.345717153811,34.326798275803,18.9592244649222,129.635816647851,22.1484542156083,106.708162526814,0.779199905428901 +6.1581683314449,11.4200839978472,1.04883185968707,25.1222019151984,0.206487535790646,69.6528106533575,8.95536136971739,2170.49767791386,803.817702071254,254.542290981472,35.3679788911352,19.4594629347137,119.828909493374,22.7328404000518,96.4107172548514,0.685351838470396 +8.06064954658003,16.9909115414474,1.07167202768276,25.1428390069104,0.202252747603392,71.2280873335428,9.15789694288407,2267.92133252094,824.614657252035,340.714854929807,36.2830449190895,19.8995605830705,170.719349656588,23.2469691627057,146.455007094015,1.01737339986701 +7.92419280530731,16.6200092149109,1.10565385076566,25.1698120655593,0.196246898019613,73.5655063466234,9.45842224456586,2416.61919001554,855.43715922407,345.938588547058,37.6392350058591,20.5525840321069,172.648061705455,24.0098410823595,147.64612893792,0.992091685175668 +6.8908488253067,13.6113322391074,1.13889386919548,25.1924313050802,0.190690403921272,75.8452541560662,9.75153267720851,2566.41257486524,885.458476510731,310.149353290477,38.9601729664722,21.1894954156135,149.999810945035,24.7538906421447,124.435643811426,0.810276491464526 +6.41599754089244,12.2285472182085,1.1661165336737,25.2085556855708,0.186357991628689,77.7078672418074,9.9910115025181,2692.28946016297,909.957982198855,295.868632925862,40.0381512167496,21.7098685342817,140.472367904898,25.361798429469,114.384093970626,0.726475504803256 +7.3733979177683,15.0548981022531,1.19057362811011,25.221423677932,0.18262294834651,79.3781419600122,10.2057611091444,2807.8376677132,931.90659601351,347.326841998786,41.0038902245944,22.1765065445043,170.487867137813,25.9069320462897,143.688062491699,0.892872599824124 +6.07867478439008,11.2527027616962,1.22068342431462,25.235408838689,0.178217073801817,81.4307557288646,10.4696685937112,2953.29153874599,958.853498691067,293.74272593349,42.1895539424069,22.7499616740187,137.281926190238,26.5768510455745,110.03897490868,0.666100235984335 +6.06000065626262,11.2030124741647,1.24318882983801,25.2446722767121,0.175055051912288,82.9625150244002,10.6666090745657,3064.31789282019,978.944867056148,298.348821838847,43.0735741504705,23.1779015224869,139.258407699534,27.07677688159,111.519340090377,0.662290727567018 +6.94113097084152,13.8093923678542,1.26559485478634,25.2529934948537,0.172012567023254,84.4855898082402,10.8624329753452,3176.81664337479,998.908093942626,348.002710117346,43.9519561334755,23.6034151094465,168.268403324654,27.57386832203,139.879150777717,0.815384224907797 +6.66338984604927,12.9963297974775,1.29321363952205,25.2621426100253,0.168399933939935,86.3605763101158,11.1035026684435,3318.1851608079,1023.46544461355,341.491974163516,45.0324795629962,24.1272450883675,163.399349707291,28.1858144660488,134.447212710534,0.766322530708364 +4.8327170357636,7.58682609842304,1.319206299117,25.2697577692411,0.165131670107867,88.1229177359919,11.330089423199,3453.95275674801,1046.52997253766,252.726033941288,46.0473187916572,24.619604511246,109.235466383031,28.7609962281204,80.0276448880751,0.446825266835415 +7.56486853832027,15.6730997778151,1.33437995131385,25.2738017781918,0.163280032288862,89.1507818105098,11.462243375637,3534.43071573915,1059.97469588777,400.217696551406,46.6388866190618,24.9067671206566,197.203225687013,29.09646395354,167.184289812915,0.922471920557719 +6.79776305306633,13.4088551560273,1.36572615086948,25.2813168180963,0.159579858834912,91.2721728025958,11.734993646048,3703.53815439624,1087.70688406786,368.19183935452,47.8591028989859,25.4994370932436,176.899979617374,29.7888300245835,146.322912327283,0.788237265507842 +6.55108153415802,12.6820625133953,1.39254386118153,25.2869431822726,0.156541488982179,93.0851255245842,11.9680875674465,3851.27012102615,1111.39082839316,361.878715467997,48.9011964492989,26.0059361988073,172.182949691934,30.3805299789028,141.057614156743,0.744805556288709 +7.37489698475984,15.1286882929579,1.41790798620833,25.2916649619828,0.15376991780891,94.7982983256089,12.188352641864,3993.58928767806,1133.75862506141,414.883579686859,49.8853795027021,26.484558989612,203.108184716727,30.9396643985779,171.280754497045,0.88776582110463 +6.84902501061994,13.5727832763006,1.44816536279424,25.2966252661696,0.150586639720526,96.8402308491593,12.4508868234633,4166.66687824375,1160.40398966829,393.599297711207,51.0577755454048,27.0550300141764,189.291895290976,31.6060973210992,156.890039655707,0.795758314169167 +6.86022254840374,13.6089402219773,1.47531092934684,25.3005267030915,0.147838658604879,98.6706967663468,12.6862324413874,4325.0044955809,1184.27726458664,401.69474130844,52.1081996418121,27.5664219211884,193.212071847264,32.203513120445,160.211253032689,0.797305694129923 +7.3477007125301,15.0596995716975,1.5025288097908,25.3039806882716,0.145180420590031,100.504782567108,12.9220434729138,4486.67224192437,1208.1867447942,438.235881322554,53.1602167709448,28.0788251440334,214.198103644545,32.8021103543197,180.514267807756,0.881725482469393 +7.00480034851913,14.0434466759859,1.53264820893419,25.3073330995929,0.142346210552373,102.533064162292,13.1828225351518,4668.97154132753,1234.61603936984,426.215701191288,54.3231057322728,28.6454823995328,205.94826783569,33.4640879738469,171.662489886118,0.821689975724731 +4.42412520338839,6.37133082916498,1.56073510228616,25.3100689184987,0.139799668103702,104.423344490898,13.4258585774011,4842.18753487884,1259.23696302049,274.154105891564,55.4064263729016,29.173585137178,113.74445662889,34.0810256195567,79.2908443697532,0.372586639580628 +7.68724424133283,16.0758050936054,1.57347776394449,25.3111987239543,0.138673703562616,105.28061092448,13.5360785474331,4921.79833277223,1270.39987472213,480.273719660655,55.8975944877737,29.4130865188593,236.977823192413,34.3608147742532,201.677133514537,0.93987490362273 +6.53549245480389,12.6512986828117,1.6056293741317,25.3137728650522,0.135910679878506,107.442784882976,13.8140723420969,5125.51335906766,1298.54699945487,416.701746662533,57.1360679760141,30.017150355036,197.72911699889,35.0664913299382,161.923360050046,0.739265618905277 +6.35274927564195,12.1079573499568,1.63093197149733,25.3155483249319,0.133811519654862,109.14359579239,14.0327480304501,5288.69975770069,1320.68096909909,411.461987712382,58.10996264036,30.4923195052863,193.715823340042,35.6215911542195,157.386983357953,0.707248827869675 +5.91699470875076,10.8109050756738,1.65514788619724,25.3170653166043,0.131861669216528,110.770786335755,14.2419582431685,5447.24427203332,1341.85148594376,388.95214086689,59.0414653815252,30.9469207449107,179.378252844273,36.1526632326586,142.594312195563,0.631277416050734 +7.11070596588075,14.3652182893664,1.67676969634859,25.3182847175782,0.130167592858358,112.223231155346,14.4287011485444,5590.76186112807,1360.74438227409,473.549340451099,59.8727528200599,31.3527018737182,229.394331454393,36.6267029155359,191.929031875615,0.838596663242167 +7.75749795348562,16.2922297157796,1.70550013292732,25.3197290275256,0.127982122009404,114.152620071343,14.6767654377441,5784.32185279272,1385.83571261183,525.505541897967,60.9767713549206,31.8917306902917,259.582223911653,37.2564045727351,221.375040254999,0.950779083919013 +4.4957307046228,6.57528448774093,1.73808459235888,25.3211528130389,0.125589859706514,116.34010643624,14.9580136846595,6007.79596612599,1414.27666358085,310.3841191862,62.2281731975576,32.5028662559439,129.391847839619,37.9703424302894,91.0379126533688,0.383592755961183 +5.53202541156165,9.66232814919672,1.75123516133436,25.3216698966454,0.124649311839636,117.222744229358,15.0714956866318,6099.17593491703,1425.75051927657,384.827232241749,62.7330228481692,32.7494558373096,173.606852133762,38.2584121276037,134.784822262239,0.56361774391899 +7.72147588826699,16.1863805557521,1.77055981763276,25.3223754169807,0.123292270403731,118.51958437557,15.238232276859,6234.69958480614,1442.60696592438,543.075469250406,63.4747065006728,33.111764443678,267.893398983633,38.6816665489498,228.26771625578,0.944016178903606 +6.5999758180716,12.8438423983546,1.80293257874426,25.3234259836732,0.121083505276179,120.691593114779,15.5174905433287,6465.04146813335,1470.83440087062,472.703818953085,64.7167136383074,33.7185759012207,224.561117648134,39.3905529176806,184.42168245272,0.748882277733266 +6.8166473964829,13.4893606625801,1.82862026354097,25.3241555825511,0.119386014914728,122.414700372915,15.7390329050891,6650.76971345345,1493.22422696236,495.192605019863,65.7018659863437,34.1999741607844,237.174458923641,39.9529296821493,196.435151692866,0.786377548626018 +5.32509727569949,9.04161832682205,1.85559898486613,25.3248348377175,0.11765340651995,124.224089088532,15.971668597097,6848.6465841758,1516.73201592906,392.557349907806,66.7362087008786,34.7054775613759,174.669398187331,40.5434664387847,133.598931172164,0.527000576382554 +7.97360835993438,16.9386276011749,1.87368222151977,25.3252453483367,0.116519801533915,125.436714529821,16.1275775824055,6982.89344186759,1532.48492032709,593.539077834348,67.4293364943918,35.0442584319123,294.639289744827,40.9392354014909,252.712872437976,0.987181905359288 +6.89300044675697,13.7156193364446,1.90755947672212,25.3259286246983,0.114453558888626,127.708128152148,16.4196164767047,7237.88095507121,1561.98899880744,522.392090520488,68.7275159475272,35.6788414268908,250.791439887642,41.6805649024044,208.311673070999,0.799201914238638 +5.26652282508213,8.86343576828241,1.93499071539501,25.3264092606553,0.11283315861876,129.547065245134,16.656051245803,7447.68453779083,1585.87267393936,404.875312643241,69.7783976533319,36.1925999940551,179.342588997512,42.2807454701152,136.545442324012,0.516401203384928 +6.08722335648038,11.3108622912311,1.95271758693158,25.3266892424396,0.111810089391957,130.73531938972,16.8088267786783,7584.85317701742,1601.3042111599,472.260819467813,70.4573852910354,36.5245720604612,219.16731726979,42.6685602843372,175.839814113116,0.658942872337212 +5.80896750876091,10.4799155435318,1.97533931151404,25.3270150597917,0.110531054310357,132.251555349208,17.0037714020411,7761.70805769517,1620.99387781336,455.899884635363,71.3237306237878,36.9481750303511,208.576787388735,43.1634197128735,164.802888571085,0.610479104775902 +7.78794480336613,16.383621599156,1.9962991426011,25.3272882528751,0.109371730506603,133.656285190855,17.1843795245385,7927.38252528015,1639.23434985549,617.70625313226,72.1263113936414,37.3406256440507,304.943589656741,43.621886485367,260.36739260079,0.954310570583362 +8.26991426172695,17.8212132925492,2.02906638579942,25.3276661158517,0.107607099897109,135.852145499919,17.4667044214181,8189.88052588774,1667.74559891803,666.710439247323,73.3808063523933,37.9541007054763,333.225319313672,44.338557377446,287.848826387601,1.03793554862492 +6.73731109428416,13.2468350160601,2.06470881238451,25.3280176012061,0.105750979513948,138.240432415899,17.7737698820442,8480.25093570845,1698.75275288279,552.702503294163,74.7451211268427,38.621335527489,263.601627983899,45.1180312390352,217.712159054683,0.771437690180207 +6.21843458017346,11.6973511006776,2.09120248241663,25.3282441052809,0.104412142668151,140.015540678156,18.0019980871914,8699.35664887321,1721.7974576653,516.686433161994,75.7590881372734,39.1172617235817,241.086049980683,45.6973797597936,194.707513437714,0.681156783176294 +5.74718958761585,10.2899098123137,2.11459718461799,25.3284224999748,0.103257713296736,141.582919860161,18.203518267735,8895.15095465248,1742.14441262629,482.876572043109,76.6543541555569,39.555152984692,220.000238941716,46.2089309873272,173.192141064549,0.599166889840218 +7.79155475132858,16.3914363885919,2.13517700424262,25.3285643825726,0.102263040731213,142.961643145127,18.3807826900877,9069.18420719124,1760.04163273695,661.018180858538,77.4418318404258,39.9403379385992,326.181606647708,46.6589099056072,278.56828789789,0.954408844211479 +6.37447890188328,12.1603164214165,2.1679598770198,25.3287645142451,0.100717462781834,145.157780644712,18.6631432257487,9349.88713364684,1788.54849537084,549.104185711371,78.696133796317,40.5538904409584,257.912496884457,47.3756712653621,209.82882214266,0.708003476435719 +6.5040551061583,12.5462724436629,2.19228050986263,25.3288947332994,0.0996006395267304,146.786946007175,18.8726073437797,9560.89098089787,1809.69492601107,566.554109032377,79.6265767444869,41.0090434015926,267.551093331778,47.9073878726715,218.913260640773,0.73044481833335 +6.02775487770983,11.1233478298667,2.21737305474996,25.3290147165361,0.0984739914083491,148.467752739632,19.0887110665241,9781.05518356689,1831.51095407081,531.076965122374,80.5864819791156,41.478623824893,245.407115591019,48.4559588611766,196.303579502662,0.647577227180994 +7.86825243186233,16.6177355200017,2.23961975040969,25.32911015301,0.0974961923026586,149.957880782505,19.2802989577506,9978.34215031868,1850.85152401609,700.192292117438,81.437467056708,41.8949328172546,346.115935346085,48.94229735429,296.206219305294,0.967418686501001 +7.4651781811241,15.413292033854,2.2728552214497,25.3292357873966,0.096071003056041,152.183978029339,19.566511460915,10276.7434095373,1879.74347733965,674.184644977029,82.7087130029446,42.5168554138806,329.375445936122,49.6688367853996,278.809345452972,0.897263697750203 +6.69499559492098,13.1125185831063,2.3036818055174,25.3293364035916,0.0947858110368597,154.248651917469,19.8319695322461,10557.4413600266,1906.53953556085,612.831978573459,83.8877395646776,43.0936798753988,291.51033548003,50.3426918895477,240.4043419674,0.763301623082351 +5.71722218118665,10.1917235708941,2.32990684268362,25.3294115009699,0.0937191958484101,156.005075976532,20.057795482697,10799.2126899284,1929.33446652182,529.289825910607,84.8907165269601,43.5843861161717,240.488833960485,50.915942379154,188.979629455971,0.593262125360478 +5.10229470289402,8.35451347447815,2.3502902898254,25.3294639495582,0.0929065863847995,157.370229459934,20.2333152162772,10989.018204555,1947.05115731749,476.49446928777,85.6702509219696,43.9657799660573,208.115063039846,51.3614924720882,156.267261558641,0.486309009116385 +6.64907817101159,12.9732577153835,2.36699931677436,25.3295034379547,0.0922508877424596,158.489275959404,20.3771926233519,11145.8404625128,1961.57373008516,625.361393806355,86.3092441237471,44.2784169389864,296.864239646173,51.7267197362011,244.382368149284,0.755151760688667 +7.50429167976302,15.526584035243,2.39294583220513,25.3295590704651,0.0912508193499798,160.226951756539,20.6006080829836,11391.5611771324,1984.12433266013,713.534576827879,87.3014706370455,44.7638853278383,348.881532517797,52.2938512875736,295.683922248864,0.903758981359336 +5.80282004170579,10.4437851701799,2.42399900027561,25.3296175203138,0.0900820386897913,162.306585417359,20.8679895536604,11689.1622292395,2011.11222220252,558.914002617513,88.488937776911,45.3448892207309,255.048105371923,52.9725888669842,201.46762567534,0.607890829598647 +6.25546251951908,11.7949993764401,2.44488657061597,25.3296524113041,0.0893125575376809,163.705404819378,21.0478377624915,11891.4973005397,2029.26477557641,607.704134529585,89.287650125362,45.7356885876282,283.608477489957,53.4291266278629,229.492819924875,0.68653093721962 +6.57297094426391,12.7425793906757,2.46847656936885,25.3296880046465,0.0884591662971433,165.285182870947,21.2509520834075,12122.0965952848,2049.76541915996,644.711447770915,90.1896784430382,46.1770438201194,305.006835304655,53.944724519419,250.320435350945,0.741675434290741 diff --git a/pyrealm_build_data/t_model/rtmodel_test_outputs.r b/pyrealm_build_data/t_model/rtmodel_test_outputs.r index 70e9cb4a..bf19857a 100644 --- a/pyrealm_build_data/t_model/rtmodel_test_outputs.r +++ b/pyrealm_build_data/t_model/rtmodel_test_outputs.r @@ -12,10 +12,10 @@ tmodel <- function(P0, year, a, cr, Hm, rho, rr, P0 <- P0 * (1 - 0.1) aa <- length(year) # simulate years output <- matrix() - output <- matrix(NA, nrow = aa, ncol = 13, byrow = T) + output <- matrix(NA, nrow = aa, ncol = 16, byrow = T) colnames(output) <- c( - "dD", "D", "H", "fc", "Ac", "Wf", "Ws", "Wss", - "GPP", "Rm1", "Rm2", "dWs", "dWfr" + "P0", "dD", "D", "H", "fc", "Ac", "Wf", "Ws", "Wss", + "GPP", "Rm1", "Rm2", "NPP", "turnover", "dWs", "dWfr" ) # you can decide which index you want output dD <- 0 NPP1 <- NA @@ -80,7 +80,7 @@ tmodel <- function(P0, year, a, cr, Hm, rho, rr, a * d * (1 - H / Hm) + H )) * (1 / sigma + zeta) * dD output[i, ] <- c( - dD / 2 * 1000, d, H, fc, Ac, Wf, Ws, Wss, GPP, Rm1, Rm2, dWs, dWfr + P0[i], dD / 2 * 1000, d, H, fc, Ac, Wf, Ws, Wss, GPP, Rm1, Rm2, NPP1, NPP2, dWs, dWfr ) } diff --git a/tests/regression/demography/test_t_model_functions_against_rtmodel.py b/tests/regression/demography/test_t_model_functions_against_rtmodel.py index 218b3a07..cb62efbc 100644 --- a/tests/regression/demography/test_t_model_functions_against_rtmodel.py +++ b/tests/regression/demography/test_t_model_functions_against_rtmodel.py @@ -1,6 +1,8 @@ -"""Test TModel class. +"""Regression tests of the demography.t_model functions. -Tests the init, grow_ttree and other methods of TModel. +The original R implementation has been used to generate a set of predicted growth +trajectories across a set of PFT definitions (default from the original paper and then +two fairly randomly chosen variants). """ from importlib import resources @@ -71,7 +73,8 @@ def rvalues(): "Wf": "mass_fol", "Ws": "mass_stm", "Wss": "mass_swd", - "GPP": "gpp_actual", + "P0": "potential_gpp", + "GPP": "crown_gpp", "Rm1": "resp_swd", "Rm2": "resp_frt", "dWs": "delta_mass_stm", @@ -84,11 +87,11 @@ def rvalues(): # millimetres, not diameter increase in metres data["delta_d"] = data["delta_d"] / 500 - # The R tmodel implementation slices off foliar respiration costs from GPP - # before doing anything - the pyrealm.tmodel implementation keeps this cost - # within the tree calculation, so proportionally inflate the GPP to make it - # match - data["gpp_actual"] = data["gpp_actual"] / (1 - pft.resp_f) + # The reported P0 in the R tmodel outputs has already had fixed foliar + # respiration costs removed before calculating anything. The pyrealm + # implementation has this as a PFT trait, so in some tests the potential GPP + # will need to be proportionally scaled up to make them match, but this is not + # true for _all_ tests so the values here are left untouched. # Add a tuple of the inputs and outputs to the return list. return_value.append((pft, dbh_init, data)) @@ -180,3 +183,163 @@ def test_calculate_sapwood_masses(rvalues): rho_s=pft.rho_s, ) assert_array_almost_equal(actual_sapwood_masses, data["mass_swd"], decimal=8) + + +def test_calculate_whole_crown_gpp(rvalues): + """Tests calculation of sapwood masses of trees. + + Note that this test can used reported P0 from R directly - no need to correct for + foliar respiration. + """ + + from pyrealm.demography.t_model_functions import calculate_whole_crown_gpp + + for pft, _, data in rvalues: + actual_whole_crown_gpp = calculate_whole_crown_gpp( + potential_gpp=data["potential_gpp"], + crown_area=data["crown_area"], + par_ext=pft.par_ext, + lai=pft.lai, + ) + assert_array_almost_equal(actual_whole_crown_gpp, data["crown_gpp"], decimal=8) + + +def test_calculate_sapwood_respiration(rvalues): + """Tests calculation of sapwood respiration of trees.""" + + from pyrealm.demography.t_model_functions import calculate_sapwood_respiration + + for pft, _, data in rvalues: + actual_sapwood_respiration = calculate_sapwood_respiration( + sapwood_mass=data["mass_swd"], + resp_s=pft.resp_s, + ) + assert_array_almost_equal( + actual_sapwood_respiration, data["resp_swd"], decimal=8 + ) + + +def test_calculate_foliar_respiration(rvalues): + """Tests calculation of foliar respiration of trees. + + This is implemented as a fixed proportion of GPP - and the reported values from R + are automatically penalised by this proportion beforehand, so this test looks + circular but is important to validate this difference. + """ + + from pyrealm.demography.t_model_functions import calculate_foliar_respiration + + for pft, _, data in rvalues: + actual_foliar_respiration = calculate_foliar_respiration( + whole_crown_gpp=data["crown_gpp"], + resp_f=pft.resp_f, + ) + assert_array_almost_equal( + actual_foliar_respiration, + data["crown_gpp"] * pft.resp_f, + decimal=8, + ) + + +def test_calculate_fine_root_respiration(rvalues): + """Tests calculation of fine root respiration of trees.""" + + from pyrealm.demography.t_model_functions import calculate_fine_root_respiration + + for pft, _, data in rvalues: + actual_fine_root_respiration = calculate_fine_root_respiration( + zeta=pft.zeta, + sla=pft.sla, + resp_r=pft.resp_r, + foliage_mass=data["mass_fol"], + ) + assert_array_almost_equal( + actual_fine_root_respiration, + data["resp_frt"], + decimal=8, + ) + + +def test_calculate_net_primary_productivity(rvalues): + """Tests calculation of fine root respiration of trees. + + Again - this test has to account for the R implementation removing foliar + respiration from potential GPP before calculating crown GPP. + """ + + from pyrealm.demography.t_model_functions import calculate_net_primary_productivity + + for pft, _, data in rvalues: + actual_npp = calculate_net_primary_productivity( + yld=pft.yld, + whole_crown_gpp=data["crown_gpp"] / (1 - pft.resp_f), + foliar_respiration=data["crown_gpp"] / (1 - pft.resp_f) * pft.resp_f, + fine_root_respiration=data["resp_frt"], + sapwood_respiration=data["resp_swd"], + ) + assert_array_almost_equal( + actual_npp, + data["NPP"], + decimal=8, + ) + + +def test_calculate_foliage_and_fine_root_turnover(rvalues): + """Tests calculation of fine root respiration of trees.""" + + from pyrealm.demography.t_model_functions import ( + calculate_foliage_and_fine_root_turnover, + ) + + for pft, _, data in rvalues: + actual_turnover = calculate_foliage_and_fine_root_turnover( + lai=pft.lai, + sla=pft.sla, + tau_f=pft.tau_f, + zeta=pft.zeta, + tau_r=pft.tau_r, + crown_area=data["crown_area"], + ) + assert_array_almost_equal( + actual_turnover, + data["turnover"], + decimal=8, + ) + + +def test_calculate_growth_increments(rvalues): + """Tests calculation of fine root respiration of trees.""" + + from pyrealm.demography.t_model_functions import ( + calculate_growth_increments, + ) + + for pft, _, data in rvalues: + delta_dbh, delta_mass_stem, delta_mass_fine_root = calculate_growth_increments( + rho_s=pft.rho_s, + a_hd=pft.a_hd, + h_max=pft.h_max, + lai=pft.lai, + ca_ratio=pft.ca_ratio, + sla=pft.sla, + zeta=pft.zeta, + npp=data["NPP"], + turnover=data["turnover"], + dbh=data["diameter"], + height=data["height"], + ) + assert_array_almost_equal( + delta_dbh, + data["delta_d"], + decimal=8, + ) + assert_array_almost_equal( + delta_mass_stem, + data["delta_mass_stm"], + decimal=8, + ) + assert_array_almost_equal( + delta_mass_fine_root, + data["delta_mass_frt"], + decimal=8, + ) diff --git a/tests/regression/tmodel/test_tmodel.py b/tests/regression/tmodel/test_tmodel.py index 8aa1e33a..cbe95afd 100644 --- a/tests/regression/tmodel/test_tmodel.py +++ b/tests/regression/tmodel/test_tmodel.py @@ -37,6 +37,7 @@ def rvalues(): ("Wf", "mass_fol"), ("Ws", "mass_stm"), ("Wss", "mass_swd"), + ("P0", "potential_gpp"), ("GPP", "gpp_actual"), ("Rm1", "resp_swd"), ("Rm2", "resp_frt"), From 2b94a2c6877cd7ea21e369b6095a7ca6a809c952 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 13 Sep 2024 22:05:01 +0100 Subject: [PATCH 094/241] Docstring updates to T model functions --- pyrealm/demography/t_model_functions.py | 185 +++++++++++++++--- .../test_t_model_functions_against_rtmodel.py | 3 +- 2 files changed, 163 insertions(+), 25 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 82f64d24..b3e20818 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -101,7 +101,7 @@ def calculate_foliage_masses(sla: Series, lai: Series, crown_area: Series) -> Se The foliage mass (:math:`W_{f}`) is calculated from the crown area (:math:`A_{c}`), along with the specific leaf area (:math:`\sigma`) and leaf area index (:math:`L`) - of the plant functional type :cite:p:`Li:2014bc`: + of the plant functional type :cite:p:`Li:2014bc`. .. math:: @@ -128,7 +128,7 @@ def calculate_sapwood_masses( The sapwood mass (:math:`W_{\cdot s}`) is calculated from the individual crown area (:math:`A_{c}`), height :math:`H` and canopy fraction (:math:`f_{c}`) along with the wood density (:math:`\rho_s`) and crown area ratio :math:`A_{c}` of the plant - functional type :cite:p:`{Equation 14, }Li:2014bc`: + functional type :cite:p:`{Equation 14, }Li:2014bc`. .. math:: @@ -150,10 +150,11 @@ def calculate_whole_crown_gpp( ) -> Series: r"""Calculate whole crown gross primary productivity. - Given an estimate of potential gross primary productivity (GPP) per metre squared - (:math:`P_0`), this function scales the GPP up to the whole crown, given the crown - area (:math:`A_c`) and leaf area index (:math:`L`) and the extinction coefficient - (:math:`k`) :cite:p:`{Equation 12, }Li:2014bc`:. + This function calculates individual GPP across the whole crown, given the + individual potential gross primary productivity (GPP) per metre squared + (:math:`P_0`) and crown area (:math:`A_c`), along with the leaf area index + (:math:`L`) and the extinction coefficient (:math:`k`) of the plant functional type + :cite:p:`{Equation 12, }Li:2014bc`. .. math:: @@ -170,19 +171,60 @@ def calculate_whole_crown_gpp( def calculate_sapwood_respiration(resp_s: Series, sapwood_mass: Series) -> Series: - """TODO docstring.""" + r"""Calculate sapwood respiration. + + Calculates the total sapwood respiration (:math:`R_{\cdot s}`) given the individual + sapwood mass (:math:`W_{\cdot s}`) and the sapwood respiration rate of the plant + functional type (:math:`r_{s}`) :cite:p:`{see Equation 13, }Li:2014bc`. + + .. math:: + R_{\cdot s} = W_{\cdot s} \, r_s + + Args: + resp_s: The sapwood respiration rate + sapwood_mass: The individual sapwood mass + """ return sapwood_mass * resp_s def calculate_foliar_respiration(resp_f: Series, whole_crown_gpp: Series) -> Series: - """TODO docstring.""" + r"""Calculate foliar respiration. + + Calculates the total foliar respiration (:math:`R_{f}`) given the individual crown + GPP (:math:`P`) and the foliar respiration rate of the plant functional type + (:math:`r_{f}`). :cite:t:`Li:2014bc` remove foliar respiration as a constant + proportion of potential GPP before calculating GPP for the crown, but ``pyrealm`` + treats this proportion as part of the definition of plant functional types. + + .. math:: + R_{f} = P \, r_f + + Args: + resp_f: The foliar respiration rate + whole_crown_gpp: The individual whole crown GPP. + """ return whole_crown_gpp * resp_f def calculate_fine_root_respiration( zeta: Series, sla: Series, resp_r: Series, foliage_mass: Series ) -> Series: - """TODO docstring.""" + r"""Calculate foliar respiration. + + Calculates the total fine root respiration (:math:`R_{r}`) given the individual + foliage mass (:math:`W_f`), along with the fine root respiration rate (:math:`r_r`), + the ratio of fine root mass to foliage area (:math:`\zeta`) and the specific leaf + area (:math:`\sigma`) :cite:p:`{see Equation 13, }Li:2014bc` + + .. math:: + R_{r} = \zeta \sigma W_f r_r + + Args: + zeta: The ratio of fine root mass to foliage area. + sla: The specific leaf area + resp_r: The respiration rate of fine roots. + foliage_mass: The individual foliage mass. + """ return zeta * sla * foliage_mass * resp_r @@ -194,7 +236,28 @@ def calculate_net_primary_productivity( fine_root_respiration: Series, sapwood_respiration: Series, ) -> Series: - """TODO docstring.""" + r"""Calculate net primary productivity. + + The net primary productivity (NPP, :math:`P_{net}`) is calculated as a plant + functional type specific yield proportion (:math:`y`) of the total GPP (:math:`P`) + for the individual minus respiration (:math:`R_m`), as the sum of the respiration + costs for foliage (:math:`R_f`), fine roots (:math:`R_r`) and sapwood + (:math:`R_s`). + + .. math:: + P_{net} = y (P - R_m) = y (P - W_{\cdot s} r_s - \zeta \sigma W_f r_r - P r_f) + + Note that this differs from Equation 13 of :cite:t:`Li:2014bc`, which removes foliar + respiration from potential GPP. This approach is equivalent but allows the foliar + respiration to vary between plant functional types. + + Args: + yld: The yield proportion. + whole_crown_gpp: The total GPP for the crown. + foliar_respiration: The total foliar respiration. + fine_root_respiration: The total fine root respiration + sapwood_respiration: The total sapwood respiration. + """ return yld * ( whole_crown_gpp @@ -205,16 +268,34 @@ def calculate_net_primary_productivity( def calculate_foliage_and_fine_root_turnover( - lai: Series, sla: Series, - tau_f: Series, zeta: Series, + tau_f: Series, tau_r: Series, - crown_area: Series, + foliage_mass: Series, ) -> Series: - """TODO docstring.""" + r"""Calculate turnover costs. - return crown_area * lai * ((1 / (sla * tau_f)) + (zeta / tau_r)) + This function calculates the costs associated with the turnover of fine roots and + foliage. This is calculated from the total foliage mass of individuals + (:math:`W_f`), along with the specific leaf area (:math:`\sigma`) and fine root mass + to foliar area ratio (:math:`\zeta`) and the turnover times of foliage + (:math:`\tau_f`) and fine roots (:math:`\tau_r`) of the plant functional type + :cite:p:`{see Equation 15, }Li:2014bc`. + + .. math:: + + T = W_f \left( \frac{1}{\tau_f} + \frac{\sigma \zeta}{\tau_f} \right) + + Args: + sla: The specific leaf area + zeta: The ratio of fine root mass to foliage area. + tau_f: The turnover time of foliage + tau_r: The turnover time of fine roots + foliage_mass: The foliage mass + """ + + return foliage_mass * ((1 / tau_f) + (sla * zeta / tau_r)) def calculate_growth_increments( @@ -230,21 +311,80 @@ def calculate_growth_increments( dbh: Series, height: Series, ) -> tuple[Series, Series, Series]: - """TODO docstring.""" - # relative increments - these are used to calculate delta_d and - # then scaled by delta_d to give actual increments - dSdD = np.pi / 8 * rho_s * dbh * (a_hd * dbh * (1 - (height / h_max)) + 2 * height) + r"""Calculate growth increments. + + Given an estimate of net primary productivity (:math:`P_{net}`), less associated + turnover costs (:math:`T`), the remaining productivity can be allocated to growth + and hence estimate resulting increments in: + + * the stem diameter (:math:`\Delta D`), + * the stem mass (:math:`\Delta W_s`), and + * the foliar mass (:math:`\Delta W_f`). + + + The stem diameter increment can be calculated using the available productivity for + growth and the rates of change in stem (:math:`\textrm{d}W_s / \textrm{d}t`) and + foliar masses (:math:`\textrm{d}W_f / \textrm{d}t`): + + .. math:: + + \Delta D = \frac{P_{net} - T}{ \textrm{d}W_s / \textrm{d}t + + \textrm{d}W_f / \textrm{d}t} + + The rates of change in stem and foliar mass can be calculated as: + + .. math:: + :nowrap: + + \[ + \begin{align*} + \textrm{d}W_s / \textrm{d}t &= \frac{\pi}{8} \rho_s D + \left(a D \left(1 - \frac{H}{H_{m}} + 2 H \right) \right) \\ + + \textrm{d}W_f / \textrm{d}t &= L \frac{\pi c}{4 a} \left(a D \left( 1 - + \frac{H}{H_{m}} + H \right) \right) \frac{1}{\sigma + \zeta} + \end{align*} + \] + + given the current stem diameter (:math:`D`) and height (:math:`H`) and the following + plant functional type traits: + + * the specific leaf area (:math:`\sigma`), + * the leaf area index (:math:`L`), + * the wood density of the PFT (:math:`\rho_s`), + * the maximum height (:math:`H_{m}`), + * the initial slope of the height/diameter relationship (:math:`a`), + * the crown area ratio (:math:`c`), and + * the ratio of fine root mass to leaf area (:math:`\zeta`). + + The resulting incremental changes in stem mass and foliar mass can then be + calculated as: + + .. math:: + :nowrap: + + \[ + \begin{align*} + \Delta W_s &= \textrm{d}W_s / \textrm{d}t \, \Delta D\\ + \Delta W_f &= \textrm{d}W_f / \textrm{d}t \, \Delta D + \end{align*} + \] + + """ + # Rates of change in stem and foliar + dWsdt = np.pi / 8 * rho_s * dbh * (a_hd * dbh * (1 - (height / h_max)) + 2 * height) - dFdD = ( + dWfdt = ( lai * ((np.pi * ca_ratio) / (4 * a_hd)) * (a_hd * dbh * (1 - height / h_max) + height) * (1 / sla + zeta) ) - delta_d = (npp - turnover) / (dSdD + dFdD) + # Increment of diameter at breast height + delta_d = (npp - turnover) / (dWsdt + dWfdt) - return (delta_d, dSdD * delta_d, dFdD * delta_d) + return (delta_d, dWsdt * delta_d, dWfdt * delta_d) def calculate_canopy_q_m(m: float, n: float) -> float: @@ -303,7 +443,6 @@ def calculate_canopy_z_max(z_max_prop: Series, height: Series) -> Series: z_max_prop: Canopy shape parameter of the PFT height: Crown area of individuals """ - """Calculate z_m, the height of maximum crown radius.""" return height * z_max_prop diff --git a/tests/regression/demography/test_t_model_functions_against_rtmodel.py b/tests/regression/demography/test_t_model_functions_against_rtmodel.py index cb62efbc..6b75df6b 100644 --- a/tests/regression/demography/test_t_model_functions_against_rtmodel.py +++ b/tests/regression/demography/test_t_model_functions_against_rtmodel.py @@ -293,12 +293,11 @@ def test_calculate_foliage_and_fine_root_turnover(rvalues): for pft, _, data in rvalues: actual_turnover = calculate_foliage_and_fine_root_turnover( - lai=pft.lai, sla=pft.sla, tau_f=pft.tau_f, zeta=pft.zeta, tau_r=pft.tau_r, - crown_area=data["crown_area"], + foliage_mass=data["mass_fol"], ) assert_array_almost_equal( actual_turnover, From c9339ce304d2b6c6a9efb9f47440536b2ab1f4f4 Mon Sep 17 00:00:00 2001 From: David Orme Date: Sat, 14 Sep 2024 12:35:07 +0100 Subject: [PATCH 095/241] Adding missing args --- pyrealm/demography/t_model_functions.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index b3e20818..6e985e13 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -220,9 +220,9 @@ def calculate_fine_root_respiration( R_{r} = \zeta \sigma W_f r_r Args: - zeta: The ratio of fine root mass to foliage area. - sla: The specific leaf area - resp_r: The respiration rate of fine roots. + zeta: The ratio of fine root mass to foliage area of the PFT. + sla: The specific leaf area of the PFT. + resp_r: The respiration rate of fine roots of the PFT. foliage_mass: The individual foliage mass. """ @@ -370,6 +370,18 @@ def calculate_growth_increments( \end{align*} \] + Args: + rho_s: Wood density of the PFT + a_hd: Initial slope of the height/diameter relationship of the PFT + h_max: Maximum height of the PFT + lai: Leaf area index of the PFT + ca_ratio: Crown area ratio of the PFT + sla: Specific leaf area of the PFT + zeta: The ratio of fine root mass to foliage area of the PFT + npp: Net primary productivity of individuals + turnover: Fine root and foliage turnover cost of individuals + dbh: Diameter at breast height of individuals + height: Stem height of individuals """ # Rates of change in stem and foliar dWsdt = np.pi / 8 * rho_s * dbh * (a_hd * dbh * (1 - (height / h_max)) + 2 * height) From 8737728512ef516008fc9fc42760d1b2858e3873 Mon Sep 17 00:00:00 2001 From: David Orme Date: Sat, 14 Sep 2024 12:52:10 +0100 Subject: [PATCH 096/241] Minor text updates --- .../demography/test_t_model_functions_against_rtmodel.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/regression/demography/test_t_model_functions_against_rtmodel.py b/tests/regression/demography/test_t_model_functions_against_rtmodel.py index 6b75df6b..0582daa2 100644 --- a/tests/regression/demography/test_t_model_functions_against_rtmodel.py +++ b/tests/regression/demography/test_t_model_functions_against_rtmodel.py @@ -19,7 +19,9 @@ def rvalues(): """Fixture to load test inputs from file. The regression test inputs consist of time series of growth from an initial DBH - using a small set of different plant functional type definitions. + run using the original R implementation of the T model, for each of a small set of + different plant functional type definitions. The PFT definitions are loaded first + and then the output file associated with each PFT is loaded. """ from pyrealm.demography.flora import PlantFunctionalType @@ -87,7 +89,7 @@ def rvalues(): # millimetres, not diameter increase in metres data["delta_d"] = data["delta_d"] / 500 - # The reported P0 in the R tmodel outputs has already had fixed foliar + # NOTE: The reported P0 in the R tmodel outputs has already had fixed foliar # respiration costs removed before calculating anything. The pyrealm # implementation has this as a PFT trait, so in some tests the potential GPP # will need to be proportionally scaled up to make them match, but this is not From 6cf5c1b19e87c406380b92c2e3868dd8d6d78b60 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 16 Sep 2024 09:23:27 +0100 Subject: [PATCH 097/241] Worked example of community use. Co-authored-by: James Emberton <60827102+j-emberton@users.noreply.github.com> --- pyrealm/demography/community.py | 82 +++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 61a93b39..b6960c93 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -10,6 +10,88 @@ Internally, the cohort data in the Community class is represented as a pandas dataframe, which makes it possible to update cohort attributes in parallel across all cohorts but also provide a clean interface for adding and removing cohorts to a Community. + +Worked example: +>>> from flora import PlantFunctionalType, Flora +>>> from t_model import ( +... calculate_heights, calculate_crown_areas, calculate_stem_masses, +... calculate_foliage_masses +... ) +>>> import pandas as pd + +>>> pft1 = PlantFunctionalType( + ... name="Evergreen Tree", + ... a_hd=120.0, + ... ca_ratio=380.0, + ... h_max=30.0, + ... rho_s=210.0, + ... lai=3.0, + ... sla=12.0, + ... tau_f=5.0, + ... tau_r=1.2, + ... par_ext=0.6, + ... yld=0.65, + ... zeta=0.18, + ... resp_r=0.95, + ... resp_s=0.045, + ... resp_f=0.12, + ... m=2.5, + ... n=4.5, + ... ) + + >>> pft2 = PlantFunctionalType( + ... name="Deciduous Shrub", + ... a_hd=100.0, + ... ca_ratio=350.0, + ... h_max=4.0, + ... rho_s=180.0, + ... lai=2.0, + ... sla=15.0, + ... tau_f=3.0, + ... tau_r=0.8, + ... par_ext=0.4, + ... yld=0.55, + ... zeta=0.15, + ... resp_r=0.85, + ... resp_s=0.05, + ... resp_f=0.1, + ... m=3.0, + ... n=5.0, + ... ) + + Create a Flora collection: + + >>> flora = Flora([pft1, pft2]) + + Define cohort data representing plant density, age, DBH (diameter at breast height), and associated PFTs: + + >>> cohort_dbh_values = np.array([0.10, 0.03, 0.12, 0.025]) # DBH in meters + >>> cohort_n_individuals = np.array([100, 200, 150, 180]) # Number of individuals + >>> cohort_pft_names = np.array(["Evergreen Tree", "Deciduous Shrub", "Evergreen Tree", "Deciduous Shrub"]) + + Initialize a Community with the given cohort data: + + >>> community = Community( + ... cell_id=1, + ... cell_area=1000.0, # Area in square meters + ... flora=flora, + ... cohort_dbh_values=cohort_dbh_values, + ... cohort_n_individuals=cohort_n_individuals, + ... cohort_pft_names=cohort_pft_names + ... ) + + Display the community's cohort data with calculated T Model predictions: + + >>> community.cohort_data[['name', 'dbh', 'n_individuals', 'height', 'crown_area', 'stem_mass', 'foliage_mass']] + name dbh n_individuals height crown_area stem_mass foliage_mass + 0 Evergreen Tree 0.10 100 21.9911 250.4934 41617.4785 62.6234 + 1 Deciduous Shrub 0.03 200 2.7315 8.1571 120.7982 1.0876 + 2 Evergreen Tree 0.12 150 24.0988 300.5911 56976.5148 75.1478 + 3 Deciduous Shrub 0.025 180 2.3607 7.0236 88.9265 0.9353 + + The example demonstrates defining PFTs, creating a Flora collection, initializing a Community, and computing + ecological metrics using the T Model for a set of plant cohorts. + """ """ # noqa: D205 from __future__ import annotations From 89e56701460b6a288f96d27fb49cb22145fa6e3a Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 16 Sep 2024 10:19:59 +0100 Subject: [PATCH 098/241] Updates from @j-emberton review --- docs/source/conf.py | 1 + pyrealm/demography/community.py | 170 +++++++++++++++++--------------- 2 files changed, 91 insertions(+), 80 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index c1f27803..9c3a2970 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -145,6 +145,7 @@ class MyReferenceStyle(AuthorYearReferenceStyle): "numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]]" ), ), + ("py:class", "pandas.core.frame.DataFrame"), ] # + diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index b6960c93..7c8b1bc3 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -11,87 +11,95 @@ which makes it possible to update cohort attributes in parallel across all cohorts but also provide a clean interface for adding and removing cohorts to a Community. -Worked example: ->>> from flora import PlantFunctionalType, Flora ->>> from t_model import ( +Worked example +============== + +The example code below demonstrates defining PFTs, creating a Flora collection, +initializing a Community, and computing ecological metrics using the T Model for a set +of plant cohorts. + +>>> import pandas as pd +>>> +>>> from pyrealm.demography.flora import PlantFunctionalType, Flora +>>> from pyrealm.demography.t_model_functions import ( ... calculate_heights, calculate_crown_areas, calculate_stem_masses, ... calculate_foliage_masses ... ) ->>> import pandas as pd >>> pft1 = PlantFunctionalType( - ... name="Evergreen Tree", - ... a_hd=120.0, - ... ca_ratio=380.0, - ... h_max=30.0, - ... rho_s=210.0, - ... lai=3.0, - ... sla=12.0, - ... tau_f=5.0, - ... tau_r=1.2, - ... par_ext=0.6, - ... yld=0.65, - ... zeta=0.18, - ... resp_r=0.95, - ... resp_s=0.045, - ... resp_f=0.12, - ... m=2.5, - ... n=4.5, - ... ) - - >>> pft2 = PlantFunctionalType( - ... name="Deciduous Shrub", - ... a_hd=100.0, - ... ca_ratio=350.0, - ... h_max=4.0, - ... rho_s=180.0, - ... lai=2.0, - ... sla=15.0, - ... tau_f=3.0, - ... tau_r=0.8, - ... par_ext=0.4, - ... yld=0.55, - ... zeta=0.15, - ... resp_r=0.85, - ... resp_s=0.05, - ... resp_f=0.1, - ... m=3.0, - ... n=5.0, - ... ) - - Create a Flora collection: - - >>> flora = Flora([pft1, pft2]) - - Define cohort data representing plant density, age, DBH (diameter at breast height), and associated PFTs: - - >>> cohort_dbh_values = np.array([0.10, 0.03, 0.12, 0.025]) # DBH in meters - >>> cohort_n_individuals = np.array([100, 200, 150, 180]) # Number of individuals - >>> cohort_pft_names = np.array(["Evergreen Tree", "Deciduous Shrub", "Evergreen Tree", "Deciduous Shrub"]) - - Initialize a Community with the given cohort data: - - >>> community = Community( - ... cell_id=1, - ... cell_area=1000.0, # Area in square meters - ... flora=flora, - ... cohort_dbh_values=cohort_dbh_values, - ... cohort_n_individuals=cohort_n_individuals, - ... cohort_pft_names=cohort_pft_names - ... ) - - Display the community's cohort data with calculated T Model predictions: - - >>> community.cohort_data[['name', 'dbh', 'n_individuals', 'height', 'crown_area', 'stem_mass', 'foliage_mass']] - name dbh n_individuals height crown_area stem_mass foliage_mass - 0 Evergreen Tree 0.10 100 21.9911 250.4934 41617.4785 62.6234 - 1 Deciduous Shrub 0.03 200 2.7315 8.1571 120.7982 1.0876 - 2 Evergreen Tree 0.12 150 24.0988 300.5911 56976.5148 75.1478 - 3 Deciduous Shrub 0.025 180 2.3607 7.0236 88.9265 0.9353 - - The example demonstrates defining PFTs, creating a Flora collection, initializing a Community, and computing - ecological metrics using the T Model for a set of plant cohorts. - """ +... name="Evergreen Tree", +... a_hd=120.0, +... ca_ratio=380.0, +... h_max=30.0, +... rho_s=210.0, +... lai=3.0, +... sla=12.0, +... tau_f=5.0, +... tau_r=1.2, +... par_ext=0.6, +... yld=0.65, +... zeta=0.18, +... resp_r=0.95, +... resp_s=0.045, +... resp_f=0.12, +... m=2.5, +... n=4.5, +... ) + +>>> pft2 = PlantFunctionalType( +... name="Deciduous Shrub", +... a_hd=100.0, +... ca_ratio=350.0, +... h_max=4.0, +... rho_s=180.0, +... lai=2.0, +... sla=15.0, +... tau_f=3.0, +... tau_r=0.8, +... par_ext=0.4, +... yld=0.55, +... zeta=0.15, +... resp_r=0.85, +... resp_s=0.05, +... resp_f=0.1, +... m=3.0, +... n=5.0, +... ) + +Create a Flora collection: + +>>> flora = Flora([pft1, pft2]) + +Define community data as size-structured cohorts of given plant functional types with a +given number of individuals. + +>>> cohort_dbh_values = np.array([0.10, 0.03, 0.12, 0.025]) +>>> cohort_n_individuals = np.array([100, 200, 150, 180]) +>>> cohort_pft_names = np.array( +... ["Evergreen Tree", "Deciduous Shrub", "Evergreen Tree", "Deciduous Shrub"] +... ) + +Initialize a Community into an area of 1000 square meter with the given cohort data: + +>>> community = Community( +... cell_id=1, +... cell_area=1000.0, +... flora=flora, +... cohort_dbh_values=cohort_dbh_values, +... cohort_n_individuals=cohort_n_individuals, +... cohort_pft_names=cohort_pft_names +... ) + +Display the community's cohort data with calculated T Model predictions: + +>>> community.cohort_data[ +... ['name', 'dbh', 'n_individuals', 'height', 'crown_area', 'stem_mass'] +... ] + name dbh n_individuals height crown_area stem_mass +0 Evergreen Tree 0.100 100 9.890399 2.459835 8.156296 +1 Deciduous Shrub 0.030 200 2.110534 0.174049 0.134266 +2 Evergreen Tree 0.120 150 11.436498 3.413238 13.581094 +3 Deciduous Shrub 0.025 180 1.858954 0.127752 0.082126 """ # noqa: D205 from __future__ import annotations @@ -108,6 +116,7 @@ from marshmallow.exceptions import ValidationError from numpy.typing import NDArray +from pyrealm.core.utilities import check_input_shapes from pyrealm.demography import t_model_functions as t_model from pyrealm.demography.flora import Flora @@ -377,10 +386,11 @@ def __post_init__( raise ValueError("Cohort data not passed as numpy arrays.") # Check the cohort inputs are of equal length - if not ( - (cohort_dbh_values.shape == cohort_n_individuals.shape) - and (cohort_dbh_values.shape == cohort_pft_names.shape) - ): + try: + check_input_shapes( + cohort_dbh_values, cohort_n_individuals, cohort_dbh_values + ) + except ValueError: raise ValueError("Cohort arrays are of unequal length") # Check the initial PFT values are known From a0bbc5c79f89774ee47cdcd016d82bf48b8d0a57 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 16 Sep 2024 11:26:05 +0100 Subject: [PATCH 099/241] Bring original TModel tests up to date with new regression dataset --- tests/regression/tmodel/test_tmodel.py | 114 ++++++++++++------------- 1 file changed, 56 insertions(+), 58 deletions(-) diff --git a/tests/regression/tmodel/test_tmodel.py b/tests/regression/tmodel/test_tmodel.py index cbe95afd..2504399a 100644 --- a/tests/regression/tmodel/test_tmodel.py +++ b/tests/regression/tmodel/test_tmodel.py @@ -3,11 +3,11 @@ Tests the init, grow_ttree and other methods of TModel. """ -import csv from contextlib import nullcontext as does_not_raise from importlib import resources import numpy as np +import pandas as pd import pytest # Fixtures: inputs and expected values from the original implementation in R @@ -22,48 +22,43 @@ def rvalues(): """ from pyrealm.tmodel import TModelTraits - datapath = resources.files("pyrealm_build_data.t_model") / "rtmodel_output.csv" - - with open(str(datapath)) as infile: - rdr = csv.DictReader(infile, quoting=csv.QUOTE_NONNUMERIC) - values = [v for v in rdr] - - name_map = ( - ("dD", "delta_d"), - ("D", "diameter"), - ("H", "height"), - ("fc", "crown_fraction"), - ("Ac", "crown_area"), - ("Wf", "mass_fol"), - ("Ws", "mass_stm"), - ("Wss", "mass_swd"), - ("P0", "potential_gpp"), - ("GPP", "gpp_actual"), - ("Rm1", "resp_swd"), - ("Rm2", "resp_frt"), - ("dWs", "delta_mass_stm"), - ("dWfr", "delta_mass_frt"), + datapath = ( + resources.files("pyrealm_build_data.t_model") / "rtmodel_output_default.csv" ) - # copy values under R names to py names - traits = TModelTraits() + data = pd.read_csv(datapath) + + data = data.rename( + columns={ + "dD": "delta_d", + "D": "diameter", + "H": "height", + "fc": "crown_fraction", + "Ac": "crown_area", + "Wf": "mass_fol", + "Ws": "mass_stm", + "Wss": "mass_swd", + "P0": "potential_gpp", + "GPP": "gpp_actual", + "Rm1": "resp_swd", + "Rm2": "resp_frt", + "dWs": "delta_mass_stm", + "dWfr": "delta_mass_frt", + } + ) - for row in values: - for rnm, pynm in name_map: - # Fix some scaling differences: - if pynm == "delta_d": - # The R tmodel implementation rescales reported delta_d as - # a radial increase in millimetres, not diameter increase in metres - row[pynm] = row[rnm] / 500 - elif pynm == "gpp_actual": - # The R tmodel implementation slices off foliar respiration costs from - # GPP before doing anything - the pyrealm.tmodel implementation keeps - # this cost within the tree calculation - row[pynm] = row[rnm] / (1 - traits.resp_f) - else: - row[pynm] = row[rnm] + # Fix some scaling differences: + # The R tmodel implementation rescales reported delta_d as a radial increase in + # millimetres, not diameter increase in metres + data["delta_d"] = data["delta_d"] / 500 + + # The R tmodel implementation slices off foliar respiration costs from + # GPP before doing anything - the pyrealm.tmodel implementation keeps + # this cost within the tree calculation + traits = TModelTraits() + data["gpp_actual"] = data["gpp_actual"] / (1 - traits.resp_f) - return values + return data @pytest.mark.parametrize(argnames="row", argvalues=np.arange(0, 100, 10)) @@ -73,10 +68,11 @@ def test_tmodel_init(rvalues, row): from pyrealm.constants.tmodel_const import TModelTraits from pyrealm.tmodel import TTree - ttree = TTree(traits=TModelTraits, diameters=rvalues[row]["diameter"]) + row = rvalues.iloc[row] + ttree = TTree(traits=TModelTraits, diameters=row["diameter"]) for geom_est in ("height", "crown_area", "mass_fol", "mass_stm", "mass_swd"): - assert np.allclose(getattr(ttree, geom_est), rvalues[row][geom_est]) + assert np.allclose(getattr(ttree, geom_est), row[geom_est]) @pytest.mark.parametrize(argnames="row", argvalues=np.arange(0, 100, 10)) @@ -87,10 +83,11 @@ def test_tmodel_reset_diameters(rvalues, row): from pyrealm.tmodel import TTree ttree = TTree(diameters=0.001, traits=TModelTraits()) - ttree.reset_diameters(rvalues[row]["diameter"]) + row = rvalues.iloc[row] + ttree.reset_diameters(row["diameter"]) for geom_est in ("height", "crown_area", "mass_fol", "mass_stm", "mass_swd"): - assert np.allclose(getattr(ttree, geom_est), rvalues[row][geom_est]) + assert np.allclose(getattr(ttree, geom_est), row[geom_est]) def test_tmodel_init_array(rvalues): @@ -99,11 +96,11 @@ def test_tmodel_init_array(rvalues): from pyrealm.constants.tmodel_const import TModelTraits from pyrealm.tmodel import TTree - diams = np.array([rw["diameter"] for rw in rvalues]) + diams = np.array(rvalues["diameter"]) ttree = TTree(diameters=diams, traits=TModelTraits) for geom_est in ("height", "crown_area", "mass_fol", "mass_stm", "mass_swd"): - vals = [rw[geom_est] for rw in rvalues] + vals = rvalues[geom_est] assert np.allclose(getattr(ttree, geom_est), vals) @@ -150,19 +147,20 @@ def test_tmodel_growth_access(sequence, raises): def test_tmodel_calculate_growth(rvalues, row): """Test calculate_growth with scalars. - Runs a test of the tmodel.TTree against output from the R implementation. - The values in the test come from simulating a 100 year run starting from - a stem diameter of 0.1 and with an annual GPP value of 7. Each row in the - file is the successive growth, but this test just runs some values from the - sequence. + Runs a test of the tmodel.TTree against output from the R implementation. The values + in the test come from simulating a 100 year run starting from a stem diameter of + 0.1. Each row in the file is the successive growth, but this test just runs some + values from the sequence. """ from pyrealm.constants.tmodel_const import TModelTraits from pyrealm.tmodel import TTree # create a tree with the initial diameter given in the row - ttree = TTree(diameters=rvalues[row]["diameter"], traits=TModelTraits()) - ttree.calculate_growth(7) + row = rvalues.iloc[row] + traits = TModelTraits() + ttree = TTree(diameters=row["diameter"], traits=traits) + ttree.calculate_growth(row["potential_gpp"] / (1 - traits.resp_f)) for growth_est in ( "delta_d", @@ -172,7 +170,7 @@ def test_tmodel_calculate_growth(rvalues, row): "delta_mass_stm", "delta_mass_frt", ): - assert np.allclose(getattr(ttree, growth_est), rvalues[row][growth_est]) + assert np.allclose(getattr(ttree, growth_est), row[growth_est]) def test_tmodel_calculate_growth_array(rvalues): @@ -182,9 +180,10 @@ def test_tmodel_calculate_growth_array(rvalues): from pyrealm.tmodel import TTree # create a tree with the initial diameter given in the row - diams = np.array([rw["diameter"] for rw in rvalues]) - ttree = TTree(diameters=diams, traits=TModelTraits) - ttree.calculate_growth(7) + diams = np.array(rvalues["diameter"]) + traits = TModelTraits() + ttree = TTree(diameters=diams, traits=traits) + ttree.calculate_growth(rvalues["potential_gpp"] / (1 - traits.resp_f)) for growth_est in ( "delta_d", @@ -194,8 +193,7 @@ def test_tmodel_calculate_growth_array(rvalues): "delta_mass_stm", "delta_mass_frt", ): - vals = [rw[growth_est] for rw in rvalues] - assert np.allclose(getattr(ttree, growth_est), vals) + assert np.allclose(getattr(ttree, growth_est), rvalues[growth_est]) # @pytest.mark.parametrize( From 5d7fde71c84eb0c33b7a5e157ec2d00663f8d31b Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 16 Sep 2024 16:16:22 +0100 Subject: [PATCH 100/241] Checkout of initial files from #231 --- pyrealm/demography/canopy.py | 47 ++++ pyrealm/demography/canopy_functions.py | 203 ++++++++++++++++++ tests/unit/demography/test_canopy.py | 10 + .../unit/demography/test_canopy_functions.py | 41 ++++ 4 files changed, 301 insertions(+) create mode 100644 pyrealm/demography/canopy.py create mode 100644 pyrealm/demography/canopy_functions.py create mode 100644 tests/unit/demography/test_canopy.py create mode 100644 tests/unit/demography/test_canopy_functions.py diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py new file mode 100644 index 00000000..18d8e86b --- /dev/null +++ b/pyrealm/demography/canopy.py @@ -0,0 +1,47 @@ +"""Functionality for canopy modelling.""" + +import numpy as np + +from pyrealm.canopy_model.functions.canopy_functions import ( + calculate_canopy_layer_heights, + calculate_gpp, + calculate_number_of_canopy_layers, + calculate_total_canopy_A_cp, + calculate_total_community_crown_area, +) +from pyrealm.canopy_model.model.community import Community + + +class Canopy: + """A class containing attributes of a canopy, including the structure.""" + + def __init__(self, community: Community, canopy_gap_fraction: float) -> None: + self.max_individual_height = community.t_model_heights.max() + + self.total_community_crown_area = calculate_total_community_crown_area( + community + ) + + self.number_of_canopy_layers = calculate_number_of_canopy_layers( + community.cell_area, self.total_community_crown_area, canopy_gap_fraction + ) + + self.canopy_layer_heights = calculate_canopy_layer_heights( + self.number_of_canopy_layers, + self.max_individual_height, + community, + canopy_gap_fraction, + ) + + # TODO there may be a more efficient solution here that does not use a loop. + self.A_cp_within_layer = map( + calculate_total_canopy_A_cp, + self.canopy_layer_heights, + np.full(self.number_of_canopy_layers, canopy_gap_fraction), + np.full(self.number_of_canopy_layers, community), + ) + + self.gpp = calculate_gpp( + np.zeros(self.number_of_canopy_layers), + np.zeros(self.number_of_canopy_layers), + ) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py new file mode 100644 index 00000000..48ec66f4 --- /dev/null +++ b/pyrealm/demography/canopy_functions.py @@ -0,0 +1,203 @@ +"""Class containing functions for calculating properties of a canopy.""" + +import numpy as np +from numpy.typing import NDArray +from scipy.optimize import root_scalar + +from pyrealm.canopy_model.functions.jaideep_t_model_extension_functions import ( + calculate_relative_canopy_radii, +) +from pyrealm.canopy_model.model.community import Community + + +def calculate_total_community_crown_area(community: Community) -> float: + """Calculate the total crown area of a community.""" + # Calculate the number of layers + cohort_crown_areas = ( + community.cohort_number_of_individuals * community.t_model_crown_areas + ) + total_community_crown_area = cohort_crown_areas.sum() + return total_community_crown_area + + +def calculate_number_of_canopy_layers( + cell_area: float, total_community_crown_area: float, fG: float +) -> int: + """Calculate the number of canopy layers in a given community.""" + number_of_layers = int(np.ceil(total_community_crown_area / (cell_area * (1 - fG)))) + return number_of_layers + + +def calculate_community_projected_area_at_z(community: Community, z: float) -> float: + """Calculate the total area of community stems.""" + projected_canopy_area_for_individuals = ( + calculate_projected_canopy_area_for_individuals( + z, + community.t_model_heights, + community.t_model_crown_areas, + community.pft_m_values, + community.pft_n_values, + community.canopy_factor_q_m_values, + community.canopy_factor_z_m_values, + ) + ) + + cohort_areas_at_z = ( + community.cohort_number_of_individuals * projected_canopy_area_for_individuals + ) + + return sum(cohort_areas_at_z) + + +def calculate_projected_canopy_area_for_individuals( + z: float, + height: NDArray[np.float32], + crown_area: NDArray[np.float32], + m: NDArray[np.float32], + n: NDArray[np.float32], + q_m: NDArray[np.float32], + z_m: NDArray[np.float32], +) -> NDArray[np.float32]: + """Calculate projected crown area above a given height. + + This function takes PFT specific parameters (shape parameters) and stem specific + sizes and estimates the projected crown area above a given height $z$. Note, + this calculation gives the canopy area for a single individual within the cohort, + not for the cohort as a whole. + :param m: + :param n: + :param crown_area: + :param height: + :param z_m: stem canopy factor from Jaideep extension of the T Model. + :param q_m: stem canopy factor from Jaideep extension of the T Model. + :param z: height on the z axis. + """ + + # Calculate q(z) + q_z = calculate_relative_canopy_radii(z, height, m, n) + + # Calculate A_p + # Calculate Ap given z > zm + A_p = crown_area * (q_z / q_m) ** 2 + # Set Ap = Ac where z <= zm + A_p = np.where(z <= z_m, crown_area, A_p) + # Set Ap = 0 where z > H + A_p = np.where(z > height, 0, A_p) + + return A_p + + +def calculate_canopy_layer_heights( + number_of_canopy_layers: int, + max_individual_height: float, + community: Community, + fG: float, +) -> NDArray: + """Calculate the heights of the layers of the canopy for a community.""" + + # Data store for z* + z_star = np.zeros(number_of_canopy_layers) + + # Loop over the layers TODO - edge case of completely filled final layer + for n in np.arange(number_of_canopy_layers - 1): + z_star[n] = root_scalar( + solve_canopy_closure_height, + args=(community, n + 1, community.cell_area, fG), + bracket=(0, max_individual_height), + ).root + + return z_star + + +def solve_canopy_closure_height( + z: float, + community: Community, + layer_index: int, + A: float, + fG: float, +) -> float: + """Solver function for canopy closure height. + + This function returns the difference between the total community projected area + at a height $z$ and the total available canopy space for canopy layer $l$, given + the community gap fraction for a given height. It is used with a root solver to + find canopy layer closure heights $z^*_l* for a community. + :param community: + :param fG: community gap fraction + :param A: community area + :param layer_index: layer index + :param z: height + """ + + community_projected_area_at_z = calculate_community_projected_area_at_z( + community, z + ) + + # Return the difference between the projected area and the available space + return community_projected_area_at_z - (A * layer_index) * (1 - fG) + + +def calculate_projected_leaf_area_for_individuals( + z: float, f_g: float, community: Community +) -> NDArray[np.float32]: + """Calculate projected crown area above a given height. + + Calculation applies to an individual within a cohort.This function takes PFT + specific parameters (shape parameters) and stem specific sizes and estimates + the projected crown area above a given height $z$. The inputs can either be + scalars describing a single stem or arrays representing a community of stems. + If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can be + scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that + PFT. + + :param community: + :param f_g: Crown gap fraction. + :param z: Height from ground. + """ + + # Calculate q(z) + q_z = calculate_relative_canopy_radii( + z, community.t_model_heights, community.pft_m_values, community.pft_n_values + ) + + # Calculate Ac terms + A_c_terms = ( + community.t_model_crown_areas * (q_z / community.canopy_factor_q_m_values) ** 2 + ) + + # Set Acp either side of zm + A_cp = np.where( + z <= community.canopy_factor_z_m_values, + community.t_model_crown_areas - A_c_terms * f_g, + A_c_terms * (1 - f_g), + ) + # Set Ap = 0 where z > H + A_cp = np.where(z > community.t_model_heights, 0, A_cp) + return A_cp + + +def calculate_total_canopy_A_cp(z: float, f_g: float, community: Community) -> float: + """Calculate total leaf area at a given height. + + :param f_g: + :param community: + :param z: Height above ground. + :return: Total leaf area in the canopy at a given height. + """ + A_cp_for_individuals = calculate_projected_leaf_area_for_individuals( + z, f_g, community + ) + + A_cp_for_cohorts = A_cp_for_individuals * community.cohort_number_of_individuals + + return A_cp_for_cohorts.sum() + + +def calculate_gpp(cell_ppfd: NDArray, lue: NDArray) -> float: + """Estimate the gross primary productivity. + + Not sure where to place this - need an array of LUE that matches to the + + """ + + return 100 diff --git a/tests/unit/demography/test_canopy.py b/tests/unit/demography/test_canopy.py new file mode 100644 index 00000000..06a78307 --- /dev/null +++ b/tests/unit/demography/test_canopy.py @@ -0,0 +1,10 @@ +"""test the canopy object in canopy.py initialises as expected.""" + + +def test_initialisation(): + """Test happy path for initialisation. + + test that when a new canopy object is instantiated, it contains the expected + properties. + """ + pass diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py new file mode 100644 index 00000000..aa3ecdb2 --- /dev/null +++ b/tests/unit/demography/test_canopy_functions.py @@ -0,0 +1,41 @@ +"""test the functions in canopy_functions.py.""" + + +def test_calculate_total_community_crown_area(): + """Test happy path for calculating total community crown area.""" + pass + + +def test_calculate_number_of_canopy_layers(): + """Test happy path for calculating number of canopy layers.""" + pass + + +def calculate_community_projected_area_at_z(): + """Test happy path for calculating total projected area for community.""" + pass + + +def test_calculate_projected_canopy_area_for_individuals(): + """Test happy path for calculating project canopy area for individuals.""" + pass + + +def test_calculate_canopy_layer_heights(): + """Test happy path for calculation of canopy layer heights.""" + pass + + +def test_solve_canopy_closure_height(): + """Test happy path for solver function for canopy closure height.""" + pass + + +def test_calculate_projected_leaf_area_for_individuals(): + """Test happy path for calculating projected leaf area for individuals.""" + pass + + +def test_calculate_total_canopy_A_cp(): + """Test happy path for calculating total canopy A_cp across a community.""" + pass From 875d9d1fd36105fb690587a2bf286364778124eb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:46:36 +0000 Subject: [PATCH 101/241] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.4 → v0.6.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.4...v0.6.5) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8fec970f..327eeef8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ repos: - id: debug-statements - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.4 + rev: v0.6.5 hooks: # Run the linter. - id: ruff From 83f0daff2b9c94ad7cd84ac5771ef670964ce668 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 17 Sep 2024 11:15:17 +0100 Subject: [PATCH 102/241] Fixing new import locations in canopy modules --- pyrealm/demography/canopy.py | 4 ++-- pyrealm/demography/canopy_functions.py | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 18d8e86b..1473d3bc 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -2,14 +2,14 @@ import numpy as np -from pyrealm.canopy_model.functions.canopy_functions import ( +from pyrealm.demography.canopy_functions import ( calculate_canopy_layer_heights, calculate_gpp, calculate_number_of_canopy_layers, calculate_total_canopy_A_cp, calculate_total_community_crown_area, ) -from pyrealm.canopy_model.model.community import Community +from pyrealm.demography.community import Community class Canopy: diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 48ec66f4..254856aa 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -4,10 +4,8 @@ from numpy.typing import NDArray from scipy.optimize import root_scalar -from pyrealm.canopy_model.functions.jaideep_t_model_extension_functions import ( - calculate_relative_canopy_radii, -) -from pyrealm.canopy_model.model.community import Community +from pyrealm.demography.community import Community +from pyrealm.demography.t_model_functions import calculate_relative_canopy_radii def calculate_total_community_crown_area(community: Community) -> float: From a40501e9587bf540d64c18afe69b7e800f88d7a5 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 17 Sep 2024 13:54:09 +0100 Subject: [PATCH 103/241] Refining functions and separating canopy functions from specific Canopy model implementation --- pyrealm/demography/canopy.py | 55 +++++-- pyrealm/demography/canopy_functions.py | 185 ++++++++++++------------ pyrealm/demography/t_model_functions.py | 29 ---- 3 files changed, 130 insertions(+), 139 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 1473d3bc..8c5ab3ae 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -1,13 +1,11 @@ """Functionality for canopy modelling.""" import numpy as np +from numpy.typing import NDArray +from scipy.optimize import root_scalar from pyrealm.demography.canopy_functions import ( - calculate_canopy_layer_heights, - calculate_gpp, - calculate_number_of_canopy_layers, - calculate_total_canopy_A_cp, - calculate_total_community_crown_area, + solve_community_projected_canopy_area, ) from pyrealm.demography.community import Community @@ -16,22 +14,49 @@ class Canopy: """A class containing attributes of a canopy, including the structure.""" def __init__(self, community: Community, canopy_gap_fraction: float) -> None: - self.max_individual_height = community.t_model_heights.max() + # Calculate community wide properties: total crown area and maximum height + self.total_crown_area: float = ( + community.cohort_data["crown_area"] * community.cohort_data["n_individuals"] + ).sum() + """Total crown area across individuals in the community (metres 2).""" - self.total_community_crown_area = calculate_total_community_crown_area( - community + self.max_height: float = community.cohort_data["height"].max() + """Maximum height of any individual in the community (metres).""" + + self.crown_area_per_layer: float = community.cell_area * ( + 1 - canopy_gap_fraction ) + """Total crown area required to fill a canopy layer, given the canopy gap + fraction.""" - self.number_of_canopy_layers = calculate_number_of_canopy_layers( - community.cell_area, self.total_community_crown_area, canopy_gap_fraction + self.n_layers: int = int( + np.ceil(self.total_crown_area / self.crown_area_per_layer) ) + """Total number of canopy layers needed to contain the total crown area.""" - self.canopy_layer_heights = calculate_canopy_layer_heights( - self.number_of_canopy_layers, - self.max_individual_height, - community, - canopy_gap_fraction, + # Find the closure heights of the canopy layers under the perfect plasticity + # approximation. + # Loop over the layers TODO - edge case of completely filled final layer + self.layer_closure_heights: NDArray[np.float32] = np.full( + (self.n_layers), np.nan ) + for layer in np.arange(self.n_layers): + target_area = (layer + 1) * community.cell_area * (1 - canopy_gap_fraction) + + self.layer_closure_heights[layer] = root_scalar( + solve_community_projected_canopy_area, + args=( + community.cohort_data["n_individuals"], # n_individuals + community.cohort_data["crown_area"], # crown_area + community.cohort_data["height"], # height + community.cohort_data["m"], # m + community.cohort_data["n"], # n + community.cohort_data["q_m"], # q_m + community.cohort_data["q_n"], # z_m + target_area, # target_area + ), + bracket=(0, self.max_height), + ).root # TODO there may be a more efficient solution here that does not use a loop. self.A_cp_within_layer = map( diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 254856aa..011642d7 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -2,52 +2,40 @@ import numpy as np from numpy.typing import NDArray -from scipy.optimize import root_scalar from pyrealm.demography.community import Community -from pyrealm.demography.t_model_functions import calculate_relative_canopy_radii -def calculate_total_community_crown_area(community: Community) -> float: - """Calculate the total crown area of a community.""" - # Calculate the number of layers - cohort_crown_areas = ( - community.cohort_number_of_individuals * community.t_model_crown_areas - ) - total_community_crown_area = cohort_crown_areas.sum() - return total_community_crown_area - - -def calculate_number_of_canopy_layers( - cell_area: float, total_community_crown_area: float, fG: float -) -> int: - """Calculate the number of canopy layers in a given community.""" - number_of_layers = int(np.ceil(total_community_crown_area / (cell_area * (1 - fG)))) - return number_of_layers - - -def calculate_community_projected_area_at_z(community: Community, z: float) -> float: - """Calculate the total area of community stems.""" - projected_canopy_area_for_individuals = ( - calculate_projected_canopy_area_for_individuals( - z, - community.t_model_heights, - community.t_model_crown_areas, - community.pft_m_values, - community.pft_n_values, - community.canopy_factor_q_m_values, - community.canopy_factor_z_m_values, - ) - ) +def calculate_relative_canopy_radius_at_z( + z: float, + height: NDArray[np.float32], + m: NDArray[np.float32], + n: NDArray[np.float32], +) -> NDArray[np.float32]: + r"""Calculate relative canopy radius at a given height. - cohort_areas_at_z = ( - community.cohort_number_of_individuals * projected_canopy_area_for_individuals - ) + The canopy shape parameters ``m`` and ``n`` define the vertical distribution of + canopy along the stem. For a stem of a given total height, this function calculates + the relative canopy radius at a given height :math:`z`: + + .. math:: - return sum(cohort_areas_at_z) + q(z) = m n \left(\dfrac{z}{H}\right) ^ {n -1} + \left( 1 - \left(\dfrac{z}{H}\right) ^ n \right)^{m-1} + + Args: + z: Height at which to calculate relative radius + height: Total height of individual stem + m: Canopy shape parameter of PFT + n: Canopy shape parameter of PFT + """ + z_over_height = z / height -def calculate_projected_canopy_area_for_individuals( + return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) + + +def calculate_stem_projected_canopy_area_at_z( z: float, height: NDArray[np.float32], crown_area: NDArray[np.float32], @@ -56,23 +44,24 @@ def calculate_projected_canopy_area_for_individuals( q_m: NDArray[np.float32], z_m: NDArray[np.float32], ) -> NDArray[np.float32]: - """Calculate projected crown area above a given height. - - This function takes PFT specific parameters (shape parameters) and stem specific - sizes and estimates the projected crown area above a given height $z$. Note, - this calculation gives the canopy area for a single individual within the cohort, - not for the cohort as a whole. - :param m: - :param n: - :param crown_area: - :param height: - :param z_m: stem canopy factor from Jaideep extension of the T Model. - :param q_m: stem canopy factor from Jaideep extension of the T Model. - :param z: height on the z axis. + """Calculate stem projected crown area above a given height. + + This function takes data on stem heights and crown areas, and then uses the canopy + shape parameters associated with each stem to calculate the projected crown area + above a given height $z$. + + Args: + z: Vertical height on the z axis. + crown_area: Crown area of each cohort + height: Stem height of each cohort + m: Canopy shape parameter ``m``` for each cohort + n: Canopy shape parameter ``n``` for each cohort + q_m: Canopy shape parameter ``q_m``` for each cohort + z_m: Canopy shape parameter ``z_m``` for each cohort """ # Calculate q(z) - q_z = calculate_relative_canopy_radii(z, height, m, n) + q_z = calculate_relative_canopy_radius_at_z(z, height, m, n) # Calculate A_p # Calculate Ap given z > zm @@ -85,54 +74,60 @@ def calculate_projected_canopy_area_for_individuals( return A_p -def calculate_canopy_layer_heights( - number_of_canopy_layers: int, - max_individual_height: float, - community: Community, - fG: float, -) -> NDArray: - """Calculate the heights of the layers of the canopy for a community.""" - - # Data store for z* - z_star = np.zeros(number_of_canopy_layers) - - # Loop over the layers TODO - edge case of completely filled final layer - for n in np.arange(number_of_canopy_layers - 1): - z_star[n] = root_scalar( - solve_canopy_closure_height, - args=(community, n + 1, community.cell_area, fG), - bracket=(0, max_individual_height), - ).root - - return z_star - - -def solve_canopy_closure_height( +def solve_community_projected_canopy_area( z: float, - community: Community, - layer_index: int, - A: float, - fG: float, -) -> float: - """Solver function for canopy closure height. - - This function returns the difference between the total community projected area - at a height $z$ and the total available canopy space for canopy layer $l$, given - the community gap fraction for a given height. It is used with a root solver to - find canopy layer closure heights $z^*_l* for a community. - :param community: - :param fG: community gap fraction - :param A: community area - :param layer_index: layer index - :param z: height + height: NDArray[np.float32], + crown_area: NDArray[np.float32], + m: NDArray[np.float32], + n: NDArray[np.float32], + q_m: NDArray[np.float32], + z_m: NDArray[np.float32], + n_individuals: NDArray[np.float32], + target_area: float = 0, +) -> NDArray[np.float32]: + """Solver function for community wide projected crown area. + + This function takes the number of individuals in each cohort along with the stem + height and crown area and a given vertical height (:math:`z`). It then uses the + canopy shape parameters associated with each cohort to calculate the community wide + projected crown area above that height (:math:`A_p(z)`). This is simply the sum of + the products of the individual stem projected area at :math:`z` and the number of + individuals in each cohort. + + The return value is the difference between the calculated :math:`A_p(z)` and a + user-specified target area, This allows the function to be used with a root solver + to find :math:`z` values that result in a given :math:`A_p(z)`. The default target + area is zero, so the default return value will be the actual total :math:`A_p(z)` + for the community. + + A typical use case for the target area would be to specify the area at which a given + canopy layer closes under the perfect plasticity approximation in order to find the + closure height. + + Args: + z: Vertical height on the z axis. + n_individuals: Number of individuals in each cohort + crown_area: Crown area of each cohort + height: Stem height of each cohort + m: Canopy shape parameter ``m``` for each cohort + n: Canopy shape parameter ``n``` for each cohort + q_m: Canopy shape parameter ``q_m``` for each cohort + z_m: Canopy shape parameter ``z_m``` for each cohort + target_area: A target projected crown area. """ - community_projected_area_at_z = calculate_community_projected_area_at_z( - community, z + # Calculate A(p) for the stems in each cohort + A_p = calculate_stem_projected_canopy_area_at_z( + z=z, + height=height, + crown_area=crown_area, + m=m, + n=n, + q_m=q_m, + z_m=z_m, ) - # Return the difference between the projected area and the available space - return community_projected_area_at_z - (A * layer_index) * (1 - fG) + return (A_p * n_individuals).sum() - target_area def calculate_projected_leaf_area_for_individuals( diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 9c2fd903..681712fd 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -228,32 +228,3 @@ def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: # z_m (height of maximum crown radius) return 1 / q_m * np.sqrt(crown_area / np.pi) - - -def calculate_relative_canopy_radii( - z: float, - height: Series, - m: Series, - n: Series, -) -> Series: - r"""Calculate relative canopy radius at a given height. - - The canopy shape parameters ``m`` and ``n`` define the vertical distribution of - canopy along the stem. For a stem of a given total height, this function calculates - the relative canopy radius at a given height :math:`z`: - - .. math:: - - q(z) = m n \left(\dfrac{z}{H}\right) ^ {n -1} - \left( 1 - \left(\dfrac{z}{H}\right) ^ n \right)^{m-1} - - Args: - z: Height at which to calculate relative radius - height: Total height of individual stem - m: Canopy shape parameter of PFT - n: Canopy shape parameter of PFT - """ - - z_over_height = z / height - - return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) From 3dc0f81f9b0a635a5a889a32cff427096f979582 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 17 Sep 2024 14:08:49 +0100 Subject: [PATCH 104/241] Relocating functions into canopy_functions and renaming imports --- pyrealm/demography/canopy_functions.py | 191 +++++++++++++----- pyrealm/demography/community.py | 5 +- pyrealm/demography/flora.py | 2 +- pyrealm/demography/t_model_functions.py | 85 -------- .../unit/demography/test_canopy_functions.py | 55 ++++- .../unit/demography/test_t_model_functions.py | 94 +++------ 6 files changed, 222 insertions(+), 210 deletions(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 011642d7..3be90f9b 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -2,8 +2,94 @@ import numpy as np from numpy.typing import NDArray +from pandas import Series -from pyrealm.demography.community import Community +# from pyrealm.demography.community import Community + + +def calculate_canopy_q_m(m: float, n: float) -> float: + """Calculate a q_m value. + + The value of q_m is a constant canopy scaling parameter derived from the ``m`` and + ``n`` attributes defined for a plant functional type. + + Args: + m: Canopy shape parameter + n: Canopy shape parameter + """ + return ( + m + * n + * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) + * (((m - 1) * n) / (m * n - 1)) ** (m - 1) + ) + + +def calculate_canopy_z_max_proportion(m: float, n: float) -> float: + r"""Calculate the z_m proportion. + + The z_m proportion (:math:`p_{zm}`) is the constant proportion of stem height at + which the maximum crown radius is found for a given plant functional type. + + .. math:: + + p_{zm} = \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}} + + Args: + m: Canopy shape parameter + n: Canopy shape parameter + """ + + return ((n - 1) / (m * n - 1)) ** (1 / n) + + +def calculate_canopy_z_max(z_max_prop: Series, height: Series) -> Series: + r"""Calculate height of maximum crown radius. + + The height of the maximum crown radius (:math:`z_m`) is derived from the canopy + shape parameters (:math:`m,n`) and the resulting fixed proportion (:math:`p_{zm}`) + for plant functional types. These shape parameters are defined as part of the + extension of the T Model presented by :cite:t:`joshi:2022a`. + + The value :math:`z_m` is the height above ground where the largest canopy radius is + found, given the proportion and the estimated stem height (:math:`H`) of + individuals. + + .. math:: + + z_m = p_{zm} H + + Args: + z_max_prop: Canopy shape parameter of the PFT + height: Crown area of individuals + """ + """Calculate z_m, the height of maximum crown radius.""" + + return height * z_max_prop + + +def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: + r"""Calculate scaling factor for height of maximum crown radius. + + This scaling factor (:math:`r_0`) is derived from the canopy shape parameters + (:math:`m,n,q_m`) for plant functional types and the estimated crown area + (:math:`A_c`) of individuals. The shape parameters are defined as part of the + extension of the T Model presented by :cite:t:`joshi:2022a` and :math:`r_0` is used + to scale the crown area such that the crown area at the maximum crown radius fits + the expectations of the T Model. + + .. math:: + + r_0 = 1/q_m \sqrt{A_c / \pi} + + Args: + q_m: Canopy shape parameter of the PFT + crown_area: Crown area of individuals + """ + # Scaling factor to give expected A_c (crown area) at + # z_m (height of maximum crown radius) + + return 1 / q_m * np.sqrt(crown_area / np.pi) def calculate_relative_canopy_radius_at_z( @@ -130,67 +216,68 @@ def solve_community_projected_canopy_area( return (A_p * n_individuals).sum() - target_area -def calculate_projected_leaf_area_for_individuals( - z: float, f_g: float, community: Community -) -> NDArray[np.float32]: - """Calculate projected crown area above a given height. - - Calculation applies to an individual within a cohort.This function takes PFT - specific parameters (shape parameters) and stem specific sizes and estimates - the projected crown area above a given height $z$. The inputs can either be - scalars describing a single stem or arrays representing a community of stems. - If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can be - scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that - PFT. - - :param community: - :param f_g: Crown gap fraction. - :param z: Height from ground. - """ +# def calculate_projected_leaf_area_for_individuals( +# z: float, f_g: float, community: Community +# ) -> NDArray[np.float32]: +# """Calculate projected crown area above a given height. - # Calculate q(z) - q_z = calculate_relative_canopy_radii( - z, community.t_model_heights, community.pft_m_values, community.pft_n_values - ) +# Calculation applies to an individual within a cohort.This function takes PFT +# specific parameters (shape parameters) and stem specific sizes and estimates +# the projected crown area above a given height $z$. The inputs can either be +# scalars describing a single stem or arrays representing a community of stems. +# If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can be +# scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that +# PFT. - # Calculate Ac terms - A_c_terms = ( - community.t_model_crown_areas * (q_z / community.canopy_factor_q_m_values) ** 2 - ) +# :param community: +# :param f_g: Crown gap fraction. +# :param z: Height from ground. +# """ - # Set Acp either side of zm - A_cp = np.where( - z <= community.canopy_factor_z_m_values, - community.t_model_crown_areas - A_c_terms * f_g, - A_c_terms * (1 - f_g), - ) - # Set Ap = 0 where z > H - A_cp = np.where(z > community.t_model_heights, 0, A_cp) - return A_cp +# # Calculate q(z) +# q_z = calculate_relative_canopy_radii( +# z, community.t_model_heights, community.pft_m_values, community.pft_n_values +# ) +# # Calculate Ac terms +# A_c_terms = ( +# community.t_model_crown_areas * +# (q_z / community.canopy_factor_q_m_values) ** 2 +# ) -def calculate_total_canopy_A_cp(z: float, f_g: float, community: Community) -> float: - """Calculate total leaf area at a given height. +# # Set Acp either side of zm +# A_cp = np.where( +# z <= community.canopy_factor_z_m_values, +# community.t_model_crown_areas - A_c_terms * f_g, +# A_c_terms * (1 - f_g), +# ) +# # Set Ap = 0 where z > H +# A_cp = np.where(z > community.t_model_heights, 0, A_cp) +# return A_cp - :param f_g: - :param community: - :param z: Height above ground. - :return: Total leaf area in the canopy at a given height. - """ - A_cp_for_individuals = calculate_projected_leaf_area_for_individuals( - z, f_g, community - ) - A_cp_for_cohorts = A_cp_for_individuals * community.cohort_number_of_individuals +# def calculate_total_canopy_A_cp(z: float, f_g: float, community: Community) -> float: +# """Calculate total leaf area at a given height. - return A_cp_for_cohorts.sum() +# :param f_g: +# :param community: +# :param z: Height above ground. +# :return: Total leaf area in the canopy at a given height. +# """ +# A_cp_for_individuals = calculate_projected_leaf_area_for_individuals( +# z, f_g, community +# ) +# A_cp_for_cohorts = A_cp_for_individuals * community.cohort_number_of_individuals -def calculate_gpp(cell_ppfd: NDArray, lue: NDArray) -> float: - """Estimate the gross primary productivity. +# return A_cp_for_cohorts.sum() - Not sure where to place this - need an array of LUE that matches to the - """ +# def calculate_gpp(cell_ppfd: NDArray, lue: NDArray) -> float: +# """Estimate the gross primary productivity. + +# Not sure where to place this - need an array of LUE that matches to the + +# """ - return 100 +# return 100 diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 7c8b1bc3..01359292 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -117,6 +117,7 @@ from numpy.typing import NDArray from pyrealm.core.utilities import check_input_shapes +from pyrealm.demography import canopy_functions from pyrealm.demography import t_model_functions as t_model from pyrealm.demography.flora import Flora @@ -467,11 +468,11 @@ def _calculate_t_model(self) -> None: ) # Canopy shape extension to T Model from PlantFATE - self.cohort_data["canopy_z_max"] = t_model.calculate_canopy_z_max( + self.cohort_data["canopy_z_max"] = canopy_functions.calculate_canopy_z_max( z_max_prop=self.cohort_data["z_max_prop"], height=self.cohort_data["height"], ) - self.cohort_data["canopy_r0"] = t_model.calculate_canopy_r0( + self.cohort_data["canopy_r0"] = canopy_functions.calculate_canopy_r0( q_m=self.cohort_data["q_m"], crown_area=self.cohort_data["crown_area"], ) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 57b72100..c0d76ff8 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -29,7 +29,7 @@ import pandas as pd from marshmallow.exceptions import ValidationError -from pyrealm.demography.t_model_functions import ( +from pyrealm.demography.canopy_functions import ( calculate_canopy_q_m, calculate_canopy_z_max_proportion, ) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 681712fd..c6a13148 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -143,88 +143,3 @@ def calculate_sapwood_masses( """ return crown_area * rho_s * height * (1 - crown_fraction / 2) / ca_ratio - - -def calculate_canopy_q_m(m: float, n: float) -> float: - """Calculate a q_m value. - - The value of q_m is a constant canopy scaling parameter derived from the ``m`` and - ``n`` attributes defined for a plant functional type. - - Args: - m: Canopy shape parameter - n: Canopy shape parameter - """ - return ( - m - * n - * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) - * (((m - 1) * n) / (m * n - 1)) ** (m - 1) - ) - - -def calculate_canopy_z_max_proportion(m: float, n: float) -> float: - r"""Calculate the z_m proportion. - - The z_m proportion (:math:`p_{zm}`) is the constant proportion of stem height at - which the maximum crown radius is found for a given plant functional type. - - .. math:: - - p_{zm} = \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}} - - Args: - m: Canopy shape parameter - n: Canopy shape parameter - """ - - return ((n - 1) / (m * n - 1)) ** (1 / n) - - -def calculate_canopy_z_max(z_max_prop: Series, height: Series) -> Series: - r"""Calculate height of maximum crown radius. - - The height of the maximum crown radius (:math:`z_m`) is derived from the canopy - shape parameters (:math:`m,n`) and the resulting fixed proportion (:math:`p_{zm}`) - for plant functional types. These shape parameters are defined as part of the - extension of the T Model presented by :cite:t:`joshi:2022a`. - - The value :math:`z_m` is the height above ground where the largest canopy radius is - found, given the proportion and the estimated stem height (:math:`H`) of - individuals. - - .. math:: - - z_m = p_{zm} H - - Args: - z_max_prop: Canopy shape parameter of the PFT - height: Crown area of individuals - """ - """Calculate z_m, the height of maximum crown radius.""" - - return height * z_max_prop - - -def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: - r"""Calculate scaling factor for height of maximum crown radius. - - This scaling factor (:math:`r_0`) is derived from the canopy shape parameters - (:math:`m,n,q_m`) for plant functional types and the estimated crown area - (:math:`A_c`) of individuals. The shape parameters are defined as part of the - extension of the T Model presented by :cite:t:`joshi:2022a` and :math:`r_0` is used - to scale the crown area such that the crown area at the maximum crown radius fits - the expectations of the T Model. - - .. math:: - - r_0 = 1/q_m \sqrt{A_c / \pi} - - Args: - q_m: Canopy shape parameter of the PFT - crown_area: Crown area of individuals - """ - # Scaling factor to give expected A_c (crown area) at - # z_m (height of maximum crown radius) - - return 1 / q_m * np.sqrt(crown_area / np.pi) diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index aa3ecdb2..8a470449 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -1,5 +1,55 @@ """test the functions in canopy_functions.py.""" +import numpy as np + + +def test_calculate_calculate_canopy_q_m_returns_q_m_for_valid_input(): + """Test happy path for calculating q_m. + + test that values of q_m are calculated correctly when valid arguments are + provided to the function. + """ + + from pyrealm.demography.canopy_functions import calculate_canopy_q_m + + m_values = np.array([2, 3]) + n_values = np.array([5, 4]) + expected_q_m_values = np.array([2.9038988210485766, 2.3953681843215673]) + actual_q_m_values = calculate_canopy_q_m(m=m_values, n=n_values) + + assert np.allclose(actual_q_m_values, expected_q_m_values) + + +def test_calculate_q_m_values_raises_exception_for_invalid_input(): + """Test unhappy path for calculating q_m. + + Test that an exception is raised when invalid arguments are provided to the + function. + """ + + pass + + +def test_calculate_z_max_values(): + """Test happy path for calculating z_max.""" + + pass + + +def test_calculate_r_0_values(): + """Test happy path for calculating r_0.""" + pass + + +def test_calculate_projected_canopy_area_for_individuals(): + """Test happy path for calculating canopy area for individuals.""" + pass + + +def test_calculate_relative_canopy_radii(): + """Test happy path for calculating relative canopy radii for individuals.""" + pass + def test_calculate_total_community_crown_area(): """Test happy path for calculating total community crown area.""" @@ -16,11 +66,6 @@ def calculate_community_projected_area_at_z(): pass -def test_calculate_projected_canopy_area_for_individuals(): - """Test happy path for calculating project canopy area for individuals.""" - pass - - def test_calculate_canopy_layer_heights(): """Test happy path for calculation of canopy layer heights.""" pass diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 26c9523c..d80f1246 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -1,21 +1,13 @@ """test the functions in t_model_functions.py.""" import numpy as np -from numpy.testing import assert_array_almost_equal - -from pyrealm.demography.t_model_functions import ( - calculate_canopy_q_m, - calculate_crown_areas, - calculate_crown_fractions, - calculate_foliage_masses, - calculate_heights, - calculate_sapwood_masses, - calculate_stem_masses, -) def test_calculate_heights(): """Tests happy path for calculation of heights of tree from diameter.""" + + from pyrealm.demography.t_model_functions import calculate_heights + pft_h_max_values = np.array([25.33, 15.33]) pft_a_hd_values = np.array([116.0, 116.0]) diameters_at_breast_height = np.array([0.2, 0.6]) @@ -25,11 +17,15 @@ def test_calculate_heights(): a_hd=pft_a_hd_values, dbh=diameters_at_breast_height, ) - assert_array_almost_equal(actual_heights, expected_heights, decimal=8) + + np.allclose(actual_heights, expected_heights) def test_calculate_crown_areas(): """Tests happy path for calculation of crown areas of trees.""" + + from pyrealm.demography.t_model_functions import calculate_crown_areas + pft_ca_ratio_values = np.array([2, 3]) pft_a_hd_values = np.array([116.0, 116.0]) diameters_at_breast_height = np.array([0.2, 0.6]) @@ -41,11 +37,15 @@ def test_calculate_crown_areas(): dbh=diameters_at_breast_height, height=heights, ) - assert_array_almost_equal(actual_crown_areas, expected_crown_areas, decimal=8) + + np.allclose(actual_crown_areas, expected_crown_areas) def test_calculate_crown_fractions(): """Tests happy path for calculation of crown fractions of trees.""" + + from pyrealm.demography.t_model_functions import calculate_crown_fractions + pft_a_hd_values = np.array([116.0, 116.0]) diameters_at_breast_height = np.array([0.2, 0.6]) heights = np.array([15.194142, 15.166396]) @@ -55,13 +55,15 @@ def test_calculate_crown_fractions(): dbh=diameters_at_breast_height, height=heights, ) - assert_array_almost_equal( - actual_crown_fractions, expected_crown_fractions, decimal=8 - ) + + np.allclose(actual_crown_fractions, expected_crown_fractions) def test_calculate_stem_masses(): """Tests happy path for calculation of stem masses.""" + + from pyrealm.demography.t_model_functions import calculate_stem_masses + diameters_at_breast_height = np.array([0.2, 0.6]) heights = np.array([15.194142, 15.166396]) pft_rho_s_values = np.array([200.0, 200.0]) @@ -69,11 +71,15 @@ def test_calculate_stem_masses(): actual_stem_masses = calculate_stem_masses( dbh=diameters_at_breast_height, height=heights, rho_s=pft_rho_s_values ) - assert_array_almost_equal(actual_stem_masses, expected_stem_masses, decimal=8) + + np.allclose(actual_stem_masses, expected_stem_masses) def test_calculate_foliage_masses(): """Tests happy path for calculation of foliage masses.""" + + from pyrealm.demography.t_model_functions import calculate_foliage_masses + crown_areas = np.array([0.04114983, 0.1848361]) pft_lai_values = np.array([1.8, 1.8]) pft_sla_values = np.array([14.0, 14.0]) @@ -81,11 +87,15 @@ def test_calculate_foliage_masses(): actual_foliage_masses = calculate_foliage_masses( crown_area=crown_areas, lai=pft_lai_values, sla=pft_sla_values ) - assert_array_almost_equal(actual_foliage_masses, expected_foliage_masses, decimal=8) + + np.allclose(actual_foliage_masses, expected_foliage_masses) def test_calculate_sapwood_masses(): """Tests happy path for calculation of sapwood masses.""" + + from pyrealm.demography.t_model_functions import calculate_sapwood_masses + crown_areas = np.array([0.04114983, 0.1848361]) pft_rho_s_values = np.array([200.0, 200.0]) heights = np.array([15.194142, 15.166396]) @@ -99,51 +109,5 @@ def test_calculate_sapwood_masses(): crown_fraction=crown_fractions, ca_ratio=pft_ca_ratio_values, ) - assert_array_almost_equal(actual_sapwood_masses, expected_sapwood_masses, decimal=8) - - -"""Test the functions in jaideeps_t_model_extension_functions.py.""" - - -def test_calculate_calculate_canopy_q_m_returns_q_m_for_valid_input(): - """Test happy path for calculating q_m. - - test that values of q_m are calculated correctly when valid arguments are - provided to the function. - """ - m_values = np.array([2, 3]) - n_values = np.array([5, 4]) - expected_q_m_values = np.array([2.9038988210485766, 2.3953681843215673]) - actual_q_m_values = calculate_canopy_q_m(m=m_values, n=n_values) - assert_array_almost_equal(actual_q_m_values, expected_q_m_values, decimal=8) - - -def test_calculate_q_m_values_raises_exception_for_invalid_input(): - """Test unhappy path for calculating q_m. - - Test that an exception is raised when invalid arguments are provided to the - function. - """ - - pass - - -def test_calculate_z_max_values(): - """Test happy path for calculating z_max.""" - - pass - - -def test_calculate_r_0_values(): - """Test happy path for calculating r_0.""" - pass - - -def test_calculate_projected_canopy_area_for_individuals(): - """Test happy path for calculating canopy area for individuals.""" - pass - -def test_calculate_relative_canopy_radii(): - """Test happy path for calculating relative canopy radii for individuals.""" - pass + np.allclose(actual_sapwood_masses, expected_sapwood_masses) From a6e4e460e2baaae437ec5dec50d25d1fda9b12d8 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 17 Sep 2024 19:11:55 +0100 Subject: [PATCH 105/241] Docstrings and initial unit tests for canopy functions --- pyrealm/demography/canopy_functions.py | 14 +- pyrealm/demography/t_model_functions.py | 2 +- .../unit/demography/test_canopy_functions.py | 227 ++++++++++++++---- 3 files changed, 190 insertions(+), 53 deletions(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 3be90f9b..dedffbb2 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -1,4 +1,6 @@ -"""Class containing functions for calculating properties of a canopy.""" +"""A set of functions implementing the canopy shape and vertical leaf distribution model +used in PlantFATE :cite:t:`joshi:2022a`. +""" # noqa: D205 import numpy as np from numpy.typing import NDArray @@ -7,8 +9,10 @@ # from pyrealm.demography.community import Community -def calculate_canopy_q_m(m: float, n: float) -> float: - """Calculate a q_m value. +def calculate_canopy_q_m( + m: float | NDArray[np.float32], n: float | NDArray[np.float32] +) -> NDArray[np.float32]: + """Calculate the canopy scaling paramater ``q_m``. The value of q_m is a constant canopy scaling parameter derived from the ``m`` and ``n`` attributes defined for a plant functional type. @@ -25,7 +29,9 @@ def calculate_canopy_q_m(m: float, n: float) -> float: ) -def calculate_canopy_z_max_proportion(m: float, n: float) -> float: +def calculate_canopy_z_max_proportion( + m: float | NDArray[np.float32], n: float | NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate the z_m proportion. The z_m proportion (:math:`p_{zm}`) is the constant proportion of stem height at diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index c6a13148..dab3a8ed 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -2,7 +2,7 @@ :cite:`Li:2014bc`:. This provides scaling relationships using the plant functional type traits defined in the :mod:`~pyrealm.demography.flora` module and the diameter at breast height of individual stems to define the stem geometry, masses, respiration and hence -the calculate stem growth given net primary productivity. +calculate stem growth given net primary productivity. """ # noqa: D205 import numpy as np diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index 8a470449..352387f4 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -1,79 +1,210 @@ """test the functions in canopy_functions.py.""" import numpy as np +import pytest -def test_calculate_calculate_canopy_q_m_returns_q_m_for_valid_input(): - """Test happy path for calculating q_m. +@pytest.fixture +def fixture_canopy_shape(): + """Fixture providing input and expected values for shape parameter calculations. - test that values of q_m are calculated correctly when valid arguments are - provided to the function. + These are hand calculated and only really test that the calculations haven't changed + from the initial implementation. """ + return { + "m": np.array([2, 3]), + "n": np.array([5, 4]), + "q_m": np.array([2.9038988210485766, 2.3953681843215673]), + "p_zm": np.array([0.850283, 0.72265688]), + } + + +@pytest.fixture +def fixture_community(): + """A fixture providing a simple community.""" + from pyrealm.demography.community import Community + from pyrealm.demography.flora import Flora, PlantFunctionalType + + # A simple community containing one sample stem + flora = Flora([PlantFunctionalType(name="test")]) + return Community( + cell_id=1, + cell_area=100, + flora=flora, + cohort_n_individuals=np.repeat([1], 4), + cohort_pft_names=np.repeat(["test"], 4), + cohort_dbh_values=np.array([0.2, 0.4, 0.6, 0.8]), + ) + + +def test_calculate_canopy_q_m(fixture_canopy_shape): + """Test calculate_canopy_q_m.""" from pyrealm.demography.canopy_functions import calculate_canopy_q_m - m_values = np.array([2, 3]) - n_values = np.array([5, 4]) - expected_q_m_values = np.array([2.9038988210485766, 2.3953681843215673]) - actual_q_m_values = calculate_canopy_q_m(m=m_values, n=n_values) + actual_q_m_values = calculate_canopy_q_m( + m=fixture_canopy_shape["m"], n=fixture_canopy_shape["n"] + ) - assert np.allclose(actual_q_m_values, expected_q_m_values) + assert np.allclose(actual_q_m_values, fixture_canopy_shape["q_m"]) -def test_calculate_q_m_values_raises_exception_for_invalid_input(): - """Test unhappy path for calculating q_m. +def test_calculate_canopy_z_max_proportion(fixture_canopy_shape): + """Test calculate_canopy_z_max_proportion.""" - Test that an exception is raised when invalid arguments are provided to the - function. - """ - - pass + from pyrealm.demography.canopy_functions import calculate_canopy_z_max_proportion + actual_p_zm = calculate_canopy_z_max_proportion( + m=fixture_canopy_shape["m"], n=fixture_canopy_shape["n"] + ) -def test_calculate_z_max_values(): - """Test happy path for calculating z_max.""" - - pass + assert np.allclose(actual_p_zm, fixture_canopy_shape["p_zm"]) -def test_calculate_r_0_values(): +@pytest.mark.parametrize( + argnames="crown_areas, expected_r0", + argvalues=( + (np.array([20, 30]), np.array([0.86887756, 1.29007041])), + (np.array([30, 40]), np.array([1.06415334, 1.489645])), + ), +) +def test_calculate_r_0_values(fixture_canopy_shape, crown_areas, expected_r0): """Test happy path for calculating r_0.""" - pass + from pyrealm.demography.canopy_functions import calculate_canopy_r0 -def test_calculate_projected_canopy_area_for_individuals(): - """Test happy path for calculating canopy area for individuals.""" - pass - + actual_r0_values = calculate_canopy_r0( + q_m=fixture_canopy_shape["q_m"], crown_area=crown_areas + ) -def test_calculate_relative_canopy_radii(): - """Test happy path for calculating relative canopy radii for individuals.""" - pass + assert np.allclose(actual_r0_values, expected_r0) -def test_calculate_total_community_crown_area(): - """Test happy path for calculating total community crown area.""" - pass - - -def test_calculate_number_of_canopy_layers(): - """Test happy path for calculating number of canopy layers.""" - pass - - -def calculate_community_projected_area_at_z(): - """Test happy path for calculating total projected area for community.""" - pass +def test_calculate_relative_canopy_radius_at_z(fixture_community): + """Test crown radius height prediction. + This test validates the expectation that the canopy shape model correctly + predicts the crown area from the T Model equations at the predicted height of + maximum crown radius. + """ -def test_calculate_canopy_layer_heights(): - """Test happy path for calculation of canopy layer heights.""" - pass + from pyrealm.demography.canopy_functions import ( + calculate_relative_canopy_radius_at_z, + ) + + # Canopy shape model gives the maximum radius at a height z_max + z_max = ( + fixture_community.cohort_data["height"] + * fixture_community.cohort_data["z_max_prop"] + ) + + # Get the relative radius at that height + q_z_values = calculate_relative_canopy_radius_at_z( + z=z_max, + height=fixture_community.cohort_data["height"], + m=fixture_community.cohort_data["m"], + n=fixture_community.cohort_data["n"], + ) + + # Now test that the circular crown area from that radius is equivalent to the direct + # prediction from the T model allometric equations. + assert np.allclose( + fixture_community.cohort_data["crown_area"], + np.pi * (q_z_values * fixture_community.cohort_data["canopy_r0"]) ** 2, + ) + + +@pytest.mark.parametrize( + argnames="heights,expected_Ap_z", + argvalues=[ + pytest.param( + np.array([15.19414157, 21.27411267, 23.70702725, 24.68056368]) + 0.01, + np.repeat(0, 4), + id="one_cm_above_stem_top", + ), + pytest.param( + np.array([12.91932028, 18.08901635, 20.15768226, 20.98546374]) + 1.00, + np.array([5.94793264, 19.6183899, 33.77430339, 47.31340371]), + id="one_metre_above_z_max", + ), + pytest.param( + np.array([12.91932028, 18.08901635, 20.15768226, 20.98546374]), + np.array([8.03306419, 22.49502702, 37.60134866, 52.19394627]), + id="at_z_max", + ), + pytest.param( + np.array([12.91932028, 18.08901635, 20.15768226, 20.98546374]) - 1.00, + np.array([8.03306419, 22.49502702, 37.60134866, 52.19394627]), + id="one_metre_below_z_max", + ), + ], +) +def test_calculate_stem_projected_canopy_area_at_z( + fixture_community, heights, expected_Ap_z +): + """Test calculate_stem_projected_canopy_area_at_z. + + The test checks cases: + * above stem H - all values should be zero + * 1 metre above z_max - all values should be less than crown area + * at z_max - all values should be equal to crown area + * 1 metre below z_max - all values should be equal to crown area + """ + from pyrealm.demography.canopy_functions import ( + calculate_stem_projected_canopy_area_at_z, + ) + + Ap_z_values = calculate_stem_projected_canopy_area_at_z( + z=heights, + height=fixture_community.cohort_data["height"], + crown_area=fixture_community.cohort_data["crown_area"], + m=fixture_community.cohort_data["m"], + n=fixture_community.cohort_data["n"], + q_m=fixture_community.cohort_data["q_m"], + z_m=fixture_community.cohort_data["canopy_z_max"], + ) + + assert np.allclose( + Ap_z_values, + expected_Ap_z, + ) + + +def test_solve_community_projected_canopy_area(fixture_community): + """Test solve_community_projected_canopy_area. + + The logic of this test is that given the cumulative sum of the crown areas in the + fixture from tallest to shortest as the target, providing the z_max of each stem as + the height _should_ always return zero, as this is exactly the height at which that + cumulative area would close: crown 1 closes at z_max 1, crown 1 + 2 closes at z_max + 2 and so on. + """ -def test_solve_canopy_closure_height(): - """Test happy path for solver function for canopy closure height.""" - pass + from pyrealm.demography.canopy_functions import ( + solve_community_projected_canopy_area, + ) + + for ( + this_height, + this_target, + ) in zip( + np.flip(fixture_community.cohort_data["canopy_z_max"]), + np.cumsum(np.flip(fixture_community.cohort_data["crown_area"])), + ): + solved = solve_community_projected_canopy_area( + z=this_height, + height=fixture_community.cohort_data["height"], + crown_area=fixture_community.cohort_data["crown_area"], + n_individuals=fixture_community.cohort_data["n_individuals"], + m=fixture_community.cohort_data["m"], + n=fixture_community.cohort_data["n"], + q_m=fixture_community.cohort_data["q_m"], + z_m=fixture_community.cohort_data["canopy_z_max"], + target_area=this_target, + ) + + assert solved == pytest.approx(0) def test_calculate_projected_leaf_area_for_individuals(): From 1db5cc2ec0e0136cd4e6b8c6cb86fea3d5713f2e Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 18 Sep 2024 09:27:36 +0100 Subject: [PATCH 106/241] Adding refs and clarification of methods differences --- pyrealm/demography/t_model_functions.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 6e985e13..1960f08e 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -247,9 +247,11 @@ def calculate_net_primary_productivity( .. math:: P_{net} = y (P - R_m) = y (P - W_{\cdot s} r_s - \zeta \sigma W_f r_r - P r_f) - Note that this differs from Equation 13 of :cite:t:`Li:2014bc`, which removes foliar - respiration from potential GPP. This approach is equivalent but allows the foliar - respiration to vary between plant functional types. + Note that this differs from Equation 13 of :cite:t:`Li:2014bc`, which does not + include a term for foliar respiration. This is because :cite:t:`Li:2014bc` remove + foliar respiration as a fixed proportion of potential GPP as the first step in their + calculations. The approach here is equivalent but allows the foliar respiration to + vary between plant functional types. Args: yld: The yield proportion. @@ -315,7 +317,7 @@ def calculate_growth_increments( Given an estimate of net primary productivity (:math:`P_{net}`), less associated turnover costs (:math:`T`), the remaining productivity can be allocated to growth - and hence estimate resulting increments in: + and hence estimate resulting increments :cite:`Li:2014bc` in: * the stem diameter (:math:`\Delta D`), * the stem mass (:math:`\Delta W_s`), and From 959d91ed5d030be4761a992113d08a1ea94ad2c2 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 18 Sep 2024 10:37:50 +0100 Subject: [PATCH 107/241] More renaming of height to stem_height, fixing tests and docstrings --- pyrealm/demography/canopy.py | 28 ++--- pyrealm/demography/canopy_functions.py | 108 ++++++++++-------- pyrealm/demography/community.py | 24 ++-- pyrealm/demography/t_model_functions.py | 24 ++-- .../test_t_model_functions_against_rtmodel.py | 8 +- .../unit/demography/test_canopy_functions.py | 8 +- tests/unit/demography/test_community.py | 2 +- .../unit/demography/test_t_model_functions.py | 16 +-- 8 files changed, 117 insertions(+), 101 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 8c5ab3ae..c005ec8d 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -20,7 +20,7 @@ def __init__(self, community: Community, canopy_gap_fraction: float) -> None: ).sum() """Total crown area across individuals in the community (metres 2).""" - self.max_height: float = community.cohort_data["height"].max() + self.max_stem_height: float = community.cohort_data["stem_height"].max() """Maximum height of any individual in the community (metres).""" self.crown_area_per_layer: float = community.cell_area * ( @@ -48,25 +48,25 @@ def __init__(self, community: Community, canopy_gap_fraction: float) -> None: args=( community.cohort_data["n_individuals"], # n_individuals community.cohort_data["crown_area"], # crown_area - community.cohort_data["height"], # height + community.cohort_data["stem_height"], # stem_height community.cohort_data["m"], # m community.cohort_data["n"], # n community.cohort_data["q_m"], # q_m community.cohort_data["q_n"], # z_m target_area, # target_area ), - bracket=(0, self.max_height), + bracket=(0, self.max_stem_height), ).root - # TODO there may be a more efficient solution here that does not use a loop. - self.A_cp_within_layer = map( - calculate_total_canopy_A_cp, - self.canopy_layer_heights, - np.full(self.number_of_canopy_layers, canopy_gap_fraction), - np.full(self.number_of_canopy_layers, community), - ) + # # TODO there may be a more efficient solution here that does not use a loop. + # self.A_cp_within_layer = map( + # calculate_total_canopy_A_cp, + # self.canopy_layer_heights, + # np.full(self.number_of_canopy_layers, canopy_gap_fraction), + # np.full(self.number_of_canopy_layers, community), + # ) - self.gpp = calculate_gpp( - np.zeros(self.number_of_canopy_layers), - np.zeros(self.number_of_canopy_layers), - ) + # self.gpp = calculate_gpp( + # np.zeros(self.number_of_canopy_layers), + # np.zeros(self.number_of_canopy_layers), + # ) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index dedffbb2..6144191f 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -49,7 +49,7 @@ def calculate_canopy_z_max_proportion( return ((n - 1) / (m * n - 1)) ** (1 / n) -def calculate_canopy_z_max(z_max_prop: Series, height: Series) -> Series: +def calculate_canopy_z_max(z_max_prop: Series, stem_height: Series) -> Series: r"""Calculate height of maximum crown radius. The height of the maximum crown radius (:math:`z_m`) is derived from the canopy @@ -67,11 +67,11 @@ def calculate_canopy_z_max(z_max_prop: Series, height: Series) -> Series: Args: z_max_prop: Canopy shape parameter of the PFT - height: Crown area of individuals + stem_height: Stem height of individuals """ """Calculate z_m, the height of maximum crown radius.""" - return height * z_max_prop + return stem_height * z_max_prop def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: @@ -100,7 +100,7 @@ def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: def calculate_relative_canopy_radius_at_z( z: float, - height: NDArray[np.float32], + stem_height: NDArray[np.float32], m: NDArray[np.float32], n: NDArray[np.float32], ) -> NDArray[np.float32]: @@ -117,19 +117,19 @@ def calculate_relative_canopy_radius_at_z( Args: z: Height at which to calculate relative radius - height: Total height of individual stem + stem_height: Total height of individual stem m: Canopy shape parameter of PFT n: Canopy shape parameter of PFT """ - z_over_height = z / height + z_over_height = z / stem_height return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) def calculate_stem_projected_canopy_area_at_z( z: float, - height: NDArray[np.float32], + stem_height: NDArray[np.float32], crown_area: NDArray[np.float32], m: NDArray[np.float32], n: NDArray[np.float32], @@ -145,7 +145,7 @@ def calculate_stem_projected_canopy_area_at_z( Args: z: Vertical height on the z axis. crown_area: Crown area of each cohort - height: Stem height of each cohort + stem_height: Stem height of each cohort m: Canopy shape parameter ``m``` for each cohort n: Canopy shape parameter ``n``` for each cohort q_m: Canopy shape parameter ``q_m``` for each cohort @@ -153,7 +153,7 @@ def calculate_stem_projected_canopy_area_at_z( """ # Calculate q(z) - q_z = calculate_relative_canopy_radius_at_z(z, height, m, n) + q_z = calculate_relative_canopy_radius_at_z(z, stem_height, m, n) # Calculate A_p # Calculate Ap given z > zm @@ -161,14 +161,14 @@ def calculate_stem_projected_canopy_area_at_z( # Set Ap = Ac where z <= zm A_p = np.where(z <= z_m, crown_area, A_p) # Set Ap = 0 where z > H - A_p = np.where(z > height, 0, A_p) + A_p = np.where(z > stem_height, 0, A_p) return A_p def solve_community_projected_canopy_area( z: float, - height: NDArray[np.float32], + stem_height: NDArray[np.float32], crown_area: NDArray[np.float32], m: NDArray[np.float32], n: NDArray[np.float32], @@ -200,7 +200,7 @@ def solve_community_projected_canopy_area( z: Vertical height on the z axis. n_individuals: Number of individuals in each cohort crown_area: Crown area of each cohort - height: Stem height of each cohort + stem_height: Stem height of each cohort m: Canopy shape parameter ``m``` for each cohort n: Canopy shape parameter ``n``` for each cohort q_m: Canopy shape parameter ``q_m``` for each cohort @@ -211,7 +211,7 @@ def solve_community_projected_canopy_area( # Calculate A(p) for the stems in each cohort A_p = calculate_stem_projected_canopy_area_at_z( z=z, - height=height, + stem_height=stem_height, crown_area=crown_area, m=m, n=n, @@ -222,44 +222,60 @@ def solve_community_projected_canopy_area( return (A_p * n_individuals).sum() - target_area -# def calculate_projected_leaf_area_for_individuals( -# z: float, f_g: float, community: Community -# ) -> NDArray[np.float32]: -# """Calculate projected crown area above a given height. +def calculate_stem_projected_leaf_area_at_z( + z: float | NDArray[np.float32], + stem_height: NDArray[np.float32], + crown_area: NDArray[np.float32], + z_max: NDArray[np.float32], + f_g: NDArray[np.float32], + m: NDArray[np.float32], + n: NDArray[np.float32], + q_m: NDArray[np.float32], + z_m: NDArray[np.float32], +) -> NDArray[np.float32]: + """Calculate projected leaf area above a given height. -# Calculation applies to an individual within a cohort.This function takes PFT -# specific parameters (shape parameters) and stem specific sizes and estimates -# the projected crown area above a given height $z$. The inputs can either be -# scalars describing a single stem or arrays representing a community of stems. -# If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can be -# scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that -# PFT. + Calculation applies to an individual within a cohort.This function takes PFT + specific parameters (shape parameters) and stem specific sizes and estimates + the projected crown area above a given height $z$. The inputs can either be + scalars describing a single stem or arrays representing a community of stems. + If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can be + scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that + PFT. -# :param community: -# :param f_g: Crown gap fraction. -# :param z: Height from ground. -# """ + Args: + z: Vertical height on the z axis. + crown_area: Crown area for a stem + stem_height: Total height of a stem + z_max: Height of maximum canopy radius for each stem + f_g: Within crown gap fraction for each stem. + m: Canopy shape parameter ``m``` for each stem + n: Canopy shape parameter ``n``` for each stem + q_m: Canopy shape parameter ``q_m``` for each stem + z_m: Canopy shape parameter ``z_m``` for each stem + """ -# # Calculate q(z) -# q_z = calculate_relative_canopy_radii( -# z, community.t_model_heights, community.pft_m_values, community.pft_n_values -# ) + # Calculate q(z) + q_z = calculate_relative_canopy_radius_at_z( + z=z, + stem_height=stem_height, + m=m, + n=n, + ) -# # Calculate Ac terms -# A_c_terms = ( -# community.t_model_crown_areas * -# (q_z / community.canopy_factor_q_m_values) ** 2 -# ) + # Calculate Ac terms + A_c_terms = crown_area * (q_z / q_m) ** 2 -# # Set Acp either side of zm -# A_cp = np.where( -# z <= community.canopy_factor_z_m_values, -# community.t_model_crown_areas - A_c_terms * f_g, -# A_c_terms * (1 - f_g), -# ) -# # Set Ap = 0 where z > H -# A_cp = np.where(z > community.t_model_heights, 0, A_cp) -# return A_cp + # Set Acp either side of zm + A_cp = np.where( + z <= z_max, + crown_area - A_c_terms * f_g, + A_c_terms * (1 - f_g), + ) + # Set Ap = 0 where z > H + A_cp = np.where(z > stem_height, 0, A_cp) + + return A_cp # def calculate_total_canopy_A_cp(z: float, f_g: float, community: Community) -> float: diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 01359292..9a1dbb09 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -93,13 +93,13 @@ Display the community's cohort data with calculated T Model predictions: >>> community.cohort_data[ -... ['name', 'dbh', 'n_individuals', 'height', 'crown_area', 'stem_mass'] +... ['name', 'dbh', 'n_individuals', 'stem_height', 'crown_area', 'stem_mass'] ... ] - name dbh n_individuals height crown_area stem_mass -0 Evergreen Tree 0.100 100 9.890399 2.459835 8.156296 -1 Deciduous Shrub 0.030 200 2.110534 0.174049 0.134266 -2 Evergreen Tree 0.120 150 11.436498 3.413238 13.581094 -3 Deciduous Shrub 0.025 180 1.858954 0.127752 0.082126 + name dbh n_individuals stem_height crown_area stem_mass +0 Evergreen Tree 0.100 100 9.890399 2.459835 8.156296 +1 Deciduous Shrub 0.030 200 2.110534 0.174049 0.134266 +2 Evergreen Tree 0.120 150 11.436498 3.413238 13.581094 +3 Deciduous Shrub 0.025 180 1.858954 0.127752 0.082126 """ # noqa: D205 from __future__ import annotations @@ -428,7 +428,7 @@ def _calculate_t_model(self) -> None: # Add data to cohort dataframes capturing the T Model geometry # - Classic T Model scaling - self.cohort_data["height"] = t_model.calculate_heights( + self.cohort_data["stem_height"] = t_model.calculate_heights( h_max=self.cohort_data["h_max"], a_hd=self.cohort_data["a_hd"], dbh=self.cohort_data["dbh"], @@ -438,19 +438,19 @@ def _calculate_t_model(self) -> None: ca_ratio=self.cohort_data["ca_ratio"], a_hd=self.cohort_data["a_hd"], dbh=self.cohort_data["dbh"], - height=self.cohort_data["height"], + stem_height=self.cohort_data["stem_height"], ) self.cohort_data["crown_fraction"] = t_model.calculate_crown_fractions( a_hd=self.cohort_data["a_hd"], dbh=self.cohort_data["dbh"], - height=self.cohort_data["height"], + stem_height=self.cohort_data["stem_height"], ) self.cohort_data["stem_mass"] = t_model.calculate_stem_masses( rho_s=self.cohort_data["rho_s"], dbh=self.cohort_data["dbh"], - height=self.cohort_data["height"], + stem_height=self.cohort_data["stem_height"], ) self.cohort_data["foliage_mass"] = t_model.calculate_foliage_masses( @@ -462,7 +462,7 @@ def _calculate_t_model(self) -> None: self.cohort_data["sapwood_mass"] = t_model.calculate_sapwood_masses( rho_s=self.cohort_data["rho_s"], ca_ratio=self.cohort_data["ca_ratio"], - height=self.cohort_data["height"], + stem_height=self.cohort_data["stem_height"], crown_area=self.cohort_data["crown_area"], crown_fraction=self.cohort_data["crown_fraction"], ) @@ -470,7 +470,7 @@ def _calculate_t_model(self) -> None: # Canopy shape extension to T Model from PlantFATE self.cohort_data["canopy_z_max"] = canopy_functions.calculate_canopy_z_max( z_max_prop=self.cohort_data["z_max_prop"], - height=self.cohort_data["height"], + stem_height=self.cohort_data["stem_height"], ) self.cohort_data["canopy_r0"] = canopy_functions.calculate_canopy_r0( q_m=self.cohort_data["q_m"], diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index acafd4a6..cb0470bd 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -31,7 +31,7 @@ def calculate_heights(h_max: Series, a_hd: Series, dbh: Series) -> Series: def calculate_crown_areas( - ca_ratio: Series, a_hd: Series, dbh: Series, height: Series + ca_ratio: Series, a_hd: Series, dbh: Series, stem_height: Series ) -> Series: r"""Calculate tree crown area under the T Model. @@ -49,13 +49,13 @@ def calculate_crown_areas( ca_ratio: Crown area ratio of the PFT a_hd: Initial slope of the height/diameter relationship of the PFT dbh: Diameter at breast height of individuals - height: Stem height of individuals + stem_height: Stem height of individuals """ - return ((np.pi * ca_ratio) / (4 * a_hd)) * dbh * height + return ((np.pi * ca_ratio) / (4 * a_hd)) * dbh * stem_height -def calculate_crown_fractions(a_hd: Series, height: Series, dbh: Series) -> Series: +def calculate_crown_fractions(a_hd: Series, stem_height: Series, dbh: Series) -> Series: r"""Calculate tree crown fraction under the T Model. The crown fraction (:math:`f_{c}`)is calculated from individual diameters at breast @@ -69,14 +69,14 @@ def calculate_crown_fractions(a_hd: Series, height: Series, dbh: Series) -> Seri Args: a_hd: Initial slope of the height/diameter relationship of the PFT + stem_height: Stem height of individuals dbh: Diameter at breast height of individuals - height: Stem height of individuals """ - return height / (a_hd * dbh) + return stem_height / (a_hd * dbh) -def calculate_stem_masses(rho_s: Series, height: Series, dbh: Series) -> Series: +def calculate_stem_masses(rho_s: Series, stem_height: Series, dbh: Series) -> Series: r"""Calculate stem mass under the T Model. The stem mass (:math:`W_{s}`) is calculated from individual diameters at breast @@ -89,11 +89,11 @@ def calculate_stem_masses(rho_s: Series, height: Series, dbh: Series) -> Series: Args: rho_s: Wood density of the PFT + stem_height: Stem height of individuals dbh: Diameter at breast height of individuals - height: Stem height of individuals """ - return (np.pi / 8) * rho_s * (dbh**2) * height + return (np.pi / 8) * rho_s * (dbh**2) * stem_height def calculate_foliage_masses(sla: Series, lai: Series, crown_area: Series) -> Series: @@ -119,7 +119,7 @@ def calculate_foliage_masses(sla: Series, lai: Series, crown_area: Series) -> Se def calculate_sapwood_masses( rho_s: Series, ca_ratio: Series, - height: Series, + stem_height: Series, crown_area: Series, crown_fraction: Series, ) -> Series: @@ -137,12 +137,12 @@ def calculate_sapwood_masses( Args: rho_s: Wood density of the PFT ca_ratio: Crown area ratio of the PFT - height: Stem height of individuals + stem_height: Stem height of individuals crown_area: Crown area of individuals crown_fraction: Crown fraction of individuals """ - return crown_area * rho_s * height * (1 - crown_fraction / 2) / ca_ratio + return crown_area * rho_s * stem_height * (1 - crown_fraction / 2) / ca_ratio def calculate_whole_crown_gpp( diff --git a/tests/regression/demography/test_t_model_functions_against_rtmodel.py b/tests/regression/demography/test_t_model_functions_against_rtmodel.py index 0582daa2..c16a76dd 100644 --- a/tests/regression/demography/test_t_model_functions_against_rtmodel.py +++ b/tests/regression/demography/test_t_model_functions_against_rtmodel.py @@ -123,7 +123,7 @@ def test_calculate_crown_areas(rvalues): ca_ratio=pft.ca_ratio, a_hd=pft.a_hd, dbh=data["diameter"], - height=data["height"], + stem_height=data["height"], ) assert_array_almost_equal(actual_crown_areas, data["crown_area"], decimal=8) @@ -138,7 +138,7 @@ def test_calculate_crown_fractions(rvalues): actual_crown_fractions = calculate_crown_fractions( a_hd=pft.a_hd, dbh=data["diameter"], - height=data["height"], + stem_height=data["height"], ) assert_array_almost_equal( actual_crown_fractions, data["crown_fraction"], decimal=8 @@ -153,7 +153,7 @@ def test_calculate_stem_masses(rvalues): for pft, _, data in rvalues: actual_stem_masses = calculate_stem_masses( dbh=data["diameter"], - height=data["height"], + stem_height=data["height"], rho_s=pft.rho_s, ) assert_array_almost_equal(actual_stem_masses, data["mass_stm"], decimal=8) @@ -179,7 +179,7 @@ def test_calculate_sapwood_masses(rvalues): for pft, _, data in rvalues: actual_sapwood_masses = calculate_sapwood_masses( crown_area=data["crown_area"], - height=data["height"], + stem_height=data["height"], crown_fraction=data["crown_fraction"], ca_ratio=pft.ca_ratio, rho_s=pft.rho_s, diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index 352387f4..b6bc955f 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -94,14 +94,14 @@ def test_calculate_relative_canopy_radius_at_z(fixture_community): # Canopy shape model gives the maximum radius at a height z_max z_max = ( - fixture_community.cohort_data["height"] + fixture_community.cohort_data["stem_height"] * fixture_community.cohort_data["z_max_prop"] ) # Get the relative radius at that height q_z_values = calculate_relative_canopy_radius_at_z( z=z_max, - height=fixture_community.cohort_data["height"], + stem_height=fixture_community.cohort_data["stem_height"], m=fixture_community.cohort_data["m"], n=fixture_community.cohort_data["n"], ) @@ -157,7 +157,7 @@ def test_calculate_stem_projected_canopy_area_at_z( Ap_z_values = calculate_stem_projected_canopy_area_at_z( z=heights, - height=fixture_community.cohort_data["height"], + stem_height=fixture_community.cohort_data["stem_height"], crown_area=fixture_community.cohort_data["crown_area"], m=fixture_community.cohort_data["m"], n=fixture_community.cohort_data["n"], @@ -194,7 +194,7 @@ def test_solve_community_projected_canopy_area(fixture_community): ): solved = solve_community_projected_canopy_area( z=this_height, - height=fixture_community.cohort_data["height"], + stem_height=fixture_community.cohort_data["stem_height"], crown_area=fixture_community.cohort_data["crown_area"], n_individuals=fixture_community.cohort_data["n_individuals"], m=fixture_community.cohort_data["m"], diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index 76b661e8..e5dcd15b 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -57,7 +57,7 @@ def check_expected(community, expected): expected["a_hd"], ) assert np.allclose( - community.cohort_data["height"], + community.cohort_data["stem_height"], expected["height"], ) diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index d80f1246..bd8a8760 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -29,13 +29,13 @@ def test_calculate_crown_areas(): pft_ca_ratio_values = np.array([2, 3]) pft_a_hd_values = np.array([116.0, 116.0]) diameters_at_breast_height = np.array([0.2, 0.6]) - heights = np.array([15.194142, 15.166396]) + stem_height = np.array([15.194142, 15.166396]) expected_crown_areas = np.array([0.04114983, 0.1848361]) actual_crown_areas = calculate_crown_areas( ca_ratio=pft_ca_ratio_values, a_hd=pft_a_hd_values, dbh=diameters_at_breast_height, - height=heights, + stem_height=stem_height, ) np.allclose(actual_crown_areas, expected_crown_areas) @@ -48,12 +48,12 @@ def test_calculate_crown_fractions(): pft_a_hd_values = np.array([116.0, 116.0]) diameters_at_breast_height = np.array([0.2, 0.6]) - heights = np.array([15.194142, 15.166396]) + stem_height = np.array([15.194142, 15.166396]) expected_crown_fractions = np.array([0.65491991, 0.21790799]) actual_crown_fractions = calculate_crown_fractions( a_hd=pft_a_hd_values, dbh=diameters_at_breast_height, - height=heights, + stem_height=stem_height, ) np.allclose(actual_crown_fractions, expected_crown_fractions) @@ -65,11 +65,11 @@ def test_calculate_stem_masses(): from pyrealm.demography.t_model_functions import calculate_stem_masses diameters_at_breast_height = np.array([0.2, 0.6]) - heights = np.array([15.194142, 15.166396]) + stem_height = np.array([15.194142, 15.166396]) pft_rho_s_values = np.array([200.0, 200.0]) expected_stem_masses = np.array([47.73380488, 428.8197443]) actual_stem_masses = calculate_stem_masses( - dbh=diameters_at_breast_height, height=heights, rho_s=pft_rho_s_values + dbh=diameters_at_breast_height, stem_height=stem_height, rho_s=pft_rho_s_values ) np.allclose(actual_stem_masses, expected_stem_masses) @@ -98,14 +98,14 @@ def test_calculate_sapwood_masses(): crown_areas = np.array([0.04114983, 0.1848361]) pft_rho_s_values = np.array([200.0, 200.0]) - heights = np.array([15.194142, 15.166396]) + stem_height = np.array([15.194142, 15.166396]) crown_fractions = np.array([0.65491991, 0.21790799]) pft_ca_ratio_values = [390.43, 390.43] expected_sapwood_masses = np.array([0.21540173, 1.27954667]) actual_sapwood_masses = calculate_sapwood_masses( crown_area=crown_areas, rho_s=pft_rho_s_values, - height=heights, + stem_height=stem_height, crown_fraction=crown_fractions, ca_ratio=pft_ca_ratio_values, ) From 3eff10038068d93c14ddb07a40599440b45c7e77 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 18 Sep 2024 11:12:31 +0100 Subject: [PATCH 108/241] Add crown gap fraction to PlantFunctionalType classes --- pyrealm/demography/flora.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index c0d76ff8..89a3f1f7 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -54,11 +54,12 @@ class PlantFunctionalTypeStrict: * The foliage maintenance respiration fraction was not explicitly included in :cite:t:`Li:2014bc` - there was assumed to be a 10% penalty on GPP before calculating the other component - but has been explicitly included here. - * This implementation adds two further canopy shape parameters (``m`` and ``n``), - which are then used to calculate two derived attributes (``q_m`` and - ``z_max_ratio``). These are used to define the vertical distribution of leaves - around a stem and follow the implementation developed in the PlantFATE model - :cite:`joshi:2022a`. + * This implementation adds two further canopy shape parameters (``m`` and ``n`` and + ``f_g``). The first two are then used to calculate two constant derived attributes + (``q_m`` and ``z_max_ratio``) that define the vertical distribution of the crown. + The last parameter (``f_g``) is the crown gap fraction, that defines the vertical + distribution of leaves within the crown. This canopy model parameterisation + follows the implementation developed in the PlantFATE model :cite:`joshi:2022a`. See also :class:`~pyrealm.demography.flora.PlantFunctionalType` for the default values implemented in that subclass. @@ -100,6 +101,8 @@ class PlantFunctionalTypeStrict: r"""Canopy shape parameter (:math:`m`, -)""" n: float r"""Canopy shape parameter (:math:`n`, -)""" + f_g: float + r"""Crown gap fraction (:math:`f_g`, -)""" q_m: float = field(init=False) """Scaling factor to derive maximum crown radius from crown area.""" @@ -132,7 +135,8 @@ class PlantFunctionalType(PlantFunctionalTypeStrict): generating plant functional type instances from data. The table below lists the attributes and default values taken from Table 1 of - :cite:t:`Li:2014bc` + :cite:t:`Li:2014bc`, except for ``m``, ``n`` and ``f_g`` which take representative + values from :cite:t:`joshi:2022a`. .. csv-table:: :header: "Attribute", "Default", "Unit" @@ -154,6 +158,7 @@ class PlantFunctionalType(PlantFunctionalTypeStrict): resp_f, 0.1, - m, 2, - n, 5, - + f_g, 0.05, - """ a_hd: float = 116.0 @@ -172,6 +177,7 @@ class PlantFunctionalType(PlantFunctionalTypeStrict): resp_f: float = 0.1 m: float = 2 n: float = 5 + f_g: float = 0.05 PlantFunctionalTypeSchema = marshmallow_dataclass.class_schema( From 1e62bd444a0561c8ee4099e73a259d58fc8107af Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 18 Sep 2024 14:09:52 +0100 Subject: [PATCH 109/241] Testing of projected leaf area --- pyrealm/demography/canopy.py | 21 ++-- .../unit/demography/test_canopy_functions.py | 98 +++++++++++++++++-- 2 files changed, 100 insertions(+), 19 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index c005ec8d..25486506 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -15,7 +15,7 @@ class Canopy: def __init__(self, community: Community, canopy_gap_fraction: float) -> None: # Calculate community wide properties: total crown area and maximum height - self.total_crown_area: float = ( + self.total_community_crown_area: float = ( community.cohort_data["crown_area"] * community.cohort_data["n_individuals"] ).sum() """Total crown area across individuals in the community (metres 2).""" @@ -26,20 +26,24 @@ def __init__(self, community: Community, canopy_gap_fraction: float) -> None: self.crown_area_per_layer: float = community.cell_area * ( 1 - canopy_gap_fraction ) - """Total crown area required to fill a canopy layer, given the canopy gap - fraction.""" + """Total crown area permitted in a single canopy layer, given the available + cell area of the community and its canopy gap fraction.""" self.n_layers: int = int( - np.ceil(self.total_crown_area / self.crown_area_per_layer) + np.ceil(self.total_community_crown_area / self.crown_area_per_layer) ) """Total number of canopy layers needed to contain the total crown area.""" # Find the closure heights of the canopy layers under the perfect plasticity - # approximation. - # Loop over the layers TODO - edge case of completely filled final layer + # approximation by solving Ac(z) - L_n = 0 across the community where L is the + # total cumulative crown area in layer n and above, discounted by the canopy gap + # fraction. + self.layer_closure_heights: NDArray[np.float32] = np.full( (self.n_layers), np.nan ) + + # Loop over the layers TODO - check edge case of completely filled final layer for layer in np.arange(self.n_layers): target_area = (layer + 1) * community.cell_area * (1 - canopy_gap_fraction) @@ -65,8 +69,3 @@ def __init__(self, community: Community, canopy_gap_fraction: float) -> None: # np.full(self.number_of_canopy_layers, canopy_gap_fraction), # np.full(self.number_of_canopy_layers, community), # ) - - # self.gpp = calculate_gpp( - # np.zeros(self.number_of_canopy_layers), - # np.zeros(self.number_of_canopy_layers), - # ) diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index b6bc955f..bca8298d 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -25,8 +25,9 @@ def fixture_community(): from pyrealm.demography.community import Community from pyrealm.demography.flora import Flora, PlantFunctionalType - # A simple community containing one sample stem - flora = Flora([PlantFunctionalType(name="test")]) + # A simple community containing one sample stem, with an initial crown gap fraction + # of zero. + flora = Flora([PlantFunctionalType(name="test", f_g=0)]) return Community( cell_id=1, cell_area=100, @@ -207,11 +208,92 @@ def test_solve_community_projected_canopy_area(fixture_community): assert solved == pytest.approx(0) -def test_calculate_projected_leaf_area_for_individuals(): - """Test happy path for calculating projected leaf area for individuals.""" - pass +def test_calculate_stem_projected_leaf_area_at_z_aligns_with(fixture_community): + """Test calculate_stem_projected_leaf_area_at_z. + This test uses hand calculated values to check predictions, but there are some more + robust theoretical checks about the expectations and crown area. + """ + + from pyrealm.demography.canopy_functions import ( + calculate_stem_projected_leaf_area_at_z, + ) + + # Calculate the leaf areas at the locations of z_max for each stem from the lowest + # to the highest + z_max = fixture_community.cohort_data["canopy_z_max"].to_numpy()[:, None] + + leaf_area_fg0 = calculate_stem_projected_leaf_area_at_z( + z=z_max, + stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), + crown_area=fixture_community.cohort_data["crown_area"].to_numpy(), + z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), + f_g=fixture_community.cohort_data["f_g"].to_numpy(), + m=fixture_community.cohort_data["m"].to_numpy(), + n=fixture_community.cohort_data["n"].to_numpy(), + q_m=fixture_community.cohort_data["q_m"].to_numpy(), + z_m=fixture_community.cohort_data["canopy_z_max"].to_numpy(), + ) + + # Pre-calculated values + expected_leaf_area_fg0 = np.array( + [ + [8.03306419, 22.49502702, 37.60134866, 52.19394627], + [0.0, 22.49502702, 37.60134866, 52.19394627], + [0.0, 9.67422125, 37.60134866, 52.19394627], + [0.0, 1.04248076, 35.02960183, 52.19394627], + ] + ) + + assert np.allclose(leaf_area_fg0, expected_leaf_area_fg0) -def test_calculate_total_canopy_A_cp(): - """Test happy path for calculating total canopy A_cp across a community.""" - pass + # More rigourous check - with f_g = 0, the projected leaf area of each stem in the + # lowest layer must equal the crown area (all the crown is now accounted for). + assert np.allclose( + leaf_area_fg0[0, :], fixture_community.cohort_data["crown_area"].to_numpy() + ) + # Also the diagonal of the resulting matrix (4 heights for 4 cohorts) should _also_ + # match the crown areas as the leaf area is all accounted for exactly at z_max. + assert np.allclose( + np.diag(leaf_area_fg0), fixture_community.cohort_data["crown_area"].to_numpy() + ) + + # Introduce some crown gap fraction and recalculate + fixture_community.cohort_data["f_g"] += 0.02 + + leaf_area_fg002 = calculate_stem_projected_leaf_area_at_z( + z=z_max, + stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), + crown_area=fixture_community.cohort_data["crown_area"].to_numpy(), + z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), + f_g=fixture_community.cohort_data["f_g"].to_numpy(), + m=fixture_community.cohort_data["m"].to_numpy(), + n=fixture_community.cohort_data["n"].to_numpy(), + q_m=fixture_community.cohort_data["q_m"].to_numpy(), + z_m=fixture_community.cohort_data["canopy_z_max"].to_numpy(), + ) + + expected_leaf_area_fg002 = np.array( + [ + [7.8724029, 22.41196859, 37.5384868, 52.12953869], + [0.0, 22.04512648, 37.03818313, 51.55306811], + [0.0, 9.48073683, 36.84932168, 51.20070245], + [0.0, 1.02163115, 34.32900979, 51.15006735], + ] + ) + + assert np.allclose(leaf_area_fg002, expected_leaf_area_fg002) + + # More rigorous checks: + # - All leaf areas with f_g = 0.02 should be lower than with f_g = 0, accounting for + # zeros. TODO - this may change if the functions return np.nan above stem height. + assert np.all( + np.logical_or(np.less(leaf_area_fg002, leaf_area_fg0), leaf_area_fg0 == 0) + ) + + # - The diagonal should be exactly (1 - f_g) times the crown area: at the z_max for + # the stem all but the crown gap fraction should be accounted for + assert np.allclose( + np.diag(leaf_area_fg002), + fixture_community.cohort_data["crown_area"].to_numpy() * 0.98, + ) From 5e294fd35ff00706a2118742dfb1f1f6d585ef2c Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 19 Sep 2024 12:53:18 +0100 Subject: [PATCH 110/241] Added more testing of input shapes, fixing new signature usages --- pyrealm/demography/canopy.py | 29 +- pyrealm/demography/canopy_functions.py | 207 +++++++++---- .../unit/demography/test_canopy_functions.py | 281 ++++++++++++++++-- 3 files changed, 432 insertions(+), 85 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 25486506..6684a4c4 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -5,6 +5,8 @@ from scipy.optimize import root_scalar from pyrealm.demography.canopy_functions import ( + calculate_relative_canopy_radius_at_z, + calculate_stem_projected_crown_area_at_z, solve_community_projected_canopy_area, ) from pyrealm.demography.community import Community @@ -55,13 +57,36 @@ def __init__(self, community: Community, canopy_gap_fraction: float) -> None: community.cohort_data["stem_height"], # stem_height community.cohort_data["m"], # m community.cohort_data["n"], # n - community.cohort_data["q_m"], # q_m - community.cohort_data["q_n"], # z_m + community.cohort_data["canopy_q_m"], # q_m + community.cohort_data["canopy_z_max"], # z_m target_area, # target_area + False, # validate ), bracket=(0, self.max_stem_height), ).root + # Find the stem projected canopy area and relative canopy radius at canopy + # closure heights + self.stem_relative_radius = calculate_relative_canopy_radius_at_z( + z=self.layer_closure_heights[:, None], + stem_height=community.cohort_data["stem_height"].to_numpy(), + m=community.cohort_data["m"].to_numpy(), + n=community.cohort_data["n"].to_numpy(), + validate=False, + ) + + self.stem_crown_area = calculate_stem_projected_crown_area_at_z( + z=self.layer_closure_heights[:, None], + q_z=self.stem_relative_radius, + crown_area=community.cohort_data["crown_area"].to_numpy(), + stem_height=community.cohort_data["stem_height"].to_numpy(), + q_m=community.cohort_data["canopy_q_m"].to_numpy(), + z_max=community.cohort_data["canopy_z_max"].to_numpy(), + validate=False, + ) + + # Find the stem projected leaf area at canopy closure heights. + # # TODO there may be a more efficient solution here that does not use a loop. # self.A_cp_within_layer = map( # calculate_total_canopy_A_cp, diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 6144191f..6cdfd286 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -6,7 +6,7 @@ from numpy.typing import NDArray from pandas import Series -# from pyrealm.demography.community import Community +from pyrealm.core.utilities import check_input_shapes def calculate_canopy_q_m( @@ -98,11 +98,78 @@ def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: return 1 / q_m * np.sqrt(crown_area / np.pi) +def _validate_z_args(z: NDArray[np.float32], *args: NDArray[np.float32]) -> None: + """Shared validation routine for vertical height arguments. + + The canopy functions that take a height argument ``z`` can take a range of input + shapes for ``z``, alongside a set of other row arrays representing cohort + properties. This function is used to check that the cohort properties are of equal + length and that the ``z`` value has one of the accepted shapes described in + :meth:`~pyrealm.demography.canopy_functions.calculate_relative_canopy_radius_at_z`. + + Args: + z: The inputs to the ``z`` argument of a function. + args: Other arrays representing cohort properties. + """ + + if z.size == 1 or z.ndim == 1: + # All same height or stem specific heights - check z is either a scalar or also + # a row vector of the right length. + check_input_shapes(z, *args) + return + elif z.ndim == 2 and z.shape[1] == 1: + # Z is a column vector, just check stem properties. + check_input_shapes(*args) + return + + raise ValueError("Invalid shape for the z value.") + + +def _validate_q_z( + z: NDArray[np.float32], + q_z: NDArray[np.float32], + stem_property: NDArray[np.float32], +) -> None: + """Shared validation routine for relative radius arguments. + + The functions + :meth:`~pyrealm.demography.canopy_functions.calculate_stem_projected_canopy_area_at_z` + and + :meth:`~pyrealm.demography.canopy_functions.calculate_stem_projected_leaf_area_at_z` + both require the arguments ``z`` and ``q_z``, where ``z`` is an array of vertical + heights and ``q_z`` is the relative canopy radius at those heights for a set of + stems. This function checks that the inputs are congruent with each other, and with + the shape of a stem property argument, given the set of expected forms of ``z`` + described in + :meth:`~pyrealm.demography.canopy_functions.calculate_relative_canopy_radius_at_z`. + + + Args: + z: The input to the ``z`` argument. + q_z: The input to the ``q_z`` argument. + stem_property: An argument input representing a stem property. + """ + + if z.size == 1 or z.ndim == 1: + # All same height or stem specific heights - q_z must then also be row vector of + # the same length as the stem propertys and z must be scalar or a row_vector. + check_input_shapes(z, q_z, stem_property) + return + elif z.ndim == 2 and z.shape[1] == 1: + # z is a column array, so check q_z is a matrix + if q_z.shape != (z.size, stem_property.size): + raise ValueError("Invalid shape for q_z.") + return + + raise ValueError("Invalid shape for the z value.") + + def calculate_relative_canopy_radius_at_z( - z: float, + z: NDArray[np.float32], stem_height: NDArray[np.float32], m: NDArray[np.float32], n: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate relative canopy radius at a given height. @@ -115,51 +182,75 @@ def calculate_relative_canopy_radius_at_z( q(z) = m n \left(\dfrac{z}{H}\right) ^ {n -1} \left( 1 - \left(\dfrac{z}{H}\right) ^ n \right)^{m-1} + This function calculates :math:`q(z)` across a set of stems: the ``stem_height``, + ``m`` and ``n`` arguments should be one-dimensional arrays ('row vectors') of equal + length :math:`I`. The value for ``z`` is then an array of heights, with one of the + following shapes: + + 1. A scalar array: :math:`q(z)` is found for all stems at the same height and the + return value is a 1D array of length :math:`I`. + 2. A row vector of length :math:`I`: :math:`q(z)` is found for all stems at + stem-specific heights and the return value is again a 1D array of length + :math:`I`. + 3. A column vector of length :math:`J`, that is a 2 dimensional array of shape + (:math:`J`, 1). This allows :math:`q(z)` to be calculated efficiently for a set + of heights for all stems and return a 2D array of shape (:math:`J`, :math:`I`). + Args: z: Height at which to calculate relative radius stem_height: Total height of individual stem m: Canopy shape parameter of PFT n: Canopy shape parameter of PFT + validate: Boolean flag to suppress argument validation. """ + if validate: + _validate_z_args(z, stem_height, m, n) + z_over_height = z / stem_height return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) -def calculate_stem_projected_canopy_area_at_z( - z: float, +def calculate_stem_projected_crown_area_at_z( + z: NDArray[np.float32], + q_z: NDArray[np.float32], stem_height: NDArray[np.float32], crown_area: NDArray[np.float32], - m: NDArray[np.float32], - n: NDArray[np.float32], q_m: NDArray[np.float32], - z_m: NDArray[np.float32], + z_max: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: """Calculate stem projected crown area above a given height. - This function takes data on stem heights and crown areas, and then uses the canopy - shape parameters associated with each stem to calculate the projected crown area - above a given height $z$. + This function calculates the projected crown area of a set of stems with given + properties at a set of vertical heights. The stem properties are given in the + arguments ``stem_height``,``crown_area``,``q_m`` and ``z_max``, which must be + one-dimensional arrays ('row vectors') of equal length. The array of vertical + heights ``z`` accepts a range of input shapes (see + :meth:`~pyrealm.demography.canopy_functions.calculate_relative_canopy_radius_at_z` + ) and this function then also requires the expected relative stem radius (``q_z``) + calculated from those heights. Args: - z: Vertical height on the z axis. - crown_area: Crown area of each cohort - stem_height: Stem height of each cohort - m: Canopy shape parameter ``m``` for each cohort - n: Canopy shape parameter ``n``` for each cohort - q_m: Canopy shape parameter ``q_m``` for each cohort - z_m: Canopy shape parameter ``z_m``` for each cohort + z: Vertical height at which to estimate crown area + q_z: Relative crown radius at those heights + crown_area: Crown area of each stem + stem_height: Stem height of each stem + q_m: Canopy shape parameter ``q_m``` for each stem + z_max: Height of maximum crown radous for each stem + validate: Boolean flag to suppress argument validation. """ - # Calculate q(z) - q_z = calculate_relative_canopy_radius_at_z(z, stem_height, m, n) + if validate: + _validate_z_args(z, stem_height, crown_area, q_m, z_max) + _validate_q_z(z, q_z, crown_area) # Calculate A_p # Calculate Ap given z > zm A_p = crown_area * (q_z / q_m) ** 2 # Set Ap = Ac where z <= zm - A_p = np.where(z <= z_m, crown_area, A_p) + A_p = np.where(z <= z_max, crown_area, A_p) # Set Ap = 0 where z > H A_p = np.where(z > stem_height, 0, A_p) @@ -173,9 +264,10 @@ def solve_community_projected_canopy_area( m: NDArray[np.float32], n: NDArray[np.float32], q_m: NDArray[np.float32], - z_m: NDArray[np.float32], + z_max: NDArray[np.float32], n_individuals: NDArray[np.float32], target_area: float = 0, + validate: bool = True, ) -> NDArray[np.float32]: """Solver function for community wide projected crown area. @@ -204,69 +296,80 @@ def solve_community_projected_canopy_area( m: Canopy shape parameter ``m``` for each cohort n: Canopy shape parameter ``n``` for each cohort q_m: Canopy shape parameter ``q_m``` for each cohort - z_m: Canopy shape parameter ``z_m``` for each cohort + z_max: Canopy shape parameter ``z_m``` for each cohort target_area: A target projected crown area. + validate: Boolean flag to suppress argument validation. """ + # Convert z to array for validation and typing + z_arr = np.array(z) + + if validate: + _validate_z_args( + z_arr, n_individuals, crown_area, stem_height, m, n, q_m, z_max + ) + q_z = calculate_relative_canopy_radius_at_z( + z=z_arr, stem_height=stem_height, m=m, n=n, validate=False + ) # Calculate A(p) for the stems in each cohort - A_p = calculate_stem_projected_canopy_area_at_z( - z=z, + A_p = calculate_stem_projected_crown_area_at_z( + z=z_arr, + q_z=q_z, stem_height=stem_height, crown_area=crown_area, - m=m, - n=n, q_m=q_m, - z_m=z_m, + z_max=z_max, + validate=False, ) return (A_p * n_individuals).sum() - target_area def calculate_stem_projected_leaf_area_at_z( - z: float | NDArray[np.float32], + z: NDArray[np.float32], + q_z: NDArray[np.float32], stem_height: NDArray[np.float32], crown_area: NDArray[np.float32], - z_max: NDArray[np.float32], f_g: NDArray[np.float32], - m: NDArray[np.float32], - n: NDArray[np.float32], q_m: NDArray[np.float32], - z_m: NDArray[np.float32], + z_max: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: """Calculate projected leaf area above a given height. - Calculation applies to an individual within a cohort.This function takes PFT - specific parameters (shape parameters) and stem specific sizes and estimates - the projected crown area above a given height $z$. The inputs can either be - scalars describing a single stem or arrays representing a community of stems. - If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can be - scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that - PFT. + This function calculates the projected leaf area of a set of stems with given + properties at a set of vertical heights. This differs from crown area in allowing + for crown openness within the crown of an individual stem that results in the + displacement of leaf area further down into the canopy. The degree of openness is + controlled by the crown gap fraction property of each stem. + + The stem properties are given in the arguments + ``stem_height``,``crown_area``,``f_g``,``q_m`` and ``z_max``, which must be + one-dimensional arrays ('row vectors') of equal length. The array of vertical + heights ``z`` accepts a range of input shapes (see + :meth:`~pyrealm.demography.canopy_functions.calculate_relative_canopy_radius_at_z` + ) and this function then also requires the expected relative stem radius (``q_z``) + calculated from those heights. Args: - z: Vertical height on the z axis. + z: Vertical heights on the z axis. + q_z: Relative crown radius at heights in z. crown_area: Crown area for a stem stem_height: Total height of a stem - z_max: Height of maximum canopy radius for each stem f_g: Within crown gap fraction for each stem. - m: Canopy shape parameter ``m``` for each stem - n: Canopy shape parameter ``n``` for each stem q_m: Canopy shape parameter ``q_m``` for each stem - z_m: Canopy shape parameter ``z_m``` for each stem + z_max: Height of maximum canopy radius for each stem + validate: Boolean flag to suppress argument validation. """ - # Calculate q(z) - q_z = calculate_relative_canopy_radius_at_z( - z=z, - stem_height=stem_height, - m=m, - n=n, - ) + if validate: + _validate_z_args(z, crown_area, stem_height, f_g, q_m, z_max) + _validate_q_z(z, q_z, crown_area) # Calculate Ac terms A_c_terms = crown_area * (q_z / q_m) ** 2 - # Set Acp either side of zm + # Set Acp either side of z_max A_cp = np.where( z <= z_max, crown_area - A_c_terms * f_g, diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index bca8298d..b3a6bff9 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -1,5 +1,7 @@ """test the functions in canopy_functions.py.""" +from contextlib import nullcontext as does_not_raise + import numpy as np import pytest @@ -81,8 +83,146 @@ def test_calculate_r_0_values(fixture_canopy_shape, crown_areas, expected_r0): assert np.allclose(actual_r0_values, expected_r0) -def test_calculate_relative_canopy_radius_at_z(fixture_community): - """Test crown radius height prediction. +@pytest.fixture +def fixture_z_qz_stem_properties(request): + """Fixture providing test cases of z, q_z and stem properties . + + This fixture allows tests to use indirect parameterisation to share a set of test + cases of inputs for the z, stem properties and q_z arguments. In each case, the + returned value is a tuple of arrays that just provide the correct shapes for the + various test cases: + + * an input value for z + * a first stem property row array + * a list giving another stem property array + * an array with the shape of the resulting q_z value from the above or None if those + inputs are invalid for calculating q_z + + The two stem property arrays allow the number of properties to be controlled at the + test level (differing number of args for different functions) but also to introduce + inconsistent property lengths. To package these up for use with, for example a total + of 3 stem properties: + + .. code:: python + + z, arg1, args, q_z = fixture_z_qz_stem_properties + stem_args = [arg1, * args * 2] + + """ + + match request.param: + case "0D_z_ok": + return (np.array(1), np.ones(4), [np.ones(4)], np.ones(4)) + case "1D_scalar_z_ok": + return (np.ones(1), np.ones(4), [np.ones(4)], np.ones(4)) + case "1D_row_z_ok": + return (np.ones(4), np.ones(4), [np.ones(4)], np.ones(4)) + case "2D_column_z_ok": + return (np.ones((4, 1)), np.ones(4), [np.ones(4)], np.ones((4, 4))) + case "1D_row_z_wrong_length": + return (np.ones(5), np.ones(4), [np.ones(4)], None) + case "2D_z_not_column": + return (np.ones((4, 2)), np.ones(4), [np.ones(4)], None) + case "inconsistent_stem_properties": + return (np.ones(4), np.ones(5), [np.ones(4)], None) + case "1D_q_z_inconsistent": + return (np.ones(4), np.ones(4), [np.ones(4)], np.ones(5)) + case "2D_q_z_inconsistent": + return (np.ones(4), np.ones(4), [np.ones(4)], np.ones((5, 4))) + + +@pytest.mark.parametrize( + argnames="fixture_z_qz_stem_properties, outcome", + argvalues=[ + ("0D_z_ok", does_not_raise()), + ("1D_scalar_z_ok", does_not_raise()), + ("1D_row_z_ok", does_not_raise()), + ("2D_column_z_ok", does_not_raise()), + ("1D_row_z_wrong_length", pytest.raises(ValueError)), + ("2D_z_not_column", pytest.raises(ValueError)), + ("inconsistent_stem_properties", pytest.raises(ValueError)), + ], + indirect=["fixture_z_qz_stem_properties"], +) +def test__validate_z_args(fixture_z_qz_stem_properties, outcome): + """Tests the validation of z args to canopy functions.""" + + from pyrealm.demography.canopy_functions import _validate_z_args + + # Build inputs + z, arg1, args, _ = fixture_z_qz_stem_properties + stem_args = [arg1, *args * 2] # length of args doesn't really matter here. + + with outcome: + _validate_z_args(z, *stem_args) + + +@pytest.mark.parametrize( + argnames="fixture_z_qz_stem_properties, outcome", + argvalues=[ + ("0D_z_ok", does_not_raise()), + ("1D_scalar_z_ok", does_not_raise()), + ("1D_row_z_ok", does_not_raise()), + ("2D_column_z_ok", does_not_raise()), + ("1D_row_z_wrong_length", pytest.raises(ValueError)), + ("2D_z_not_column", pytest.raises(ValueError)), + ("inconsistent_stem_properties", pytest.raises(ValueError)), + ("1D_q_z_inconsistent", pytest.raises(ValueError)), + ("2D_q_z_inconsistent", pytest.raises(ValueError)), + ], + indirect=["fixture_z_qz_stem_properties"], +) +def test__validate_q_z_args(fixture_z_qz_stem_properties, outcome): + """Tests the validation of z args to canopy functions.""" + + from pyrealm.demography.canopy_functions import _validate_q_z + + # Build inputs + z, stem_property, _, q_z = fixture_z_qz_stem_properties + + with outcome: + _validate_q_z(z, q_z, stem_property) + + +@pytest.mark.parametrize( + argnames="fixture_z_qz_stem_properties, outcome", + argvalues=[ + ("0D_z_ok", does_not_raise()), + ("1D_scalar_z_ok", does_not_raise()), + ("1D_row_z_ok", does_not_raise()), + ("2D_column_z_ok", does_not_raise()), + ("1D_row_z_wrong_length", pytest.raises(ValueError)), + ("2D_z_not_column", pytest.raises(ValueError)), + ("inconsistent_stem_properties", pytest.raises(ValueError)), + ], + indirect=["fixture_z_qz_stem_properties"], +) +def test_calculate_relative_canopy_radius_at_z_inputs( + fixture_z_qz_stem_properties, outcome +): + """Test calculate_relative_canopy_radius_at_z input and output shapes . + + This test checks the function behaviour with different inputs. + """ + + from pyrealm.demography.canopy_functions import ( + calculate_relative_canopy_radius_at_z, + ) + + # Build inputs + z, arg1, args, q_z = fixture_z_qz_stem_properties + stem_args = [arg1, *args * 2] # Need 3 stem arguments. + + with outcome: + # Get the relative radius at that height + q_z_values = calculate_relative_canopy_radius_at_z(z, *stem_args) + + if isinstance(outcome, does_not_raise): + assert q_z_values.shape == q_z.shape + + +def test_calculate_relative_canopy_radius_at_z_values(fixture_community): + """Test calculate_relative_canopy_radius_at_z. This test validates the expectation that the canopy shape model correctly predicts the crown area from the T Model equations at the predicted height of @@ -97,14 +237,14 @@ def test_calculate_relative_canopy_radius_at_z(fixture_community): z_max = ( fixture_community.cohort_data["stem_height"] * fixture_community.cohort_data["z_max_prop"] - ) + ).to_numpy() # Get the relative radius at that height q_z_values = calculate_relative_canopy_radius_at_z( z=z_max, - stem_height=fixture_community.cohort_data["stem_height"], - m=fixture_community.cohort_data["m"], - n=fixture_community.cohort_data["n"], + stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), + m=fixture_community.cohort_data["m"].to_numpy(), + n=fixture_community.cohort_data["n"].to_numpy(), ) # Now test that the circular crown area from that radius is equivalent to the direct @@ -115,6 +255,39 @@ def test_calculate_relative_canopy_radius_at_z(fixture_community): ) +@pytest.mark.parametrize( + argnames="fixture_z_qz_stem_properties, outcome", + argvalues=[ + ("0D_z_ok", does_not_raise()), + ("1D_scalar_z_ok", does_not_raise()), + ("1D_row_z_ok", does_not_raise()), + ("2D_column_z_ok", does_not_raise()), + ("1D_row_z_wrong_length", pytest.raises(ValueError)), + ("2D_z_not_column", pytest.raises(ValueError)), + ("inconsistent_stem_properties", pytest.raises(ValueError)), + ("1D_q_z_inconsistent", pytest.raises(ValueError)), + ("2D_q_z_inconsistent", pytest.raises(ValueError)), + ], + indirect=["fixture_z_qz_stem_properties"], +) +def test_calculate_stem_projected_crown_area_at_z_inputs( + fixture_z_qz_stem_properties, outcome +): + """Tests the validation of inputs to calculate_stem_projected_crown_area_at_z.""" + from pyrealm.demography.canopy_functions import ( + calculate_stem_projected_crown_area_at_z, + ) + + # Build inputs + z, arg1, args, q_z = fixture_z_qz_stem_properties + stem_args = [arg1, *args * 3] # Need 4 stem arguments. + with outcome: + Ap_z_values = calculate_stem_projected_crown_area_at_z(z, q_z, *stem_args) + + if isinstance(outcome, does_not_raise): + assert Ap_z_values.shape == q_z.shape + + @pytest.mark.parametrize( argnames="heights,expected_Ap_z", argvalues=[ @@ -140,7 +313,7 @@ def test_calculate_relative_canopy_radius_at_z(fixture_community): ), ], ) -def test_calculate_stem_projected_canopy_area_at_z( +def test_calculate_stem_projected_crown_area_at_z_values( fixture_community, heights, expected_Ap_z ): """Test calculate_stem_projected_canopy_area_at_z. @@ -153,17 +326,26 @@ def test_calculate_stem_projected_canopy_area_at_z( """ from pyrealm.demography.canopy_functions import ( - calculate_stem_projected_canopy_area_at_z, + calculate_relative_canopy_radius_at_z, + calculate_stem_projected_crown_area_at_z, ) - Ap_z_values = calculate_stem_projected_canopy_area_at_z( + # Calculate the required q_z + q_z = calculate_relative_canopy_radius_at_z( z=heights, - stem_height=fixture_community.cohort_data["stem_height"], - crown_area=fixture_community.cohort_data["crown_area"], - m=fixture_community.cohort_data["m"], - n=fixture_community.cohort_data["n"], - q_m=fixture_community.cohort_data["q_m"], - z_m=fixture_community.cohort_data["canopy_z_max"], + stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), + m=fixture_community.cohort_data["m"].to_numpy(), + n=fixture_community.cohort_data["n"].to_numpy(), + ) + + # Calculate and test these values + Ap_z_values = calculate_stem_projected_crown_area_at_z( + z=heights, + q_z=q_z, + stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), + crown_area=fixture_community.cohort_data["crown_area"].to_numpy(), + q_m=fixture_community.cohort_data["q_m"].to_numpy(), + z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), ) assert np.allclose( @@ -195,20 +377,53 @@ def test_solve_community_projected_canopy_area(fixture_community): ): solved = solve_community_projected_canopy_area( z=this_height, - stem_height=fixture_community.cohort_data["stem_height"], - crown_area=fixture_community.cohort_data["crown_area"], - n_individuals=fixture_community.cohort_data["n_individuals"], - m=fixture_community.cohort_data["m"], - n=fixture_community.cohort_data["n"], - q_m=fixture_community.cohort_data["q_m"], - z_m=fixture_community.cohort_data["canopy_z_max"], + stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), + crown_area=fixture_community.cohort_data["crown_area"].to_numpy(), + n_individuals=fixture_community.cohort_data["n_individuals"].to_numpy(), + m=fixture_community.cohort_data["m"].to_numpy(), + n=fixture_community.cohort_data["n"].to_numpy(), + q_m=fixture_community.cohort_data["q_m"].to_numpy(), + z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), target_area=this_target, ) assert solved == pytest.approx(0) -def test_calculate_stem_projected_leaf_area_at_z_aligns_with(fixture_community): +@pytest.mark.parametrize( + argnames="fixture_z_qz_stem_properties, outcome", + argvalues=[ + ("0D_z_ok", does_not_raise()), + ("1D_scalar_z_ok", does_not_raise()), + ("1D_row_z_ok", does_not_raise()), + ("2D_column_z_ok", does_not_raise()), + ("1D_row_z_wrong_length", pytest.raises(ValueError)), + ("2D_z_not_column", pytest.raises(ValueError)), + ("inconsistent_stem_properties", pytest.raises(ValueError)), + ("1D_q_z_inconsistent", pytest.raises(ValueError)), + ("2D_q_z_inconsistent", pytest.raises(ValueError)), + ], + indirect=["fixture_z_qz_stem_properties"], +) +def test_calculate_stem_projected_leaf_area_at_z_inputs( + fixture_z_qz_stem_properties, outcome +): + """Tests the validation of inputs to calculate_stem_projected_crown_area_at_z.""" + from pyrealm.demography.canopy_functions import ( + calculate_stem_projected_leaf_area_at_z, + ) + + # Build inputs + z, arg1, args, q_z = fixture_z_qz_stem_properties + stem_args = [arg1, *args * 4] # Need 5 stem arguments. + with outcome: + Ap_z_values = calculate_stem_projected_leaf_area_at_z(z, q_z, *stem_args) + + if isinstance(outcome, does_not_raise): + assert Ap_z_values.shape == q_z.shape + + +def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): """Test calculate_stem_projected_leaf_area_at_z. This test uses hand calculated values to check predictions, but there are some more @@ -216,6 +431,7 @@ def test_calculate_stem_projected_leaf_area_at_z_aligns_with(fixture_community): """ from pyrealm.demography.canopy_functions import ( + calculate_relative_canopy_radius_at_z, calculate_stem_projected_leaf_area_at_z, ) @@ -223,16 +439,21 @@ def test_calculate_stem_projected_leaf_area_at_z_aligns_with(fixture_community): # to the highest z_max = fixture_community.cohort_data["canopy_z_max"].to_numpy()[:, None] + q_z = calculate_relative_canopy_radius_at_z( + z=z_max, + stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), + m=fixture_community.cohort_data["m"].to_numpy(), + n=fixture_community.cohort_data["n"].to_numpy(), + ) + leaf_area_fg0 = calculate_stem_projected_leaf_area_at_z( z=z_max, + q_z=q_z, stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), crown_area=fixture_community.cohort_data["crown_area"].to_numpy(), - z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), f_g=fixture_community.cohort_data["f_g"].to_numpy(), - m=fixture_community.cohort_data["m"].to_numpy(), - n=fixture_community.cohort_data["n"].to_numpy(), q_m=fixture_community.cohort_data["q_m"].to_numpy(), - z_m=fixture_community.cohort_data["canopy_z_max"].to_numpy(), + z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), ) # Pre-calculated values @@ -263,14 +484,12 @@ def test_calculate_stem_projected_leaf_area_at_z_aligns_with(fixture_community): leaf_area_fg002 = calculate_stem_projected_leaf_area_at_z( z=z_max, + q_z=q_z, stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), crown_area=fixture_community.cohort_data["crown_area"].to_numpy(), - z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), f_g=fixture_community.cohort_data["f_g"].to_numpy(), - m=fixture_community.cohort_data["m"].to_numpy(), - n=fixture_community.cohort_data["n"].to_numpy(), q_m=fixture_community.cohort_data["q_m"].to_numpy(), - z_m=fixture_community.cohort_data["canopy_z_max"].to_numpy(), + z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), ) expected_leaf_area_fg002 = np.array( From d4f24261941be7c35b41a0541e50114ec17ba711 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 19 Sep 2024 14:41:28 +0100 Subject: [PATCH 111/241] Fixed missing new f_g trait in test_flora inputs --- pyrealm/demography/canopy.py | 127 ++++++++++++++++--------- pyrealm/demography/canopy_functions.py | 3 + pyrealm_build_data/community/pfts.csv | 6 +- pyrealm_build_data/community/pfts.json | 83 ++++++++-------- pyrealm_build_data/community/pfts.toml | 10 +- tests/unit/demography/test_canopy.py | 45 ++++++++- tests/unit/demography/test_flora.py | 1 + 7 files changed, 180 insertions(+), 95 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 6684a4c4..e7b4752a 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -7,15 +7,26 @@ from pyrealm.demography.canopy_functions import ( calculate_relative_canopy_radius_at_z, calculate_stem_projected_crown_area_at_z, + calculate_stem_projected_leaf_area_at_z, solve_community_projected_canopy_area, ) from pyrealm.demography.community import Community class Canopy: - """A class containing attributes of a canopy, including the structure.""" - - def __init__(self, community: Community, canopy_gap_fraction: float) -> None: + """A class containing attributes of a canopy, including the structure. + + at which canopy layers close. This also includes + ground level, which will capture all remaning crown and leaf area below the last + closed layer. + """ + + def __init__( + self, + community: Community, + canopy_gap_fraction: float, + layer_tolerance: float = 0.001, + ) -> None: # Calculate community wide properties: total crown area and maximum height self.total_community_crown_area: float = ( community.cohort_data["crown_area"] * community.cohort_data["n_individuals"] @@ -34,63 +45,89 @@ def __init__(self, community: Community, canopy_gap_fraction: float) -> None: self.n_layers: int = int( np.ceil(self.total_community_crown_area / self.crown_area_per_layer) ) - """Total number of canopy layers needed to contain the total crown area.""" + """Total number of canopy layers.""" + + self.n_cohorts: int = community.number_of_cohorts + """Total number of cohorts in the canopy.""" # Find the closure heights of the canopy layers under the perfect plasticity # approximation by solving Ac(z) - L_n = 0 across the community where L is the # total cumulative crown area in layer n and above, discounted by the canopy gap # fraction. - self.layer_closure_heights: NDArray[np.float32] = np.full( - (self.n_layers), np.nan + self.layer_heights: NDArray[np.float32] = np.zeros( + (self.n_layers, 1), dtype=np.float32 ) + """Column vector of the heights of canopy layers.""" - # Loop over the layers TODO - check edge case of completely filled final layer - for layer in np.arange(self.n_layers): + # Loop over the layers except for the final layer, which will be the partial + # remaining vegetation below the last closed layer. + starting_guess = self.max_stem_height + for layer in np.arange(self.n_layers - 1): target_area = (layer + 1) * community.cell_area * (1 - canopy_gap_fraction) - self.layer_closure_heights[layer] = root_scalar( + # TODO - the solution here is predictably closer to the upper bracket, might + # be a better algorithm to find the root. + solution = root_scalar( solve_community_projected_canopy_area, args=( - community.cohort_data["n_individuals"], # n_individuals - community.cohort_data["crown_area"], # crown_area - community.cohort_data["stem_height"], # stem_height - community.cohort_data["m"], # m - community.cohort_data["n"], # n - community.cohort_data["canopy_q_m"], # q_m - community.cohort_data["canopy_z_max"], # z_m - target_area, # target_area + community.cohort_data["stem_height"].to_numpy(), + community.cohort_data["crown_area"].to_numpy(), + community.cohort_data["m"].to_numpy(), + community.cohort_data["n"].to_numpy(), + community.cohort_data["q_m"].to_numpy(), + community.cohort_data["canopy_z_max"].to_numpy(), + community.cohort_data["n_individuals"].to_numpy(), + target_area, False, # validate ), - bracket=(0, self.max_stem_height), - ).root - - # Find the stem projected canopy area and relative canopy radius at canopy - # closure heights - self.stem_relative_radius = calculate_relative_canopy_radius_at_z( - z=self.layer_closure_heights[:, None], - stem_height=community.cohort_data["stem_height"].to_numpy(), - m=community.cohort_data["m"].to_numpy(), - n=community.cohort_data["n"].to_numpy(), - validate=False, + bracket=(0, starting_guess), + xtol=layer_tolerance, + ) + + if not solution.converged: + raise RuntimeError( + "Estimation of canopy layer closure heights failed to converge." + ) + + self.layer_heights[layer] = starting_guess = solution.root + + # Find relative canopy radius at the layer heights + self.stem_relative_radius: NDArray[np.float32] = ( + calculate_relative_canopy_radius_at_z( + z=self.layer_heights, + stem_height=community.cohort_data["stem_height"].to_numpy(), + m=community.cohort_data["m"].to_numpy(), + n=community.cohort_data["n"].to_numpy(), + validate=False, + ) ) - - self.stem_crown_area = calculate_stem_projected_crown_area_at_z( - z=self.layer_closure_heights[:, None], - q_z=self.stem_relative_radius, - crown_area=community.cohort_data["crown_area"].to_numpy(), - stem_height=community.cohort_data["stem_height"].to_numpy(), - q_m=community.cohort_data["canopy_q_m"].to_numpy(), - z_max=community.cohort_data["canopy_z_max"].to_numpy(), - validate=False, + """Relative radius values of stems at canopy layer heights.""" + + self.stem_crown_area: NDArray[np.float32] = ( + calculate_stem_projected_crown_area_at_z( + z=self.layer_heights, + q_z=self.stem_relative_radius, + crown_area=community.cohort_data["crown_area"].to_numpy(), + stem_height=community.cohort_data["stem_height"].to_numpy(), + q_m=community.cohort_data["q_m"].to_numpy(), + z_max=community.cohort_data["canopy_z_max"].to_numpy(), + validate=False, + ) ) + """Stem projected crown area at canopy layer heights.""" # Find the stem projected leaf area at canopy closure heights. - - # # TODO there may be a more efficient solution here that does not use a loop. - # self.A_cp_within_layer = map( - # calculate_total_canopy_A_cp, - # self.canopy_layer_heights, - # np.full(self.number_of_canopy_layers, canopy_gap_fraction), - # np.full(self.number_of_canopy_layers, community), - # ) + self.stem_leaf_area: NDArray[np.float32] = ( + calculate_stem_projected_leaf_area_at_z( + z=self.layer_heights, + q_z=self.stem_relative_radius, + crown_area=community.cohort_data["crown_area"].to_numpy(), + stem_height=community.cohort_data["stem_height"].to_numpy(), + f_g=community.cohort_data["f_g"].to_numpy(), + q_m=community.cohort_data["q_m"].to_numpy(), + z_max=community.cohort_data["canopy_z_max"].to_numpy(), + validate=False, + ) + ) + """Stem projected leaf area at canopy layer heights.""" diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 6cdfd286..79312bbe 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -362,6 +362,9 @@ def calculate_stem_projected_leaf_area_at_z( validate: Boolean flag to suppress argument validation. """ + # TODO - could this merge with the stem crown area function? A lot of overlap, so + # could be much more efficient to return both from one function. + if validate: _validate_z_args(z, crown_area, stem_height, f_g, q_m, z_max) _validate_q_z(z, q_z, crown_area) diff --git a/pyrealm_build_data/community/pfts.csv b/pyrealm_build_data/community/pfts.csv index 1f0c0aab..648fcae6 100644 --- a/pyrealm_build_data/community/pfts.csv +++ b/pyrealm_build_data/community/pfts.csv @@ -1,3 +1,3 @@ -name,a_hd,ca_ratio,h_max,lai,par_ext,resp_f,resp_r,resp_s,rho_s,sla,tau_f,tau_r,yld,zeta,m,n -test1,116.0,390.43,25.33,1.8,0.5,0.1,0.913,0.044,200.0,14.0,4.0,1.04,0.17,0.17,2,5 -test2,116.0,390.43,15.33,1.8,0.5,0.1,0.913,0.044,200.0,14.0,4.0,1.04,0.17,0.17,2,5 \ No newline at end of file +name,a_hd,ca_ratio,h_max,lai,par_ext,resp_f,resp_r,resp_s,rho_s,sla,tau_f,tau_r,yld,zeta,f_g,m,n +test1,116.0,390.43,25.33,1.8,0.5,0.1,0.913,0.044,200.0,14.0,4.0,1.04,0.17,0.17,0.02,2,5 +test2,116.0,390.43,15.33,1.8,0.5,0.1,0.913,0.044,200.0,14.0,4.0,1.04,0.17,0.17,0.02,2,5 \ No newline at end of file diff --git a/pyrealm_build_data/community/pfts.json b/pyrealm_build_data/community/pfts.json index 5cafa9d2..a6860578 100644 --- a/pyrealm_build_data/community/pfts.json +++ b/pyrealm_build_data/community/pfts.json @@ -1,41 +1,44 @@ -{"pft": [ - { - "name": "test1", - "a_hd": 116.0, - "ca_ratio": 390.43, - "h_max": 25.33, - "lai": 1.8, - "par_ext": 0.5, - "resp_f": 0.1, - "resp_r": 0.913, - "resp_s": 0.044, - "rho_s": 200.0, - "sla": 14.0, - "tau_f": 4.0, - "tau_r": 1.04, - "yld": 0.17, - "zeta": 0.17, - "m": 2, - "n": 5 - }, - { - "name": "test2", - "a_hd": 116.0, - "ca_ratio": 390.43, - "h_max": 15.33, - "lai": 1.8, - "par_ext": 0.5, - "resp_f": 0.1, - "resp_r": 0.913, - "resp_s": 0.044, - "rho_s": 200.0, - "sla": 14.0, - "tau_f": 4.0, - "tau_r": 1.04, - "yld": 0.17, - "zeta": 0.17, - "m": 2, - "n": 5 - } -] +{ + "pft": [ + { + "name": "test1", + "a_hd": 116.0, + "ca_ratio": 390.43, + "h_max": 25.33, + "lai": 1.8, + "par_ext": 0.5, + "resp_f": 0.1, + "resp_r": 0.913, + "resp_s": 0.044, + "rho_s": 200.0, + "sla": 14.0, + "tau_f": 4.0, + "tau_r": 1.04, + "yld": 0.17, + "zeta": 0.17, + "f_g": 0.02, + "m": 2, + "n": 5 + }, + { + "name": "test2", + "a_hd": 116.0, + "ca_ratio": 390.43, + "h_max": 15.33, + "lai": 1.8, + "par_ext": 0.5, + "resp_f": 0.1, + "resp_r": 0.913, + "resp_s": 0.044, + "rho_s": 200.0, + "sla": 14.0, + "tau_f": 4.0, + "tau_r": 1.04, + "yld": 0.17, + "zeta": 0.17, + "f_g": 0.02, + "m": 2, + "n": 5 + } + ] } \ No newline at end of file diff --git a/pyrealm_build_data/community/pfts.toml b/pyrealm_build_data/community/pfts.toml index 4e31c832..c2f18f91 100644 --- a/pyrealm_build_data/community/pfts.toml +++ b/pyrealm_build_data/community/pfts.toml @@ -1,8 +1,11 @@ [[pft]] a_hd = 116.0 ca_ratio = 390.43 +f_g = 0.02 h_max = 25.33 lai = 1.8 +m = 2 +n = 5 name = 'test1' par_ext = 0.5 resp_f = 0.1 @@ -14,14 +17,15 @@ tau_f = 4.0 tau_r = 1.04 yld = 0.17 zeta = 0.17 -m = 2 -n = 5 [[pft]] a_hd = 116.0 ca_ratio = 390.43 +f_g = 0.02 h_max = 15.33 lai = 1.8 +m = 2 +n = 5 name = 'test2' par_ext = 0.5 resp_f = 0.1 @@ -33,5 +37,3 @@ tau_f = 4.0 tau_r = 1.04 yld = 0.17 zeta = 0.17 -m = 2 -n = 5 diff --git a/tests/unit/demography/test_canopy.py b/tests/unit/demography/test_canopy.py index 06a78307..c937c8eb 100644 --- a/tests/unit/demography/test_canopy.py +++ b/tests/unit/demography/test_canopy.py @@ -1,10 +1,49 @@ -"""test the canopy object in canopy.py initialises as expected.""" +"""Testing the Canopy object.""" +import numpy as np -def test_initialisation(): + +def test_Canopy__init__(): """Test happy path for initialisation. test that when a new canopy object is instantiated, it contains the expected properties. """ - pass + + from pyrealm.demography.canopy import Canopy + from pyrealm.demography.community import Community + from pyrealm.demography.flora import Flora, PlantFunctionalType + + flora = Flora( + [ + PlantFunctionalType(name="broadleaf", h_max=30), + PlantFunctionalType(name="conifer", h_max=20), + ] + ) + + community = Community( + cell_id=1, + cell_area=20, + cohort_pft_names=np.array(["broadleaf", "conifer"]), + cohort_n_individuals=np.array([6, 1]), + cohort_dbh_values=np.array([0.2, 0.5]), + flora=flora, + ) + + canopy_gap_fraction = 0.05 + canopy = Canopy(community, canopy_gap_fraction=canopy_gap_fraction) + + # Simply check that the shape of the stem leaf area matrix is the right shape + n_layers_from_crown_area = int( + np.ceil( + ( + ( + community.cohort_data["crown_area"] + * community.cohort_data["n_individuals"] + ).sum() + * (1 + canopy_gap_fraction) + ) + / community.cell_area + ) + ) + assert canopy.stem_leaf_area.shape == (n_layers_from_crown_area, canopy.n_cohorts) diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index ad975788..00fa574f 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -33,6 +33,7 @@ tau_r=1.04, yld=0.17, zeta=0.17, + f_g=0.02, m=2, n=5, ) From 663aac606feb0b9790f901b66bda2e104a2762f7 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 20 Sep 2024 22:23:19 +0100 Subject: [PATCH 112/241] Initial sketch of flora.get_allometries --- pyrealm/demography/flora.py | 47 +++++++++++++++++++ pyrealm/demography/t_model_functions.py | 30 ++++++++++++ .../unit/demography/test_t_model_functions.py | 29 ++++++++++++ 3 files changed, 106 insertions(+) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 57b72100..c18fcc8f 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -28,10 +28,12 @@ import numpy as np import pandas as pd from marshmallow.exceptions import ValidationError +from numpy.typing import NDArray from pyrealm.demography.t_model_functions import ( calculate_canopy_q_m, calculate_canopy_z_max_proportion, + calculate_dbh_from_height, ) if sys.version_info[:2] >= (3, 11): @@ -302,3 +304,48 @@ def from_csv(cls, path: Path) -> Flora: raise excep return cls._from_file_data({"pft": data.to_dict(orient="records")}) + + def get_allometries( + self, dbh: NDArray[np.float32] | None, stem_height: NDArray[np.float32] | None + ) -> dict[str, NDArray]: + """Populates the T Model allometry from the initial size data.""" + + # Need exclusively one of dbh or stem_height - use XOR + if not ((dbh is None) ^ (stem_height is None)): + raise ValueError("Provide one of either dbh or stem_height") + + # Convert pft data to dict of numpy arrays - TODO: this may become redundant if + # self.data adopts the dict of arrays format + pft_data: dict[str, NDArray] = { + k: v.to_numpy() for k, v in self.data.to_dict(orient="series").items() + } + + # Convert stem height to DBH for the plant functional type + if stem_height is not None: + self.dbh = calculate_dbh_from_height( + h_max=pft_data["h_max"], a_hd=pft_data["h_max"], stem_height=stem_height + ) + + return {} + + +# @dataclass +# class PFTAllometry: +# """TODO.""" + +# pft: type[PlantFunctionalTypeStrict] +# dbh: NDArray[np.float32] | None +# stem_height: NDArray[np.float32] | None +# data: dict[str, NDArray[np.float32]] = field(init=False) + +# def __post_init__(self) -> None: +# """Populates the T Model allometry from the initial size data.""" +# # Need one of dbh or stem_height - use XOR +# if not ((self.dbh is None) ^ (self.stem_height is None)): +# raise ValueError("Provide one of either dbh or stem_height") + +# # Convert stem height to DBH for the plant functional type +# if self.stem_height is not None: +# self.dbh = calculate_dbh_from_height( +# h_max=self.pft.h_max, a_hd=self.pft.a_hd, stem_height=self.stem_height +# ) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 1960f08e..14ce54e9 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -30,6 +30,36 @@ def calculate_heights(h_max: Series, a_hd: Series, dbh: Series) -> Series: return h_max * (1 - np.exp(-a_hd * dbh / h_max)) +def calculate_dbh_from_height( + h_max: Series, a_hd: Series, stem_height: Series +) -> Series: + r"""Calculate diameter at breast height from stem height under the T Model. + + This function inverts the normal calculation of stem height (:math:`H`) from + diameter at breast height (:math:`D`) in the T Model (see + :meth:`~pyrealm.demography.t_model_functions.calculate_heights`). This is a helper + function to allow users to convert known stem heights for a plant functional type, + with maximum height (:math:`H_{m}`) and initial slope of the height/diameter + relationship (:math:`a`) into the expected :math:`D` values. + + .. math:: + + D = \frac{H \left( \log \left(\frac{H}{H_{m}-H}\right)\right)}{a} + + Args: + h_max: Maximum height of the PFT + a_hd: Initial slope of the height/diameter relationship of the PFT + stem_height: Stem height of individuals + """ + + if np.any(stem_height > h_max): + raise ValueError( + "Stem height values must not be greater than maximum stem height" + ) + + return (h_max * np.log(h_max / (h_max - stem_height))) / a_hd + + def calculate_crown_areas( ca_ratio: Series, a_hd: Series, dbh: Series, height: Series ) -> Series: diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 26c9523c..21f51c76 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -1,6 +1,9 @@ """test the functions in t_model_functions.py.""" +from contextlib import nullcontext as does_not_raise + import numpy as np +import pytest from numpy.testing import assert_array_almost_equal from pyrealm.demography.t_model_functions import ( @@ -28,6 +31,32 @@ def test_calculate_heights(): assert_array_almost_equal(actual_heights, expected_heights, decimal=8) +@pytest.mark.parametrize( + argnames="stem_heights,outcome,expected_dbh", + argvalues=[ + (np.array([15.19414157, 15.16639589]), does_not_raise(), np.array([0.2, 0.6])), + (np.array([30, 20]), pytest.raises(ValueError), None), + ], +) +def test_calculate_dbh_from_height(stem_heights, outcome, expected_dbh): + """Tests inverted calculation of dbh from height, checking for overheight stems.""" + + from pyrealm.demography.t_model_functions import calculate_dbh_from_height + + pft_h_max_values = np.array([25.33, 15.33]) + pft_a_hd_values = np.array([116.0, 116.0]) + + with outcome: + actual_dbh = calculate_dbh_from_height( + h_max=pft_h_max_values, + a_hd=pft_a_hd_values, + stem_height=stem_heights, + ) + + if isinstance(outcome, does_not_raise): + assert np.allclose(actual_dbh, expected_dbh) + + def test_calculate_crown_areas(): """Tests happy path for calculation of crown areas of trees.""" pft_ca_ratio_values = np.array([2, 3]) From 2a6ef85a36da3bf3ea6c792a8e52527d16fac6c0 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 20 Sep 2024 22:25:08 +0100 Subject: [PATCH 113/241] Update to sketch --- pyrealm/demography/flora.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index c18fcc8f..8a2e17d9 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -314,11 +314,11 @@ def get_allometries( if not ((dbh is None) ^ (stem_height is None)): raise ValueError("Provide one of either dbh or stem_height") - # Convert pft data to dict of numpy arrays - TODO: this may become redundant if - # self.data adopts the dict of arrays format - pft_data: dict[str, NDArray] = { - k: v.to_numpy() for k, v in self.data.to_dict(orient="series").items() - } + # # Convert pft data to dict of numpy arrays - TODO: this may become redundant if + # # self.data adopts the dict of arrays format + # pft_data: dict[str, NDArray] = { + # k: v.to_numpy() for k, v in self.data.to_dict(orient="series").items() + # } # Convert stem height to DBH for the plant functional type if stem_height is not None: From e40ae25d0d09c91ad821b2fb5864449d1d325b69 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 20 Sep 2024 22:31:37 +0100 Subject: [PATCH 114/241] Flora.data now a dict of arrays --- pyrealm/demography/flora.py | 9 +++------ tests/unit/demography/test_flora.py | 10 +++------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 57b72100..72118131 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -28,6 +28,7 @@ import numpy as np import pandas as pd from marshmallow.exceptions import ValidationError +from numpy.typing import NDArray from pyrealm.demography.t_model_functions import ( calculate_canopy_q_m, @@ -237,12 +238,8 @@ def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: [getattr(pft, pft_field) for pft in self.values()] ) - self.data: pd.DataFrame = pd.DataFrame(data) - """A dataframe of trait values as numpy arrays. - - The 'name' column can be used with cohort names to broadcast plant functional - type data out to cohorts. - """ + self.data: dict[str, NDArray] = data + """A dictionary of trait values as numpy arrays.""" @classmethod def _from_file_data(cls, file_data: dict) -> Flora: diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index ad975788..c03ca0f0 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -2,11 +2,9 @@ import sys from contextlib import nullcontext as does_not_raise -from dataclasses import fields from importlib import resources from json import JSONDecodeError -import pandas as pd import pytest from marshmallow.exceptions import ValidationError from pandas.errors import ParserError @@ -177,11 +175,9 @@ def test_Flora__init__(flora_inputs, outcome): assert k == v.name # Check data view is correct - assert isinstance(flora.data, pd.DataFrame) - assert flora.data.shape == ( - len(flora_inputs), - len(fields(next(iter(flora.values())))), - ) + assert isinstance(flora.data, dict) + for trait_array in flora.data.values(): + assert trait_array.shape == (len(flora),) # From f9f69f687379481210c305cdd85ccbba6d3e9e59 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 20 Sep 2024 22:54:28 +0100 Subject: [PATCH 115/241] Re-typing Community.cohort_data to numpy, splitting into PFT v cohort dicts --- pyrealm/demography/community.py | 40 ++++++++++++++++++++++----------- pyrealm/demography/flora.py | 3 +++ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 7c8b1bc3..e89ed83f 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -354,9 +354,8 @@ class Community: # Post init properties number_of_cohorts: int = field(init=False) - - # Dataframe of cohort data - cohort_data: pd.DataFrame = field(init=False) + cohort_data: dict[str, NDArray] = field(init=False) + pft_data: dict[str, NDArray] = field(init=False) def __post_init__( self, @@ -401,22 +400,37 @@ def __post_init__( f"Plant functional types unknown in flora: {','.join(unknown_pfts)}" ) - # Convert to a dataframe - cohort_data = pd.DataFrame( - { - "name": cohort_pft_names, - "dbh": cohort_dbh_values, - "n_individuals": cohort_n_individuals, - } - ) + # Store as a dictionary + self.cohort_data: dict[str, NDArray] = { + "name": cohort_pft_names, + "dbh": cohort_dbh_values, + "n_individuals": cohort_n_individuals, + } + # Broadcast the pft trait data to the cohort data by merging with the flora data # and then store as the cohort data attribute - self.cohort_data = pd.merge(cohort_data, self.flora.data) - self.number_of_cohorts = self.cohort_data.shape[0] + self.pft_data = self._unpack_pft_data(cohort_pft_names) + + self.number_of_cohorts = len(cohort_pft_names) # Populate the T model fields self._calculate_t_model() + def _unpack_pft_data( + self, cohort_pft_names: NDArray[np.str_] + ) -> dict[str, NDArray]: + """Creates a dictionary of PFT data for a set of cohorts. + + Args: + cohort_pft_names: The PFT name for each cohort + """ + # Find the index of the PFT names in the flora PFT data + pft_index = np.array([self.flora[nm] for nm in cohort_pft_names]) + + # Use that index to duplicate the PFT specific data into a per cohort entry for + # each of the PFT traits + return {k: v[pft_index] for k, v in self.flora.data.items()} + def _calculate_t_model(self) -> None: """Calculate T Model predictions across cohort data. diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 72118131..60603620 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -241,6 +241,9 @@ def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: self.data: dict[str, NDArray] = data """A dictionary of trait values as numpy arrays.""" + self.pft_indices = {k: v for k, v in enumerate(self.data["name"])} + """An dictionary giving the index of each PFT name in the PFT data.""" + @classmethod def _from_file_data(cls, file_data: dict) -> Flora: """Create a Flora object from a JSON string. From dc541ceaba7f55cdcb29ed5e8e5c7c50a878e7db Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 20 Sep 2024 23:09:08 +0100 Subject: [PATCH 116/241] Converting t_model_functions to use NDArray not pd.Series --- pyrealm/demography/t_model_functions.py | 123 ++++++++++++++---------- 1 file changed, 74 insertions(+), 49 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 1960f08e..6918404c 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -6,10 +6,12 @@ """ # noqa: D205 import numpy as np -from pandas import Series +from numpy.typing import NDArray -def calculate_heights(h_max: Series, a_hd: Series, dbh: Series) -> Series: +def calculate_heights( + h_max: NDArray[np.float32], a_hd: NDArray[np.float32], dbh: NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate tree height under the T Model. The height of trees (:math:`H`) are calculated from individual diameters at breast @@ -31,8 +33,11 @@ def calculate_heights(h_max: Series, a_hd: Series, dbh: Series) -> Series: def calculate_crown_areas( - ca_ratio: Series, a_hd: Series, dbh: Series, height: Series -) -> Series: + ca_ratio: NDArray[np.float32], + a_hd: NDArray[np.float32], + dbh: NDArray[np.float32], + height: NDArray[np.float32], +) -> NDArray[np.float32]: r"""Calculate tree crown area under the T Model. The tree crown area (:math:`A_{c}`)is calculated from individual diameters at breast @@ -55,7 +60,9 @@ def calculate_crown_areas( return ((np.pi * ca_ratio) / (4 * a_hd)) * dbh * height -def calculate_crown_fractions(a_hd: Series, height: Series, dbh: Series) -> Series: +def calculate_crown_fractions( + a_hd: NDArray[np.float32], height: NDArray[np.float32], dbh: NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate tree crown fraction under the T Model. The crown fraction (:math:`f_{c}`)is calculated from individual diameters at breast @@ -76,7 +83,9 @@ def calculate_crown_fractions(a_hd: Series, height: Series, dbh: Series) -> Seri return height / (a_hd * dbh) -def calculate_stem_masses(rho_s: Series, height: Series, dbh: Series) -> Series: +def calculate_stem_masses( + rho_s: NDArray[np.float32], height: NDArray[np.float32], dbh: NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate stem mass under the T Model. The stem mass (:math:`W_{s}`) is calculated from individual diameters at breast @@ -96,7 +105,9 @@ def calculate_stem_masses(rho_s: Series, height: Series, dbh: Series) -> Series: return (np.pi / 8) * rho_s * (dbh**2) * height -def calculate_foliage_masses(sla: Series, lai: Series, crown_area: Series) -> Series: +def calculate_foliage_masses( + sla: NDArray[np.float32], lai: NDArray[np.float32], crown_area: NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate foliage mass under the T Model. The foliage mass (:math:`W_{f}`) is calculated from the crown area (:math:`A_{c}`), @@ -117,12 +128,12 @@ def calculate_foliage_masses(sla: Series, lai: Series, crown_area: Series) -> Se def calculate_sapwood_masses( - rho_s: Series, - ca_ratio: Series, - height: Series, - crown_area: Series, - crown_fraction: Series, -) -> Series: + rho_s: NDArray[np.float32], + ca_ratio: NDArray[np.float32], + height: NDArray[np.float32], + crown_area: NDArray[np.float32], + crown_fraction: NDArray[np.float32], +) -> NDArray[np.float32]: r"""Calculate sapwood mass under the T Model. The sapwood mass (:math:`W_{\cdot s}`) is calculated from the individual crown area @@ -146,8 +157,11 @@ def calculate_sapwood_masses( def calculate_whole_crown_gpp( - potential_gpp: Series, crown_area: Series, par_ext: Series, lai: Series -) -> Series: + potential_gpp: NDArray[np.float32], + crown_area: NDArray[np.float32], + par_ext: NDArray[np.float32], + lai: NDArray[np.float32], +) -> NDArray[np.float32]: r"""Calculate whole crown gross primary productivity. This function calculates individual GPP across the whole crown, given the @@ -170,7 +184,9 @@ def calculate_whole_crown_gpp( return potential_gpp * crown_area * (1 - np.exp(-(par_ext * lai))) -def calculate_sapwood_respiration(resp_s: Series, sapwood_mass: Series) -> Series: +def calculate_sapwood_respiration( + resp_s: NDArray[np.float32], sapwood_mass: NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate sapwood respiration. Calculates the total sapwood respiration (:math:`R_{\cdot s}`) given the individual @@ -187,7 +203,9 @@ def calculate_sapwood_respiration(resp_s: Series, sapwood_mass: Series) -> Serie return sapwood_mass * resp_s -def calculate_foliar_respiration(resp_f: Series, whole_crown_gpp: Series) -> Series: +def calculate_foliar_respiration( + resp_f: NDArray[np.float32], whole_crown_gpp: NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate foliar respiration. Calculates the total foliar respiration (:math:`R_{f}`) given the individual crown @@ -207,8 +225,11 @@ def calculate_foliar_respiration(resp_f: Series, whole_crown_gpp: Series) -> Ser def calculate_fine_root_respiration( - zeta: Series, sla: Series, resp_r: Series, foliage_mass: Series -) -> Series: + zeta: NDArray[np.float32], + sla: NDArray[np.float32], + resp_r: NDArray[np.float32], + foliage_mass: NDArray[np.float32], +) -> NDArray[np.float32]: r"""Calculate foliar respiration. Calculates the total fine root respiration (:math:`R_{r}`) given the individual @@ -230,12 +251,12 @@ def calculate_fine_root_respiration( def calculate_net_primary_productivity( - yld: Series, - whole_crown_gpp: Series, - foliar_respiration: Series, - fine_root_respiration: Series, - sapwood_respiration: Series, -) -> Series: + yld: NDArray[np.float32], + whole_crown_gpp: NDArray[np.float32], + foliar_respiration: NDArray[np.float32], + fine_root_respiration: NDArray[np.float32], + sapwood_respiration: NDArray[np.float32], +) -> NDArray[np.float32]: r"""Calculate net primary productivity. The net primary productivity (NPP, :math:`P_{net}`) is calculated as a plant @@ -270,12 +291,12 @@ def calculate_net_primary_productivity( def calculate_foliage_and_fine_root_turnover( - sla: Series, - zeta: Series, - tau_f: Series, - tau_r: Series, - foliage_mass: Series, -) -> Series: + sla: NDArray[np.float32], + zeta: NDArray[np.float32], + tau_f: NDArray[np.float32], + tau_r: NDArray[np.float32], + foliage_mass: NDArray[np.float32], +) -> NDArray[np.float32]: r"""Calculate turnover costs. This function calculates the costs associated with the turnover of fine roots and @@ -301,18 +322,18 @@ def calculate_foliage_and_fine_root_turnover( def calculate_growth_increments( - rho_s: Series, - a_hd: Series, - h_max: Series, - lai: Series, - ca_ratio: Series, - sla: Series, - zeta: Series, - npp: Series, - turnover: Series, - dbh: Series, - height: Series, -) -> tuple[Series, Series, Series]: + rho_s: NDArray[np.float32], + a_hd: NDArray[np.float32], + h_max: NDArray[np.float32], + lai: NDArray[np.float32], + ca_ratio: NDArray[np.float32], + sla: NDArray[np.float32], + zeta: NDArray[np.float32], + npp: NDArray[np.float32], + turnover: NDArray[np.float32], + dbh: NDArray[np.float32], + height: NDArray[np.float32], +) -> tuple[NDArray[np.float32], NDArray[np.float32], NDArray[np.float32]]: r"""Calculate growth increments. Given an estimate of net primary productivity (:math:`P_{net}`), less associated @@ -437,7 +458,9 @@ def calculate_canopy_z_max_proportion(m: float, n: float) -> float: return ((n - 1) / (m * n - 1)) ** (1 / n) -def calculate_canopy_z_max(z_max_prop: Series, height: Series) -> Series: +def calculate_canopy_z_max( + z_max_prop: NDArray[np.float32], height: NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate height of maximum crown radius. The height of the maximum crown radius (:math:`z_m`) is derived from the canopy @@ -461,7 +484,9 @@ def calculate_canopy_z_max(z_max_prop: Series, height: Series) -> Series: return height * z_max_prop -def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: +def calculate_canopy_r0( + q_m: NDArray[np.float32], crown_area: NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate scaling factor for height of maximum crown radius. This scaling factor (:math:`r_0`) is derived from the canopy shape parameters @@ -487,10 +512,10 @@ def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: def calculate_relative_canopy_radii( z: float, - height: Series, - m: Series, - n: Series, -) -> Series: + height: NDArray[np.float32], + m: NDArray[np.float32], + n: NDArray[np.float32], +) -> NDArray[np.float32]: r"""Calculate relative canopy radius at a given height. The canopy shape parameters ``m`` and ``n`` define the vertical distribution of From 2c41147704ecd6de80ee415e5979dc7d42b62c1d Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 20 Sep 2024 23:10:36 +0100 Subject: [PATCH 117/241] Fixing up indexing of cohort PFT names onto flora data --- pyrealm/demography/community.py | 11 +++++------ pyrealm/demography/flora.py | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index e89ed83f..33e6facf 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -355,7 +355,6 @@ class Community: # Post init properties number_of_cohorts: int = field(init=False) cohort_data: dict[str, NDArray] = field(init=False) - pft_data: dict[str, NDArray] = field(init=False) def __post_init__( self, @@ -407,9 +406,9 @@ def __post_init__( "n_individuals": cohort_n_individuals, } - # Broadcast the pft trait data to the cohort data by merging with the flora data - # and then store as the cohort data attribute - self.pft_data = self._unpack_pft_data(cohort_pft_names) + # Duplicate the pft trait data to match the cohort data and add to the cohort + # data dictionary. + self.cohort_data.update(self._unpack_pft_data(cohort_pft_names)) self.number_of_cohorts = len(cohort_pft_names) @@ -424,8 +423,8 @@ def _unpack_pft_data( Args: cohort_pft_names: The PFT name for each cohort """ - # Find the index of the PFT names in the flora PFT data - pft_index = np.array([self.flora[nm] for nm in cohort_pft_names]) + # Get the indices for the cohort PFT names in the flora PFT data + pft_index = [self.flora.pft_indices[str(nm)] for nm in cohort_pft_names] # Use that index to duplicate the PFT specific data into a per cohort entry for # each of the PFT traits diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 60603620..cc49ad42 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -241,7 +241,7 @@ def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: self.data: dict[str, NDArray] = data """A dictionary of trait values as numpy arrays.""" - self.pft_indices = {k: v for k, v in enumerate(self.data["name"])} + self.pft_indices = {v: k for k, v in enumerate(self.data["name"])} """An dictionary giving the index of each PFT name in the PFT data.""" @classmethod From 3e73ba511c273c23301f754352befc0b2d658e88 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 20 Sep 2024 23:14:16 +0100 Subject: [PATCH 118/241] Fixing display of community cohort data in docstring --- pyrealm/demography/community.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 33e6facf..63f09870 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -90,9 +90,10 @@ ... cohort_pft_names=cohort_pft_names ... ) -Display the community's cohort data with calculated T Model predictions: +Convert the community cohort data to a :class:`pandas.DataFrame` for nicer display and +show some of the calculated T Model predictions: ->>> community.cohort_data[ +>>> pd.DataFrame(community.cohort_data)[ ... ['name', 'dbh', 'n_individuals', 'height', 'crown_area', 'stem_mass'] ... ] name dbh n_individuals height crown_area stem_mass From 621531ab6bb9f318988d6d019189ae852105fd32 Mon Sep 17 00:00:00 2001 From: David Orme Date: Sat, 21 Sep 2024 12:54:27 +0100 Subject: [PATCH 119/241] Draft validation function for T Model arguments --- pyrealm/demography/t_model_functions.py | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 6918404c..b888ac98 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -8,6 +8,38 @@ import numpy as np from numpy.typing import NDArray +from pyrealm.core.utilities import check_input_shapes + + +def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> None: + """Shared validation for T model function inputs. + + Args: + pft_args: A list of row arrays representing trait values + size_args: A list of arrays representing stem sizes at which to evaluate + functions. + """ + pft_args_shape = check_input_shapes(*pft_args) + size_args_shape = check_input_shapes(*pft_args) + + if len(pft_args_shape) > 1: + raise ValueError("T model functions only accept 1D arrays of PFT traits") + + if len(size_args_shape) == 1 and not pft_args_shape == size_args_shape: + raise ValueError( + "Incompatible one dimensional PFT trait and size data arrays. " + "If you want predictions across a range of size for each PFT, convert " + "the size inputs to a column array, using e.g. dbh[:, None]" + ) + + elif len(size_args_shape) == 2 and size_args_shape[1] != 1: + raise ValueError( + "Two dimensional size data is not a column array: the second axis length " + "is not one." + ) + else: + raise ValueError("Size data arrays can only be one or two dimensional") + def calculate_heights( h_max: NDArray[np.float32], a_hd: NDArray[np.float32], dbh: NDArray[np.float32] From f291ebfa85b1c42008ebecbffe6300cca7cd50bf Mon Sep 17 00:00:00 2001 From: David Orme Date: Sat, 21 Sep 2024 13:55:39 +0100 Subject: [PATCH 120/241] Fixing up _validate_t_model_args and adding tests --- pyrealm/demography/t_model_functions.py | 34 ++++----- .../unit/demography/test_t_model_functions.py | 75 +++++++++++++++++++ 2 files changed, 91 insertions(+), 18 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index b888ac98..1dd8e89b 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -19,26 +19,24 @@ def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> size_args: A list of arrays representing stem sizes at which to evaluate functions. """ - pft_args_shape = check_input_shapes(*pft_args) - size_args_shape = check_input_shapes(*pft_args) + + try: + pft_args_shape = check_input_shapes(*pft_args) + except ValueError: + raise ValueError("PFT trait values are not of equal length") + + try: + size_args_shape = check_input_shapes(*size_args) + except ValueError: + raise ValueError("Size arrays are not of equal length") if len(pft_args_shape) > 1: - raise ValueError("T model functions only accept 1D arrays of PFT traits") - - if len(size_args_shape) == 1 and not pft_args_shape == size_args_shape: - raise ValueError( - "Incompatible one dimensional PFT trait and size data arrays. " - "If you want predictions across a range of size for each PFT, convert " - "the size inputs to a column array, using e.g. dbh[:, None]" - ) - - elif len(size_args_shape) == 2 and size_args_shape[1] != 1: - raise ValueError( - "Two dimensional size data is not a column array: the second axis length " - "is not one." - ) - else: - raise ValueError("Size data arrays can only be one or two dimensional") + raise ValueError("T model functions only accept 1D arrays of PFT trait values") + + try: + _ = np.broadcast_shapes(pft_args_shape, size_args_shape) + except ValueError: + raise ValueError("PFT and size inputs to T model function are not compatible.") def calculate_heights( diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 26c9523c..a442a2a8 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -1,6 +1,9 @@ """test the functions in t_model_functions.py.""" +from contextlib import nullcontext as does_not_raise + import numpy as np +import pytest from numpy.testing import assert_array_almost_equal from pyrealm.demography.t_model_functions import ( @@ -14,6 +17,78 @@ ) +@pytest.mark.parametrize( + argnames="pft_args, size_args, outcome, excep_message", + argvalues=[ + pytest.param( + [np.ones(4), np.ones(4)], + [np.ones(4), np.ones(4)], + does_not_raise(), + None, + id="all_1d_ok", + ), + pytest.param( + [np.ones(5), np.ones(4)], + [np.ones(4), np.ones(4)], + pytest.raises(ValueError), + "PFT trait values are not of equal length", + id="pfts_unequal", + ), + pytest.param( + [np.ones(4), np.ones(4)], + [np.ones(5), np.ones(4)], + pytest.raises(ValueError), + "Size arrays are not of equal length", + id="shape_unequal", + ), + pytest.param( + [np.ones((4, 2)), np.ones((4, 2))], + [np.ones(4), np.ones(4)], + pytest.raises(ValueError), + "T model functions only accept 1D arrays of PFT trait values", + id="pfts_not_row_arrays", + ), + pytest.param( + [np.ones(4), np.ones(4)], + [np.ones(5), np.ones(5)], + pytest.raises(ValueError), + "PFT and size inputs to T model function are not compatible.", + id="sizes_row_array_of_bad_length", + ), + pytest.param( + [np.ones(4), np.ones(4)], + [np.ones((5, 1)), np.ones((5, 1))], + does_not_raise(), + None, + id="size_2d_columns_ok", + ), + pytest.param( + [np.ones(4), np.ones(4)], + [np.ones((5, 2)), np.ones((5, 2))], + pytest.raises(ValueError), + "PFT and size inputs to T model function are not compatible.", + id="size_2d_not_ok", + ), + pytest.param( + [np.ones(4), np.ones(4)], + [np.ones((5, 4)), np.ones((5, 4))], + does_not_raise(), + None, + id="size_2d_weird_but_ok", + ), + ], +) +def test__validate_t_model_args(pft_args, size_args, outcome, excep_message): + """Test shared input validation function.""" + from pyrealm.demography.t_model_functions import _validate_t_model_args + + with outcome as excep: + _validate_t_model_args(pft_args=pft_args, size_args=size_args) + return + + assert str(excep.value).startswith(excep_message) + + def test_calculate_heights(): """Tests happy path for calculation of heights of tree from diameter.""" pft_h_max_values = np.array([25.33, 15.33]) From 95759adbd0470976a61a9af4efa4aeb579a1acce Mon Sep 17 00:00:00 2001 From: David Orme Date: Sun, 22 Sep 2024 10:58:15 +0100 Subject: [PATCH 121/241] Clearing out old Series.to_numpy() casting --- pyrealm/demography/canopy.py | 38 +++++----- pyrealm/demography/canopy_functions.py | 9 ++- .../unit/demography/test_canopy_functions.py | 74 +++++++++---------- 3 files changed, 61 insertions(+), 60 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index e7b4752a..742e1a3a 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -71,13 +71,13 @@ def __init__( solution = root_scalar( solve_community_projected_canopy_area, args=( - community.cohort_data["stem_height"].to_numpy(), - community.cohort_data["crown_area"].to_numpy(), - community.cohort_data["m"].to_numpy(), - community.cohort_data["n"].to_numpy(), - community.cohort_data["q_m"].to_numpy(), - community.cohort_data["canopy_z_max"].to_numpy(), - community.cohort_data["n_individuals"].to_numpy(), + community.cohort_data["stem_height"], + community.cohort_data["crown_area"], + community.cohort_data["m"], + community.cohort_data["n"], + community.cohort_data["q_m"], + community.cohort_data["canopy_z_max"], + community.cohort_data["n_individuals"], target_area, False, # validate ), @@ -96,9 +96,9 @@ def __init__( self.stem_relative_radius: NDArray[np.float32] = ( calculate_relative_canopy_radius_at_z( z=self.layer_heights, - stem_height=community.cohort_data["stem_height"].to_numpy(), - m=community.cohort_data["m"].to_numpy(), - n=community.cohort_data["n"].to_numpy(), + stem_height=community.cohort_data["stem_height"], + m=community.cohort_data["m"], + n=community.cohort_data["n"], validate=False, ) ) @@ -108,10 +108,10 @@ def __init__( calculate_stem_projected_crown_area_at_z( z=self.layer_heights, q_z=self.stem_relative_radius, - crown_area=community.cohort_data["crown_area"].to_numpy(), - stem_height=community.cohort_data["stem_height"].to_numpy(), - q_m=community.cohort_data["q_m"].to_numpy(), - z_max=community.cohort_data["canopy_z_max"].to_numpy(), + crown_area=community.cohort_data["crown_area"], + stem_height=community.cohort_data["stem_height"], + q_m=community.cohort_data["q_m"], + z_max=community.cohort_data["canopy_z_max"], validate=False, ) ) @@ -122,11 +122,11 @@ def __init__( calculate_stem_projected_leaf_area_at_z( z=self.layer_heights, q_z=self.stem_relative_radius, - crown_area=community.cohort_data["crown_area"].to_numpy(), - stem_height=community.cohort_data["stem_height"].to_numpy(), - f_g=community.cohort_data["f_g"].to_numpy(), - q_m=community.cohort_data["q_m"].to_numpy(), - z_max=community.cohort_data["canopy_z_max"].to_numpy(), + crown_area=community.cohort_data["crown_area"], + stem_height=community.cohort_data["stem_height"], + f_g=community.cohort_data["f_g"], + q_m=community.cohort_data["q_m"], + z_max=community.cohort_data["canopy_z_max"], validate=False, ) ) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 79312bbe..9fc5426b 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -4,7 +4,6 @@ import numpy as np from numpy.typing import NDArray -from pandas import Series from pyrealm.core.utilities import check_input_shapes @@ -49,7 +48,9 @@ def calculate_canopy_z_max_proportion( return ((n - 1) / (m * n - 1)) ** (1 / n) -def calculate_canopy_z_max(z_max_prop: Series, stem_height: Series) -> Series: +def calculate_canopy_z_max( + z_max_prop: NDArray[np.float32], stem_height: NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate height of maximum crown radius. The height of the maximum crown radius (:math:`z_m`) is derived from the canopy @@ -74,7 +75,9 @@ def calculate_canopy_z_max(z_max_prop: Series, stem_height: Series) -> Series: return stem_height * z_max_prop -def calculate_canopy_r0(q_m: Series, crown_area: Series) -> Series: +def calculate_canopy_r0( + q_m: NDArray[np.float32], crown_area: NDArray[np.float32] +) -> NDArray[np.float32]: r"""Calculate scaling factor for height of maximum crown radius. This scaling factor (:math:`r_0`) is derived from the canopy shape parameters diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index b3a6bff9..03019170 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -29,7 +29,7 @@ def fixture_community(): # A simple community containing one sample stem, with an initial crown gap fraction # of zero. - flora = Flora([PlantFunctionalType(name="test", f_g=0)]) + flora = Flora([PlantFunctionalType(name="test", f_g=0.0)]) return Community( cell_id=1, cell_area=100, @@ -237,14 +237,14 @@ def test_calculate_relative_canopy_radius_at_z_values(fixture_community): z_max = ( fixture_community.cohort_data["stem_height"] * fixture_community.cohort_data["z_max_prop"] - ).to_numpy() + ) # Get the relative radius at that height q_z_values = calculate_relative_canopy_radius_at_z( z=z_max, - stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), - m=fixture_community.cohort_data["m"].to_numpy(), - n=fixture_community.cohort_data["n"].to_numpy(), + stem_height=fixture_community.cohort_data["stem_height"], + m=fixture_community.cohort_data["m"], + n=fixture_community.cohort_data["n"], ) # Now test that the circular crown area from that radius is equivalent to the direct @@ -333,19 +333,19 @@ def test_calculate_stem_projected_crown_area_at_z_values( # Calculate the required q_z q_z = calculate_relative_canopy_radius_at_z( z=heights, - stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), - m=fixture_community.cohort_data["m"].to_numpy(), - n=fixture_community.cohort_data["n"].to_numpy(), + stem_height=fixture_community.cohort_data["stem_height"], + m=fixture_community.cohort_data["m"], + n=fixture_community.cohort_data["n"], ) # Calculate and test these values Ap_z_values = calculate_stem_projected_crown_area_at_z( z=heights, q_z=q_z, - stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), - crown_area=fixture_community.cohort_data["crown_area"].to_numpy(), - q_m=fixture_community.cohort_data["q_m"].to_numpy(), - z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), + stem_height=fixture_community.cohort_data["stem_height"], + crown_area=fixture_community.cohort_data["crown_area"], + q_m=fixture_community.cohort_data["q_m"], + z_max=fixture_community.cohort_data["canopy_z_max"], ) assert np.allclose( @@ -377,13 +377,13 @@ def test_solve_community_projected_canopy_area(fixture_community): ): solved = solve_community_projected_canopy_area( z=this_height, - stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), - crown_area=fixture_community.cohort_data["crown_area"].to_numpy(), - n_individuals=fixture_community.cohort_data["n_individuals"].to_numpy(), - m=fixture_community.cohort_data["m"].to_numpy(), - n=fixture_community.cohort_data["n"].to_numpy(), - q_m=fixture_community.cohort_data["q_m"].to_numpy(), - z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), + stem_height=fixture_community.cohort_data["stem_height"], + crown_area=fixture_community.cohort_data["crown_area"], + n_individuals=fixture_community.cohort_data["n_individuals"], + m=fixture_community.cohort_data["m"], + n=fixture_community.cohort_data["n"], + q_m=fixture_community.cohort_data["q_m"], + z_max=fixture_community.cohort_data["canopy_z_max"], target_area=this_target, ) @@ -437,23 +437,23 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): # Calculate the leaf areas at the locations of z_max for each stem from the lowest # to the highest - z_max = fixture_community.cohort_data["canopy_z_max"].to_numpy()[:, None] + z_max = fixture_community.cohort_data["canopy_z_max"][:, None] q_z = calculate_relative_canopy_radius_at_z( z=z_max, - stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), - m=fixture_community.cohort_data["m"].to_numpy(), - n=fixture_community.cohort_data["n"].to_numpy(), + stem_height=fixture_community.cohort_data["stem_height"], + m=fixture_community.cohort_data["m"], + n=fixture_community.cohort_data["n"], ) leaf_area_fg0 = calculate_stem_projected_leaf_area_at_z( z=z_max, q_z=q_z, - stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), - crown_area=fixture_community.cohort_data["crown_area"].to_numpy(), - f_g=fixture_community.cohort_data["f_g"].to_numpy(), - q_m=fixture_community.cohort_data["q_m"].to_numpy(), - z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), + stem_height=fixture_community.cohort_data["stem_height"], + crown_area=fixture_community.cohort_data["crown_area"], + f_g=fixture_community.cohort_data["f_g"], + q_m=fixture_community.cohort_data["q_m"], + z_max=fixture_community.cohort_data["canopy_z_max"], ) # Pre-calculated values @@ -470,13 +470,11 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): # More rigourous check - with f_g = 0, the projected leaf area of each stem in the # lowest layer must equal the crown area (all the crown is now accounted for). - assert np.allclose( - leaf_area_fg0[0, :], fixture_community.cohort_data["crown_area"].to_numpy() - ) + assert np.allclose(leaf_area_fg0[0, :], fixture_community.cohort_data["crown_area"]) # Also the diagonal of the resulting matrix (4 heights for 4 cohorts) should _also_ # match the crown areas as the leaf area is all accounted for exactly at z_max. assert np.allclose( - np.diag(leaf_area_fg0), fixture_community.cohort_data["crown_area"].to_numpy() + np.diag(leaf_area_fg0), fixture_community.cohort_data["crown_area"] ) # Introduce some crown gap fraction and recalculate @@ -485,11 +483,11 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): leaf_area_fg002 = calculate_stem_projected_leaf_area_at_z( z=z_max, q_z=q_z, - stem_height=fixture_community.cohort_data["stem_height"].to_numpy(), - crown_area=fixture_community.cohort_data["crown_area"].to_numpy(), - f_g=fixture_community.cohort_data["f_g"].to_numpy(), - q_m=fixture_community.cohort_data["q_m"].to_numpy(), - z_max=fixture_community.cohort_data["canopy_z_max"].to_numpy(), + stem_height=fixture_community.cohort_data["stem_height"], + crown_area=fixture_community.cohort_data["crown_area"], + f_g=fixture_community.cohort_data["f_g"], + q_m=fixture_community.cohort_data["q_m"], + z_max=fixture_community.cohort_data["canopy_z_max"], ) expected_leaf_area_fg002 = np.array( @@ -514,5 +512,5 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): # the stem all but the crown gap fraction should be accounted for assert np.allclose( np.diag(leaf_area_fg002), - fixture_community.cohort_data["crown_area"].to_numpy() * 0.98, + fixture_community.cohort_data["crown_area"] * 0.98, ) From dcda1a0b798e1abf1a73ac2cbd71101a53547c48 Mon Sep 17 00:00:00 2001 From: David Orme Date: Sun, 22 Sep 2024 10:59:44 +0100 Subject: [PATCH 122/241] Fixing broken reference to stem_height in docstring --- pyrealm/demography/community.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 0fefc1eb..31ce1573 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -94,7 +94,7 @@ show some of the calculated T Model predictions: >>> pd.DataFrame(community.cohort_data)[ -... ['name', 'dbh', 'n_individuals', 'height', 'crown_area', 'stem_mass'] +... ['name', 'dbh', 'n_individuals', 'stem_height', 'crown_area', 'stem_mass'] ... ] name dbh n_individuals stem_height crown_area stem_mass 0 Evergreen Tree 0.100 100 9.890399 2.459835 8.156296 From 894c2bb51d1eb5998744a9115e16a30d06f8b16b Mon Sep 17 00:00:00 2001 From: David Orme Date: Sun, 22 Sep 2024 21:25:48 +0100 Subject: [PATCH 123/241] Array based testing of T model functions using inputs from R implementation --- .../t_model/rtmodel_test_outputs.r | 30 ++ .../t_model/rtmodel_unit_testing.csv | 19 ++ .../unit/demography/test_t_model_functions.py | 286 +++++++++++++----- 3 files changed, 255 insertions(+), 80 deletions(-) create mode 100644 pyrealm_build_data/t_model/rtmodel_unit_testing.csv diff --git a/pyrealm_build_data/t_model/rtmodel_test_outputs.r b/pyrealm_build_data/t_model/rtmodel_test_outputs.r index bf19857a..f24edacf 100644 --- a/pyrealm_build_data/t_model/rtmodel_test_outputs.r +++ b/pyrealm_build_data/t_model/rtmodel_test_outputs.r @@ -90,6 +90,7 @@ tmodel <- function(P0, year, a, cr, Hm, rho, rr, # Load alternative plant functional types pfts <- read.csv("pft_definitions.csv") +# Generate 100 year sequences of plant growth to do fine regression testing for (pft_idx in seq_len(nrow(pfts))) { # Get the PFT pft <- as.list(pfts[pft_idx, ]) @@ -110,3 +111,32 @@ for (pft_idx in seq_len(nrow(pfts))) { row.names = FALSE ) } + +# Generate some simple snapshot predictions for single years to provide +# expectations for varying matrix inputs in unit testing. + + +dbh <- c(0.01, 0.05, 0.1, 0.25, 0.5, 1.0) +results <- list() + +for (pft_idx in seq_len(nrow(pfts))) { + # Get the PFT + pft <- as.list(pfts[pft_idx, ]) + + # Seperate off the name + name <- pft[["name"]] + pft[["name"]] <- NULL + pft[["P0"]] <- 7 / 0.9 + pft[["year"]] <- 1 + + for (dbh_val in dbh) { + pft[["d"]] <- dbh_val + tmodel_run <- do.call(tmodel, pft) + these_res <- data.frame(tmodel_run) + these_res["pft_name"] <- name + results <- c(results, list(these_res)) + } +} + +results <- do.call(rbind, results) +write.csv(results, "rtmodel_unit_testing.csv", row.names = FALSE) diff --git a/pyrealm_build_data/t_model/rtmodel_unit_testing.csv b/pyrealm_build_data/t_model/rtmodel_unit_testing.csv new file mode 100644 index 00000000..e38c2dca --- /dev/null +++ b/pyrealm_build_data/t_model/rtmodel_unit_testing.csv @@ -0,0 +1,19 @@ +"P0","dD","D","H","fc","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","NPP","turnover","dWs","dWfr","pft_name" +7,5.70741929397614,0.01,1.13383947446635,0.977447822815821,0.0299727537555677,0.00385363976857298,0.00890515440833401,0.0089006252406062,0.124507190217744,0.000391627510586673,0.00837372799872298,0.0694451008250608,0.00978231633560834,0.0302642888449712,0.0293984956444813,"default" +7,9.5791419726667,0.05,5.18387490395112,0.893771535163986,0.685171973170725,0.0880935394076647,1.01785145721133,1.0063655259377,2.84621286022436,0.0442800831412588,0.191421975520491,1.56630648093757,0.223622061573303,1.12706849973198,0.215615919632286,"default" +7,10.6105692527994,0.1,9.30685130731739,0.802314767872188,2.46024211324268,0.316316843131202,7.30958392378022,7.02392939699003,10.2198762006748,0.309052893467561,0.687337521113514,5.53409147165622,0.802958140256128,4.32536164819343,0.405771683206663,"default" +7,11.7637394224589,0.25,17.2684811731791,0.595464868040658,11.4121960293356,1.46728234662886,84.7664587379892,70.8945402515097,47.4064036095691,3.11935977106643,3.18831650228371,24.6592364017314,3.72463980298094,20.2184120516854,0.716184547065038,"default" +7,12.8402855712512,0.5,22.764343237458,0.392488676507897,30.0884767918617,3.86851844466794,446.976834241216,282.011090375506,124.987905143371,12.4084879765223,8.40605846915675,62.5040152186153,9.82008528261861,51.8390391221915,0.844890813805198,"default" +7,13.8365326045864,1,25.0701265446831,0.216121780557613,66.2722322221465,8.52071557141883,1969.00313443357,759.119499551716,275.295673221369,33.4012579802755,18.5150036937588,134.027646928401,21.629508758217,111.563319727657,0.83481844252716,"default" +7,1.83444217811377,0.01,1.19117522504391,0.960625181487024,0.0265287885308908,0.0106115154123563,0.0187109366806806,0.0186819276872839,0.168855057924845,0.000635185541367653,0.0189797564665405,0.0746200579584684,0.0298797933979506,0.0203205832332554,0.0244196813272623,"alt_one" +7,3.35239242002716,0.05,5.09947451213283,0.822495889053683,0.567854661962317,0.227141864784927,2.00255895806061,1.93946291234798,3.61438034484271,0.0659417390198313,0.40626593935432,1.57108633323428,0.639583671894399,0.75495150429744,0.17655115704244,"alt_one" +7,3.82334219687197,0.1,8.5026254561057,0.685695601298846,1.89362864455212,0.757451457820848,13.3558928345636,12.03650084279,12.052897707397,0.409241028654861,1.35477767745837,5.1444395006419,2.1328238417587,2.70589084803833,0.305724810844866,"alt_one" +7,4.41366360248733,0.25,13.3008175897075,0.429058631926048,7.40559763388914,2.96223905355565,130.580471333009,88.0146267929695,47.1364388156046,2.99249731096096,5.29826077118964,19.422840366727,8.34104154553829,10.643838562029,0.437960259159747,"alt_one" +7,4.84427320472723,0.5,15.0614037016151,0.242925866155082,16.771705177288,6.70868207091519,591.459940271801,252.458025048401,106.751472873017,8.58357285164563,11.9991487520389,43.0843756346661,18.890236357577,23.7481533896797,0.445985887409373,"alt_one" +7,4.98313200608632,1,15.3252939353225,0.123591080123569,34.1311230653682,13.6524492261473,2407.29154206567,558.268734986536,217.243722061862,18.9811369895422,24.418770685887,86.9219071932166,38.4424228209936,48.0429983617394,0.436486010483598,"alt_one" +7,9.32056923353382,0.01,1.00860974930819,0.988833087557045,0.0315404037817721,0.0015019239896082,0.00396080122345705,0.00396030731180784,0.0727876720675438,0.000213856594837624,0.00455128026570971,0.0476157746448975,0.00244062648311332,0.0220673955612297,0.0231077526005545,"alt_two" +7,15.8212577468342,0.05,4.82356735319007,0.945797520233348,0.754192898157791,0.0359139475313234,0.473552617527422,0.472161363119038,1.74049595961436,0.0254967136084281,0.108830035204169,1.12431844756123,0.0583601647384005,0.882521133998623,0.183437148824208,"alt_two" +7,17.3535539836585,0.1,9.13385868584714,0.89547634174972,2.85626419172396,0.136012580558284,3.58685791829809,3.54767079562267,6.59157133066325,0.191574222963624,0.412158922865767,4.1914867293837,0.221020443407211,3.59987124872461,0.37059503725188,"alt_two" +7,18.47872940595,0.25,19.5028128756488,0.764816191201915,15.2468928988697,0.726042518993794,47.8671044175584,45.2195067132589,35.1861646429922,2.44185336251598,2.20012664530689,21.3809292446185,1.17981909336491,19.423864497651,0.777245653602662,"alt_two" +7,19.0310275658185,0.5,30.6147210510423,0.600288648059653,47.8679025400313,2.27942393047768,300.559321080173,252.539209357306,110.467615340376,13.6371173052945,6.90733833652652,62.9462117889886,3.70406388702623,58.1326237149391,1.10952418702328,"alt_two" +7,19.7708744588825,1,40.5530435794036,0.397578858621604,126.814099303671,6.03876663350814,1592.51429737201,1014.57297240453,292.656464943263,54.7869405098448,18.2992745295197,153.699174932729,9.81299577945072,142.632567732373,1.25361142090522,"alt_two" diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index cc6bd0c0..97031e86 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -1,8 +1,10 @@ """test the functions in t_model_functions.py.""" from contextlib import nullcontext as does_not_raise +from importlib import resources import numpy as np +import pandas as pd import pytest @@ -78,111 +80,235 @@ def test__validate_t_model_args(pft_args, size_args, outcome, excep_message): assert str(excep.value).startswith(excep_message) -def test_calculate_heights(): - """Tests happy path for calculation of heights of tree from diameter.""" - - from pyrealm.demography.t_model_functions import calculate_heights +@pytest.fixture +def rtmodel_data(): + """Loads some simple predictions from the R implementation for testing.""" + + # Load the PFT definitions and rename to pyrealm attributes + pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" + pft_definitions = pd.read_csv(pfts_path) + + # Map the PFT trait args from the R implementation to pyrealm + pft_definitions = pft_definitions.rename( + columns={ + "a": "a_hd", + "cr": "ca_ratio", + "Hm": "h_max", + "rho": "rho_s", + "L": "lai", + "sigma": "sla", + "tf": "tau_f", + "tr": "tau_r", + "K": "par_ext", + "y": "yld", + "rr": "resp_r", + "rs": "resp_s", + } + ) - pft_h_max_values = np.array([25.33, 15.33]) - pft_a_hd_values = np.array([116.0, 116.0]) - diameters_at_breast_height = np.array([0.2, 0.6]) - expected_heights = np.array([15.19414157, 15.16639589]) - actual_heights = calculate_heights( - h_max=pft_h_max_values, - a_hd=pft_a_hd_values, - dbh=diameters_at_breast_height, + rdata_path = ( + resources.files("pyrealm_build_data.t_model") / "rtmodel_unit_testing.csv" + ) + rdata = pd.read_csv(rdata_path) + + rdata = rdata.rename( + columns={ + "dD": "delta_d", + "D": "diameter", + "H": "height", + "fc": "crown_fraction", + "Ac": "crown_area", + "Wf": "mass_fol", + "Ws": "mass_stm", + "Wss": "mass_swd", + "P0": "potential_gpp", + "GPP": "crown_gpp", + "Rm1": "resp_swd", + "Rm2": "resp_frt", + "dWs": "delta_mass_stm", + "dWfr": "delta_mass_frt", + } ) - np.allclose(actual_heights, expected_heights) + # Fix some scaling differences: + # The R tmodel implementation rescales reported delta_d as a radial increase in + # millimetres, not diameter increase in metres + rdata["delta_d"] = rdata["delta_d"] / 500 + # Wrap the return data into arrays with PFT as columns and diameter values as rows + pft_arrays = {k: v.to_numpy() for k, v in pft_definitions.items()} + rdata_arrays = {k: np.reshape(v, (3, 6)).T for k, v in rdata.items()} -def test_calculate_crown_areas(): - """Tests happy path for calculation of crown areas of trees.""" + return pft_arrays, rdata_arrays - from pyrealm.demography.t_model_functions import calculate_crown_areas - pft_ca_ratio_values = np.array([2, 3]) - pft_a_hd_values = np.array([116.0, 116.0]) - diameters_at_breast_height = np.array([0.2, 0.6]) - stem_height = np.array([15.194142, 15.166396]) - expected_crown_areas = np.array([0.04114983, 0.1848361]) - actual_crown_areas = calculate_crown_areas( - ca_ratio=pft_ca_ratio_values, - a_hd=pft_a_hd_values, - dbh=diameters_at_breast_height, - stem_height=stem_height, - ) +@pytest.mark.parametrize( + argnames="data_idx, pft_idx, out_idx, exp_shape", + argvalues=[ + pytest.param((0, slice(None)), slice(None), (0, slice(None)), (3,), id="row_1"), + pytest.param((1, slice(None)), slice(None), (1, slice(None)), (3,), id="row_2"), + pytest.param((2, slice(None)), slice(None), (2, slice(None)), (3,), id="row_3"), + pytest.param((3, slice(None)), slice(None), (3, slice(None)), (3,), id="row_4"), + pytest.param((4, slice(None)), slice(None), (4, slice(None)), (3,), id="row_5"), + pytest.param((5, slice(None)), slice(None), (5, slice(None)), (3,), id="row_6"), + pytest.param((slice(None), [0]), [0], (slice(None), [0]), (6, 1), id="col_1"), + pytest.param((slice(None), [1]), [1], (slice(None), [1]), (6, 1), id="col_1"), + pytest.param((slice(None), [2]), [2], (slice(None), [2]), (6, 1), id="col_1"), + pytest.param( + (slice(None), slice(None)), + slice(None), + (slice(None), slice(None)), + (6, 3), + id="array", + ), + pytest.param( + (slice(None), [0]), + slice(None), + (slice(None), slice(None)), + (6, 3), + id="column_broadcast", + ), + ], +) +class TestTModel: + """Test T Model functions. - np.allclose(actual_crown_areas, expected_crown_areas) + A class is used here to pass the same parameterisation of input array shapes to each + of the T model functions. The combination of data_idx and pft_idx slice up the + inputs to provide a wide range of input shape combinations + * each data row against full pft array + * each column against a scalar pft array for a single PFT + * whole array against full pft array -def test_calculate_crown_fractions(): - """Tests happy path for calculation of crown fractions of trees.""" + The last paramaterization broadcasts the whole first column of data against the full + row array of PFT data. This only works for the special case of calculating height + from DBH, which shares a single set of values across all PFTs. All other data input + value then have PFT specific predictions across columns so cannot be broadcast in + this way. + """ - from pyrealm.demography.t_model_functions import calculate_crown_fractions + def test_calculate_heights( + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of heights of tree from diameter.""" + from pyrealm.demography.t_model_functions import calculate_heights - pft_a_hd_values = np.array([116.0, 116.0]) - diameters_at_breast_height = np.array([0.2, 0.6]) - stem_height = np.array([15.194142, 15.166396]) - expected_crown_fractions = np.array([0.65491991, 0.21790799]) - actual_crown_fractions = calculate_crown_fractions( - a_hd=pft_a_hd_values, - dbh=diameters_at_breast_height, - stem_height=stem_height, - ) + pfts, data = rtmodel_data - np.allclose(actual_crown_fractions, expected_crown_fractions) + result = calculate_heights( + h_max=pfts["h_max"][pft_idx], + a_hd=pfts["a_hd"][pft_idx], + dbh=data["diameter"][data_idx], + ) + assert result.shape == exp_shape + assert np.allclose(result, data["height"][out_idx]) -def test_calculate_stem_masses(): - """Tests happy path for calculation of stem masses.""" + def test_calculate_crown_areas( + self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of crown areas of trees.""" - from pyrealm.demography.t_model_functions import calculate_stem_masses + from pyrealm.demography.t_model_functions import calculate_crown_areas - diameters_at_breast_height = np.array([0.2, 0.6]) - stem_height = np.array([15.194142, 15.166396]) - pft_rho_s_values = np.array([200.0, 200.0]) - expected_stem_masses = np.array([47.73380488, 428.8197443]) - actual_stem_masses = calculate_stem_masses( - dbh=diameters_at_breast_height, stem_height=stem_height, rho_s=pft_rho_s_values - ) + if request.node.callspec.id == "column_broadcast": + pytest.skip() - np.allclose(actual_stem_masses, expected_stem_masses) + pfts, data = rtmodel_data + result = calculate_crown_areas( + ca_ratio=pfts["ca_ratio"][pft_idx], + a_hd=pfts["a_hd"][pft_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], + ) -def test_calculate_foliage_masses(): - """Tests happy path for calculation of foliage masses.""" + assert result.shape == exp_shape + assert np.allclose(result, data["crown_area"][out_idx]) - from pyrealm.demography.t_model_functions import calculate_foliage_masses + def test_calculate_crown_fractions( + self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of crown fraction of trees.""" - crown_areas = np.array([0.04114983, 0.1848361]) - pft_lai_values = np.array([1.8, 1.8]) - pft_sla_values = np.array([14.0, 14.0]) - expected_foliage_masses = np.array([0.00529069, 0.02376464]) - actual_foliage_masses = calculate_foliage_masses( - crown_area=crown_areas, lai=pft_lai_values, sla=pft_sla_values - ) + from pyrealm.demography.t_model_functions import calculate_crown_fractions - np.allclose(actual_foliage_masses, expected_foliage_masses) + if request.node.callspec.id == "column_broadcast": + pytest.skip() + pfts, data = rtmodel_data -def test_calculate_sapwood_masses(): - """Tests happy path for calculation of sapwood masses.""" + result = calculate_crown_fractions( + a_hd=pfts["a_hd"][pft_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], + ) - from pyrealm.demography.t_model_functions import calculate_sapwood_masses + assert result.shape == exp_shape + assert np.allclose(result, data["crown_fraction"][out_idx]) - crown_areas = np.array([0.04114983, 0.1848361]) - pft_rho_s_values = np.array([200.0, 200.0]) - stem_height = np.array([15.194142, 15.166396]) - crown_fractions = np.array([0.65491991, 0.21790799]) - pft_ca_ratio_values = [390.43, 390.43] - expected_sapwood_masses = np.array([0.21540173, 1.27954667]) - actual_sapwood_masses = calculate_sapwood_masses( - crown_area=crown_areas, - rho_s=pft_rho_s_values, - stem_height=stem_height, - crown_fraction=crown_fractions, - ca_ratio=pft_ca_ratio_values, - ) + def test_calculate_stem_masses( + self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of stem masses of trees.""" + + from pyrealm.demography.t_model_functions import calculate_stem_masses + + if request.node.callspec.id == "column_broadcast": + pytest.skip() + + pfts, data = rtmodel_data + + result = calculate_stem_masses( + rho_s=pfts["rho_s"][pft_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["mass_stm"][out_idx]) + + def test_calculate_foliage_masses( + self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of stem masses of trees.""" + + from pyrealm.demography.t_model_functions import calculate_foliage_masses + + if request.node.callspec.id == "column_broadcast": + pytest.skip() + + pfts, data = rtmodel_data + + result = calculate_foliage_masses( + lai=pfts["lai"][pft_idx], + sla=pfts["sla"][pft_idx], + crown_area=data["crown_area"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["mass_fol"][out_idx]) + + def test_calculate_sapwood_masses( + self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of stem masses of trees.""" + + from pyrealm.demography.t_model_functions import calculate_sapwood_masses + + if request.node.callspec.id == "column_broadcast": + pytest.skip() + + pfts, data = rtmodel_data + + result = calculate_sapwood_masses( + rho_s=pfts["rho_s"][pft_idx], + ca_ratio=pfts["ca_ratio"][pft_idx], + crown_area=data["crown_area"][data_idx], + stem_height=data["height"][data_idx], + crown_fraction=data["crown_fraction"][data_idx], + ) - np.allclose(actual_sapwood_masses, expected_sapwood_masses) + assert result.shape == exp_shape + assert np.allclose(result, data["mass_swd"][out_idx]) From dc7940b26059dd69d3ea4839db510106d6fd8f75 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 10:38:43 +0100 Subject: [PATCH 124/241] Extending T Model unit test suite to all T model functions --- pyrealm/demography/t_model_functions.py | 24 +- .../unit/demography/test_t_model_functions.py | 247 +++++++++++++++--- 2 files changed, 219 insertions(+), 52 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 2b2ccaf5..2a11a636 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -198,11 +198,11 @@ def calculate_whole_crown_gpp( ) -> NDArray[np.float32]: r"""Calculate whole crown gross primary productivity. - This function calculates individual GPP across the whole crown, given the - individual potential gross primary productivity (GPP) per metre squared - (:math:`P_0`) and crown area (:math:`A_c`), along with the leaf area index - (:math:`L`) and the extinction coefficient (:math:`k`) of the plant functional type - :cite:p:`{Equation 12, }Li:2014bc`. + This function calculates individual GPP across the whole crown, given the individual + potential gross primary productivity (GPP) per metre squared (:math:`P_0`) and crown + area (:math:`A_c`), along with the leaf area index (:math:`L`) and the extinction + coefficient (:math:`k`) of the plant functional type :cite:p:`{Equation 12, + }Li:2014bc`. .. math:: @@ -366,7 +366,7 @@ def calculate_growth_increments( npp: NDArray[np.float32], turnover: NDArray[np.float32], dbh: NDArray[np.float32], - height: NDArray[np.float32], + stem_height: NDArray[np.float32], ) -> tuple[NDArray[np.float32], NDArray[np.float32], NDArray[np.float32]]: r"""Calculate growth increments. @@ -438,15 +438,21 @@ def calculate_growth_increments( npp: Net primary productivity of individuals turnover: Fine root and foliage turnover cost of individuals dbh: Diameter at breast height of individuals - height: Stem height of individuals + stem_height: Stem height of individuals """ # Rates of change in stem and foliar - dWsdt = np.pi / 8 * rho_s * dbh * (a_hd * dbh * (1 - (height / h_max)) + 2 * height) + dWsdt = ( + np.pi + / 8 + * rho_s + * dbh + * (a_hd * dbh * (1 - (stem_height / h_max)) + 2 * stem_height) + ) dWfdt = ( lai * ((np.pi * ca_ratio) / (4 * a_hd)) - * (a_hd * dbh * (1 - height / h_max) + height) + * (a_hd * dbh * (1 - stem_height / h_max) + stem_height) * (1 / sla + zeta) ) diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 97031e86..f05061e6 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -106,6 +106,10 @@ def rtmodel_data(): } ) + # Add foliar respiration rate as 0.1, as this is handled outside of the R + # implementation as a function of GPP. + pft_definitions["resp_f"] = 0.1 + rdata_path = ( resources.files("pyrealm_build_data.t_model") / "rtmodel_unit_testing.csv" ) @@ -145,47 +149,62 @@ def rtmodel_data(): @pytest.mark.parametrize( argnames="data_idx, pft_idx, out_idx, exp_shape", argvalues=[ - pytest.param((0, slice(None)), slice(None), (0, slice(None)), (3,), id="row_1"), - pytest.param((1, slice(None)), slice(None), (1, slice(None)), (3,), id="row_2"), - pytest.param((2, slice(None)), slice(None), (2, slice(None)), (3,), id="row_3"), - pytest.param((3, slice(None)), slice(None), (3, slice(None)), (3,), id="row_4"), - pytest.param((4, slice(None)), slice(None), (4, slice(None)), (3,), id="row_5"), - pytest.param((5, slice(None)), slice(None), (5, slice(None)), (3,), id="row_6"), - pytest.param((slice(None), [0]), [0], (slice(None), [0]), (6, 1), id="col_1"), + pytest.param((0, slice(None)), slice(None), (0, slice(None)), (3,), id="row_0"), + pytest.param((1, slice(None)), slice(None), (1, slice(None)), (3,), id="row_1"), + pytest.param((2, slice(None)), slice(None), (2, slice(None)), (3,), id="row_2"), + pytest.param((3, slice(None)), slice(None), (3, slice(None)), (3,), id="row_3"), + pytest.param((4, slice(None)), slice(None), (4, slice(None)), (3,), id="row_4"), + pytest.param((5, slice(None)), slice(None), (5, slice(None)), (3,), id="row_5"), + pytest.param((slice(None), [0]), [0], (slice(None), [0]), (6, 1), id="col_0"), pytest.param((slice(None), [1]), [1], (slice(None), [1]), (6, 1), id="col_1"), - pytest.param((slice(None), [2]), [2], (slice(None), [2]), (6, 1), id="col_1"), + pytest.param((slice(None), [2]), [2], (slice(None), [2]), (6, 1), id="col_2"), pytest.param( - (slice(None), slice(None)), - slice(None), - (slice(None), slice(None)), + (slice(None), [0]), + [0, 0, 0], + (slice(None), [0, 0, 0]), (6, 3), - id="array", + id="column_broadcast_0", ), pytest.param( - (slice(None), [0]), + (slice(None), [1]), + [1, 1, 1], + (slice(None), [1, 1, 1]), + (6, 3), + id="column_broadcast_1", + ), + pytest.param( + (slice(None), [2]), + [2, 2, 2], + (slice(None), [2, 2, 2]), + (6, 3), + id="column_broadcast_2", + ), + pytest.param( + (slice(None), slice(None)), slice(None), (slice(None), slice(None)), (6, 3), - id="column_broadcast", + id="array", ), ], ) class TestTModel: """Test T Model functions. - A class is used here to pass the same parameterisation of input array shapes to each + A class is used here to pass a shared parameterisation of input array shapes to each of the T model functions. The combination of data_idx and pft_idx slice up the inputs to provide a wide range of input shape combinations - * each data row against full pft array - * each column against a scalar pft array for a single PFT - * whole array against full pft array + * each data row against full pft array: (3,) + (3,) -> (3,) + * each column against a scalar pft array for a single PFT: (6,1) + (1,) -> (6,1) + * each column broadcast against a row array of three PFTs: (6,1) + (3,) -> (6,3) + * whole array against full pft array: (6,3) + (3,) -> (6,3) - The last paramaterization broadcasts the whole first column of data against the full - row array of PFT data. This only works for the special case of calculating height - from DBH, which shares a single set of values across all PFTs. All other data input - value then have PFT specific predictions across columns so cannot be broadcast in - this way. + The column broadcast has an added complexity, which is that the data values in the + columns are PFT specific predictions (apart from the initial stem diameters), so do + not match if a single column is broadcast across PFTs. To get around this and test + the broadcasting, these tests duplicate a single PFT trait to (3,) and duplicate the + expected outputs to repeat the single column expectations across (6, 3) """ def test_calculate_heights( @@ -206,15 +225,12 @@ def test_calculate_heights( assert np.allclose(result, data["height"][out_idx]) def test_calculate_crown_areas( - self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape ): """Tests calculation of crown areas of trees.""" from pyrealm.demography.t_model_functions import calculate_crown_areas - if request.node.callspec.id == "column_broadcast": - pytest.skip() - pfts, data = rtmodel_data result = calculate_crown_areas( @@ -228,15 +244,12 @@ def test_calculate_crown_areas( assert np.allclose(result, data["crown_area"][out_idx]) def test_calculate_crown_fractions( - self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape ): """Tests calculation of crown fraction of trees.""" from pyrealm.demography.t_model_functions import calculate_crown_fractions - if request.node.callspec.id == "column_broadcast": - pytest.skip() - pfts, data = rtmodel_data result = calculate_crown_fractions( @@ -249,15 +262,12 @@ def test_calculate_crown_fractions( assert np.allclose(result, data["crown_fraction"][out_idx]) def test_calculate_stem_masses( - self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_stem_masses - if request.node.callspec.id == "column_broadcast": - pytest.skip() - pfts, data = rtmodel_data result = calculate_stem_masses( @@ -270,15 +280,12 @@ def test_calculate_stem_masses( assert np.allclose(result, data["mass_stm"][out_idx]) def test_calculate_foliage_masses( - self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_foliage_masses - if request.node.callspec.id == "column_broadcast": - pytest.skip() - pfts, data = rtmodel_data result = calculate_foliage_masses( @@ -291,15 +298,12 @@ def test_calculate_foliage_masses( assert np.allclose(result, data["mass_fol"][out_idx]) def test_calculate_sapwood_masses( - self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_sapwood_masses - if request.node.callspec.id == "column_broadcast": - pytest.skip() - pfts, data = rtmodel_data result = calculate_sapwood_masses( @@ -312,3 +316,160 @@ def test_calculate_sapwood_masses( assert result.shape == exp_shape assert np.allclose(result, data["mass_swd"][out_idx]) + + def test_calculate_whole_crown_gpp( + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of whole crown GPP.""" + + from pyrealm.demography.t_model_functions import calculate_whole_crown_gpp + + pfts, data = rtmodel_data + + result = calculate_whole_crown_gpp( + lai=pfts["lai"][pft_idx], + par_ext=pfts["par_ext"][pft_idx], + crown_area=data["crown_area"][data_idx], + potential_gpp=data["potential_gpp"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["crown_gpp"][out_idx]) + + def test_calculate_sapwood_respiration( + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of sapwood respiration.""" + + from pyrealm.demography.t_model_functions import calculate_sapwood_respiration + + pfts, data = rtmodel_data + + result = calculate_sapwood_respiration( + resp_s=pfts["resp_s"][pft_idx], + sapwood_mass=data["mass_swd"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["resp_swd"][out_idx]) + + def test_calculate_foliar_respiration( + self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of foliar respiration. + + NOTE - this test is extremely circular, because the R implementation does not + apply this in the same way. This is mostly just to validate array shape and + broadcasting + """ + + from pyrealm.demography.t_model_functions import calculate_foliar_respiration + + pfts, data = rtmodel_data + + result = calculate_foliar_respiration( + resp_f=pfts["resp_f"][pft_idx], + whole_crown_gpp=data["crown_gpp"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose( + result, data["crown_gpp"][data_idx] * pfts["resp_f"][pft_idx] + ) + + def test_calculate_fine_root_respiration( + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of fine root respiration.""" + + from pyrealm.demography.t_model_functions import calculate_fine_root_respiration + + pfts, data = rtmodel_data + + result = calculate_fine_root_respiration( + zeta=pfts["zeta"][pft_idx], + sla=pfts["sla"][pft_idx], + resp_r=pfts["resp_r"][pft_idx], + foliage_mass=data["mass_fol"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["resp_frt"][out_idx]) + + def test_calculate_net_primary_productivity( + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of net primary productivity.""" + + from pyrealm.demography.t_model_functions import ( + calculate_net_primary_productivity, + ) + + pfts, data = rtmodel_data + + result = calculate_net_primary_productivity( + yld=pfts["yld"][pft_idx], + whole_crown_gpp=data["crown_gpp"][data_idx], + foliar_respiration=0, # Not included here in the R implementation + fine_root_respiration=data["resp_frt"][data_idx], + sapwood_respiration=data["resp_swd"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["NPP"][out_idx]) + + def test_calculate_foliage_and_fine_root_turnover( + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of foliage and fine root turnover.""" + + from pyrealm.demography.t_model_functions import ( + calculate_foliage_and_fine_root_turnover, + ) + + pfts, data = rtmodel_data + + result = calculate_foliage_and_fine_root_turnover( + sla=pfts["sla"][pft_idx], + zeta=pfts["zeta"][pft_idx], + tau_f=pfts["tau_f"][pft_idx], + tau_r=pfts["tau_r"][pft_idx], + foliage_mass=data["mass_fol"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["turnover"][out_idx]) + + def test_calculate_calculate_growth_increments( + self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + ): + """Tests calculation of growth increments.""" + + from pyrealm.demography.t_model_functions import ( + calculate_growth_increments, + ) + + pfts, data = rtmodel_data + + delta_d, delta_mass_stm, delta_mass_frt = calculate_growth_increments( + rho_s=pfts["rho_s"][pft_idx], + a_hd=pfts["a_hd"][pft_idx], + h_max=pfts["h_max"][pft_idx], + lai=pfts["lai"][pft_idx], + ca_ratio=pfts["ca_ratio"][pft_idx], + sla=pfts["sla"][pft_idx], + zeta=pfts["zeta"][pft_idx], + npp=data["NPP"][data_idx], + turnover=data["turnover"][data_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], + ) + + assert delta_d.shape == exp_shape + assert np.allclose(delta_d, data["delta_d"][out_idx]) + + assert delta_mass_stm.shape == exp_shape + assert np.allclose(delta_mass_stm, data["delta_mass_stm"][out_idx]) + + assert delta_mass_frt.shape == exp_shape + assert np.allclose(delta_mass_frt, data["delta_mass_frt"][out_idx]) From 4b8a53337cd738452600d3d8a80e12918a50f2aa Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 11:42:40 +0100 Subject: [PATCH 125/241] Adding optional input validation to T model functions --- pyrealm/demography/t_model_functions.py | 93 +++- .../unit/demography/test_t_model_functions.py | 448 ++++++++++++------ 2 files changed, 396 insertions(+), 145 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 2a11a636..7cbf8ed5 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -40,7 +40,10 @@ def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> def calculate_heights( - h_max: NDArray[np.float32], a_hd: NDArray[np.float32], dbh: NDArray[np.float32] + h_max: NDArray[np.float32], + a_hd: NDArray[np.float32], + dbh: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate tree height under the T Model. @@ -57,8 +60,12 @@ def calculate_heights( h_max: Maximum height of the PFT a_hd: Initial slope of the height/diameter relationship of the PFT dbh: Diameter at breast height of individuals + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args(pft_args=[h_max, a_hd], size_args=[dbh]) + return h_max * (1 - np.exp(-a_hd * dbh / h_max)) @@ -67,6 +74,7 @@ def calculate_crown_areas( a_hd: NDArray[np.float32], dbh: NDArray[np.float32], stem_height: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate tree crown area under the T Model. @@ -85,8 +93,12 @@ def calculate_crown_areas( a_hd: Initial slope of the height/diameter relationship of the PFT dbh: Diameter at breast height of individuals stem_height: Stem height of individuals + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args(pft_args=[ca_ratio, a_hd], size_args=[dbh, stem_height]) + return ((np.pi * ca_ratio) / (4 * a_hd)) * dbh * stem_height @@ -94,6 +106,7 @@ def calculate_crown_fractions( a_hd: NDArray[np.float32], stem_height: NDArray[np.float32], dbh: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate tree crown fraction under the T Model. @@ -110,7 +123,10 @@ def calculate_crown_fractions( a_hd: Initial slope of the height/diameter relationship of the PFT stem_height: Stem height of individuals dbh: Diameter at breast height of individuals + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args(pft_args=[a_hd], size_args=[dbh, stem_height]) return stem_height / (a_hd * dbh) @@ -119,6 +135,7 @@ def calculate_stem_masses( rho_s: NDArray[np.float32], stem_height: NDArray[np.float32], dbh: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate stem mass under the T Model. @@ -134,13 +151,19 @@ def calculate_stem_masses( rho_s: Wood density of the PFT stem_height: Stem height of individuals dbh: Diameter at breast height of individuals + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args(pft_args=[rho_s], size_args=[dbh, stem_height]) return (np.pi / 8) * rho_s * (dbh**2) * stem_height def calculate_foliage_masses( - sla: NDArray[np.float32], lai: NDArray[np.float32], crown_area: NDArray[np.float32] + sla: NDArray[np.float32], + lai: NDArray[np.float32], + crown_area: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate foliage mass under the T Model. @@ -156,7 +179,10 @@ def calculate_foliage_masses( sla: Specific leaf area of the PFT lai: Leaf area index of the PFT crown_area: Crown area of individuals + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args(pft_args=[sla, lai], size_args=[crown_area]) return crown_area * lai * (1 / sla) @@ -167,6 +193,7 @@ def calculate_sapwood_masses( stem_height: NDArray[np.float32], crown_area: NDArray[np.float32], crown_fraction: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate sapwood mass under the T Model. @@ -185,7 +212,13 @@ def calculate_sapwood_masses( stem_height: Stem height of individuals crown_area: Crown area of individuals crown_fraction: Crown fraction of individuals + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args( + pft_args=[rho_s, ca_ratio], + size_args=[stem_height, crown_area, crown_fraction], + ) return crown_area * rho_s * stem_height * (1 - crown_fraction / 2) / ca_ratio @@ -195,6 +228,7 @@ def calculate_whole_crown_gpp( crown_area: NDArray[np.float32], par_ext: NDArray[np.float32], lai: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate whole crown gross primary productivity. @@ -209,17 +243,24 @@ def calculate_whole_crown_gpp( P = P_0 A_c (1 - e^{-kL}) Args: + lai: The leaf area index + par_ext: The extinction coefficient potential_gpp: Potential GPP per metre squared crown_area: The crown area in metres squared - par_ext: The extinction coefficient - lai: The leaf area index + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args( + pft_args=[lai, par_ext], size_args=[potential_gpp, crown_area] + ) return potential_gpp * crown_area * (1 - np.exp(-(par_ext * lai))) def calculate_sapwood_respiration( - resp_s: NDArray[np.float32], sapwood_mass: NDArray[np.float32] + resp_s: NDArray[np.float32], + sapwood_mass: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate sapwood respiration. @@ -233,12 +274,18 @@ def calculate_sapwood_respiration( Args: resp_s: The sapwood respiration rate sapwood_mass: The individual sapwood mass + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args(pft_args=[resp_s], size_args=[sapwood_mass]) + return sapwood_mass * resp_s def calculate_foliar_respiration( - resp_f: NDArray[np.float32], whole_crown_gpp: NDArray[np.float32] + resp_f: NDArray[np.float32], + whole_crown_gpp: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate foliar respiration. @@ -254,7 +301,11 @@ def calculate_foliar_respiration( Args: resp_f: The foliar respiration rate whole_crown_gpp: The individual whole crown GPP. + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args(pft_args=[resp_f], size_args=[whole_crown_gpp]) + return whole_crown_gpp * resp_f @@ -263,6 +314,7 @@ def calculate_fine_root_respiration( sla: NDArray[np.float32], resp_r: NDArray[np.float32], foliage_mass: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate foliar respiration. @@ -279,7 +331,10 @@ def calculate_fine_root_respiration( sla: The specific leaf area of the PFT. resp_r: The respiration rate of fine roots of the PFT. foliage_mass: The individual foliage mass. + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args(pft_args=[zeta, sla, resp_r], size_args=[foliage_mass]) return zeta * sla * foliage_mass * resp_r @@ -290,6 +345,7 @@ def calculate_net_primary_productivity( foliar_respiration: NDArray[np.float32], fine_root_respiration: NDArray[np.float32], sapwood_respiration: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate net primary productivity. @@ -314,7 +370,18 @@ def calculate_net_primary_productivity( foliar_respiration: The total foliar respiration. fine_root_respiration: The total fine root respiration sapwood_respiration: The total sapwood respiration. + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args( + pft_args=[yld], + size_args=[ + whole_crown_gpp, + foliar_respiration, + fine_root_respiration, + sapwood_respiration, + ], + ) return yld * ( whole_crown_gpp @@ -330,6 +397,7 @@ def calculate_foliage_and_fine_root_turnover( tau_f: NDArray[np.float32], tau_r: NDArray[np.float32], foliage_mass: NDArray[np.float32], + validate: bool = True, ) -> NDArray[np.float32]: r"""Calculate turnover costs. @@ -350,7 +418,12 @@ def calculate_foliage_and_fine_root_turnover( tau_f: The turnover time of foliage tau_r: The turnover time of fine roots foliage_mass: The foliage mass + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args( + pft_args=[sla, zeta, tau_f, tau_r], size_args=[foliage_mass] + ) return foliage_mass * ((1 / tau_f) + (sla * zeta / tau_r)) @@ -367,6 +440,7 @@ def calculate_growth_increments( turnover: NDArray[np.float32], dbh: NDArray[np.float32], stem_height: NDArray[np.float32], + validate: bool = True, ) -> tuple[NDArray[np.float32], NDArray[np.float32], NDArray[np.float32]]: r"""Calculate growth increments. @@ -439,7 +513,14 @@ def calculate_growth_increments( turnover: Fine root and foliage turnover cost of individuals dbh: Diameter at breast height of individuals stem_height: Stem height of individuals + validate: Boolean flag to suppress argument validation """ + if validate: + _validate_t_model_args( + pft_args=[rho_s, a_hd, h_max, lai, ca_ratio, sla, zeta], + size_args=[npp, turnover, dbh, stem_height], + ) + # Rates of change in stem and foliar dWsdt = ( np.pi diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index f05061e6..7137c652 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -147,20 +147,94 @@ def rtmodel_data(): @pytest.mark.parametrize( - argnames="data_idx, pft_idx, out_idx, exp_shape", + argnames="data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape", argvalues=[ - pytest.param((0, slice(None)), slice(None), (0, slice(None)), (3,), id="row_0"), - pytest.param((1, slice(None)), slice(None), (1, slice(None)), (3,), id="row_1"), - pytest.param((2, slice(None)), slice(None), (2, slice(None)), (3,), id="row_2"), - pytest.param((3, slice(None)), slice(None), (3, slice(None)), (3,), id="row_3"), - pytest.param((4, slice(None)), slice(None), (4, slice(None)), (3,), id="row_4"), - pytest.param((5, slice(None)), slice(None), (5, slice(None)), (3,), id="row_5"), - pytest.param((slice(None), [0]), [0], (slice(None), [0]), (6, 1), id="col_0"), - pytest.param((slice(None), [1]), [1], (slice(None), [1]), (6, 1), id="col_1"), - pytest.param((slice(None), [2]), [2], (slice(None), [2]), (6, 1), id="col_2"), + pytest.param( + (0, slice(None)), + slice(None), + does_not_raise(), + None, + (0, slice(None)), + (3,), + id="row_0", + ), + pytest.param( + (1, slice(None)), + slice(None), + does_not_raise(), + None, + (1, slice(None)), + (3,), + id="row_1", + ), + pytest.param( + (2, slice(None)), + slice(None), + does_not_raise(), + None, + (2, slice(None)), + (3,), + id="row_2", + ), + pytest.param( + (3, slice(None)), + slice(None), + does_not_raise(), + None, + (3, slice(None)), + (3,), + id="row_3", + ), + pytest.param( + (4, slice(None)), + slice(None), + does_not_raise(), + None, + (4, slice(None)), + (3,), + id="row_4", + ), + pytest.param( + (5, slice(None)), + slice(None), + does_not_raise(), + None, + (5, slice(None)), + (3,), + id="row_5", + ), + pytest.param( + (slice(None), [0]), + [0], + does_not_raise(), + None, + (slice(None), [0]), + (6, 1), + id="col_0", + ), + pytest.param( + (slice(None), [1]), + [1], + does_not_raise(), + None, + (slice(None), [1]), + (6, 1), + id="col_1", + ), + pytest.param( + (slice(None), [2]), + [2], + does_not_raise(), + None, + (slice(None), [2]), + (6, 1), + id="col_2", + ), pytest.param( (slice(None), [0]), [0, 0, 0], + does_not_raise(), + None, (slice(None), [0, 0, 0]), (6, 3), id="column_broadcast_0", @@ -168,6 +242,8 @@ def rtmodel_data(): pytest.param( (slice(None), [1]), [1, 1, 1], + does_not_raise(), + None, (slice(None), [1, 1, 1]), (6, 3), id="column_broadcast_1", @@ -175,6 +251,8 @@ def rtmodel_data(): pytest.param( (slice(None), [2]), [2, 2, 2], + does_not_raise(), + None, (slice(None), [2, 2, 2]), (6, 3), id="column_broadcast_2", @@ -182,10 +260,39 @@ def rtmodel_data(): pytest.param( (slice(None), slice(None)), slice(None), + does_not_raise(), + None, (slice(None), slice(None)), (6, 3), id="array", ), + pytest.param( + (0, slice(None)), + [0, 1, 2, 0], + pytest.raises(ValueError), + "PFT and size inputs to T model function are not compatible.", + None, + None, + id="fail_PFT_too_long", + ), + pytest.param( + (0, slice(None)), + np.newaxis, + pytest.raises(ValueError), + "T model functions only accept 1D arrays of PFT trait values", + None, + None, + id="fail_2D_PFT", + ), + pytest.param( + ([0, 1, 2, 0], 0), + slice(None), + pytest.raises(ValueError), + "PFT and size inputs to T model function are not compatible.", + None, + None, + id="fail_row_size_data_too_long", + ), ], ) class TestTModel: @@ -204,28 +311,35 @@ class TestTModel: columns are PFT specific predictions (apart from the initial stem diameters), so do not match if a single column is broadcast across PFTs. To get around this and test the broadcasting, these tests duplicate a single PFT trait to (3,) and duplicate the - expected outputs to repeat the single column expectations across (6, 3) + expected outputs to repeat the single column expectations across (6, 3). + + The parameterization also includes three cases that check the failure modes for + inputs. """ def test_calculate_heights( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of heights of tree from diameter.""" from pyrealm.demography.t_model_functions import calculate_heights pfts, data = rtmodel_data - result = calculate_heights( - h_max=pfts["h_max"][pft_idx], - a_hd=pfts["a_hd"][pft_idx], - dbh=data["diameter"][data_idx], - ) + with outcome as excep: + result = calculate_heights( + h_max=pfts["h_max"][pft_idx], + a_hd=pfts["a_hd"][pft_idx], + dbh=data["diameter"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["height"][out_idx]) + return - assert result.shape == exp_shape - assert np.allclose(result, data["height"][out_idx]) + assert str(excep.value).startswith(excep_msg) def test_calculate_crown_areas( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of crown areas of trees.""" @@ -233,18 +347,22 @@ def test_calculate_crown_areas( pfts, data = rtmodel_data - result = calculate_crown_areas( - ca_ratio=pfts["ca_ratio"][pft_idx], - a_hd=pfts["a_hd"][pft_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], - ) + with outcome as excep: + result = calculate_crown_areas( + ca_ratio=pfts["ca_ratio"][pft_idx], + a_hd=pfts["a_hd"][pft_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], + ) - assert result.shape == exp_shape - assert np.allclose(result, data["crown_area"][out_idx]) + assert result.shape == exp_shape + assert np.allclose(result, data["crown_area"][out_idx]) + return + + assert str(excep.value).startswith(excep_msg) def test_calculate_crown_fractions( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of crown fraction of trees.""" @@ -252,17 +370,21 @@ def test_calculate_crown_fractions( pfts, data = rtmodel_data - result = calculate_crown_fractions( - a_hd=pfts["a_hd"][pft_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], - ) + with outcome as excep: + result = calculate_crown_fractions( + a_hd=pfts["a_hd"][pft_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], + ) - assert result.shape == exp_shape - assert np.allclose(result, data["crown_fraction"][out_idx]) + assert result.shape == exp_shape + assert np.allclose(result, data["crown_fraction"][out_idx]) + return + + assert str(excep.value).startswith(excep_msg) def test_calculate_stem_masses( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of stem masses of trees.""" @@ -270,17 +392,21 @@ def test_calculate_stem_masses( pfts, data = rtmodel_data - result = calculate_stem_masses( - rho_s=pfts["rho_s"][pft_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], - ) + with outcome as excep: + result = calculate_stem_masses( + rho_s=pfts["rho_s"][pft_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], + ) - assert result.shape == exp_shape - assert np.allclose(result, data["mass_stm"][out_idx]) + assert result.shape == exp_shape + assert np.allclose(result, data["mass_stm"][out_idx]) + return + + assert str(excep.value).startswith(excep_msg) def test_calculate_foliage_masses( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of stem masses of trees.""" @@ -288,17 +414,21 @@ def test_calculate_foliage_masses( pfts, data = rtmodel_data - result = calculate_foliage_masses( - lai=pfts["lai"][pft_idx], - sla=pfts["sla"][pft_idx], - crown_area=data["crown_area"][data_idx], - ) + with outcome as excep: + result = calculate_foliage_masses( + lai=pfts["lai"][pft_idx], + sla=pfts["sla"][pft_idx], + crown_area=data["crown_area"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["mass_fol"][out_idx]) + return - assert result.shape == exp_shape - assert np.allclose(result, data["mass_fol"][out_idx]) + assert str(excep.value).startswith(excep_msg) def test_calculate_sapwood_masses( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of stem masses of trees.""" @@ -306,19 +436,23 @@ def test_calculate_sapwood_masses( pfts, data = rtmodel_data - result = calculate_sapwood_masses( - rho_s=pfts["rho_s"][pft_idx], - ca_ratio=pfts["ca_ratio"][pft_idx], - crown_area=data["crown_area"][data_idx], - stem_height=data["height"][data_idx], - crown_fraction=data["crown_fraction"][data_idx], - ) + with outcome as excep: + result = calculate_sapwood_masses( + rho_s=pfts["rho_s"][pft_idx], + ca_ratio=pfts["ca_ratio"][pft_idx], + crown_area=data["crown_area"][data_idx], + stem_height=data["height"][data_idx], + crown_fraction=data["crown_fraction"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["mass_swd"][out_idx]) + return - assert result.shape == exp_shape - assert np.allclose(result, data["mass_swd"][out_idx]) + assert str(excep.value).startswith(excep_msg) def test_calculate_whole_crown_gpp( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of whole crown GPP.""" @@ -326,18 +460,22 @@ def test_calculate_whole_crown_gpp( pfts, data = rtmodel_data - result = calculate_whole_crown_gpp( - lai=pfts["lai"][pft_idx], - par_ext=pfts["par_ext"][pft_idx], - crown_area=data["crown_area"][data_idx], - potential_gpp=data["potential_gpp"][data_idx], - ) + with outcome as excep: + result = calculate_whole_crown_gpp( + lai=pfts["lai"][pft_idx], + par_ext=pfts["par_ext"][pft_idx], + crown_area=data["crown_area"][data_idx], + potential_gpp=data["potential_gpp"][data_idx], + ) - assert result.shape == exp_shape - assert np.allclose(result, data["crown_gpp"][out_idx]) + assert result.shape == exp_shape + assert np.allclose(result, data["crown_gpp"][out_idx]) + return + + assert str(excep.value).startswith(excep_msg) def test_calculate_sapwood_respiration( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of sapwood respiration.""" @@ -345,16 +483,28 @@ def test_calculate_sapwood_respiration( pfts, data = rtmodel_data - result = calculate_sapwood_respiration( - resp_s=pfts["resp_s"][pft_idx], - sapwood_mass=data["mass_swd"][data_idx], - ) + with outcome as excep: + result = calculate_sapwood_respiration( + resp_s=pfts["resp_s"][pft_idx], + sapwood_mass=data["mass_swd"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["resp_swd"][out_idx]) + return - assert result.shape == exp_shape - assert np.allclose(result, data["resp_swd"][out_idx]) + assert str(excep.value).startswith(excep_msg) def test_calculate_foliar_respiration( - self, request, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, + request, + rtmodel_data, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of foliar respiration. @@ -367,18 +517,22 @@ def test_calculate_foliar_respiration( pfts, data = rtmodel_data - result = calculate_foliar_respiration( - resp_f=pfts["resp_f"][pft_idx], - whole_crown_gpp=data["crown_gpp"][data_idx], - ) + with outcome as excep: + result = calculate_foliar_respiration( + resp_f=pfts["resp_f"][pft_idx], + whole_crown_gpp=data["crown_gpp"][data_idx], + ) - assert result.shape == exp_shape - assert np.allclose( - result, data["crown_gpp"][data_idx] * pfts["resp_f"][pft_idx] - ) + assert result.shape == exp_shape + assert np.allclose( + result, data["crown_gpp"][data_idx] * pfts["resp_f"][pft_idx] + ) + return + + assert str(excep.value).startswith(excep_msg) def test_calculate_fine_root_respiration( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of fine root respiration.""" @@ -386,18 +540,22 @@ def test_calculate_fine_root_respiration( pfts, data = rtmodel_data - result = calculate_fine_root_respiration( - zeta=pfts["zeta"][pft_idx], - sla=pfts["sla"][pft_idx], - resp_r=pfts["resp_r"][pft_idx], - foliage_mass=data["mass_fol"][data_idx], - ) + with outcome as excep: + result = calculate_fine_root_respiration( + zeta=pfts["zeta"][pft_idx], + sla=pfts["sla"][pft_idx], + resp_r=pfts["resp_r"][pft_idx], + foliage_mass=data["mass_fol"][data_idx], + ) - assert result.shape == exp_shape - assert np.allclose(result, data["resp_frt"][out_idx]) + assert result.shape == exp_shape + assert np.allclose(result, data["resp_frt"][out_idx]) + return + + assert str(excep.value).startswith(excep_msg) def test_calculate_net_primary_productivity( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of net primary productivity.""" @@ -407,19 +565,23 @@ def test_calculate_net_primary_productivity( pfts, data = rtmodel_data - result = calculate_net_primary_productivity( - yld=pfts["yld"][pft_idx], - whole_crown_gpp=data["crown_gpp"][data_idx], - foliar_respiration=0, # Not included here in the R implementation - fine_root_respiration=data["resp_frt"][data_idx], - sapwood_respiration=data["resp_swd"][data_idx], - ) + with outcome as excep: + result = calculate_net_primary_productivity( + yld=pfts["yld"][pft_idx], + whole_crown_gpp=data["crown_gpp"][data_idx], + foliar_respiration=0, # Not included here in the R implementation + fine_root_respiration=data["resp_frt"][data_idx], + sapwood_respiration=data["resp_swd"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["NPP"][out_idx]) + return - assert result.shape == exp_shape - assert np.allclose(result, data["NPP"][out_idx]) + assert str(excep.value).startswith(excep_msg) def test_calculate_foliage_and_fine_root_turnover( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of foliage and fine root turnover.""" @@ -429,19 +591,23 @@ def test_calculate_foliage_and_fine_root_turnover( pfts, data = rtmodel_data - result = calculate_foliage_and_fine_root_turnover( - sla=pfts["sla"][pft_idx], - zeta=pfts["zeta"][pft_idx], - tau_f=pfts["tau_f"][pft_idx], - tau_r=pfts["tau_r"][pft_idx], - foliage_mass=data["mass_fol"][data_idx], - ) + with outcome as excep: + result = calculate_foliage_and_fine_root_turnover( + sla=pfts["sla"][pft_idx], + zeta=pfts["zeta"][pft_idx], + tau_f=pfts["tau_f"][pft_idx], + tau_r=pfts["tau_r"][pft_idx], + foliage_mass=data["mass_fol"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, data["turnover"][out_idx]) + return - assert result.shape == exp_shape - assert np.allclose(result, data["turnover"][out_idx]) + assert str(excep.value).startswith(excep_msg) def test_calculate_calculate_growth_increments( - self, rtmodel_data, data_idx, pft_idx, out_idx, exp_shape + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of growth increments.""" @@ -451,25 +617,29 @@ def test_calculate_calculate_growth_increments( pfts, data = rtmodel_data - delta_d, delta_mass_stm, delta_mass_frt = calculate_growth_increments( - rho_s=pfts["rho_s"][pft_idx], - a_hd=pfts["a_hd"][pft_idx], - h_max=pfts["h_max"][pft_idx], - lai=pfts["lai"][pft_idx], - ca_ratio=pfts["ca_ratio"][pft_idx], - sla=pfts["sla"][pft_idx], - zeta=pfts["zeta"][pft_idx], - npp=data["NPP"][data_idx], - turnover=data["turnover"][data_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], - ) - - assert delta_d.shape == exp_shape - assert np.allclose(delta_d, data["delta_d"][out_idx]) - - assert delta_mass_stm.shape == exp_shape - assert np.allclose(delta_mass_stm, data["delta_mass_stm"][out_idx]) - - assert delta_mass_frt.shape == exp_shape - assert np.allclose(delta_mass_frt, data["delta_mass_frt"][out_idx]) + with outcome as excep: + delta_d, delta_mass_stm, delta_mass_frt = calculate_growth_increments( + rho_s=pfts["rho_s"][pft_idx], + a_hd=pfts["a_hd"][pft_idx], + h_max=pfts["h_max"][pft_idx], + lai=pfts["lai"][pft_idx], + ca_ratio=pfts["ca_ratio"][pft_idx], + sla=pfts["sla"][pft_idx], + zeta=pfts["zeta"][pft_idx], + npp=data["NPP"][data_idx], + turnover=data["turnover"][data_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], + ) + + assert delta_d.shape == exp_shape + assert np.allclose(delta_d, data["delta_d"][out_idx]) + + assert delta_mass_stm.shape == exp_shape + assert np.allclose(delta_mass_stm, data["delta_mass_stm"][out_idx]) + + assert delta_mass_frt.shape == exp_shape + assert np.allclose(delta_mass_frt, data["delta_mass_frt"][out_idx]) + return + + assert str(excep.value).startswith(excep_msg) From 527c9cbb14e51a31946b5d768083c5d59fc28dcf Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 12:44:31 +0100 Subject: [PATCH 126/241] Updating regression tests --- pyrealm/demography/t_model_functions.py | 17 +++- .../test_t_model_functions_against_rtmodel.py | 84 +++++++++++-------- 2 files changed, 60 insertions(+), 41 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 7cbf8ed5..a2575fdd 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -16,23 +16,32 @@ def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> Args: pft_args: A list of row arrays representing trait values - size_args: A list of arrays representing stem sizes at which to evaluate - functions. + size_args: A list of arrays representing points in the stem size and growth + allometries at which to evaluate functions. """ + # Check PFT inputs all line up and are 1D (row) arrays try: pft_args_shape = check_input_shapes(*pft_args) except ValueError: raise ValueError("PFT trait values are not of equal length") + if len(pft_args_shape) > 1: + raise ValueError("T model functions only accept 1D arrays of PFT trait values") + + # Check size and growth inputs try: size_args_shape = check_input_shapes(*size_args) except ValueError: raise ValueError("Size arrays are not of equal length") - if len(pft_args_shape) > 1: - raise ValueError("T model functions only accept 1D arrays of PFT trait values") + # Explicitly check to see if the size arrays are row arrays and - if so - enforce + # that they are the same length.abs + + if len(size_args_shape) == 1 and not pft_args_shape == size_args_shape: + raise ValueError("Trait and size inputs are row arrays and unequal length.") + # Otherwise use np.broadcast_shapes to catch issues try: _ = np.broadcast_shapes(pft_args_shape, size_args_shape) except ValueError: diff --git a/tests/regression/demography/test_t_model_functions_against_rtmodel.py b/tests/regression/demography/test_t_model_functions_against_rtmodel.py index c16a76dd..d66550e3 100644 --- a/tests/regression/demography/test_t_model_functions_against_rtmodel.py +++ b/tests/regression/demography/test_t_model_functions_against_rtmodel.py @@ -7,6 +7,7 @@ from importlib import resources +import numpy as np import pandas as pd import pytest from numpy.testing import assert_array_almost_equal @@ -23,7 +24,6 @@ def rvalues(): different plant functional type definitions. The PFT definitions are loaded first and then the output file associated with each PFT is loaded. """ - from pyrealm.demography.flora import PlantFunctionalType # Load the PFT definitions and rename to pyrealm attributes pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" @@ -53,15 +53,21 @@ def rvalues(): return_value = [] # Loop over the PFT definitions - for pft_args in pft_definitions: - # Record the starting DBH and create the PFT instances - dbh_init = pft_args.pop("d") - pft = PlantFunctionalType(**pft_args) + for pft in pft_definitions: + # Record the starting DBH and name + dbh_init = pft.pop("d") + pft_name = pft.pop("name") + + # Add foliar respiration + pft["resp_f"] = 0.1 + + # Convert dict values to row arrays + pft = {k: np.array([v]) for k, v in pft.items()} # Load the appropriate output file and then remap the field names datapath = ( resources.files("pyrealm_build_data.t_model") - / f"rtmodel_output_{pft.name}.csv" + / f"rtmodel_output_{pft_name}.csv" ) data = pd.read_csv(datapath) @@ -95,6 +101,10 @@ def rvalues(): # will need to be proportionally scaled up to make them match, but this is not # true for _all_ tests so the values here are left untouched. + # Convert data to column arrays + data = data.to_dict(orient="list") + data = {k: np.array(v)[:, None] for k, v in data.items()} + # Add a tuple of the inputs and outputs to the return list. return_value.append((pft, dbh_init, data)) @@ -108,7 +118,7 @@ def test_calculate_heights(rvalues): for pft, _, data in rvalues: actual_heights = calculate_heights( - h_max=pft.h_max, a_hd=pft.a_hd, dbh=data["diameter"] + h_max=pft["h_max"], a_hd=pft["a_hd"], dbh=data["diameter"] ) assert_array_almost_equal(actual_heights, data["height"], decimal=8) @@ -120,8 +130,8 @@ def test_calculate_crown_areas(rvalues): for pft, _, data in rvalues: actual_crown_areas = calculate_crown_areas( - ca_ratio=pft.ca_ratio, - a_hd=pft.a_hd, + ca_ratio=pft["ca_ratio"], + a_hd=pft["a_hd"], dbh=data["diameter"], stem_height=data["height"], ) @@ -136,7 +146,7 @@ def test_calculate_crown_fractions(rvalues): for pft, _, data in rvalues: actual_crown_fractions = calculate_crown_fractions( - a_hd=pft.a_hd, + a_hd=pft["a_hd"], dbh=data["diameter"], stem_height=data["height"], ) @@ -154,7 +164,7 @@ def test_calculate_stem_masses(rvalues): actual_stem_masses = calculate_stem_masses( dbh=data["diameter"], stem_height=data["height"], - rho_s=pft.rho_s, + rho_s=pft["rho_s"], ) assert_array_almost_equal(actual_stem_masses, data["mass_stm"], decimal=8) @@ -166,7 +176,7 @@ def test_calculate_foliage_masses(rvalues): for pft, _, data in rvalues: actual_foliage_masses = calculate_foliage_masses( - crown_area=data["crown_area"], lai=pft.lai, sla=pft.sla + crown_area=data["crown_area"], lai=pft["lai"], sla=pft["sla"] ) assert_array_almost_equal(actual_foliage_masses, data["mass_fol"], decimal=8) @@ -181,8 +191,8 @@ def test_calculate_sapwood_masses(rvalues): crown_area=data["crown_area"], stem_height=data["height"], crown_fraction=data["crown_fraction"], - ca_ratio=pft.ca_ratio, - rho_s=pft.rho_s, + ca_ratio=pft["ca_ratio"], + rho_s=pft["rho_s"], ) assert_array_almost_equal(actual_sapwood_masses, data["mass_swd"], decimal=8) @@ -200,8 +210,8 @@ def test_calculate_whole_crown_gpp(rvalues): actual_whole_crown_gpp = calculate_whole_crown_gpp( potential_gpp=data["potential_gpp"], crown_area=data["crown_area"], - par_ext=pft.par_ext, - lai=pft.lai, + par_ext=pft["par_ext"], + lai=pft["lai"], ) assert_array_almost_equal(actual_whole_crown_gpp, data["crown_gpp"], decimal=8) @@ -214,7 +224,7 @@ def test_calculate_sapwood_respiration(rvalues): for pft, _, data in rvalues: actual_sapwood_respiration = calculate_sapwood_respiration( sapwood_mass=data["mass_swd"], - resp_s=pft.resp_s, + resp_s=pft["resp_s"], ) assert_array_almost_equal( actual_sapwood_respiration, data["resp_swd"], decimal=8 @@ -234,11 +244,11 @@ def test_calculate_foliar_respiration(rvalues): for pft, _, data in rvalues: actual_foliar_respiration = calculate_foliar_respiration( whole_crown_gpp=data["crown_gpp"], - resp_f=pft.resp_f, + resp_f=pft["resp_f"], ) assert_array_almost_equal( actual_foliar_respiration, - data["crown_gpp"] * pft.resp_f, + data["crown_gpp"] * pft["resp_f"], decimal=8, ) @@ -250,9 +260,9 @@ def test_calculate_fine_root_respiration(rvalues): for pft, _, data in rvalues: actual_fine_root_respiration = calculate_fine_root_respiration( - zeta=pft.zeta, - sla=pft.sla, - resp_r=pft.resp_r, + zeta=pft["zeta"], + sla=pft["sla"], + resp_r=pft["resp_r"], foliage_mass=data["mass_fol"], ) assert_array_almost_equal( @@ -273,9 +283,9 @@ def test_calculate_net_primary_productivity(rvalues): for pft, _, data in rvalues: actual_npp = calculate_net_primary_productivity( - yld=pft.yld, - whole_crown_gpp=data["crown_gpp"] / (1 - pft.resp_f), - foliar_respiration=data["crown_gpp"] / (1 - pft.resp_f) * pft.resp_f, + yld=pft["yld"], + whole_crown_gpp=data["crown_gpp"] / (1 - pft["resp_f"]), + foliar_respiration=data["crown_gpp"] / (1 - pft["resp_f"]) * pft["resp_f"], fine_root_respiration=data["resp_frt"], sapwood_respiration=data["resp_swd"], ) @@ -295,10 +305,10 @@ def test_calculate_foliage_and_fine_root_turnover(rvalues): for pft, _, data in rvalues: actual_turnover = calculate_foliage_and_fine_root_turnover( - sla=pft.sla, - tau_f=pft.tau_f, - zeta=pft.zeta, - tau_r=pft.tau_r, + sla=pft["sla"], + tau_f=pft["tau_f"], + zeta=pft["zeta"], + tau_r=pft["tau_r"], foliage_mass=data["mass_fol"], ) assert_array_almost_equal( @@ -317,17 +327,17 @@ def test_calculate_growth_increments(rvalues): for pft, _, data in rvalues: delta_dbh, delta_mass_stem, delta_mass_fine_root = calculate_growth_increments( - rho_s=pft.rho_s, - a_hd=pft.a_hd, - h_max=pft.h_max, - lai=pft.lai, - ca_ratio=pft.ca_ratio, - sla=pft.sla, - zeta=pft.zeta, + rho_s=pft["rho_s"], + a_hd=pft["a_hd"], + h_max=pft["h_max"], + lai=pft["lai"], + ca_ratio=pft["ca_ratio"], + sla=pft["sla"], + zeta=pft["zeta"], npp=data["NPP"], turnover=data["turnover"], dbh=data["diameter"], - height=data["height"], + stem_height=data["height"], ) assert_array_almost_equal( delta_dbh, From 49c8b35e45869a920fcf0975aa6952c41bc4fab7 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 13:01:29 +0100 Subject: [PATCH 127/241] Fixing tmodel unit tests for new failure mode --- pyrealm/demography/t_model_functions.py | 2 +- tests/unit/demography/test_t_model_functions.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index a2575fdd..59b18fb7 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -39,7 +39,7 @@ def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> # that they are the same length.abs if len(size_args_shape) == 1 and not pft_args_shape == size_args_shape: - raise ValueError("Trait and size inputs are row arrays and unequal length.") + raise ValueError("Trait and size inputs are row arrays of unequal length.") # Otherwise use np.broadcast_shapes to catch issues try: diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 7137c652..06c15824 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -43,7 +43,7 @@ [np.ones(4), np.ones(4)], [np.ones(5), np.ones(5)], pytest.raises(ValueError), - "PFT and size inputs to T model function are not compatible.", + "Trait and size inputs are row arrays of unequal length.", id="sizes_row_array_of_bad_length", ), pytest.param( @@ -270,10 +270,10 @@ def rtmodel_data(): (0, slice(None)), [0, 1, 2, 0], pytest.raises(ValueError), - "PFT and size inputs to T model function are not compatible.", + "Trait and size inputs are row arrays of unequal length.", None, None, - id="fail_PFT_too_long", + id="fail_PFT_and_sizes_rows_but_not_equal_length", ), pytest.param( (0, slice(None)), @@ -285,13 +285,13 @@ def rtmodel_data(): id="fail_2D_PFT", ), pytest.param( - ([0, 1, 2, 0], 0), + (slice(None), [0, 1]), slice(None), pytest.raises(ValueError), "PFT and size inputs to T model function are not compatible.", None, None, - id="fail_row_size_data_too_long", + id="fail_badly_shaped_2D", ), ], ) From 97ad0ed8da643a49739bf262aa115c165b6f776e Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 13:32:06 +0100 Subject: [PATCH 128/241] Out of date docstring --- pyrealm/demography/community.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 63f09870..4f6a05b5 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -7,9 +7,8 @@ post processing to align the input formats to the initialisation arguments to the Community class. -Internally, the cohort data in the Community class is represented as a pandas dataframe, -which makes it possible to update cohort attributes in parallel across all cohorts but -also provide a clean interface for adding and removing cohorts to a Community. +Internally, the cohort data in the Community class is represented as a dictionary of +`numpy` arrays. Worked example ============== From 901b790f921b7aa0acfec7f7588503991a4a1f39 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 15:13:28 +0100 Subject: [PATCH 129/241] Fixed docstring and default from @omarjamil --- pyrealm/demography/canopy.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 742e1a3a..f87b8532 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -2,7 +2,7 @@ import numpy as np from numpy.typing import NDArray -from scipy.optimize import root_scalar +from scipy.optimize import root_scalar # type: ignore [import-untyped] from pyrealm.demography.canopy_functions import ( calculate_relative_canopy_radius_at_z, @@ -14,17 +14,30 @@ class Canopy: - """A class containing attributes of a canopy, including the structure. - - at which canopy layers close. This also includes - ground level, which will capture all remaning crown and leaf area below the last - closed layer. + """Model of the canopy for a plant community. + + This class generates a canopy structure for a community of trees using the + perfect-plasticity approximation model :cite:`purves:2008a`. In this approach, each + individual is assumed to arrange its canopy crown area plastically to take up space + in canopy layers and that new layers form below the canopy top as the available + space is occupied. + + Real canopies contain canopy gaps, through process such as crown shyness. This + is included in the model through the canopy gap fraction, which sets the proportion + of the available space that will remain unfilled by any canopy. + + Args: + community: A Community object that will be used to generate the canopy model. + canopy_gap_fraction: The proportion of the available space unfilled by canopy + (default: 0.05). + layer_tolerance: The minimum precision used by the solver to find canopy layer + closure heights (default: 0.001 metres) """ def __init__( self, community: Community, - canopy_gap_fraction: float, + canopy_gap_fraction: float = 0.05, layer_tolerance: float = 0.001, ) -> None: # Calculate community wide properties: total crown area and maximum height From 6a13444a506d5a6da45b459126987bf5b5b4a261 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 15:37:27 +0100 Subject: [PATCH 130/241] Fixes from @MarionBWeinzierl --- pyrealm/demography/canopy.py | 7 +++++-- pyrealm/demography/canopy_functions.py | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index f87b8532..d54ec7c1 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -79,8 +79,8 @@ def __init__( for layer in np.arange(self.n_layers - 1): target_area = (layer + 1) * community.cell_area * (1 - canopy_gap_fraction) - # TODO - the solution here is predictably closer to the upper bracket, might - # be a better algorithm to find the root. + # TODO - the solution here is typically closer to the upper bracket, might + # be a better algorithm to find the root (#293). solution = root_scalar( solve_community_projected_canopy_area, args=( @@ -106,6 +106,9 @@ def __init__( self.layer_heights[layer] = starting_guess = solution.root # Find relative canopy radius at the layer heights + # NOTE - here and in the calls below, validate=False is enforced because the + # Community class structures and code should guarantee valid inputs and so + # turning off the validation internally should simply speed up the code. self.stem_relative_radius: NDArray[np.float32] = ( calculate_relative_canopy_radius_at_z( z=self.layer_heights, diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 9fc5426b..08271cf0 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -365,8 +365,9 @@ def calculate_stem_projected_leaf_area_at_z( validate: Boolean flag to suppress argument validation. """ - # TODO - could this merge with the stem crown area function? A lot of overlap, so - # could be much more efficient to return both from one function. + # NOTE: Although the internals of this function overlap a lot with + # calculate_stem_projected_crown_area_at_z, we want that function to be as + # lean as possible, as it used within solve_community_projected_canopy_area. if validate: _validate_z_args(z, crown_area, stem_height, f_g, q_m, z_max) From e2b571ab3ad26e26c9b6f97ffbe64ca8f905ca2c Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 18:30:29 +0100 Subject: [PATCH 131/241] Draft of central ensemble T model allometry function and Flora.get_allometries --- pyrealm/demography/flora.py | 24 ++++---- pyrealm/demography/t_model_functions.py | 56 +++++++++++++++++++ .../unit/demography/test_t_model_functions.py | 2 +- 3 files changed, 69 insertions(+), 13 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 3039a7af..1dfb636e 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -34,7 +34,10 @@ calculate_canopy_q_m, calculate_canopy_z_max_proportion, ) -from pyrealm.demography.t_model_functions import calculate_dbh_from_height +from pyrealm.demography.t_model_functions import ( + calculate_dbh_from_height, + calculate_t_model, +) if sys.version_info[:2] >= (3, 11): import tomllib @@ -235,8 +238,8 @@ def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: for name, pft in zip(pft_names, pfts): self[name] = pft - # Generate an dataframe representation to facilitate merging to cohort data. - # - assemble pft fields into arrays + # Generate a dictionary of arrays of traits across PFTs and an index mapping PFT + # names onto the index of those arrays. data = {} pft_fields = [f.name for f in fields(PlantFunctionalTypeStrict)] @@ -319,19 +322,16 @@ def get_allometries( if not ((dbh is None) ^ (stem_height is None)): raise ValueError("Provide one of either dbh or stem_height") - # # Convert pft data to dict of numpy arrays - TODO: this may become redundant if - # # self.data adopts the dict of arrays format - # pft_data: dict[str, NDArray] = { - # k: v.to_numpy() for k, v in self.data.to_dict(orient="series").items() - # } - # Convert stem height to DBH for the plant functional type + # TODO - make this return np.nan for overheight, not fail. if stem_height is not None: - self.dbh = calculate_dbh_from_height( - h_max=pft_data["h_max"], a_hd=pft_data["h_max"], stem_height=stem_height + dbh = calculate_dbh_from_height( + h_max=self.data["h_max"], + a_hd=self.data["a_hd"], + stem_height=stem_height, ) - return {} + return calculate_t_model(pft_data=self.data, dbh=dbh) # type: ignore [arg-type] # @dataclass diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index b9fb7365..1d6427bc 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -101,6 +101,7 @@ def calculate_dbh_from_height( h_max: Maximum height of the PFT a_hd: Initial slope of the height/diameter relationship of the PFT stem_height: Stem height of individuals + validate: Boolean flag to suppress argument validation """ if validate: @@ -586,3 +587,58 @@ def calculate_growth_increments( delta_d = (npp - turnover) / (dWsdt + dWfdt) return (delta_d, dWsdt * delta_d, dWfdt * delta_d) + + +def calculate_t_model( + pft_data: dict[str, NDArray[np.float32]], dbh: NDArray[np.float32] +) -> dict[str, NDArray[np.float32]]: + """Calculate T Model predictions across cohort data. + + This method calculate predictions of stem allometries under the T Model + :cite:`Li:2014bc`, given diameters at breast height for a set of plant functional + traits. + + """ + + stem_data = {"dbh": dbh} + + stem_data["stem_height"] = calculate_heights( + h_max=pft_data["h_max"], + a_hd=pft_data["a_hd"], + dbh=stem_data["diameter"], + ) + + stem_data["crown_area"] = calculate_crown_areas( + ca_ratio=pft_data["ca_ratio"], + a_hd=pft_data["a_hd"], + dbh=stem_data["dbh"], + stem_height=stem_data["stem_height"], + ) + + stem_data["crown_fraction"] = calculate_crown_fractions( + a_hd=pft_data["a_hd"], + dbh=stem_data["dbh"], + stem_height=stem_data["stem_height"], + ) + + stem_data["stem_mass"] = calculate_stem_masses( + rho_s=pft_data["rho_s"], + dbh=stem_data["dbh"], + stem_height=stem_data["stem_height"], + ) + + stem_data["foliage_mass"] = calculate_foliage_masses( + sla=pft_data["sla"], + lai=pft_data["lai"], + crown_area=stem_data["crown_area"], + ) + + stem_data["sapwood_mass"] = calculate_sapwood_masses( + rho_s=pft_data["rho_s"], + ca_ratio=pft_data["ca_ratio"], + stem_height=stem_data["stem_height"], + crown_area=stem_data["crown_area"], + crown_fraction=stem_data["crown_fraction"], + ) + + return stem_data diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index ac55785c..0a877305 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -341,7 +341,7 @@ def test_calculate_heights( def test_calculate_dbh_from_height( self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): - """Tests inverted calculation of dbh from height""" + """Tests inverted calculation of dbh from height.""" from pyrealm.demography.t_model_functions import calculate_dbh_from_height From ed0100aac8c9cac18e61fdbb4506fdf55043ed2e Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 18:40:07 +0100 Subject: [PATCH 132/241] Moved demography T model test fixture into shared conftest.py --- tests/unit/demography/conftest.py | 73 +++++++++++++++++++ .../unit/demography/test_t_model_functions.py | 68 ----------------- 2 files changed, 73 insertions(+), 68 deletions(-) create mode 100644 tests/unit/demography/conftest.py diff --git a/tests/unit/demography/conftest.py b/tests/unit/demography/conftest.py new file mode 100644 index 00000000..f925e3d8 --- /dev/null +++ b/tests/unit/demography/conftest.py @@ -0,0 +1,73 @@ +"""Shared fixtures for testing the demography module.""" + +from importlib import resources + +import numpy as np +import pandas as pd +import pytest + + +@pytest.fixture +def rtmodel_data(): + """Loads some simple predictions from the R implementation for testing.""" + + # Load the PFT definitions and rename to pyrealm attributes + pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" + pft_definitions = pd.read_csv(pfts_path) + + # Map the PFT trait args from the R implementation to pyrealm + pft_definitions = pft_definitions.rename( + columns={ + "a": "a_hd", + "cr": "ca_ratio", + "Hm": "h_max", + "rho": "rho_s", + "L": "lai", + "sigma": "sla", + "tf": "tau_f", + "tr": "tau_r", + "K": "par_ext", + "y": "yld", + "rr": "resp_r", + "rs": "resp_s", + } + ) + + # Add foliar respiration rate as 0.1, as this is handled outside of the R + # implementation as a function of GPP. + pft_definitions["resp_f"] = 0.1 + + rdata_path = ( + resources.files("pyrealm_build_data.t_model") / "rtmodel_unit_testing.csv" + ) + rdata = pd.read_csv(rdata_path) + + rdata = rdata.rename( + columns={ + "dD": "delta_d", + "D": "diameter", + "H": "height", + "fc": "crown_fraction", + "Ac": "crown_area", + "Wf": "mass_fol", + "Ws": "mass_stm", + "Wss": "mass_swd", + "P0": "potential_gpp", + "GPP": "crown_gpp", + "Rm1": "resp_swd", + "Rm2": "resp_frt", + "dWs": "delta_mass_stm", + "dWfr": "delta_mass_frt", + } + ) + + # Fix some scaling differences: + # The R tmodel implementation rescales reported delta_d as a radial increase in + # millimetres, not diameter increase in metres + rdata["delta_d"] = rdata["delta_d"] / 500 + + # Wrap the return data into arrays with PFT as columns and diameter values as rows + pft_arrays = {k: v.to_numpy() for k, v in pft_definitions.items()} + rdata_arrays = {k: np.reshape(v, (3, 6)).T for k, v in rdata.items()} + + return pft_arrays, rdata_arrays diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 0a877305..a5fcf50b 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -1,10 +1,8 @@ """test the functions in t_model_functions.py.""" from contextlib import nullcontext as does_not_raise -from importlib import resources import numpy as np -import pandas as pd import pytest @@ -80,72 +78,6 @@ def test__validate_t_model_args(pft_args, size_args, outcome, excep_message): assert str(excep.value).startswith(excep_message) -@pytest.fixture -def rtmodel_data(): - """Loads some simple predictions from the R implementation for testing.""" - - # Load the PFT definitions and rename to pyrealm attributes - pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" - pft_definitions = pd.read_csv(pfts_path) - - # Map the PFT trait args from the R implementation to pyrealm - pft_definitions = pft_definitions.rename( - columns={ - "a": "a_hd", - "cr": "ca_ratio", - "Hm": "h_max", - "rho": "rho_s", - "L": "lai", - "sigma": "sla", - "tf": "tau_f", - "tr": "tau_r", - "K": "par_ext", - "y": "yld", - "rr": "resp_r", - "rs": "resp_s", - } - ) - - # Add foliar respiration rate as 0.1, as this is handled outside of the R - # implementation as a function of GPP. - pft_definitions["resp_f"] = 0.1 - - rdata_path = ( - resources.files("pyrealm_build_data.t_model") / "rtmodel_unit_testing.csv" - ) - rdata = pd.read_csv(rdata_path) - - rdata = rdata.rename( - columns={ - "dD": "delta_d", - "D": "diameter", - "H": "height", - "fc": "crown_fraction", - "Ac": "crown_area", - "Wf": "mass_fol", - "Ws": "mass_stm", - "Wss": "mass_swd", - "P0": "potential_gpp", - "GPP": "crown_gpp", - "Rm1": "resp_swd", - "Rm2": "resp_frt", - "dWs": "delta_mass_stm", - "dWfr": "delta_mass_frt", - } - ) - - # Fix some scaling differences: - # The R tmodel implementation rescales reported delta_d as a radial increase in - # millimetres, not diameter increase in metres - rdata["delta_d"] = rdata["delta_d"] / 500 - - # Wrap the return data into arrays with PFT as columns and diameter values as rows - pft_arrays = {k: v.to_numpy() for k, v in pft_definitions.items()} - rdata_arrays = {k: np.reshape(v, (3, 6)).T for k, v in rdata.items()} - - return pft_arrays, rdata_arrays - - @pytest.mark.parametrize( argnames="data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape", argvalues=[ From bbe0c6948b7f11ddef90babb4b7ae6ec72dfe560 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 19:11:18 +0100 Subject: [PATCH 133/241] More unpacking of shared fixtures in demography unit tests --- tests/unit/demography/conftest.py | 31 +- .../unit/demography/test_t_model_functions.py | 305 +++++++++++------- 2 files changed, 216 insertions(+), 120 deletions(-) diff --git a/tests/unit/demography/conftest.py b/tests/unit/demography/conftest.py index f925e3d8..bf03cc65 100644 --- a/tests/unit/demography/conftest.py +++ b/tests/unit/demography/conftest.py @@ -8,8 +8,10 @@ @pytest.fixture -def rtmodel_data(): - """Loads some simple predictions from the R implementation for testing.""" +def rtmodel_flora(): + """Generates a flora object from the rtmodel test definitions.""" + + from pyrealm.demography.flora import Flora, PlantFunctionalType # Load the PFT definitions and rename to pyrealm attributes pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" @@ -33,9 +35,25 @@ def rtmodel_data(): } ) - # Add foliar respiration rate as 0.1, as this is handled outside of the R - # implementation as a function of GPP. - pft_definitions["resp_f"] = 0.1 + pft_definitions = pft_definitions.drop(columns=["d"]) + + return Flora( + pfts=[ + PlantFunctionalType(**args) + for args in pft_definitions.to_dict(orient="records") + ] + ) + + +@pytest.fixture() +def rtmodel_flora_dict(rtmodel_flora): + """Returns the data dictionary attribute of the rtmodel Flora object.""" + return rtmodel_flora.data + + +@pytest.fixture +def rtmodel_data(): + """Loads some simple predictions from the R implementation for testing.""" rdata_path = ( resources.files("pyrealm_build_data.t_model") / "rtmodel_unit_testing.csv" @@ -67,7 +85,6 @@ def rtmodel_data(): rdata["delta_d"] = rdata["delta_d"] / 500 # Wrap the return data into arrays with PFT as columns and diameter values as rows - pft_arrays = {k: v.to_numpy() for k, v in pft_definitions.items()} rdata_arrays = {k: np.reshape(v, (3, 6)).T for k, v in rdata.items()} - return pft_arrays, rdata_arrays + return rdata_arrays diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index a5fcf50b..0e494d55 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -250,201 +250,255 @@ class TestTModel: """ def test_calculate_heights( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of heights of tree from diameter.""" from pyrealm.demography.t_model_functions import calculate_heights - pfts, data = rtmodel_data - with outcome as excep: result = calculate_heights( - h_max=pfts["h_max"][pft_idx], - a_hd=pfts["a_hd"][pft_idx], - dbh=data["diameter"][data_idx], + h_max=rtmodel_flora_dict["h_max"][pft_idx], + a_hd=rtmodel_flora_dict["a_hd"][pft_idx], + dbh=rtmodel_data["diameter"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["height"][out_idx]) + assert np.allclose(result, rtmodel_data["height"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_dbh_from_height( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests inverted calculation of dbh from height.""" from pyrealm.demography.t_model_functions import calculate_dbh_from_height - pfts, data = rtmodel_data - with outcome as excep: result = calculate_dbh_from_height( - h_max=pfts["h_max"][pft_idx], - a_hd=pfts["a_hd"][pft_idx], - stem_height=data["height"][data_idx], + h_max=rtmodel_flora_dict["h_max"][pft_idx], + a_hd=rtmodel_flora_dict["a_hd"][pft_idx], + stem_height=rtmodel_data["height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["diameter"][out_idx]) + assert np.allclose(result, rtmodel_data["diameter"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_crown_areas( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of crown areas of trees.""" from pyrealm.demography.t_model_functions import calculate_crown_areas - pfts, data = rtmodel_data - with outcome as excep: result = calculate_crown_areas( - ca_ratio=pfts["ca_ratio"][pft_idx], - a_hd=pfts["a_hd"][pft_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], + ca_ratio=rtmodel_flora_dict["ca_ratio"][pft_idx], + a_hd=rtmodel_flora_dict["a_hd"][pft_idx], + dbh=rtmodel_data["diameter"][data_idx], + stem_height=rtmodel_data["height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["crown_area"][out_idx]) + assert np.allclose(result, rtmodel_data["crown_area"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_crown_fractions( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of crown fraction of trees.""" from pyrealm.demography.t_model_functions import calculate_crown_fractions - pfts, data = rtmodel_data - with outcome as excep: result = calculate_crown_fractions( - a_hd=pfts["a_hd"][pft_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], + a_hd=rtmodel_flora_dict["a_hd"][pft_idx], + dbh=rtmodel_data["diameter"][data_idx], + stem_height=rtmodel_data["height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["crown_fraction"][out_idx]) + assert np.allclose(result, rtmodel_data["crown_fraction"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_stem_masses( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_stem_masses - pfts, data = rtmodel_data - with outcome as excep: result = calculate_stem_masses( - rho_s=pfts["rho_s"][pft_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], + rho_s=rtmodel_flora_dict["rho_s"][pft_idx], + dbh=rtmodel_data["diameter"][data_idx], + stem_height=rtmodel_data["height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["mass_stm"][out_idx]) + assert np.allclose(result, rtmodel_data["mass_stm"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_foliage_masses( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_foliage_masses - pfts, data = rtmodel_data - with outcome as excep: result = calculate_foliage_masses( - lai=pfts["lai"][pft_idx], - sla=pfts["sla"][pft_idx], - crown_area=data["crown_area"][data_idx], + lai=rtmodel_flora_dict["lai"][pft_idx], + sla=rtmodel_flora_dict["sla"][pft_idx], + crown_area=rtmodel_data["crown_area"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["mass_fol"][out_idx]) + assert np.allclose(result, rtmodel_data["mass_fol"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_sapwood_masses( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_sapwood_masses - pfts, data = rtmodel_data - with outcome as excep: result = calculate_sapwood_masses( - rho_s=pfts["rho_s"][pft_idx], - ca_ratio=pfts["ca_ratio"][pft_idx], - crown_area=data["crown_area"][data_idx], - stem_height=data["height"][data_idx], - crown_fraction=data["crown_fraction"][data_idx], + rho_s=rtmodel_flora_dict["rho_s"][pft_idx], + ca_ratio=rtmodel_flora_dict["ca_ratio"][pft_idx], + crown_area=rtmodel_data["crown_area"][data_idx], + stem_height=rtmodel_data["height"][data_idx], + crown_fraction=rtmodel_data["crown_fraction"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["mass_swd"][out_idx]) + assert np.allclose(result, rtmodel_data["mass_swd"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_whole_crown_gpp( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of whole crown GPP.""" from pyrealm.demography.t_model_functions import calculate_whole_crown_gpp - pfts, data = rtmodel_data - with outcome as excep: result = calculate_whole_crown_gpp( - lai=pfts["lai"][pft_idx], - par_ext=pfts["par_ext"][pft_idx], - crown_area=data["crown_area"][data_idx], - potential_gpp=data["potential_gpp"][data_idx], + lai=rtmodel_flora_dict["lai"][pft_idx], + par_ext=rtmodel_flora_dict["par_ext"][pft_idx], + crown_area=rtmodel_data["crown_area"][data_idx], + potential_gpp=rtmodel_data["potential_gpp"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["crown_gpp"][out_idx]) + assert np.allclose(result, rtmodel_data["crown_gpp"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_sapwood_respiration( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of sapwood respiration.""" from pyrealm.demography.t_model_functions import calculate_sapwood_respiration - pfts, data = rtmodel_data - with outcome as excep: result = calculate_sapwood_respiration( - resp_s=pfts["resp_s"][pft_idx], - sapwood_mass=data["mass_swd"][data_idx], + resp_s=rtmodel_flora_dict["resp_s"][pft_idx], + sapwood_mass=rtmodel_data["mass_swd"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["resp_swd"][out_idx]) + assert np.allclose(result, rtmodel_data["resp_swd"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -453,6 +507,7 @@ def test_calculate_foliar_respiration( self, request, rtmodel_data, + rtmodel_flora_dict, data_idx, pft_idx, outcome, @@ -469,47 +524,61 @@ def test_calculate_foliar_respiration( from pyrealm.demography.t_model_functions import calculate_foliar_respiration - pfts, data = rtmodel_data - with outcome as excep: result = calculate_foliar_respiration( - resp_f=pfts["resp_f"][pft_idx], - whole_crown_gpp=data["crown_gpp"][data_idx], + resp_f=rtmodel_flora_dict["resp_f"][pft_idx], + whole_crown_gpp=rtmodel_data["crown_gpp"][data_idx], ) assert result.shape == exp_shape assert np.allclose( - result, data["crown_gpp"][data_idx] * pfts["resp_f"][pft_idx] + result, + rtmodel_data["crown_gpp"][data_idx] + * rtmodel_flora_dict["resp_f"][pft_idx], ) return assert str(excep.value).startswith(excep_msg) def test_calculate_fine_root_respiration( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of fine root respiration.""" from pyrealm.demography.t_model_functions import calculate_fine_root_respiration - pfts, data = rtmodel_data - with outcome as excep: result = calculate_fine_root_respiration( - zeta=pfts["zeta"][pft_idx], - sla=pfts["sla"][pft_idx], - resp_r=pfts["resp_r"][pft_idx], - foliage_mass=data["mass_fol"][data_idx], + zeta=rtmodel_flora_dict["zeta"][pft_idx], + sla=rtmodel_flora_dict["sla"][pft_idx], + resp_r=rtmodel_flora_dict["resp_r"][pft_idx], + foliage_mass=rtmodel_data["mass_fol"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["resp_frt"][out_idx]) + assert np.allclose(result, rtmodel_data["resp_frt"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_net_primary_productivity( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of net primary productivity.""" @@ -517,25 +586,31 @@ def test_calculate_net_primary_productivity( calculate_net_primary_productivity, ) - pfts, data = rtmodel_data - with outcome as excep: result = calculate_net_primary_productivity( - yld=pfts["yld"][pft_idx], - whole_crown_gpp=data["crown_gpp"][data_idx], + yld=rtmodel_flora_dict["yld"][pft_idx], + whole_crown_gpp=rtmodel_data["crown_gpp"][data_idx], foliar_respiration=0, # Not included here in the R implementation - fine_root_respiration=data["resp_frt"][data_idx], - sapwood_respiration=data["resp_swd"][data_idx], + fine_root_respiration=rtmodel_data["resp_frt"][data_idx], + sapwood_respiration=rtmodel_data["resp_swd"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["NPP"][out_idx]) + assert np.allclose(result, rtmodel_data["NPP"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_foliage_and_fine_root_turnover( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of foliage and fine root turnover.""" @@ -543,25 +618,31 @@ def test_calculate_foliage_and_fine_root_turnover( calculate_foliage_and_fine_root_turnover, ) - pfts, data = rtmodel_data - with outcome as excep: result = calculate_foliage_and_fine_root_turnover( - sla=pfts["sla"][pft_idx], - zeta=pfts["zeta"][pft_idx], - tau_f=pfts["tau_f"][pft_idx], - tau_r=pfts["tau_r"][pft_idx], - foliage_mass=data["mass_fol"][data_idx], + sla=rtmodel_flora_dict["sla"][pft_idx], + zeta=rtmodel_flora_dict["zeta"][pft_idx], + tau_f=rtmodel_flora_dict["tau_f"][pft_idx], + tau_r=rtmodel_flora_dict["tau_r"][pft_idx], + foliage_mass=rtmodel_data["mass_fol"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["turnover"][out_idx]) + assert np.allclose(result, rtmodel_data["turnover"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_calculate_growth_increments( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora_dict, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of growth increments.""" @@ -569,31 +650,29 @@ def test_calculate_calculate_growth_increments( calculate_growth_increments, ) - pfts, data = rtmodel_data - with outcome as excep: delta_d, delta_mass_stm, delta_mass_frt = calculate_growth_increments( - rho_s=pfts["rho_s"][pft_idx], - a_hd=pfts["a_hd"][pft_idx], - h_max=pfts["h_max"][pft_idx], - lai=pfts["lai"][pft_idx], - ca_ratio=pfts["ca_ratio"][pft_idx], - sla=pfts["sla"][pft_idx], - zeta=pfts["zeta"][pft_idx], - npp=data["NPP"][data_idx], - turnover=data["turnover"][data_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], + rho_s=rtmodel_flora_dict["rho_s"][pft_idx], + a_hd=rtmodel_flora_dict["a_hd"][pft_idx], + h_max=rtmodel_flora_dict["h_max"][pft_idx], + lai=rtmodel_flora_dict["lai"][pft_idx], + ca_ratio=rtmodel_flora_dict["ca_ratio"][pft_idx], + sla=rtmodel_flora_dict["sla"][pft_idx], + zeta=rtmodel_flora_dict["zeta"][pft_idx], + npp=rtmodel_data["NPP"][data_idx], + turnover=rtmodel_data["turnover"][data_idx], + dbh=rtmodel_data["diameter"][data_idx], + stem_height=rtmodel_data["height"][data_idx], ) assert delta_d.shape == exp_shape - assert np.allclose(delta_d, data["delta_d"][out_idx]) + assert np.allclose(delta_d, rtmodel_data["delta_d"][out_idx]) assert delta_mass_stm.shape == exp_shape - assert np.allclose(delta_mass_stm, data["delta_mass_stm"][out_idx]) + assert np.allclose(delta_mass_stm, rtmodel_data["delta_mass_stm"][out_idx]) assert delta_mass_frt.shape == exp_shape - assert np.allclose(delta_mass_frt, data["delta_mass_frt"][out_idx]) + assert np.allclose(delta_mass_frt, rtmodel_data["delta_mass_frt"][out_idx]) return assert str(excep.value).startswith(excep_msg) From ba9009a98ed5a603267a0989ebaf1265db6223e7 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 23 Sep 2024 19:48:26 +0100 Subject: [PATCH 134/241] Test get_allometry against rtmodel, synchronise dict names with args --- pyrealm/demography/flora.py | 4 +- pyrealm/demography/t_model_functions.py | 2 +- tests/unit/demography/conftest.py | 10 ++--- tests/unit/demography/test_flora.py | 10 +++++ .../unit/demography/test_t_model_functions.py | 38 +++++++++---------- 5 files changed, 38 insertions(+), 26 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 1dfb636e..88a7fdbe 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -314,7 +314,9 @@ def from_csv(cls, path: Path) -> Flora: return cls._from_file_data({"pft": data.to_dict(orient="records")}) def get_allometries( - self, dbh: NDArray[np.float32] | None, stem_height: NDArray[np.float32] | None + self, + dbh: NDArray[np.float32] | None = None, + stem_height: NDArray[np.float32] | None = None, ) -> dict[str, NDArray]: """Populates the T Model allometry from the initial size data.""" diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 1d6427bc..7aa495ca 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -605,7 +605,7 @@ def calculate_t_model( stem_data["stem_height"] = calculate_heights( h_max=pft_data["h_max"], a_hd=pft_data["a_hd"], - dbh=stem_data["diameter"], + dbh=stem_data["dbh"], ) stem_data["crown_area"] = calculate_crown_areas( diff --git a/tests/unit/demography/conftest.py b/tests/unit/demography/conftest.py index bf03cc65..8e77c2d5 100644 --- a/tests/unit/demography/conftest.py +++ b/tests/unit/demography/conftest.py @@ -63,13 +63,13 @@ def rtmodel_data(): rdata = rdata.rename( columns={ "dD": "delta_d", - "D": "diameter", - "H": "height", + "D": "dbh", + "H": "stem_height", "fc": "crown_fraction", "Ac": "crown_area", - "Wf": "mass_fol", - "Ws": "mass_stm", - "Wss": "mass_swd", + "Wf": "foliage_mass", + "Ws": "stem_mass", + "Wss": "sapwood_mass", "P0": "potential_gpp", "GPP": "crown_gpp", "Rm1": "resp_swd", diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index 76558d94..b4754890 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -5,6 +5,7 @@ from importlib import resources from json import JSONDecodeError +import numpy as np import pytest from marshmallow.exceptions import ValidationError from pandas.errors import ParserError @@ -264,6 +265,15 @@ def test_flora_from_csv(filename, outcome): assert nm in flora +def test_Flora_get_allometries(rtmodel_data, rtmodel_flora): + """Test the get allometries method.""" + + result = rtmodel_flora.get_allometries(rtmodel_data["dbh"]) + + for key, value in result.items(): + assert np.allclose(value, rtmodel_data[key]) + + # # Test PlantFunctionalType __post_init__ functions # diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 0e494d55..d20036ee 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -267,11 +267,11 @@ def test_calculate_heights( result = calculate_heights( h_max=rtmodel_flora_dict["h_max"][pft_idx], a_hd=rtmodel_flora_dict["a_hd"][pft_idx], - dbh=rtmodel_data["diameter"][data_idx], + dbh=rtmodel_data["dbh"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["height"][out_idx]) + assert np.allclose(result, rtmodel_data["stem_height"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -295,11 +295,11 @@ def test_calculate_dbh_from_height( result = calculate_dbh_from_height( h_max=rtmodel_flora_dict["h_max"][pft_idx], a_hd=rtmodel_flora_dict["a_hd"][pft_idx], - stem_height=rtmodel_data["height"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["diameter"][out_idx]) + assert np.allclose(result, rtmodel_data["dbh"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -323,8 +323,8 @@ def test_calculate_crown_areas( result = calculate_crown_areas( ca_ratio=rtmodel_flora_dict["ca_ratio"][pft_idx], a_hd=rtmodel_flora_dict["a_hd"][pft_idx], - dbh=rtmodel_data["diameter"][data_idx], - stem_height=rtmodel_data["height"][data_idx], + dbh=rtmodel_data["dbh"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], ) assert result.shape == exp_shape @@ -351,8 +351,8 @@ def test_calculate_crown_fractions( with outcome as excep: result = calculate_crown_fractions( a_hd=rtmodel_flora_dict["a_hd"][pft_idx], - dbh=rtmodel_data["diameter"][data_idx], - stem_height=rtmodel_data["height"][data_idx], + dbh=rtmodel_data["dbh"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], ) assert result.shape == exp_shape @@ -379,12 +379,12 @@ def test_calculate_stem_masses( with outcome as excep: result = calculate_stem_masses( rho_s=rtmodel_flora_dict["rho_s"][pft_idx], - dbh=rtmodel_data["diameter"][data_idx], - stem_height=rtmodel_data["height"][data_idx], + dbh=rtmodel_data["dbh"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["mass_stm"][out_idx]) + assert np.allclose(result, rtmodel_data["stem_mass"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -412,7 +412,7 @@ def test_calculate_foliage_masses( ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["mass_fol"][out_idx]) + assert np.allclose(result, rtmodel_data["foliage_mass"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -437,12 +437,12 @@ def test_calculate_sapwood_masses( rho_s=rtmodel_flora_dict["rho_s"][pft_idx], ca_ratio=rtmodel_flora_dict["ca_ratio"][pft_idx], crown_area=rtmodel_data["crown_area"][data_idx], - stem_height=rtmodel_data["height"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], crown_fraction=rtmodel_data["crown_fraction"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["mass_swd"][out_idx]) + assert np.allclose(result, rtmodel_data["sapwood_mass"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -494,7 +494,7 @@ def test_calculate_sapwood_respiration( with outcome as excep: result = calculate_sapwood_respiration( resp_s=rtmodel_flora_dict["resp_s"][pft_idx], - sapwood_mass=rtmodel_data["mass_swd"][data_idx], + sapwood_mass=rtmodel_data["sapwood_mass"][data_idx], ) assert result.shape == exp_shape @@ -560,7 +560,7 @@ def test_calculate_fine_root_respiration( zeta=rtmodel_flora_dict["zeta"][pft_idx], sla=rtmodel_flora_dict["sla"][pft_idx], resp_r=rtmodel_flora_dict["resp_r"][pft_idx], - foliage_mass=rtmodel_data["mass_fol"][data_idx], + foliage_mass=rtmodel_data["foliage_mass"][data_idx], ) assert result.shape == exp_shape @@ -624,7 +624,7 @@ def test_calculate_foliage_and_fine_root_turnover( zeta=rtmodel_flora_dict["zeta"][pft_idx], tau_f=rtmodel_flora_dict["tau_f"][pft_idx], tau_r=rtmodel_flora_dict["tau_r"][pft_idx], - foliage_mass=rtmodel_data["mass_fol"][data_idx], + foliage_mass=rtmodel_data["foliage_mass"][data_idx], ) assert result.shape == exp_shape @@ -661,8 +661,8 @@ def test_calculate_calculate_growth_increments( zeta=rtmodel_flora_dict["zeta"][pft_idx], npp=rtmodel_data["NPP"][data_idx], turnover=rtmodel_data["turnover"][data_idx], - dbh=rtmodel_data["diameter"][data_idx], - stem_height=rtmodel_data["height"][data_idx], + dbh=rtmodel_data["dbh"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], ) assert delta_d.shape == exp_shape From db4b195bfcec716b9e6f32821be7c04a62df963c Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 24 Sep 2024 11:30:04 +0100 Subject: [PATCH 135/241] Better handling of edge cases in calculate_dbh_from_height --- pyrealm/demography/t_model_functions.py | 25 +++++++++++---- .../unit/demography/test_t_model_functions.py | 31 ++++++++++++------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 7aa495ca..15c12b91 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -97,6 +97,14 @@ def calculate_dbh_from_height( D = \frac{H \left( \log \left(\frac{H}{H_{m}-H}\right)\right)}{a} + Warning: + Where the stem height is greater than the maximum height for a PFT, then + :math:`D` is undefined and the return array will contain `np.nan`. Where the + stem height equals the maximum height, the model predicts an infinite stem + diameter: the `h_max` parameter is the asymptotic maximum stem height of an + exponential function. Similarly, heights very close the maximum height may lead + to unrealistically large predictions of DBH. + Args: h_max: Maximum height of the PFT a_hd: Initial slope of the height/diameter relationship of the PFT @@ -107,12 +115,17 @@ def calculate_dbh_from_height( if validate: _validate_t_model_args(pft_args=[h_max, a_hd], size_args=[stem_height]) - if np.any(stem_height > h_max): - raise ValueError( - "Stem height values must not be greater than maximum stem height" - ) - - return (h_max * np.log(h_max / (h_max - stem_height))) / a_hd + # The equation here blows up in a couple of ways: + # - H > h_max leads to negative logs which generates np.nan with an invalid value + # warning. The np.nan here is what we want to happen, so the warning needs + # suppressing. + # - H = h_max generates a divide by zero which returns inf with a warning. Here the + # answer should be h_max so that needs trapping. + + with np.testing.suppress_warnings() as sup: + sup.filter(RuntimeWarning, "divide by zero encountered in divide") + sup.filter(RuntimeWarning, "invalid value encountered in log") + return (h_max * np.log(h_max / (h_max - stem_height))) / a_hd def calculate_crown_areas( diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index d20036ee..4fa42ce0 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -678,21 +678,30 @@ def test_calculate_calculate_growth_increments( assert str(excep.value).startswith(excep_msg) -def test_calculate_dbh_from_height_overheight(): - """Test inverted calculation of dbh from height raises with overheight stems. +def test_calculate_dbh_from_height_edge_cases(): + """Test inverted calculation of dbh from height handles edges cases. - If H > h_max, dbh is not calculable and should raise a ValueError + * If H > h_max, dbh is not calculable and should be np.nan + * If H = h_max, dbh is infinite. """ from pyrealm.demography.t_model_functions import calculate_dbh_from_height - pft_h_max_values = np.array([25.33, 15.33]) + pft_h_max_values = np.array([20, 30]) pft_a_hd_values = np.array([116.0, 116.0]) - stem_heights = np.array([30, 20]) + stem_heights = np.array([[0], [10], [20], [30], [40]]) - with pytest.raises(ValueError): - _ = calculate_dbh_from_height( - h_max=pft_h_max_values, - a_hd=pft_a_hd_values, - stem_height=stem_heights, - ) + dbh = calculate_dbh_from_height( + h_max=pft_h_max_values, + a_hd=pft_a_hd_values, + stem_height=stem_heights, + ) + + # first row should be all zeros (zero height gives zero diameter) + assert np.all(dbh[0, :] == 0) + + # Infinite entries + assert np.all(np.isinf(dbh) == np.array([[0, 0], [0, 0], [1, 0], [0, 1], [0, 0]])) + + # Undefined entries + assert np.all(np.isnan(dbh) == np.array([[0, 0], [0, 0], [0, 0], [1, 0], [1, 1]])) From 3c5c63b64e817c0f218b0a7b1ddce7037f8508b4 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 24 Sep 2024 11:35:59 +0100 Subject: [PATCH 136/241] Test driven development of Flora.get_allometries --- pyrealm/demography/flora.py | 56 +++++++++++++++-- tests/unit/demography/test_flora.py | 95 ++++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 8 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 88a7fdbe..f586177d 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -254,6 +254,9 @@ def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: self.pft_indices = {v: k for k, v in enumerate(self.data["name"])} """An dictionary giving the index of each PFT name in the PFT data.""" + self.n_pfts = len(pfts) + """The number of plant functional types in the Flora instance.""" + @classmethod def _from_file_data(cls, file_data: dict) -> Flora: """Create a Flora object from a JSON string. @@ -318,22 +321,65 @@ def get_allometries( dbh: NDArray[np.float32] | None = None, stem_height: NDArray[np.float32] | None = None, ) -> dict[str, NDArray]: - """Populates the T Model allometry from the initial size data.""" + """Calculate T Model scalings for the Flora members. + + This method calculates the allometric predictions of the T Model for all of the + plant functional types within a Flora, given an array of stem sizes at which to + calculate the predictions. The T Model uses diameter at breast height (DBH) as + the fundamental metric of stem size but this method will also accept a set of + stem heights as an alternative size metric. Stem heights are converted back into + the expected DBH before calculating the allometric predictions - if any of the + stem heights are higher than the maximum height for a PFT, these will be shown + as `np.nan` values. + + Both ``dbh`` and ``stem_height`` must be provided as one-dimensional arrays and + it is an error to provide both. The method returns a dictionary of the + allometric predictions of the T Model: + + * 'dbh' + * 'stem_height' + * 'crown_area' + * 'crown_fraction', + * 'stem_mass' + * 'foliage_mass' + * 'sapwood_mass' + + Each dictionary entry is a 2D array with PFTs as columns and the predictions for + each size value as rows. + + Args: + dbh: An array of diameter at breast height values. + stem_height: An array of stem height values. + """ # Need exclusively one of dbh or stem_height - use XOR if not ((dbh is None) ^ (stem_height is None)): raise ValueError("Provide one of either dbh or stem_height") - # Convert stem height to DBH for the plant functional type - # TODO - make this return np.nan for overheight, not fail. if stem_height is not None: - dbh = calculate_dbh_from_height( + # Check array dimensions + if stem_height.ndim != 1: + raise ValueError("Stem heights must be a one dimensional array") + + # Convert stem heights back into an array of initial DBH values + # - broadcast to (n_heights, n_pfts) + stem_height = np.broadcast_to( + stem_height[:, None], (stem_height.size, self.n_pfts) + ) + dbh_arr = calculate_dbh_from_height( h_max=self.data["h_max"], a_hd=self.data["a_hd"], stem_height=stem_height, ) + elif dbh is not None: + # Check array dimensions + if dbh.ndim != 1: + raise ValueError("DBH must be a one dimensional array") + + # Broadcast the dbh to a (n_heights, n_pfts) + dbh_arr = np.broadcast_to(dbh[:, None], (dbh.size, self.n_pfts)) - return calculate_t_model(pft_data=self.data, dbh=dbh) # type: ignore [arg-type] + return calculate_t_model(pft_data=self.data, dbh=dbh_arr) # @dataclass diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index b4754890..317f6cae 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -265,15 +265,104 @@ def test_flora_from_csv(filename, outcome): assert nm in flora -def test_Flora_get_allometries(rtmodel_data, rtmodel_flora): - """Test the get allometries method.""" +def test_Flora_get_allometries_dbh_against_rtmodel(rtmodel_data, rtmodel_flora): + """Test the get allometries method against reference values using dbh. - result = rtmodel_flora.get_allometries(rtmodel_data["dbh"]) + This test checks that the outcome of running a column array of the rtmodel test data + DBH values (which are the same for each PFT) into get_allometries returns the + correct values. So the shapes go (3,) x (6, 1) -> (6,3) + """ + + result = rtmodel_flora.get_allometries(dbh=rtmodel_data["dbh"][:, 0]) for key, value in result.items(): assert np.allclose(value, rtmodel_data[key]) +def test_Flora_get_allometries_stem_height_against_rtmodel(rtmodel_data, rtmodel_flora): + """Test the get allometries method against reference values using stem height. + + The stem heights differ for each PFT, so for this to work with stem height as a 1D + input each PFT needs to be run separately. So the test does three iterations of + (1,) x (6, 1) -> (6, 1) and checks each column. + """ + from pyrealm.demography.flora import Flora + + for idx, (name, pft) in enumerate(rtmodel_flora.items()): + single_pft_flora = Flora(pfts=[pft]) + result = single_pft_flora.get_allometries( + stem_height=rtmodel_data["stem_height"][:, idx] + ) + + for key, value in result.items(): + assert np.allclose(value, rtmodel_data[key][:, [idx]]) + + +@pytest.mark.parametrize( + argnames="dbh,stem_height,outcome,excep_msg", + argvalues=[ + pytest.param( + None, + None, + pytest.raises(ValueError), + "Provide one of either dbh or stem_height", + id="fail_no_size_data", + ), + pytest.param( + np.array([0.1, 0.2, 0.3]), + np.array([10, 20, 30]), + pytest.raises(ValueError), + "Provide one of either dbh or stem_height", + id="fail_too_much_size_data", + ), + pytest.param( + np.array([[0.1, 0.2, 0.3]]), + None, + pytest.raises(ValueError), + "DBH must be a one dimensional array", + id="fail_dbh_not_1D", + ), + pytest.param( + None, + np.array([[10, 20, 30]]), + pytest.raises(ValueError), + "Stem heights must be a one dimensional array", + id="fail_stem_height_not_1D", + ), + pytest.param( + np.array([0.1, 0.2, 0.3]), + None, + does_not_raise(), + None, + id="ok_with_dbh", + ), + pytest.param( + None, + np.array([5, 10, 15]), + does_not_raise(), + None, + id="ok_with_stem_heights", + ), + pytest.param( + None, + np.array([0, 5, 10, 15, 45.33, 1000]), + does_not_raise(), + None, + id="ok_with_edgy_stem_heights", + ), # 0, at max height and > max height + ], +) +def test_Flora_get_allometries_setup( + rtmodel_flora, dbh, stem_height, outcome, excep_msg +): + """Test the get allometries input checking.""" + with outcome as excep: + _ = rtmodel_flora.get_allometries(dbh=dbh, stem_height=stem_height) + return + + assert str(excep.value) == excep_msg + + # # Test PlantFunctionalType __post_init__ functions # From 8334a4a6b346f458af89949763a6b438a1d84395 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 24 Sep 2024 13:38:15 +0100 Subject: [PATCH 137/241] Start of simple user description doc of Flora, __repr__ for Flora --- docs/source/users/demography/flora.md | 87 +++++++++++++++++++++++++++ pyrealm/demography/flora.py | 5 ++ 2 files changed, 92 insertions(+) create mode 100644 docs/source/users/demography/flora.md diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md new file mode 100644 index 00000000..d6a9de8a --- /dev/null +++ b/docs/source/users/demography/flora.md @@ -0,0 +1,87 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Plant Functional Types and the Flora object + +:::{admonition} Warning + +This area of `pyrealm` is in active development and this notebook currently contains +notes and initial demonstration code. + +::: + +```{code-cell} ipython3 +from matplotlib import pyplot as plt +import numpy as np + +from pyrealm.demography.flora import PlantFunctionalType, Flora +``` + +The code below creates a simple `Flora` object containing 3 plant functional types with +different maximum stem heights. + +```{code-cell} ipython3 +flora = Flora( + [ + PlantFunctionalType(name='short', h_max=10), + PlantFunctionalType(name='medium', h_max=20), + PlantFunctionalType(name='tall', h_max=30), + ] +) + +flora +``` + +We can visualise how the stem size, canopy size and various masses of a plant functional +type change with stem diameter by using the `Flora.get_allometries` method. This takes +an array of values for diameter at breast height (metres) and returns a dictionary +containing the predictions of the T Model for: + +* Stem height ('stem_height', m) +* Crown area ('crown_area', m2) +* Crown fraction ('crown_fraction', -) +* Stem mass ('stem_mass', kg) +* Foliage mass ('foliage_mass', kg) +* Sapwood mass ('sapwood_mass', kg) + +The returned values in the dictionary are 2 dimensional arrays with each DBH value as a +row and each PFT as a column. This makes them convenient to plot using `matplotlib`. + +```{code-cell} ipython3 +dbh = np.arange(0, 1.6, 0.01) +allometries = flora.get_allometries(dbh=dbh) +``` + +The code below shows how to use the returned allometries to generate a plot of the +scaling relationships across all of the PFTs in a `Flora` instance. + +```{code-cell} ipython3 +fig, axes = plt.subplots(ncols=2, nrows=3, sharex=True, figsize=(10, 8)) + +plot_details = [ + ('stem_height', "Stem height (m)"), + ('crown_area', "Crown area (m2)"), + ('crown_fraction', "Crown fraction (-)"), + ('stem_mass', "Stem mass (kg)"), + ('foliage_mass', "Foliage mass (kg)"), + ('sapwood_mass', "Sapwood mass (kg)"), +] + +for ax, (var, ylab) in zip(axes.flatten(), plot_details): + ax.plot(dbh, allometries[var], label=flora.keys()) + ax.set_xlabel("Diameter at breast height (m)") + ax.set_ylabel(ylab) + + if var == "sapwood_mass": + ax.legend(frameon=False) +``` diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index f586177d..7a75f79c 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -257,6 +257,11 @@ def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: self.n_pfts = len(pfts) """The number of plant functional types in the Flora instance.""" + def __repr__(self) -> str: + """Simple representation of the Flora instance.""" + + return f"Flora with {self.n_pfts} functional types: {', '.join(self.keys())}" + @classmethod def _from_file_data(cls, file_data: dict) -> Flora: """Create a Flora object from a JSON string. From 439de92d63fd43a077065860566cac809e66c653 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 24 Sep 2024 18:56:48 +0100 Subject: [PATCH 138/241] Adding draft of Flora.get_growth and backend functions --- docs/source/users/demography/flora.md | 60 ++++++++++++---- pyproject.toml | 16 ++--- pyrealm/demography/flora.py | 85 ++++++++++++++++++++++- pyrealm/demography/t_model_functions.py | 91 +++++++++++++++++++++++-- 4 files changed, 225 insertions(+), 27 deletions(-) diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index d6a9de8a..a1b19fc1 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -20,7 +20,7 @@ notes and initial demonstration code. ::: -```{code-cell} ipython3 +```{code-cell} from matplotlib import pyplot as plt import numpy as np @@ -30,12 +30,12 @@ from pyrealm.demography.flora import PlantFunctionalType, Flora The code below creates a simple `Flora` object containing 3 plant functional types with different maximum stem heights. -```{code-cell} ipython3 +```{code-cell} flora = Flora( [ - PlantFunctionalType(name='short', h_max=10), - PlantFunctionalType(name='medium', h_max=20), - PlantFunctionalType(name='tall', h_max=30), + PlantFunctionalType(name="short", h_max=10), + PlantFunctionalType(name="medium", h_max=20), + PlantFunctionalType(name="tall", h_max=30), ] ) @@ -57,7 +57,7 @@ containing the predictions of the T Model for: The returned values in the dictionary are 2 dimensional arrays with each DBH value as a row and each PFT as a column. This makes them convenient to plot using `matplotlib`. -```{code-cell} ipython3 +```{code-cell} dbh = np.arange(0, 1.6, 0.01) allometries = flora.get_allometries(dbh=dbh) ``` @@ -65,16 +65,16 @@ allometries = flora.get_allometries(dbh=dbh) The code below shows how to use the returned allometries to generate a plot of the scaling relationships across all of the PFTs in a `Flora` instance. -```{code-cell} ipython3 +```{code-cell} fig, axes = plt.subplots(ncols=2, nrows=3, sharex=True, figsize=(10, 8)) plot_details = [ - ('stem_height', "Stem height (m)"), - ('crown_area', "Crown area (m2)"), - ('crown_fraction', "Crown fraction (-)"), - ('stem_mass', "Stem mass (kg)"), - ('foliage_mass', "Foliage mass (kg)"), - ('sapwood_mass', "Sapwood mass (kg)"), + ("stem_height", "Stem height (m)"), + ("crown_area", "Crown area (m2)"), + ("crown_fraction", "Crown fraction (-)"), + ("stem_mass", "Stem mass (kg)"), + ("foliage_mass", "Foliage mass (kg)"), + ("sapwood_mass", "Sapwood mass (kg)"), ] for ax, (var, ylab) in zip(axes.flatten(), plot_details): @@ -85,3 +85,37 @@ for ax, (var, ylab) in zip(axes.flatten(), plot_details): if var == "sapwood_mass": ax.legend(frameon=False) ``` + +```{code-cell} +potential_gpp = np.repeat(55, dbh.size) +allometries = flora.get_growth(dbh=dbh, potential_gpp=potential_gpp) +``` + +```{code-cell} +fig, axes = plt.subplots(ncols=2, nrows=5, sharex=True, figsize=(10, 12)) + +plot_details = [ + ("whole_crown_gpp", "whole_crown_gpp"), + ("sapwood_respiration", "sapwood_respiration"), + ("foliar_respiration", "foliar_respiration"), + ("fine_root_respiration", "fine_root_respiration"), + ("npp", "npp"), + ("turnover", "turnover"), + ("delta_dbh", "delta_dbh"), + ("delta_stem_mass", "delta_stem_mass"), + ("delta_foliage_mass", "delta_foliage_mass"), +] + +axes = axes.flatten() + +for ax, (var, ylab) in zip(axes, plot_details): + ax.plot(dbh, allometries[var], label=flora.keys()) + ax.set_xlabel("Diameter at breast height (m)") + ax.set_ylabel(ylab) + + if var == "whole_crown_gpp": + ax.legend(frameon=False) + +# Delete unused panel in 5 x 2 grid +fig.delaxes(axes[-1]) +``` diff --git a/pyproject.toml b/pyproject.toml index 2823f7cc..e72b8031 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,15 +31,15 @@ repository = "https://github.com/ImperialCollegeLondon/pyrealm" version = "1.0.0" [tool.poetry.dependencies] -dacite = "^1.6.0" -numpy = "^2.0.0" +dacite = "^1.6.0" +numpy = "^2.0.0" python = ">=3.10" -scipy = "^1.7.3" -tabulate = "^0.8.10" +scipy = "^1.7.3" +tabulate = "^0.8.10" marshmallow = "^3.22.0" -pandas = "^2.2.2" marshmallow-dataclass = "^8.7.0" +pandas = "^2.2.2" pandas-stubs = "^2.2.2.240909" [tool.poetry.group.types.dependencies] pandas-stubs = "^2.2.0.240218" @@ -132,7 +132,7 @@ select = [ "I", # isort "UP", # pyupgrade "RUF", # RUF specific checks - "NPY201" + "NPY201", ] # On top of the Google convention, disable: @@ -148,5 +148,5 @@ convention = "google" [tool.jupytext] # Stop jupytext from removing mystnb and other settings in MyST Notebook YAML headers notebook_metadata_filter = "-jupytext.text_representation.jupytext_version,settings,mystnb" -# Also stop it from stripping cell metadata. -cell_metadata_filter = "all" \ No newline at end of file +# Also stop it from stripping cell metadata except for a few cases. +cell_metadata_filter = "all,-autoscroll,-collapsed,-scrolled,-trusted,-ExecuteTime" diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 7a75f79c..30b0a25d 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -36,7 +36,8 @@ ) from pyrealm.demography.t_model_functions import ( calculate_dbh_from_height, - calculate_t_model, + calculate_t_model_allometry, + calculate_t_model_growth, ) if sys.version_info[:2] >= (3, 11): @@ -384,7 +385,87 @@ def get_allometries( # Broadcast the dbh to a (n_heights, n_pfts) dbh_arr = np.broadcast_to(dbh[:, None], (dbh.size, self.n_pfts)) - return calculate_t_model(pft_data=self.data, dbh=dbh_arr) + return calculate_t_model_allometry(pft_data=self.data, dbh=dbh_arr) + + def get_growth( + self, + potential_gpp: NDArray[np.float32], + dbh: NDArray[np.float32] | None = None, + stem_height: NDArray[np.float32] | None = None, + ) -> dict[str, NDArray]: + """Calculate T Model scalings for the Flora members. + + This method calculates the allometric predictions of the T Model for all of the + plant functional types within a Flora, given an array of stem sizes at which to + calculate the predictions. The T Model uses diameter at breast height (DBH) as + the fundamental metric of stem size but this method will also accept a set of + stem heights as an alternative size metric. Stem heights are converted back into + the expected DBH before calculating the allometric predictions - if any of the + stem heights are higher than the maximum height for a PFT, these will be shown + as `np.nan` values. + + Both ``dbh`` and ``stem_height`` must be provided as one-dimensional arrays and + it is an error to provide both. The method returns a dictionary of the + allometric predictions of the T Model: + + + * "whole_crown_gpp" + * "sapwood_respiration" + * "foliar_respiration" + * "fine_root_respiration" + * "npp" + * "turnover" + * "delta_dbh" + * "delta_stem_mass" + * "delta_foliage_mass"], + + Each dictionary entry is a 2D array with PFTs as columns and the predictions for + each size value as rows. + + Args: + potential_gpp: An array of potential GPP values. + dbh: An array of diameter at breast height values. + stem_height: An array of stem height values. + """ + + # Need exclusively one of dbh or stem_height - use XOR + if not ((dbh is None) ^ (stem_height is None)): + raise ValueError("Provide one of either dbh or stem_height") + + if stem_height is not None: + # Check array dimensions + if stem_height.ndim != 1: + raise ValueError("Stem heights must be a one dimensional array") + + # Convert stem heights back into an array of initial DBH values + # - broadcast to (n_heights, n_pfts) + n_size = stem_height.size + stem_height = np.broadcast_to(stem_height[:, None], (n_size, self.n_pfts)) + dbh_arr = calculate_dbh_from_height( + h_max=self.data["h_max"], + a_hd=self.data["a_hd"], + stem_height=stem_height, + ) + elif dbh is not None: + # Check array dimensions + if dbh.ndim != 1: + raise ValueError("DBH must be a one dimensional array") + + # Broadcast the dbh to a (n_heights, n_pfts) + n_size = dbh.size + dbh_arr = np.broadcast_to(dbh[:, None], (n_size, self.n_pfts)) + + if not ((potential_gpp.ndim == 1) and (potential_gpp.size == n_size)): + raise ValueError( + "GPP must be a one dimensional array of the same " + "size as DBH or stem height" + ) + + gpp_arr = np.broadcast_to(potential_gpp[:, None], (n_size, self.n_pfts)) + + return calculate_t_model_growth( + pft_data=self.data, dbh=dbh_arr, potential_gpp=gpp_arr + ) # @dataclass diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 15c12b91..4076253a 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -511,7 +511,6 @@ def calculate_growth_increments( * the stem mass (:math:`\Delta W_s`), and * the foliar mass (:math:`\Delta W_f`). - The stem diameter increment can be calculated using the available productivity for growth and the rates of change in stem (:math:`\textrm{d}W_s / \textrm{d}t`) and foliar masses (:math:`\textrm{d}W_f / \textrm{d}t`): @@ -573,6 +572,10 @@ def calculate_growth_increments( dbh: Diameter at breast height of individuals stem_height: Stem height of individuals validate: Boolean flag to suppress argument validation + + Returns: + A tuple of arrays containing the calculated increments in stem diameter, stem + mass and foliar mass. """ if validate: _validate_t_model_args( @@ -602,15 +605,21 @@ def calculate_growth_increments( return (delta_d, dWsdt * delta_d, dWfdt * delta_d) -def calculate_t_model( +def calculate_t_model_allometry( pft_data: dict[str, NDArray[np.float32]], dbh: NDArray[np.float32] ) -> dict[str, NDArray[np.float32]]: - """Calculate T Model predictions across cohort data. + """Calculate T Model allometric predictions across cohort data. - This method calculate predictions of stem allometries under the T Model + This method calculate predictions of stem allometries for stem height, crown area, + crown fraction, stem mass, foliage mass and sapwood mass under the T Model :cite:`Li:2014bc`, given diameters at breast height for a set of plant functional traits. + Args: + pft_data: A dictionary of plant functional trait data, as for example returned + from :attr:`Flora.data` attribute. + dbh: An array of diameter at breast height values for which to predict stem + allometry values. """ stem_data = {"dbh": dbh} @@ -655,3 +664,77 @@ def calculate_t_model( ) return stem_data + + +def calculate_t_model_growth( + pft_data: dict[str, NDArray[np.float32]], + dbh: NDArray[np.float32], + potential_gpp: NDArray[np.float32], +) -> dict[str, NDArray[np.float32]]: + """Calculate T Model predictions across cohort data. + + This method calculate predictions of stem allometries and growth predictions under + the T Model :cite:`Li:2014bc`, given both diameters at breast height for a set of + plant functional traits and potential gross primary productivity estimates for each + height. + """ + + stem_data = calculate_t_model_allometry(pft_data=pft_data, dbh=dbh) + + stem_data["whole_crown_gpp"] = calculate_whole_crown_gpp( + potential_gpp=potential_gpp, + crown_area=stem_data["crown_area"], + par_ext=pft_data["par_ext"], + lai=pft_data["lai"], + ) + + stem_data["sapwood_respiration"] = calculate_sapwood_respiration( + resp_s=pft_data["lai"], sapwood_mass=stem_data["sapwood_mass"] + ) + + stem_data["foliar_respiration"] = calculate_foliar_respiration( + resp_f=pft_data["resp_f"], whole_crown_gpp=stem_data["whole_crown_gpp"] + ) + + stem_data["fine_root_respiration"] = calculate_fine_root_respiration( + zeta=pft_data["zeta"], + sla=pft_data["sla"], + resp_r=pft_data["resp_r"], + foliage_mass=stem_data["foliage_mass"], + ) + + stem_data["npp"] = calculate_net_primary_productivity( + yld=pft_data["yld"], + whole_crown_gpp=stem_data["whole_crown_gpp"], + foliar_respiration=stem_data["foliar_respiration"], + fine_root_respiration=stem_data["fine_root_respiration"], + sapwood_respiration=stem_data["sapwood_respiration"], + ) + + stem_data["turnover"] = calculate_foliage_and_fine_root_turnover( + sla=pft_data["sla"], + zeta=pft_data["zeta"], + tau_f=pft_data["tau_f"], + tau_r=pft_data["tau_r"], + foliage_mass=stem_data["foliage_mass"], + ) + + ( + stem_data["delta_dbh"], + stem_data["delta_stem_mass"], + stem_data["delta_foliage_mass"], + ) = calculate_growth_increments( + rho_s=pft_data["rho_s"], + a_hd=pft_data["a_hd"], + h_max=pft_data["h_max"], + lai=pft_data["lai"], + ca_ratio=pft_data["ca_ratio"], + sla=pft_data["sla"], + zeta=pft_data["zeta"], + npp=stem_data["npp"], + turnover=stem_data["turnover"], + dbh=stem_data["dbh"], + stem_height=stem_data["stem_height"], + ) + + return stem_data From 9a5d1d222f00fe83861afc125c4e7de56055e858 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 24 Sep 2024 23:31:46 +0100 Subject: [PATCH 139/241] Refactor of Canopy.__init__ to isolate init from calculation --- pyrealm/demography/canopy.py | 125 ++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 54 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index d54ec7c1..c7a00d5b 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -40,44 +40,69 @@ def __init__( canopy_gap_fraction: float = 0.05, layer_tolerance: float = 0.001, ) -> None: - # Calculate community wide properties: total crown area and maximum height - self.total_community_crown_area: float = ( - community.cohort_data["crown_area"] * community.cohort_data["n_individuals"] - ).sum() + self.canopy_gap_fraction: float = canopy_gap_fraction + """Canopy gap fraction.""" + self.layer_tolerance: float = layer_tolerance + """Numerical tolerance for solving canopy layer closure.""" + self.total_community_crown_area: float """Total crown area across individuals in the community (metres 2).""" - - self.max_stem_height: float = community.cohort_data["stem_height"].max() + self.max_stem_height: float """Maximum height of any individual in the community (metres).""" - - self.crown_area_per_layer: float = community.cell_area * ( - 1 - canopy_gap_fraction - ) + self.crown_area_per_layer: float """Total crown area permitted in a single canopy layer, given the available cell area of the community and its canopy gap fraction.""" + self.n_layers: int + """Total number of canopy layers.""" + self.n_cohorts: int + """Total number of cohorts in the canopy.""" + self.layer_heights: NDArray[np.float32] + """Column vector of the heights of canopy layers.""" + self.stem_relative_radius: NDArray[np.float32] + """Relative radius values of stems at canopy layer heights.""" + self.stem_crown_area: NDArray[np.float32] + """Stem projected crown area at canopy layer heights.""" + self.stem_leaf_area: NDArray[np.float32] + """Stem projected leaf area at canopy layer heights.""" + + self._calculate_canopy(community=community) - self.n_layers: int = int( + def _calculate_canopy(self, community: Community) -> None: + """Calculate the canopy structure. + + This private method runs the calculations needed to populate the instance + attributes. + + Args: + community: The Community object passed to the instance. + """ + + # Calculate community wide properties: total crown area, maximum height, crown + # area required to fill a layer and total number of canopy layers + self.total_community_crown_area = ( + community.cohort_data["crown_area"] * community.cohort_data["n_individuals"] + ).sum() + + self.max_stem_height = community.cohort_data["stem_height"].max() + + self.crown_area_per_layer = community.cell_area * (1 - self.canopy_gap_fraction) + + self.n_layers = int( np.ceil(self.total_community_crown_area / self.crown_area_per_layer) ) - """Total number of canopy layers.""" - - self.n_cohorts: int = community.number_of_cohorts - """Total number of cohorts in the canopy.""" + self.n_cohorts = community.number_of_cohorts # Find the closure heights of the canopy layers under the perfect plasticity # approximation by solving Ac(z) - L_n = 0 across the community where L is the # total cumulative crown area in layer n and above, discounted by the canopy gap # fraction. - self.layer_heights: NDArray[np.float32] = np.zeros( - (self.n_layers, 1), dtype=np.float32 - ) - """Column vector of the heights of canopy layers.""" + self.layer_heights = np.zeros((self.n_layers, 1), dtype=np.float32) # Loop over the layers except for the final layer, which will be the partial # remaining vegetation below the last closed layer. starting_guess = self.max_stem_height for layer in np.arange(self.n_layers - 1): - target_area = (layer + 1) * community.cell_area * (1 - canopy_gap_fraction) + target_area = (layer + 1) * self.crown_area_per_layer # TODO - the solution here is typically closer to the upper bracket, might # be a better algorithm to find the root (#293). @@ -95,7 +120,7 @@ def __init__( False, # validate ), bracket=(0, starting_guess), - xtol=layer_tolerance, + xtol=self.layer_tolerance, ) if not solution.converged: @@ -109,41 +134,33 @@ def __init__( # NOTE - here and in the calls below, validate=False is enforced because the # Community class structures and code should guarantee valid inputs and so # turning off the validation internally should simply speed up the code. - self.stem_relative_radius: NDArray[np.float32] = ( - calculate_relative_canopy_radius_at_z( - z=self.layer_heights, - stem_height=community.cohort_data["stem_height"], - m=community.cohort_data["m"], - n=community.cohort_data["n"], - validate=False, - ) + self.stem_relative_radius = calculate_relative_canopy_radius_at_z( + z=self.layer_heights, + stem_height=community.cohort_data["stem_height"], + m=community.cohort_data["m"], + n=community.cohort_data["n"], + validate=False, ) - """Relative radius values of stems at canopy layer heights.""" - self.stem_crown_area: NDArray[np.float32] = ( - calculate_stem_projected_crown_area_at_z( - z=self.layer_heights, - q_z=self.stem_relative_radius, - crown_area=community.cohort_data["crown_area"], - stem_height=community.cohort_data["stem_height"], - q_m=community.cohort_data["q_m"], - z_max=community.cohort_data["canopy_z_max"], - validate=False, - ) + # Calculate projected crown area of a cohort stem at canopy closure heights. + self.stem_crown_area = calculate_stem_projected_crown_area_at_z( + z=self.layer_heights, + q_z=self.stem_relative_radius, + crown_area=community.cohort_data["crown_area"], + stem_height=community.cohort_data["stem_height"], + q_m=community.cohort_data["q_m"], + z_max=community.cohort_data["canopy_z_max"], + validate=False, ) - """Stem projected crown area at canopy layer heights.""" - # Find the stem projected leaf area at canopy closure heights. - self.stem_leaf_area: NDArray[np.float32] = ( - calculate_stem_projected_leaf_area_at_z( - z=self.layer_heights, - q_z=self.stem_relative_radius, - crown_area=community.cohort_data["crown_area"], - stem_height=community.cohort_data["stem_height"], - f_g=community.cohort_data["f_g"], - q_m=community.cohort_data["q_m"], - z_max=community.cohort_data["canopy_z_max"], - validate=False, - ) + # Find the projected leaf area of a cohort stem at canopy closure heights. + self.stem_leaf_area = calculate_stem_projected_leaf_area_at_z( + z=self.layer_heights, + q_z=self.stem_relative_radius, + crown_area=community.cohort_data["crown_area"], + stem_height=community.cohort_data["stem_height"], + f_g=community.cohort_data["f_g"], + q_m=community.cohort_data["q_m"], + z_max=community.cohort_data["canopy_z_max"], + validate=False, ) - """Stem projected leaf area at canopy layer heights.""" From ec55432b871379eaf7d7e47c9587a80978e7cc96 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 24 Sep 2024 23:32:57 +0100 Subject: [PATCH 140/241] Typo in docstring --- pyrealm/demography/flora.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 30b0a25d..7df326a0 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -417,7 +417,7 @@ def get_growth( * "turnover" * "delta_dbh" * "delta_stem_mass" - * "delta_foliage_mass"], + * "delta_foliage_mass" Each dictionary entry is a 2D array with PFTs as columns and the predictions for each size value as rows. From 165615693282041d9f4542759e23d517be7c099e Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 25 Sep 2024 09:40:05 +0100 Subject: [PATCH 141/241] Updated typing on q_m and p_zm functions --- pyrealm/demography/canopy_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 08271cf0..a4ffa4a4 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -10,7 +10,7 @@ def calculate_canopy_q_m( m: float | NDArray[np.float32], n: float | NDArray[np.float32] -) -> NDArray[np.float32]: +) -> float | NDArray[np.float32]: """Calculate the canopy scaling paramater ``q_m``. The value of q_m is a constant canopy scaling parameter derived from the ``m`` and @@ -30,7 +30,7 @@ def calculate_canopy_q_m( def calculate_canopy_z_max_proportion( m: float | NDArray[np.float32], n: float | NDArray[np.float32] -) -> NDArray[np.float32]: +) -> float | NDArray[np.float32]: r"""Calculate the z_m proportion. The z_m proportion (:math:`p_{zm}`) is the constant proportion of stem height at From 1b4b812d20150dd62f4c781319352dd21a70b08d Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 25 Sep 2024 13:02:49 +0100 Subject: [PATCH 142/241] Merge canopy validation functions to avoid duplication and provide better exception messages; partial update tests --- pyrealm/demography/canopy_functions.py | 144 ++++---- .../unit/demography/test_canopy_functions.py | 309 +++++++++++++----- 2 files changed, 310 insertions(+), 143 deletions(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index a4ffa4a4..38fd9d78 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -101,70 +101,83 @@ def calculate_canopy_r0( return 1 / q_m * np.sqrt(crown_area / np.pi) -def _validate_z_args(z: NDArray[np.float32], *args: NDArray[np.float32]) -> None: - """Shared validation routine for vertical height arguments. - - The canopy functions that take a height argument ``z`` can take a range of input - shapes for ``z``, alongside a set of other row arrays representing cohort - properties. This function is used to check that the cohort properties are of equal - length and that the ``z`` value has one of the accepted shapes described in - :meth:`~pyrealm.demography.canopy_functions.calculate_relative_canopy_radius_at_z`. - - Args: - z: The inputs to the ``z`` argument of a function. - args: Other arrays representing cohort properties. - """ - - if z.size == 1 or z.ndim == 1: - # All same height or stem specific heights - check z is either a scalar or also - # a row vector of the right length. - check_input_shapes(z, *args) - return - elif z.ndim == 2 and z.shape[1] == 1: - # Z is a column vector, just check stem properties. - check_input_shapes(*args) - return - - raise ValueError("Invalid shape for the z value.") - - -def _validate_q_z( +def _validate_z_qz_args( z: NDArray[np.float32], - q_z: NDArray[np.float32], - stem_property: NDArray[np.float32], + stem_properties: list[NDArray[np.float32]], + q_z: NDArray[np.float32] | None = None, ) -> None: - """Shared validation routine for relative radius arguments. - - The functions - :meth:`~pyrealm.demography.canopy_functions.calculate_stem_projected_canopy_area_at_z` - and - :meth:`~pyrealm.demography.canopy_functions.calculate_stem_projected_leaf_area_at_z` - both require the arguments ``z`` and ``q_z``, where ``z`` is an array of vertical - heights and ``q_z`` is the relative canopy radius at those heights for a set of - stems. This function checks that the inputs are congruent with each other, and with - the shape of a stem property argument, given the set of expected forms of ``z`` - described in - :meth:`~pyrealm.demography.canopy_functions.calculate_relative_canopy_radius_at_z`. - + """Shared validation of for canopy function arguments. + + Several of the canopy functions in this module require a vertical height (``z``) + argument and, in some cases, the relative canopy radius (``q_z``) at that height. + These arguments need to have shapes that are congruent with each other and with the + arrays providing stem properties for which values are calculated. + + This function provides the following validation checks (see also the documentation + of accepted shapes for ``z`` in + :meth:`~pyrealm.demography.canopy_functions.calculate_relative_canopy_radius_at_z`). + + * Stem properties are identically shaped row (1D) arrays. + * The ``z`` argument is then one of: + * a scalar arrays (i.e. np.array(42) or np.array([42])), + * a row array with identical shape to the stem properties, or + * a column vector array (i.e. with shape ``(N, 1)``). + * If ``q_z`` is provided then: + * if ``z`` is a row array, ``q_z`` must then have identical shape, or + * if ``z`` is a column array ``(N, 1)``, ``q_z`` must then have shape ``(N, + n_stem_properties``). Args: - z: The input to the ``z`` argument. - q_z: The input to the ``q_z`` argument. - stem_property: An argument input representing a stem property. + z: An array input to the ``z`` argument of a canopy function. + stem_properties: A list of array inputs representing stem properties. + q_z: An optional array input to the ``q_z`` argument of a canopy function. """ - if z.size == 1 or z.ndim == 1: - # All same height or stem specific heights - q_z must then also be row vector of - # the same length as the stem propertys and z must be scalar or a row_vector. - check_input_shapes(z, q_z, stem_property) - return - elif z.ndim == 2 and z.shape[1] == 1: - # z is a column array, so check q_z is a matrix - if q_z.shape != (z.size, stem_property.size): - raise ValueError("Invalid shape for q_z.") - return + # Check the stem properties + try: + stem_shape = check_input_shapes(*stem_properties) + except ValueError: + raise ValueError("Stem properties are not of equal size") + + if len(stem_shape) > 1: + raise ValueError("Stem properties are not row arrays") + + # Record the number of stems + n_stems = stem_shape[0] + + # Trap error conditions for z array + if z.size == 1: + pass + elif (z.ndim == 1) and (z.shape != stem_shape): + raise ValueError( + f"The z argument is a row array (shape: {z.shape}) but is not congruent " + f"with the cohort data (shape: {stem_shape})." + ) + elif (z.ndim == 2) and (z.shape[1] != 1): + raise ValueError( + f"The z argument is two dimensional (shape: {z.shape}) but is " + "not a column array." + ) + elif z.ndim > 2: + raise ValueError( + f"The z argument (shape: {z.shape}) is not a row or column vector array" + ) + + # Now test q_z congruence with z if provided + if q_z is not None: + if ((z.size == 1) or (z.ndim == 1)) and (z.shape != q_z.shape): + raise ValueError( + f"The q_z argument (shape: {q_z.shape}) is not a row array " + f"matching stem properties (shape: {stem_shape})" + ) + elif (z.ndim == 2) and (q_z.shape != (z.size, n_stems)): + raise ValueError( + f"The q_z argument (shape: {q_z.shape}) is not a 2D array congruent " + f"with the broadcasted shape of the z argument (shape: {z.shape}) " + f"and stem property arguments (shape: {stem_shape})" + ) - raise ValueError("Invalid shape for the z value.") + return def calculate_relative_canopy_radius_at_z( @@ -208,7 +221,7 @@ def calculate_relative_canopy_radius_at_z( """ if validate: - _validate_z_args(z, stem_height, m, n) + _validate_z_qz_args(z=z, stem_properties=[stem_height, m, n]) z_over_height = z / stem_height @@ -246,8 +259,9 @@ def calculate_stem_projected_crown_area_at_z( """ if validate: - _validate_z_args(z, stem_height, crown_area, q_m, z_max) - _validate_q_z(z, q_z, crown_area) + _validate_z_qz_args( + z=z, stem_properties=[stem_height, crown_area, q_m, z_max], q_z=q_z + ) # Calculate A_p # Calculate Ap given z > zm @@ -307,8 +321,9 @@ def solve_community_projected_canopy_area( z_arr = np.array(z) if validate: - _validate_z_args( - z_arr, n_individuals, crown_area, stem_height, m, n, q_m, z_max + _validate_z_qz_args( + z=z_arr, + stem_properties=[n_individuals, crown_area, stem_height, m, n, q_m, z_max], ) q_z = calculate_relative_canopy_radius_at_z( @@ -370,8 +385,9 @@ def calculate_stem_projected_leaf_area_at_z( # lean as possible, as it used within solve_community_projected_canopy_area. if validate: - _validate_z_args(z, crown_area, stem_height, f_g, q_m, z_max) - _validate_q_z(z, q_z, crown_area) + _validate_z_qz_args( + z=z, stem_properties=[crown_area, stem_height, f_g, q_m, z_max], q_z=q_z + ) # Calculate Ac terms A_c_terms = crown_area * (q_z / q_m) ** 2 diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index 03019170..31f9997a 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -1,5 +1,6 @@ """test the functions in canopy_functions.py.""" +from collections import namedtuple from contextlib import nullcontext as does_not_raise import numpy as np @@ -83,105 +84,255 @@ def test_calculate_r_0_values(fixture_canopy_shape, crown_areas, expected_r0): assert np.allclose(actual_r0_values, expected_r0) -@pytest.fixture -def fixture_z_qz_stem_properties(request): - """Fixture providing test cases of z, q_z and stem properties . +ZQZInput = namedtuple( + "ZQZInput", ["z", "stem", "more_stem", "q_z", "outcome", "excep_msg"] +) +"""Simple named tuple to make inputs to z and qz checking a bit clearer. - This fixture allows tests to use indirect parameterisation to share a set of test - cases of inputs for the z, stem properties and q_z arguments. In each case, the - returned value is a tuple of arrays that just provide the correct shapes for the - various test cases: +Contents: +* an input value for z +* a first stem property row array +* a list giving another stem property array +* a value for q_z array or None +* the validation outcome: a pytest.raises or does_not_raise context handler +* the start of the expected message on failure or None. - * an input value for z - * a first stem property row array - * a list giving another stem property array - * an array with the shape of the resulting q_z value from the above or None if those - inputs are invalid for calculating q_z - The two stem property arrays allow the number of properties to be controlled at the - test level (differing number of args for different functions) but also to introduce - inconsistent property lengths. To package these up for use with, for example a total - of 3 stem properties: +The two stem property elements allow the number of properties to be controlled at +the test level (differing number of args for different functions) but also to +introduce inconsistent property lengths. To package these up for use with, for +example a total of 3 stem properties: - .. code:: python +.. code:: python - z, arg1, args, q_z = fixture_z_qz_stem_properties - stem_args = [arg1, * args * 2] + z, stem, more_stem, q_z, outcome, excep_msg = fixture_z_qz_stem_properties + stem_args = [stem, * more_stem * 2] +""" - """ - match request.param: - case "0D_z_ok": - return (np.array(1), np.ones(4), [np.ones(4)], np.ones(4)) - case "1D_scalar_z_ok": - return (np.ones(1), np.ones(4), [np.ones(4)], np.ones(4)) - case "1D_row_z_ok": - return (np.ones(4), np.ones(4), [np.ones(4)], np.ones(4)) - case "2D_column_z_ok": - return (np.ones((4, 1)), np.ones(4), [np.ones(4)], np.ones((4, 4))) - case "1D_row_z_wrong_length": - return (np.ones(5), np.ones(4), [np.ones(4)], None) - case "2D_z_not_column": - return (np.ones((4, 2)), np.ones(4), [np.ones(4)], None) - case "inconsistent_stem_properties": - return (np.ones(4), np.ones(5), [np.ones(4)], None) - case "1D_q_z_inconsistent": - return (np.ones(4), np.ones(4), [np.ones(4)], np.ones(5)) - case "2D_q_z_inconsistent": - return (np.ones(4), np.ones(4), [np.ones(4)], np.ones((5, 4))) - - -@pytest.mark.parametrize( - argnames="fixture_z_qz_stem_properties, outcome", - argvalues=[ - ("0D_z_ok", does_not_raise()), - ("1D_scalar_z_ok", does_not_raise()), - ("1D_row_z_ok", does_not_raise()), - ("2D_column_z_ok", does_not_raise()), - ("1D_row_z_wrong_length", pytest.raises(ValueError)), - ("2D_z_not_column", pytest.raises(ValueError)), - ("inconsistent_stem_properties", pytest.raises(ValueError)), - ], - indirect=["fixture_z_qz_stem_properties"], -) -def test__validate_z_args(fixture_z_qz_stem_properties, outcome): - """Tests the validation of z args to canopy functions.""" +@pytest.fixture +def fixture_z_qz_stem_properties(request): + """Fixture providing test cases of z, q_z and stem properties . - from pyrealm.demography.canopy_functions import _validate_z_args + This fixture provides a menu of inputs that can be used by tests throught indirect + parameterisation to share a set of test cases of inputs for the z, stem properties + q_z arguments and expected outcome and exception message. In each case, the returned + value is a ZQZInput instance. - # Build inputs - z, arg1, args, _ = fixture_z_qz_stem_properties - stem_args = [arg1, *args * 2] # length of args doesn't really matter here. + The tests here are ordered in the execution order of _validate_z_qz_arg, so failing + inputs only provide non-None values for the elements required to trigger the fail. + """ - with outcome: - _validate_z_args(z, *stem_args) + match request.param: + case "fail_stem_props_unequal": + return ZQZInput( + z=None, + stem=np.ones(5), + more_stem=[np.ones(4)], + q_z=None, + outcome=pytest.raises(ValueError), + excep_msg="Stem properties are not of equal size", + ) + case "fail_stem_props_not_1D": + return ZQZInput( + z=None, + stem=np.ones((5, 2)), + more_stem=[np.ones((5, 2))], + q_z=None, + outcome=pytest.raises(ValueError), + excep_msg="Stem properties are not row arrays", + ) + case "fail_1D_z_not_congruent_with_stem": + return ZQZInput( + z=np.ones(5), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=None, + outcome=pytest.raises(ValueError), + excep_msg="The z argument is a row array (shape: (5,)) but is not " + "congruent with the cohort data (shape: (4,))", + ) + case "fail_2D_z_not_column_array": + return ZQZInput( + z=np.ones((5, 2)), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=None, + outcome=pytest.raises(ValueError), + excep_msg="The z argument is two dimensional (shape: (5, 2)) but is " + "not a column array.", + ) + case "fail_z_more_than_2D": + return ZQZInput( + z=np.ones((5, 2, 6)), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=None, + outcome=pytest.raises(ValueError), + excep_msg="The z argument (shape: (5, 2, 6)) is not " + "a row or column vector array", + ) + case "pass_0D_z": + return ZQZInput( + z=np.array(1), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=None, + outcome=does_not_raise(), + excep_msg=None, + ) + case "pass_1D_scalar_z": + return ZQZInput( + z=np.ones(1), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=None, + outcome=does_not_raise(), + excep_msg=None, + ) + case "pass_1D_row_array_z": + return ZQZInput( + z=np.ones(4), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=None, + outcome=does_not_raise(), + excep_msg=None, + ) + case "pass_2D_column_array_z": + return ZQZInput( + z=np.ones((5, 1)), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=None, + outcome=does_not_raise(), + excep_msg=None, + ) + case "fail_0D_z_but_q_z_not_row": + return ZQZInput( + z=np.array(1), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=np.ones(7), + outcome=pytest.raises(ValueError), + excep_msg="The q_z argument (shape: (7,)) is not a row array " + "matching stem properties (shape: (4,))", + ) + case "fail_1D_scalar_z_but_q_z_not_row": + return ZQZInput( + z=np.ones(1), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=np.ones((6, 9)), + outcome=pytest.raises(ValueError), + excep_msg="The q_z argument (shape: (6, 9)) is not a row array " + "matching stem properties (shape: (4,))", + ) + case "fail_1D_row_z_but_q_z_not_row": + return ZQZInput( + z=np.ones(4), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=np.array(1), + outcome=pytest.raises(ValueError), + excep_msg="The q_z argument (shape: ()) is not a row array " + "matching stem properties (shape: (4,))", + ) + case "fail_2D_column_z_but_q_z_not_congruent": + return ZQZInput( + z=np.ones((5, 1)), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=np.ones((6, 9)), + outcome=pytest.raises(ValueError), + excep_msg="The q_z argument (shape: (6, 9)) is not a 2D array " + "congruent with the broadcasted shape of the z argument (shape: " + "(5, 1)) and stem property arguments (shape: (4,))", + ) + + # case "0D_z_ok": + # return (np.array(1), np.ones(4), [np.ones(4)], np.ones(4)) + # case "1D_scalar_z_ok": + # return (np.ones(1), np.ones(4), [np.ones(4)], np.ones(4)) + # case "1D_row_z_ok": + # return (np.ones(4), np.ones(4), [np.ones(4)], np.ones(4)) + # case "2D_column_z_ok": + # return (np.ones((4, 1)), np.ones(4), [np.ones(4)], np.ones((4, 4))) + # case "1D_row_z_wrong_length": + # return (np.ones(5), np.ones(4), [np.ones(4)], None) + # case "2D_z_not_column": + # return (np.ones((4, 2)), np.ones(4), [np.ones(4)], None) + # case "stem_properties_not_1D": + # return (np.ones(4), np.ones((4, 2)), [np.ones((4, 2))], None) + # case "inconsistent_stem_properties": + # return (np.ones(4), np.ones(5), [np.ones(4)], None) + # case "1D_q_z_inconsistent": + # return (np.ones(4), np.ones(4), [np.ones(4)], np.ones(5)) + # case "2D_q_z_inconsistent": + # return (np.ones(4), np.ones(4), [np.ones(4)], np.ones((5, 4))) @pytest.mark.parametrize( - argnames="fixture_z_qz_stem_properties, outcome", + argnames="fixture_z_qz_stem_properties", argvalues=[ - ("0D_z_ok", does_not_raise()), - ("1D_scalar_z_ok", does_not_raise()), - ("1D_row_z_ok", does_not_raise()), - ("2D_column_z_ok", does_not_raise()), - ("1D_row_z_wrong_length", pytest.raises(ValueError)), - ("2D_z_not_column", pytest.raises(ValueError)), - ("inconsistent_stem_properties", pytest.raises(ValueError)), - ("1D_q_z_inconsistent", pytest.raises(ValueError)), - ("2D_q_z_inconsistent", pytest.raises(ValueError)), + "fail_stem_props_unequal", + "fail_stem_props_not_1D", + "fail_1D_z_not_congruent_with_stem", + "fail_2D_z_not_column_array", + "fail_z_more_than_2D", + "pass_0D_z", + "pass_1D_scalar_z", + "pass_1D_row_array_z", + "pass_2D_column_array_z", + "fail_0D_z_but_q_z_not_row", + "fail_1D_scalar_z_but_q_z_not_row", + "fail_1D_row_z_but_q_z_not_row", + "fail_2D_column_z_but_q_z_not_congruent", + # pytest.param("0D_z_ok", does_not_raise(), None, id="0D_z_ok"), + # pytest.param("1D_scalar_z_ok", does_not_raise(), None, id="1D_scalar_z_ok"), + # pytest.param("1D_row_z_ok", does_not_raise(), None, id="1D_row_z_ok"), + # pytest.param("2D_column_z_ok", does_not_raise(), None, id="2D_column_z_ok"), + # pytest.param( + # "1D_row_z_wrong_length", + # pytest.raises(ValueError), + # "The z argument is a row array", + # id="1D_row_z_wrong_length", + # ), + # pytest.param( + # "2D_z_not_column", + # pytest.raises(ValueError), + # "The z argument is two dimensional", + # id="2D_z_not_column", + # ), + # pytest.param( + # "inconsistent_stem_properties", + # pytest.raises(ValueError), + # "Cohort properties are not of equal size", + # id="inconsistent_stem_properties", + # ), + # pytest.param( + # "stem_properties_not_1D", + # pytest.raises(ValueError), + # "Cohort properties are not row arrays", + # id="stem_properties_not_1D", + # ), ], indirect=["fixture_z_qz_stem_properties"], ) -def test__validate_q_z_args(fixture_z_qz_stem_properties, outcome): - """Tests the validation of z args to canopy functions.""" +def test__validate_z_qz__args(fixture_z_qz_stem_properties): + """Tests the validation function for arguments to canopy functions.""" - from pyrealm.demography.canopy_functions import _validate_q_z + from pyrealm.demography.canopy_functions import _validate_z_qz_args - # Build inputs - z, stem_property, _, q_z = fixture_z_qz_stem_properties + # Unpack the input arguments for the test case + z, stem, more_stem, q_z, outcome, excep_msg = fixture_z_qz_stem_properties + stem_args = [stem, *more_stem * 2] # length of args doesn't really matter here. - with outcome: - _validate_q_z(z, q_z, stem_property) + with outcome as excep: + _validate_z_qz_args(z=z, stem_properties=stem_args, q_z=q_z) + return + + assert str(excep.value).startswith(excep_msg) @pytest.mark.parametrize( From c2814e3b70c49a1de667a00fee852ded9ed6689f Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 25 Sep 2024 14:28:28 +0100 Subject: [PATCH 143/241] Updating the rest of the test_canopy_functions --- pyrealm/demography/canopy_functions.py | 2 +- .../unit/demography/test_canopy_functions.py | 241 ++++++++++-------- 2 files changed, 139 insertions(+), 104 deletions(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 38fd9d78..15eae194 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -165,7 +165,7 @@ def _validate_z_qz_args( # Now test q_z congruence with z if provided if q_z is not None: - if ((z.size == 1) or (z.ndim == 1)) and (z.shape != q_z.shape): + if ((z.size == 1) or (z.ndim == 1)) and (q_z.shape != stem_shape): raise ValueError( f"The q_z argument (shape: {q_z.shape}) is not a row array " f"matching stem properties (shape: {stem_shape})" diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index 31f9997a..e79533c2 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -85,7 +85,8 @@ def test_calculate_r_0_values(fixture_canopy_shape, crown_areas, expected_r0): ZQZInput = namedtuple( - "ZQZInput", ["z", "stem", "more_stem", "q_z", "outcome", "excep_msg"] + "ZQZInput", + ["z", "stem", "more_stem", "q_z", "outcome", "excep_msg", "output_shape"], ) """Simple named tuple to make inputs to z and qz checking a bit clearer. @@ -96,7 +97,7 @@ def test_calculate_r_0_values(fixture_canopy_shape, crown_areas, expected_r0): * a value for q_z array or None * the validation outcome: a pytest.raises or does_not_raise context handler * the start of the expected message on failure or None. - +* the expected shape of successful output The two stem property elements allow the number of properties to be controlled at the test level (differing number of args for different functions) but also to @@ -105,7 +106,9 @@ def test_calculate_r_0_values(fixture_canopy_shape, crown_areas, expected_r0): .. code:: python - z, stem, more_stem, q_z, outcome, excep_msg = fixture_z_qz_stem_properties + z, stem, more_stem, q_z, outcome, excep_msg, exp_shape = ( + fixture_z_qz_stem_properties + ) stem_args = [stem, * more_stem * 2] """ @@ -132,6 +135,7 @@ def fixture_z_qz_stem_properties(request): q_z=None, outcome=pytest.raises(ValueError), excep_msg="Stem properties are not of equal size", + output_shape=None, ) case "fail_stem_props_not_1D": return ZQZInput( @@ -141,6 +145,7 @@ def fixture_z_qz_stem_properties(request): q_z=None, outcome=pytest.raises(ValueError), excep_msg="Stem properties are not row arrays", + output_shape=None, ) case "fail_1D_z_not_congruent_with_stem": return ZQZInput( @@ -151,6 +156,7 @@ def fixture_z_qz_stem_properties(request): outcome=pytest.raises(ValueError), excep_msg="The z argument is a row array (shape: (5,)) but is not " "congruent with the cohort data (shape: (4,))", + output_shape=None, ) case "fail_2D_z_not_column_array": return ZQZInput( @@ -161,6 +167,7 @@ def fixture_z_qz_stem_properties(request): outcome=pytest.raises(ValueError), excep_msg="The z argument is two dimensional (shape: (5, 2)) but is " "not a column array.", + output_shape=None, ) case "fail_z_more_than_2D": return ZQZInput( @@ -171,6 +178,7 @@ def fixture_z_qz_stem_properties(request): outcome=pytest.raises(ValueError), excep_msg="The z argument (shape: (5, 2, 6)) is not " "a row or column vector array", + output_shape=None, ) case "pass_0D_z": return ZQZInput( @@ -180,6 +188,7 @@ def fixture_z_qz_stem_properties(request): q_z=None, outcome=does_not_raise(), excep_msg=None, + output_shape=(4,), ) case "pass_1D_scalar_z": return ZQZInput( @@ -189,6 +198,7 @@ def fixture_z_qz_stem_properties(request): q_z=None, outcome=does_not_raise(), excep_msg=None, + output_shape=(4,), ) case "pass_1D_row_array_z": return ZQZInput( @@ -198,6 +208,7 @@ def fixture_z_qz_stem_properties(request): q_z=None, outcome=does_not_raise(), excep_msg=None, + output_shape=(4,), ) case "pass_2D_column_array_z": return ZQZInput( @@ -207,6 +218,7 @@ def fixture_z_qz_stem_properties(request): q_z=None, outcome=does_not_raise(), excep_msg=None, + output_shape=(5, 4), ) case "fail_0D_z_but_q_z_not_row": return ZQZInput( @@ -217,6 +229,7 @@ def fixture_z_qz_stem_properties(request): outcome=pytest.raises(ValueError), excep_msg="The q_z argument (shape: (7,)) is not a row array " "matching stem properties (shape: (4,))", + output_shape=None, ) case "fail_1D_scalar_z_but_q_z_not_row": return ZQZInput( @@ -227,6 +240,7 @@ def fixture_z_qz_stem_properties(request): outcome=pytest.raises(ValueError), excep_msg="The q_z argument (shape: (6, 9)) is not a row array " "matching stem properties (shape: (4,))", + output_shape=None, ) case "fail_1D_row_z_but_q_z_not_row": return ZQZInput( @@ -237,6 +251,7 @@ def fixture_z_qz_stem_properties(request): outcome=pytest.raises(ValueError), excep_msg="The q_z argument (shape: ()) is not a row array " "matching stem properties (shape: (4,))", + output_shape=None, ) case "fail_2D_column_z_but_q_z_not_congruent": return ZQZInput( @@ -248,28 +263,48 @@ def fixture_z_qz_stem_properties(request): excep_msg="The q_z argument (shape: (6, 9)) is not a 2D array " "congruent with the broadcasted shape of the z argument (shape: " "(5, 1)) and stem property arguments (shape: (4,))", + output_shape=None, + ) + case "pass_0D_z_and_q_z_row": + return ZQZInput( + z=np.array(1), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=np.ones(4), + outcome=does_not_raise(), + excep_msg=None, + output_shape=(4,), + ) + case "pass_1D_scalar_z_and_q_z_row": + return ZQZInput( + z=np.ones(1), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=np.ones(4), + outcome=does_not_raise(), + excep_msg=None, + output_shape=(4,), + ) + case "pass_1D_row_z_and_q_z_row": + return ZQZInput( + z=np.ones(4), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=np.ones(4), + outcome=does_not_raise(), + excep_msg=None, + output_shape=(4,), + ) + case "pass_2D_column_z_and_congruent_q_z": + return ZQZInput( + z=np.ones((5, 1)), + stem=np.ones(4), + more_stem=[np.ones(4)], + q_z=np.ones((5, 4)), + outcome=does_not_raise(), + excep_msg=None, + output_shape=(5, 4), ) - - # case "0D_z_ok": - # return (np.array(1), np.ones(4), [np.ones(4)], np.ones(4)) - # case "1D_scalar_z_ok": - # return (np.ones(1), np.ones(4), [np.ones(4)], np.ones(4)) - # case "1D_row_z_ok": - # return (np.ones(4), np.ones(4), [np.ones(4)], np.ones(4)) - # case "2D_column_z_ok": - # return (np.ones((4, 1)), np.ones(4), [np.ones(4)], np.ones((4, 4))) - # case "1D_row_z_wrong_length": - # return (np.ones(5), np.ones(4), [np.ones(4)], None) - # case "2D_z_not_column": - # return (np.ones((4, 2)), np.ones(4), [np.ones(4)], None) - # case "stem_properties_not_1D": - # return (np.ones(4), np.ones((4, 2)), [np.ones((4, 2))], None) - # case "inconsistent_stem_properties": - # return (np.ones(4), np.ones(5), [np.ones(4)], None) - # case "1D_q_z_inconsistent": - # return (np.ones(4), np.ones(4), [np.ones(4)], np.ones(5)) - # case "2D_q_z_inconsistent": - # return (np.ones(4), np.ones(4), [np.ones(4)], np.ones((5, 4))) @pytest.mark.parametrize( @@ -288,34 +323,10 @@ def fixture_z_qz_stem_properties(request): "fail_1D_scalar_z_but_q_z_not_row", "fail_1D_row_z_but_q_z_not_row", "fail_2D_column_z_but_q_z_not_congruent", - # pytest.param("0D_z_ok", does_not_raise(), None, id="0D_z_ok"), - # pytest.param("1D_scalar_z_ok", does_not_raise(), None, id="1D_scalar_z_ok"), - # pytest.param("1D_row_z_ok", does_not_raise(), None, id="1D_row_z_ok"), - # pytest.param("2D_column_z_ok", does_not_raise(), None, id="2D_column_z_ok"), - # pytest.param( - # "1D_row_z_wrong_length", - # pytest.raises(ValueError), - # "The z argument is a row array", - # id="1D_row_z_wrong_length", - # ), - # pytest.param( - # "2D_z_not_column", - # pytest.raises(ValueError), - # "The z argument is two dimensional", - # id="2D_z_not_column", - # ), - # pytest.param( - # "inconsistent_stem_properties", - # pytest.raises(ValueError), - # "Cohort properties are not of equal size", - # id="inconsistent_stem_properties", - # ), - # pytest.param( - # "stem_properties_not_1D", - # pytest.raises(ValueError), - # "Cohort properties are not row arrays", - # id="stem_properties_not_1D", - # ), + "pass_0D_z_and_q_z_row", + "pass_1D_scalar_z_and_q_z_row", + "pass_1D_row_z_and_q_z_row", + "pass_2D_column_z_and_congruent_q_z", ], indirect=["fixture_z_qz_stem_properties"], ) @@ -324,8 +335,8 @@ def test__validate_z_qz__args(fixture_z_qz_stem_properties): from pyrealm.demography.canopy_functions import _validate_z_qz_args - # Unpack the input arguments for the test case - z, stem, more_stem, q_z, outcome, excep_msg = fixture_z_qz_stem_properties + # Unpack the input arguments for the test case - not testing outputs here + z, stem, more_stem, q_z, outcome, excep_msg, _ = fixture_z_qz_stem_properties stem_args = [stem, *more_stem * 2] # length of args doesn't really matter here. with outcome as excep: @@ -336,21 +347,21 @@ def test__validate_z_qz__args(fixture_z_qz_stem_properties): @pytest.mark.parametrize( - argnames="fixture_z_qz_stem_properties, outcome", + argnames="fixture_z_qz_stem_properties", argvalues=[ - ("0D_z_ok", does_not_raise()), - ("1D_scalar_z_ok", does_not_raise()), - ("1D_row_z_ok", does_not_raise()), - ("2D_column_z_ok", does_not_raise()), - ("1D_row_z_wrong_length", pytest.raises(ValueError)), - ("2D_z_not_column", pytest.raises(ValueError)), - ("inconsistent_stem_properties", pytest.raises(ValueError)), + "fail_stem_props_unequal", + "fail_stem_props_not_1D", + "fail_1D_z_not_congruent_with_stem", + "fail_2D_z_not_column_array", + "fail_z_more_than_2D", + "pass_0D_z", + "pass_1D_scalar_z", + "pass_1D_row_array_z", + "pass_2D_column_array_z", ], indirect=["fixture_z_qz_stem_properties"], ) -def test_calculate_relative_canopy_radius_at_z_inputs( - fixture_z_qz_stem_properties, outcome -): +def test_calculate_relative_canopy_radius_at_z_inputs(fixture_z_qz_stem_properties): """Test calculate_relative_canopy_radius_at_z input and output shapes . This test checks the function behaviour with different inputs. @@ -361,15 +372,19 @@ def test_calculate_relative_canopy_radius_at_z_inputs( ) # Build inputs - z, arg1, args, q_z = fixture_z_qz_stem_properties - stem_args = [arg1, *args * 2] # Need 3 stem arguments. + z, stem, more_stem, _, outcome, excep_msg, out_shape = fixture_z_qz_stem_properties + stem_args = [stem, *more_stem * 2] # Need 3 stem arguments. - with outcome: + with outcome as excep: # Get the relative radius at that height q_z_values = calculate_relative_canopy_radius_at_z(z, *stem_args) if isinstance(outcome, does_not_raise): - assert q_z_values.shape == q_z.shape + assert q_z_values.shape == out_shape + + return + + assert str(excep.value).startswith(excep_msg) def test_calculate_relative_canopy_radius_at_z_values(fixture_community): @@ -407,36 +422,46 @@ def test_calculate_relative_canopy_radius_at_z_values(fixture_community): @pytest.mark.parametrize( - argnames="fixture_z_qz_stem_properties, outcome", + argnames="fixture_z_qz_stem_properties", argvalues=[ - ("0D_z_ok", does_not_raise()), - ("1D_scalar_z_ok", does_not_raise()), - ("1D_row_z_ok", does_not_raise()), - ("2D_column_z_ok", does_not_raise()), - ("1D_row_z_wrong_length", pytest.raises(ValueError)), - ("2D_z_not_column", pytest.raises(ValueError)), - ("inconsistent_stem_properties", pytest.raises(ValueError)), - ("1D_q_z_inconsistent", pytest.raises(ValueError)), - ("2D_q_z_inconsistent", pytest.raises(ValueError)), + "fail_stem_props_unequal", + "fail_stem_props_not_1D", + "fail_1D_z_not_congruent_with_stem", + "fail_2D_z_not_column_array", + "fail_z_more_than_2D", + "fail_0D_z_but_q_z_not_row", + "fail_1D_scalar_z_but_q_z_not_row", + "fail_1D_row_z_but_q_z_not_row", + "fail_2D_column_z_but_q_z_not_congruent", + "pass_0D_z_and_q_z_row", + "pass_1D_scalar_z_and_q_z_row", + "pass_1D_row_z_and_q_z_row", + "pass_2D_column_z_and_congruent_q_z", ], indirect=["fixture_z_qz_stem_properties"], ) -def test_calculate_stem_projected_crown_area_at_z_inputs( - fixture_z_qz_stem_properties, outcome -): +def test_calculate_stem_projected_crown_area_at_z_inputs(fixture_z_qz_stem_properties): """Tests the validation of inputs to calculate_stem_projected_crown_area_at_z.""" from pyrealm.demography.canopy_functions import ( calculate_stem_projected_crown_area_at_z, ) # Build inputs - z, arg1, args, q_z = fixture_z_qz_stem_properties - stem_args = [arg1, *args * 3] # Need 4 stem arguments. - with outcome: + z, stem, more_stem, q_z, outcome, excep_msg, out_shape = ( + fixture_z_qz_stem_properties + ) + stem_args = [stem, *more_stem * 3] # Need 4 stem arguments. + + with outcome as excep: + # Get the relative radius at that height Ap_z_values = calculate_stem_projected_crown_area_at_z(z, q_z, *stem_args) if isinstance(outcome, does_not_raise): - assert Ap_z_values.shape == q_z.shape + assert Ap_z_values.shape == out_shape + + return + + assert str(excep.value).startswith(excep_msg) @pytest.mark.parametrize( @@ -542,36 +567,46 @@ def test_solve_community_projected_canopy_area(fixture_community): @pytest.mark.parametrize( - argnames="fixture_z_qz_stem_properties, outcome", + argnames="fixture_z_qz_stem_properties", argvalues=[ - ("0D_z_ok", does_not_raise()), - ("1D_scalar_z_ok", does_not_raise()), - ("1D_row_z_ok", does_not_raise()), - ("2D_column_z_ok", does_not_raise()), - ("1D_row_z_wrong_length", pytest.raises(ValueError)), - ("2D_z_not_column", pytest.raises(ValueError)), - ("inconsistent_stem_properties", pytest.raises(ValueError)), - ("1D_q_z_inconsistent", pytest.raises(ValueError)), - ("2D_q_z_inconsistent", pytest.raises(ValueError)), + "fail_stem_props_unequal", + "fail_stem_props_not_1D", + "fail_1D_z_not_congruent_with_stem", + "fail_2D_z_not_column_array", + "fail_z_more_than_2D", + "fail_0D_z_but_q_z_not_row", + "fail_1D_scalar_z_but_q_z_not_row", + "fail_1D_row_z_but_q_z_not_row", + "fail_2D_column_z_but_q_z_not_congruent", + "pass_0D_z_and_q_z_row", + "pass_1D_scalar_z_and_q_z_row", + "pass_1D_row_z_and_q_z_row", + "pass_2D_column_z_and_congruent_q_z", ], indirect=["fixture_z_qz_stem_properties"], ) -def test_calculate_stem_projected_leaf_area_at_z_inputs( - fixture_z_qz_stem_properties, outcome -): +def test_calculate_stem_projected_leaf_area_at_z_inputs(fixture_z_qz_stem_properties): """Tests the validation of inputs to calculate_stem_projected_crown_area_at_z.""" from pyrealm.demography.canopy_functions import ( calculate_stem_projected_leaf_area_at_z, ) # Build inputs - z, arg1, args, q_z = fixture_z_qz_stem_properties - stem_args = [arg1, *args * 4] # Need 5 stem arguments. - with outcome: + z, stem, more_stem, q_z, outcome, excep_msg, out_shape = ( + fixture_z_qz_stem_properties + ) + stem_args = [stem, *more_stem * 4] # Need 5 stem arguments. + + with outcome as excep: + # Get the relative radius at that height Ap_z_values = calculate_stem_projected_leaf_area_at_z(z, q_z, *stem_args) if isinstance(outcome, does_not_raise): - assert Ap_z_values.shape == q_z.shape + assert Ap_z_values.shape == out_shape + + return + + assert str(excep.value).startswith(excep_msg) def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): From d2606fb83931f48c2ae163cb0936ae177042d840 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:06:40 +0000 Subject: [PATCH 144/241] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../pmodel/pmodel_details/extreme_values.md | 5 ---- .../pmodel/pmodel_details/worked_examples.md | 24 ------------------- .../subdaily_details/subdaily_calculations.md | 23 ------------------ .../pmodel/subdaily_details/worked_example.md | 20 ---------------- 4 files changed, 72 deletions(-) diff --git a/docs/source/users/pmodel/pmodel_details/extreme_values.md b/docs/source/users/pmodel/pmodel_details/extreme_values.md index 7119ac7f..01c92446 100644 --- a/docs/source/users/pmodel/pmodel_details/extreme_values.md +++ b/docs/source/users/pmodel/pmodel_details/extreme_values.md @@ -53,7 +53,6 @@ Note that the default values for C3 photosynthesis give **non-zero values below ```{code-cell} :tags: [hide-input] -:trusted: true from matplotlib import pyplot import numpy as np @@ -93,7 +92,6 @@ that again, $\Gamma^_$ has non-zero values for sub-zero temperatures. ```{code-cell} :tags: [hide-input] -:trusted: true # Calculate gammastar at different pressures tc_1d = np.linspace(-80, 100, n_pts) @@ -119,7 +117,6 @@ temperature and atmospheric pressure and again behaves smoothly with extreme val ```{code-cell} :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) @@ -144,7 +141,6 @@ issue with low temperatures arising from the equations for the density of water. ```{code-cell} :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) @@ -169,7 +165,6 @@ predictions below about -30 °C. ```{code-cell} :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) diff --git a/docs/source/users/pmodel/pmodel_details/worked_examples.md b/docs/source/users/pmodel/pmodel_details/worked_examples.md index f3db6947..6e9e2f0e 100644 --- a/docs/source/users/pmodel/pmodel_details/worked_examples.md +++ b/docs/source/users/pmodel/pmodel_details/worked_examples.md @@ -39,8 +39,6 @@ The example shows the steps required using a single site with: ### Estimate photosynthetic environment ```{code-cell} -:trusted: true - from importlib import resources from matplotlib import pyplot as plt @@ -61,14 +59,10 @@ terse - just the shape of the data - but the more detailed summary of the attributes. ```{code-cell} -:trusted: true - env ``` ```{code-cell} -:trusted: true - env.summarize() ``` @@ -78,8 +72,6 @@ Next, the P Model can be fitted to the photosynthetic environment using the ({class}`~pyrealm.pmodel.pmodel.PModel`) class: ```{code-cell} -:trusted: true - model = PModel(env) ``` @@ -87,8 +79,6 @@ The returned model object holds a lot of information. The representation of the model object shows a terse display of the settings used to run the model: ```{code-cell} -:trusted: true - model ``` @@ -99,8 +89,6 @@ photosynthetic efficiency: the intrinsic water use efficiency (``iwue``) and the use efficiency (``lue``). ```{code-cell} -:trusted: true - model.summarize() ``` @@ -113,8 +101,6 @@ This object also has a {meth}`~pyrealm.pmodel.optimal_chi.OptimalChiABC.summariz method: ```{code-cell} -:trusted: true - model.optchi.summarize() ``` @@ -131,8 +117,6 @@ Here we are using: * a PPFD of 834 µmol m-2 s-1. ```{code-cell} -:trusted: true - model.estimate_productivity(fapar=0.91, ppfd=834) model.summarize() ``` @@ -165,8 +149,6 @@ to be the same size so some of the variables have repeated data across dimension * Elevation is constant across months, so the data for each month is repeated. ```{code-cell} -:trusted: true - # Load an example dataset containing the forcing variables. data_path = resources.files("pyrealm_build_data.rpmodel") / "pmodel_global.nc" ds = xarray.load_dataset(data_path) @@ -186,8 +168,6 @@ data to atmospheric pressure, and then this is used to set the photosynthetic environment for the model: ```{code-cell} -:trusted: true - # Convert elevation to atmospheric pressure patm = calc_patm(elev) @@ -206,8 +186,6 @@ That environment can then be run to calculate the P model predictions for light efficiency: ```{code-cell} -:trusted: true - # Run the P model model = PModel(env) @@ -221,8 +199,6 @@ Finally, the light use efficiency can be used to calculate GPP given the photosynthetic photon flux density and fAPAR. ```{code-cell} -:trusted: true - # Scale the outputs from values per unit iabs to realised values model.estimate_productivity(fapar, ppfd) diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md index 1a134c84..b4b71cb1 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md @@ -21,7 +21,6 @@ are handled internally by the model fitting in `pyrealm`. ```{code-cell} :tags: [hide-input] -:trusted: true from importlib import resources @@ -48,8 +47,6 @@ site](https://fluxnet.org/doi/FLUXNET2015/BE-Vie), which was also used as a demonstration in {cite:t}`mengoli:2022a`. ```{code-cell} -:trusted: true - data_path = resources.files("pyrealm_build_data.subdaily") / "subdaily_BE_Vie_2014.csv" data = pandas.read_csv(str(data_path)) @@ -71,8 +68,6 @@ subdaily timescale. The code below also estimates GPP under the standard P Model slow responses for comparison. ```{code-cell} -:trusted: true - # Calculate the photosynthetic environment subdaily_env = PModelEnvironment( tc=temp_subdaily, @@ -99,8 +94,6 @@ conditions at the observation closest to noon, or the mean environmental conditi window around noon. ```{code-cell} -:trusted: true - # Create the fast slow scaler fsscaler = SubdailyScaler(datetime_subdaily) @@ -122,7 +115,6 @@ pmodel_subdaily = SubdailyPModel( ```{code-cell} :tags: [hide-input] -:trusted: true idx = np.arange(48 * 120, 48 * 130) plt.figure(figsize=(10, 4)) @@ -146,8 +138,6 @@ inputs to the standard P Model to calculate the optimal behaviour of plants unde conditions. ```{code-cell} -:trusted: true - # Get the daily acclimation conditions for the forcing variables temp_acclim = fsscaler.get_daily_means(temp_subdaily) co2_acclim = fsscaler.get_daily_means(co2_subdaily) @@ -179,8 +169,6 @@ at 25°C. This is acheived by multiplying by the reciprocal of the exponential p the Arrhenius equation ($h^{-1}$ in {cite}`mengoli:2022a`). ```{code-cell} -:trusted: true - # Are these any of the existing values in the constants? ha_vcmax25 = 65330 ha_jmax25 = 43900 @@ -196,8 +184,6 @@ The memory effect can now be applied to the three parameters with slow responses to calculate realised values, here using the default 15 day window. ```{code-cell} -:trusted: true - # Calculation of memory effect in xi, vcmax25 and jmax25 xi_real = memory_effect(pmodel_acclim.optchi.xi, alpha=1 / 15) vcmax25_real = memory_effect(vcmax25_acclim, alpha=1 / 15, allow_holdover=True) @@ -210,7 +196,6 @@ application of the memory effect. ```{code-cell} :tags: [hide-input] -:trusted: true fig, axes = plt.subplots(1, 3, figsize=(16, 5)) @@ -244,8 +229,6 @@ temperature at fast scales: responses of $J_{max}$ and $V_{cmax}$. ```{code-cell} -:trusted: true - tk_subdaily = subdaily_env.tc + pmodel_subdaily.env.core_const.k_CtoK # Fill the realised jmax and vcmax from subdaily to daily @@ -266,8 +249,6 @@ optimal $\chi$, rather than calculating the instantaneously optimal values of $\ as is the case in the standard P Model. ```{code-cell} -:trusted: true - # Interpolate xi to subdaily scale xi_subdaily = fsscaler.fill_daily_to_subdaily(xi_real) @@ -287,8 +268,6 @@ include the slow responses of $V_{cmax25}$ and $J_{max25}$ and fast responses to temperature. ```{code-cell} -:trusted: true - # Calculate Ac Ac_subdaily = ( vcmax_subdaily @@ -319,7 +298,5 @@ print(np.nanmin(diff), np.nanmax(diff)) ``` ```{code-cell} -:trusted: true - ``` diff --git a/docs/source/users/pmodel/subdaily_details/worked_example.md b/docs/source/users/pmodel/subdaily_details/worked_example.md index fac12b6a..db699027 100644 --- a/docs/source/users/pmodel/subdaily_details/worked_example.md +++ b/docs/source/users/pmodel/subdaily_details/worked_example.md @@ -14,8 +14,6 @@ kernelspec: # Worked example of the Subdaily P Model ```{code-cell} -:trusted: true - from importlib import resources import xarray @@ -61,8 +59,6 @@ The test data use some UK WFDE data for three sites in order to compare predicti over a time series. ```{code-cell} -:trusted: true - # Loading the example dataset: dpath = ( resources.files("pyrealm_build_data.uk_data") / "UK_WFDE5_FAPAR_2018_JuneJuly.nc" @@ -84,8 +80,6 @@ The WFDE data need some conversion for use in the PModel, along with the definit the atmospheric CO2 concentration. ```{code-cell} -:trusted: true - # Variable set up # Air temperature in °C from Tair in Kelvin tc = (ds["Tair"] - 273.15).to_numpy() @@ -105,8 +99,6 @@ co2 = np.ones_like(tc) * 400 The code below then calculates the photosynthetic environment. ```{code-cell} -:trusted: true - # Generate and check the PModelEnvironment pm_env = PModelEnvironment(tc=tc, patm=patm, vpd=vpd, co2=co2) pm_env.summarize() @@ -118,8 +110,6 @@ The standard implementation of the P Model used below assumes that plants can instantaneously adopt optimal behaviour. ```{code-cell} -:trusted: true - # Standard PModels pmodC3 = PModel( env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="prentice14" @@ -129,8 +119,6 @@ pmodC3.summarize() ``` ```{code-cell} -:trusted: true - pmodC4 = PModel( env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="c4_no_gamma" ) @@ -147,8 +135,6 @@ calculations: essentially the plant does not acclimate until the optimal values calculated again to update those realised estimates. ```{code-cell} -:trusted: true - # Set the acclimation window to an hour either side of noon fsscaler = SubdailyScaler(datetimes) fsscaler.set_window( @@ -188,8 +174,6 @@ shown above and plots the instantaneous predictions against predictions includin photosynthetic responses. ```{code-cell} -:trusted: true - # Store the predictions in the xarray Dataset to use indexing ds["GPP_pmodC3"] = (ds["Tair"].dims, pmodC3.gpp) ds["GPP_subdailyC3"] = (ds["Tair"].dims, subdailyC3.gpp) @@ -247,8 +231,6 @@ The subdaily models can also be obtained directly from the standard models, usin `convert_pmodel_to_subdaily` method: ```{code-cell} -:trusted: true - # Convert standard C3 model converted_C3 = convert_pmodel_to_subdaily( pmodel=pmodC3, @@ -270,8 +252,6 @@ This produces the same outputs as the `SubdailyPModel` class, but is convenient compact when the two models are going to be compared. ```{code-cell} -:trusted: true - # Models have identical GPP - maximum absolute difference is zero. print(np.nanmax(abs(subdailyC3.gpp.flatten() - converted_C3.gpp.flatten()))) print(np.nanmax(abs(subdailyC4.gpp.flatten() - converted_C4.gpp.flatten()))) From 916c1132f9e19d1a9da53cb01dbc823d9584556d Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 26 Sep 2024 13:53:33 +0100 Subject: [PATCH 145/241] Adding crown functions and a crown profiling method for Flora, along with user doc sketch --- docs/source/users/demography/crown.md | 261 ++++++++++++++++++++++++ docs/source/users/demography/flora.md | 4 + pyrealm/demography/canopy_functions.py | 116 +++++++++-- pyrealm/demography/flora.py | 123 +++++------ pyrealm/demography/t_model_functions.py | 19 +- 5 files changed, 443 insertions(+), 80 deletions(-) create mode 100644 docs/source/users/demography/crown.md diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md new file mode 100644 index 00000000..1c875f30 --- /dev/null +++ b/docs/source/users/demography/crown.md @@ -0,0 +1,261 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# The tree crown model + +```{code-cell} +from matplotlib import pyplot as plt +import numpy as np +import pandas as pd + +from pyrealm.demography.canopy_functions import ( + calculate_canopy_q_m, + calculate_canopy_z_max_proportion, +) + +from pyrealm.demography.flora import PlantFunctionalType, Flora +``` + +The {mod}`pyrealm.demography` module uses three-dimensional model of crown shape to +define the vertical distribution of leaf area. This is driven by four parameters within +the {class}`~pyrealm.demography.flora.PlantFunctionalType`: + +* The `m` and `n` parameters that define the vertical shape of the crown profile. +* The `ca_ratio` parameters that defines the size of the crown relative to the stem size. +* The `f_g` parameter that define the crown gap fraction and sets the vertical + distribution of leaves within the crown. + +The code below provides a demonstration of the impacts of each parameter and shows the +use of `pyrealm` tools to visualise the crown model for individual stems. + +## Crown shape parameters + +The `m` and `n` parameters define the vertical profile of the crown but are also define +two further parameters: + +* `q_m`, which is used to scale the size of the crown radius to match the expected crown + area, given the crown shape. +* `z_max_prop`, which sets the height on the stem at which the maximum crown radius is found. + +The code below calculates `q_m` and `z_max_prop` for combinations of `m` and `n` and +then plots the resulting values. + +```{code-cell} +m = n = np.arange(1.0, 5, 0.1) +q_m = calculate_canopy_q_m(m=m, n=n[:, None]) +z_max_prop = calculate_canopy_z_max_proportion(m=m, n=n[:, None]) +``` + +```{code-cell} +fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10.9, 4)) + +# Plot q_m as a function of m and n +cntr_set1 = ax1.contourf(m, n, q_m, levels=10) +fig.colorbar(cntr_set1, ax=ax1, label="q_m") +ax1.set_xlabel("m") +ax1.set_ylabel("n") +ax1.set_aspect("equal") + +# Plot z_max_prop as a function of m and n +cntr_set2 = ax2.contourf(m, n, p_zm, levels=10) +fig.colorbar(cntr_set2, ax=ax2, label="z_max_prop") +ax2.set_xlabel("m") +ax2.set_ylabel("n") +ax2.set_aspect("equal") +``` + +## Plotting crown profiles + +The examples below show the calculation of crown profiles for a set of plant functional +types (PFTs) with differing crown trait values. We first need to create a +:class:`~pyrealm.demography.flora.Flora` object that defines those PFTs. + +```{code-cell} +flora = Flora( + [ + PlantFunctionalType(name="short", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=20), + PlantFunctionalType( + name="medium", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=500 + ), + PlantFunctionalType(name="tall", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=2000), + ] +) + +flora +``` + +We then also need to specify the size of a stem of each PFT, along with the resulting +allometric predictions from the T Model. + +```{code-cell} +# Generate the expected stem allometries at a single height for each PFT +stem_height = np.array([18, 18, 18]) +allometry = flora.get_allometries(stem_height=stem_height) +``` + +We can use {mod}`pandas` to visualise those allometric predictions. + +```{code-cell} +pandas.DataFrame(allometry) +``` + +We can now use the {meth}`~pyrealm.demography.flora.Flora.get_canopy_profile` method to +calculate the canopy profile for each stem for a set of vertical heights. The heights +need to be defined as a column array, that is with a shape `(N, 1)`, in order to show +that we want the canopy variables to be calculated at each height for each PFT. + +```{code-cell} +# Create a set of vertical heights as a column array. +z = np.linspace(0, 18.0, num=181)[:, None] + +# Calculate the crown profile across those heights for each PFT +crown_profiles = flora.get_canopy_profile( + z=z, + crown_area=allometry["crown_area"], + stem_height=allometry["stem_height"], + r0=allometry["canopy_r0"], + z_max=allometry["canopy_z_max"], +) +``` + +The `crown_profiles` object is a dictionary containing values for four crown profile +variables. + +* The relative crown radius: this value is driven purely by `m`, `n` and the stem height + and defines the vertical profile of the crown. +* The crown radius: this is simply a rescaling of the relative radius so that the + maximum crown radius matches the expected crown area predicted by the allometry of the + T Model. +* The projected crown area: this value shows how crown area accumulates from the top of + the crown to the ground. +* The projected leaf area: this value shows how _leaf_ area accumulates from the top of + the crown to the ground. The difference from the crown area is driven by the crown gap + fraction for a given PFT. + ++++ + +### Crown radius values + +The relative crown radius values are arbitrary - they simply define the shape of the +vertical profile. For the example PFTs in the `Flora` object, the maximum relative +radius values on each stem are: + +```{code-cell} +max_relative_crown_radius = canopy_profiles["relative_canopy_radius"].max(axis=0) +print(max_relative_crown_radius) +``` + +However the scaled maximum radius values match the expected crown area in the allometry +table above + +```{code-cell} +max_crown_radius = canopy_profiles["crown_radius"].max(axis=0) +print(max_crown_radius) +print(max_crown_radius**2 * np.pi) +``` + +The code below generates a plot of the vertical shape profiles of the crowns for each +stem. For each stem: + +* the dashed line shows how the relative crown radius varies with height, +* the solid line shows the actual crown radius profile with height, and +* the dotted line shows the height at which the maximum crown radius is found. + +```{code-cell} +fig, ax = plt.subplots(ncols=1) + +# Find the maximum of the actual and relative maximum crown widths +stem_max_width = np.maximum(max_crown_radius, max_relative_crown_radius) + +for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 12), ("r", "g", "b")): + + # Plot relative radius either side of offset + stem_qz = canopy_profiles["relative_canopy_radius"][:, pft_idx] + ax.plot(stem_qz + offset, z, color=colour, linestyle="--", linewidth=1) + ax.plot(-stem_qz + offset, z, color=colour, linestyle="--", linewidth=1) + + # Plot actual crown radius either side of offset + stem_rz = canopy_profiles["crown_radius"][:, pft_idx] + ax.plot(stem_rz + offset, z, color=colour) + ax.plot(-stem_rz + offset, z, color=colour) + + # Add the height of maximum crown radius + stem_rz_max = stem_max_width[pft_idx] + + ax.plot( + [offset - stem_rz_max, offset + stem_rz_max], + [allometry["canopy_z_max"][pft_idx]] * 2, + color=colour, + linewidth=1, + linestyle=":", + ) + +ax.set_aspect(aspect=1) +``` + +### Projected crown and leaf areas + +We can use the crown profile to generate projected area plots, but it is much easier to +compare the effects when comparing stems with similar crown areas. The code below +generates these new predictions for a new set of PFTs. + +```{code-cell} +flora2 = Flora( + [ + PlantFunctionalType(name="short", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=380), + PlantFunctionalType( + name="medium", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=400 + ), + PlantFunctionalType(name="tall", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=420), + ] +) + +allometry2 = flora2.get_allometries(stem_height=stem_height) + + +# Calculate the crown profile across those heights for each PFT +crown_profiles2 = flora2.get_canopy_profile( + z=z, + crown_area=allometry2["crown_area"], + stem_height=allometry2["stem_height"], + r0=allometry2["canopy_r0"], + z_max=allometry2["canopy_z_max"], +) +``` + +The plot below shows how projected crown area (solid lines) and leaf area (dashed lines) +change with height along the stem. + +* The projected crown area increases from zero at the top of the canopy, according to + the canopy profile, until it reaches the maximum crown radius, at which point it + remains constant down to ground level. The total crown areas differs for each stem + because of the slightly different values used for the crown area ratio. + +* The projected leaf area is very similar but leaf area is displaced towards the ground + because of the crown gap fraction (`f_g`). Where `f_g = 0` (the red line), the two + lines are identical, but as `f_g` increases, more of the leaf area is displaced down + within the canopy. + +```{code-cell} +fig, ax = plt.subplots(ncols=1) + +for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 10), ("r", "g", "b")): + + ax.plot(crown_profiles2["projected_crown_area"][:, pft_idx], z, color=colour) + ax.plot( + crown_profiles2["projected_leaf_area"][:, pft_idx], + z, + color=colour, + linestyle="--", + ) +``` diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index a1b19fc1..059ca146 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -119,3 +119,7 @@ for ax, (var, ylab) in zip(axes, plot_details): # Delete unused panel in 5 x 2 grid fig.delaxes(axes[-1]) ``` + +```{code-cell} + +``` diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 15eae194..642b53b5 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -78,7 +78,7 @@ def calculate_canopy_z_max( def calculate_canopy_r0( q_m: NDArray[np.float32], crown_area: NDArray[np.float32] ) -> NDArray[np.float32]: - r"""Calculate scaling factor for height of maximum crown radius. + r"""Calculate scaling factor width of maximum crown radius. This scaling factor (:math:`r_0`) is derived from the canopy shape parameters (:math:`m,n,q_m`) for plant functional types and the estimated crown area @@ -225,9 +225,44 @@ def calculate_relative_canopy_radius_at_z( z_over_height = z / stem_height + # Remove predictions of canopy radius above stem height + z_over_height = np.where(z > stem_height, np.nan, z_over_height) + return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) +def calculate_canopy_radius( + q_z: NDArray[np.float32], + r0: NDArray[np.float32], + validate: bool = True, +) -> NDArray[np.float32]: + r"""Calculate canopy radius from relative radius and canopy r0. + + The relative canopy radius (:math:`q(z)`) at a given height :math:`z` describes the + vertical profile of the canopy shape, but only varies with the ``m`` and ``n`` shape + parameters and the stem height. The actual crown radius at a given height + (:math:`r(z)`) needs to be scaled using :math:`r_0` such that the maximum crown area + equals the expected crown area given the crown area ratio traiit for the plant + functional type: + + .. math:: + + r(z) = r_0 q(z) + + This function calculates :math:`r(z)` given estimated ``r0`` and an array of + relative radius values. + + Args: + q_z: TODO + r0: TODO + validate: Boolean flag to suppress argument validation. + """ + + # TODO - think about validation here. qz must be row array or 2D (N, n_pft) + + return r0 * q_z + + def calculate_stem_projected_crown_area_at_z( z: NDArray[np.float32], q_z: NDArray[np.float32], @@ -404,28 +439,73 @@ def calculate_stem_projected_leaf_area_at_z( return A_cp -# def calculate_total_canopy_A_cp(z: float, f_g: float, community: Community) -> float: -# """Calculate total leaf area at a given height. +def calculate_canopy_profiles( + pft_data: dict[str, NDArray[np.float32]], + z: NDArray[np.float32], + stem_height: NDArray[np.float32], + crown_area: NDArray[np.float32], + r0: NDArray[np.float32], + z_max: NDArray[np.float32], +) -> dict[str, NDArray[np.float32]]: + """Calculate vertical canopy profiles for stems. -# :param f_g: -# :param community: -# :param z: Height above ground. -# :return: Total leaf area in the canopy at a given height. -# """ -# A_cp_for_individuals = calculate_projected_leaf_area_for_individuals( -# z, f_g, community -# ) + This method calculates canopy profile predictions, given an array of vertical + heights (``z``) for: -# A_cp_for_cohorts = A_cp_for_individuals * community.cohort_number_of_individuals + * relativate canopy radius, + * actual canopy radius, + * projected crown area, and + * project leaf area. -# return A_cp_for_cohorts.sum() + The predictions require a set of plant functional types (PFTs) but also the expected + allometric predictions of stem height, crown area and z_max for an actual stem of a + given size for each PFT. + Args: + pft_data: A dictionary of plant functional trait data, as for example returned + from :attr:`Flora.data` attribute. + z: An array of vertical height values at which to calculate canopy profiles. + stem_height: A row array providing expected stem height for each PFT. + crown_area: A row array providing expected crown area for each PFT. + r0: A row array providing expected r0 for each PFT. + z_max: A row array providing expected z_max height for each PFT. + """ -# def calculate_gpp(cell_ppfd: NDArray, lue: NDArray) -> float: -# """Estimate the gross primary productivity. + # Calculate relative radius + relative_canopy_radius = calculate_relative_canopy_radius_at_z( + z=z, + m=pft_data["m"], + n=pft_data["n"], + stem_height=stem_height, + ) -# Not sure where to place this - need an array of LUE that matches to the + # Calculate actual radius + crown_radius = calculate_canopy_radius(q_z=relative_canopy_radius, r0=r0) -# """ + # Calculate projected crown area + projected_crown_area = calculate_stem_projected_crown_area_at_z( + z=z, + q_z=relative_canopy_radius, + crown_area=crown_area, + q_m=pft_data["q_m"], + stem_height=stem_height, + z_max=z_max, + ) + + # Calculate projected leaf area + projected_leaf_area = calculate_stem_projected_leaf_area_at_z( + z=z, + q_z=relative_canopy_radius, + f_g=pft_data["f_g"], + crown_area=crown_area, + q_m=pft_data["q_m"], + stem_height=stem_height, + z_max=z_max, + ) -# return 100 + return dict( + relative_canopy_radius=relative_canopy_radius, + crown_radius=crown_radius, + projected_crown_area=projected_crown_area, + projected_leaf_area=projected_leaf_area, + ) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 7df326a0..293d7088 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -31,13 +31,15 @@ from numpy.typing import NDArray from pyrealm.demography.canopy_functions import ( + _validate_z_qz_args, + calculate_canopy_profiles, calculate_canopy_q_m, calculate_canopy_z_max_proportion, ) from pyrealm.demography.t_model_functions import ( calculate_dbh_from_height, + calculate_t_model_allocation, calculate_t_model_allometry, - calculate_t_model_growth, ) if sys.version_info[:2] >= (3, 11): @@ -331,15 +333,7 @@ def get_allometries( This method calculates the allometric predictions of the T Model for all of the plant functional types within a Flora, given an array of stem sizes at which to - calculate the predictions. The T Model uses diameter at breast height (DBH) as - the fundamental metric of stem size but this method will also accept a set of - stem heights as an alternative size metric. Stem heights are converted back into - the expected DBH before calculating the allometric predictions - if any of the - stem heights are higher than the maximum height for a PFT, these will be shown - as `np.nan` values. - - Both ``dbh`` and ``stem_height`` must be provided as one-dimensional arrays and - it is an error to provide both. The method returns a dictionary of the + calculate the predictions. The method returns a dictionary of the following allometric predictions of the T Model: * 'dbh' @@ -351,7 +345,15 @@ def get_allometries( * 'sapwood_mass' Each dictionary entry is a 2D array with PFTs as columns and the predictions for - each size value as rows. + each stem size as rows. + + The T Model uses diameter at breast height (DBH) as the fundamental metric of + stem size but this method will also accept a set of stem heights as an + alternative size metric. Stem heights are converted back into the expected DBH + before calculating the allometric predictions - if any of the stem heights are + higher than the maximum height for a PFT, these will be shown as `np.nan` + values. One of ``dbh`` and ``stem_height`` must be provided as a one-dimensional + array. Args: dbh: An array of diameter at breast height values. @@ -363,31 +365,26 @@ def get_allometries( raise ValueError("Provide one of either dbh or stem_height") if stem_height is not None: - # Check array dimensions - if stem_height.ndim != 1: - raise ValueError("Stem heights must be a one dimensional array") + # TODO: This steals the validation from the canopy functions - this might be + # a general function for the module - see also the + # validate_t_model_args function. + _validate_z_qz_args(z=stem_height, stem_properties=[self.data["h_max"]]) - # Convert stem heights back into an array of initial DBH values - # - broadcast to (n_heights, n_pfts) - stem_height = np.broadcast_to( - stem_height[:, None], (stem_height.size, self.n_pfts) - ) - dbh_arr = calculate_dbh_from_height( + dbh = calculate_dbh_from_height( h_max=self.data["h_max"], a_hd=self.data["a_hd"], stem_height=stem_height, ) elif dbh is not None: - # Check array dimensions - if dbh.ndim != 1: - raise ValueError("DBH must be a one dimensional array") + # TODO: This steals the validation from the canopy functions - this might be + # a general function for the module - see also the + # validate_t_model_args function. + _validate_z_qz_args(z=dbh, stem_properties=[self.data["h_max"]]) - # Broadcast the dbh to a (n_heights, n_pfts) - dbh_arr = np.broadcast_to(dbh[:, None], (dbh.size, self.n_pfts)) + # DBH is now always populated so ignore warning that it might be None + return calculate_t_model_allometry(pft_data=self.data, dbh=dbh) # type: ignore [arg-type] - return calculate_t_model_allometry(pft_data=self.data, dbh=dbh_arr) - - def get_growth( + def get_allocation( self, potential_gpp: NDArray[np.float32], dbh: NDArray[np.float32] | None = None, @@ -395,19 +392,10 @@ def get_growth( ) -> dict[str, NDArray]: """Calculate T Model scalings for the Flora members. - This method calculates the allometric predictions of the T Model for all of the - plant functional types within a Flora, given an array of stem sizes at which to - calculate the predictions. The T Model uses diameter at breast height (DBH) as - the fundamental metric of stem size but this method will also accept a set of - stem heights as an alternative size metric. Stem heights are converted back into - the expected DBH before calculating the allometric predictions - if any of the - stem heights are higher than the maximum height for a PFT, these will be shown - as `np.nan` values. - - Both ``dbh`` and ``stem_height`` must be provided as one-dimensional arrays and - it is an error to provide both. The method returns a dictionary of the - allometric predictions of the T Model: - + This method calculates the predicted allocation of potential gross primary + productivity (GPP) under the T Model for all of the plant functional types + within a Flora, given values for stem size and potential GPP. The method returns + a dictionary of the allocation predictions of the T Model: * "whole_crown_gpp" * "sapwood_respiration" @@ -422,6 +410,14 @@ def get_growth( Each dictionary entry is a 2D array with PFTs as columns and the predictions for each size value as rows. + The T Model uses diameter at breast height (DBH) as the fundamental metric of + stem size but this method will also accept a set of stem heights as an + alternative size metric. Stem heights are converted back into the expected DBH + before calculating the allometric predictions - if any of the stem heights are + higher than the maximum height for a PFT, these will be shown as `np.nan` + values. One of ``dbh`` and ``stem_height`` must be provided as a one-dimensional + array, and ``potential_gpp`` must have the same shape. + Args: potential_gpp: An array of potential GPP values. dbh: An array of diameter at breast height values. @@ -463,28 +459,37 @@ def get_growth( gpp_arr = np.broadcast_to(potential_gpp[:, None], (n_size, self.n_pfts)) - return calculate_t_model_growth( + return calculate_t_model_allocation( pft_data=self.data, dbh=dbh_arr, potential_gpp=gpp_arr ) + def get_canopy_profile( + self, + z: NDArray[np.float32], + stem_height: NDArray[np.float32], + crown_area: NDArray[np.float32], + r0: NDArray[np.float32], + z_max: NDArray[np.float32], + ) -> dict[str, NDArray]: + """Calculate T Model scalings for the Flora members. -# @dataclass -# class PFTAllometry: -# """TODO.""" + TODO: Description -# pft: type[PlantFunctionalTypeStrict] -# dbh: NDArray[np.float32] | None -# stem_height: NDArray[np.float32] | None -# data: dict[str, NDArray[np.float32]] = field(init=False) + Args: + z: TODO + stem_height: TODO + crown_area: TODO + r0: TODO + z_max: TODO + """ -# def __post_init__(self) -> None: -# """Populates the T Model allometry from the initial size data.""" -# # Need one of dbh or stem_height - use XOR -# if not ((self.dbh is None) ^ (self.stem_height is None)): -# raise ValueError("Provide one of either dbh or stem_height") + # TODO - validation -# # Convert stem height to DBH for the plant functional type -# if self.stem_height is not None: -# self.dbh = calculate_dbh_from_height( -# h_max=self.pft.h_max, a_hd=self.pft.a_hd, stem_height=self.stem_height -# ) + return calculate_canopy_profiles( + pft_data=self.data, + z=z, + stem_height=stem_height, + crown_area=crown_area, + r0=r0, + z_max=z_max, + ) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 4076253a..8a35f029 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -9,6 +9,10 @@ from numpy.typing import NDArray from pyrealm.core.utilities import check_input_shapes +from pyrealm.demography.canopy_functions import ( + calculate_canopy_r0, + calculate_canopy_z_max, +) def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> None: @@ -36,8 +40,7 @@ def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> raise ValueError("Size arrays are not of equal length") # Explicitly check to see if the size arrays are row arrays and - if so - enforce - # that they are the same length.abs - + # that they are the same length. if len(size_args_shape) == 1 and not pft_args_shape == size_args_shape: raise ValueError("Trait and size inputs are row arrays of unequal length.") @@ -663,10 +666,20 @@ def calculate_t_model_allometry( crown_fraction=stem_data["crown_fraction"], ) + stem_data["canopy_r0"] = calculate_canopy_r0( + q_m=pft_data["q_m"], + crown_area=stem_data["crown_area"], + ) + + stem_data["canopy_z_max"] = calculate_canopy_z_max( + z_max_prop=pft_data["z_max_prop"], + stem_height=stem_data["stem_height"], + ) + return stem_data -def calculate_t_model_growth( +def calculate_t_model_allocation( pft_data: dict[str, NDArray[np.float32]], dbh: NDArray[np.float32], potential_gpp: NDArray[np.float32], From c415feb00b69cb4e91ee95a9fcc10f21c0785ecb Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 26 Sep 2024 18:11:23 +0100 Subject: [PATCH 146/241] Fixing broadcast issue in get_allometries, fix up failing tests --- pyrealm/demography/t_model_functions.py | 59 +++++++++++++++---------- tests/unit/demography/test_flora.py | 38 ++++++++++++---- 2 files changed, 64 insertions(+), 33 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 8a35f029..30a36317 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -625,58 +625,69 @@ def calculate_t_model_allometry( allometry values. """ - stem_data = {"dbh": dbh} - - stem_data["stem_height"] = calculate_heights( + stem_height = calculate_heights( h_max=pft_data["h_max"], a_hd=pft_data["a_hd"], - dbh=stem_data["dbh"], + dbh=dbh, ) - stem_data["crown_area"] = calculate_crown_areas( + # Broadcast dbh to shape of stem height to get congruent shapes + dbh = np.broadcast_to(dbh, stem_height.shape) + + crown_area = calculate_crown_areas( ca_ratio=pft_data["ca_ratio"], a_hd=pft_data["a_hd"], - dbh=stem_data["dbh"], - stem_height=stem_data["stem_height"], + dbh=dbh, + stem_height=stem_height, ) - stem_data["crown_fraction"] = calculate_crown_fractions( + crown_fraction = calculate_crown_fractions( a_hd=pft_data["a_hd"], - dbh=stem_data["dbh"], - stem_height=stem_data["stem_height"], + dbh=dbh, + stem_height=stem_height, ) - stem_data["stem_mass"] = calculate_stem_masses( + stem_mass = calculate_stem_masses( rho_s=pft_data["rho_s"], - dbh=stem_data["dbh"], - stem_height=stem_data["stem_height"], + dbh=dbh, + stem_height=stem_height, ) - stem_data["foliage_mass"] = calculate_foliage_masses( + foliage_mass = calculate_foliage_masses( sla=pft_data["sla"], lai=pft_data["lai"], - crown_area=stem_data["crown_area"], + crown_area=crown_area, ) - stem_data["sapwood_mass"] = calculate_sapwood_masses( + sapwood_mass = calculate_sapwood_masses( rho_s=pft_data["rho_s"], ca_ratio=pft_data["ca_ratio"], - stem_height=stem_data["stem_height"], - crown_area=stem_data["crown_area"], - crown_fraction=stem_data["crown_fraction"], + stem_height=stem_height, + crown_area=crown_area, + crown_fraction=crown_fraction, ) - stem_data["canopy_r0"] = calculate_canopy_r0( + canopy_r0 = calculate_canopy_r0( q_m=pft_data["q_m"], - crown_area=stem_data["crown_area"], + crown_area=crown_area, ) - stem_data["canopy_z_max"] = calculate_canopy_z_max( + canopy_z_max = calculate_canopy_z_max( z_max_prop=pft_data["z_max_prop"], - stem_height=stem_data["stem_height"], + stem_height=stem_height, ) - return stem_data + return dict( + dbh=dbh, + stem_height=stem_height, + crown_area=crown_area, + crown_fraction=crown_fraction, + stem_mass=stem_mass, + foliage_mass=foliage_mass, + sapwood_mass=sapwood_mass, + canopy_r0=canopy_r0, + canopy_z_max=canopy_z_max, + ) def calculate_t_model_allocation( diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index 317f6cae..04a84e33 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -273,10 +273,12 @@ def test_Flora_get_allometries_dbh_against_rtmodel(rtmodel_data, rtmodel_flora): correct values. So the shapes go (3,) x (6, 1) -> (6,3) """ - result = rtmodel_flora.get_allometries(dbh=rtmodel_data["dbh"][:, 0]) + result = rtmodel_flora.get_allometries(dbh=rtmodel_data["dbh"][:, [0]]) for key, value in result.items(): - assert np.allclose(value, rtmodel_data[key]) + # Skip canopy shape allometries that are not in the original T Model + if key not in ("canopy_r0", "canopy_z_max"): + assert np.allclose(value, rtmodel_data[key]) def test_Flora_get_allometries_stem_height_against_rtmodel(rtmodel_data, rtmodel_flora): @@ -291,11 +293,13 @@ def test_Flora_get_allometries_stem_height_against_rtmodel(rtmodel_data, rtmodel for idx, (name, pft) in enumerate(rtmodel_flora.items()): single_pft_flora = Flora(pfts=[pft]) result = single_pft_flora.get_allometries( - stem_height=rtmodel_data["stem_height"][:, idx] + stem_height=rtmodel_data["stem_height"][:, [idx]] ) for key, value in result.items(): - assert np.allclose(value, rtmodel_data[key][:, [idx]]) + # Skip canopy shape allometries that are not in the original T Model + if key not in ("canopy_r0", "canopy_z_max"): + assert np.allclose(value, rtmodel_data[key][:, [idx]]) @pytest.mark.parametrize( @@ -319,14 +323,16 @@ def test_Flora_get_allometries_stem_height_against_rtmodel(rtmodel_data, rtmodel np.array([[0.1, 0.2, 0.3]]), None, pytest.raises(ValueError), - "DBH must be a one dimensional array", + "The z argument is two dimensional (shape: (1, 3)) " + "but is not a column array.", # TODO - fix to DBH not z id="fail_dbh_not_1D", ), pytest.param( None, np.array([[10, 20, 30]]), pytest.raises(ValueError), - "Stem heights must be a one dimensional array", + "The z argument is two dimensional (shape: (1, 3)) " + "but is not a column array.", # TODO - fix to stem_height not z id="fail_stem_height_not_1D", ), pytest.param( @@ -334,18 +340,32 @@ def test_Flora_get_allometries_stem_height_against_rtmodel(rtmodel_data, rtmodel None, does_not_raise(), None, - id="ok_with_dbh", + id="ok_with_dbh_as_row", ), pytest.param( None, np.array([5, 10, 15]), does_not_raise(), None, - id="ok_with_stem_heights", + id="ok_with_stem_heights_as_row", ), pytest.param( + np.array([[0.1], [0.2], [0.3]]), None, - np.array([0, 5, 10, 15, 45.33, 1000]), + does_not_raise(), + None, + id="ok_with_dbh_as_col", + ), + pytest.param( + None, + np.array([[5], [10], [15]]), + does_not_raise(), + None, + id="ok_with_stem_heights_as_col", + ), + pytest.param( + None, + np.array([[0], [5], [10], [15], [45.33], [1000]]), does_not_raise(), None, id="ok_with_edgy_stem_heights", From 7d78f4802c31f7a33ecf8fd1c6822d8fbeb45428 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 26 Sep 2024 21:49:22 +0100 Subject: [PATCH 147/241] Doc fixes and validation fixes --- docs/source/_toc.yml | 2 + docs/source/users/demography/crown.md | 19 +++++++--- docs/source/users/demography/flora.md | 12 ++---- pyrealm/demography/canopy_functions.py | 2 +- pyrealm/demography/flora.py | 39 ++++++++------------ pyrealm/demography/t_model_functions.py | 49 +++++++++++++++---------- 6 files changed, 64 insertions(+), 59 deletions(-) diff --git a/docs/source/_toc.yml b/docs/source/_toc.yml index 73c15779..1674a45f 100644 --- a/docs/source/_toc.yml +++ b/docs/source/_toc.yml @@ -27,6 +27,8 @@ subtrees: - file: users/pmodel/subdaily_details/worked_example.md - file: users/pmodel/c3c4model.md - file: users/pmodel/isotopic_discrimination.md + - file: users/demography/flora.md + - file: users/demography/crown.md - file: users/tmodel/tmodel.md - file: users/tmodel/canopy.md - file: users/splash.md diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md index 1c875f30..aa9d15e0 100644 --- a/docs/source/users/demography/crown.md +++ b/docs/source/users/demography/crown.md @@ -13,6 +13,13 @@ kernelspec: # The tree crown model +:::{admonition} Warning + +This area of `pyrealm` is in active development and this notebook currently contains +notes and initial demonstration code. + +::: + ```{code-cell} from matplotlib import pyplot as plt import numpy as np @@ -67,7 +74,7 @@ ax1.set_ylabel("n") ax1.set_aspect("equal") # Plot z_max_prop as a function of m and n -cntr_set2 = ax2.contourf(m, n, p_zm, levels=10) +cntr_set2 = ax2.contourf(m, n, z_max_prop, levels=10) fig.colorbar(cntr_set2, ax=ax2, label="z_max_prop") ax2.set_xlabel("m") ax2.set_ylabel("n") @@ -106,7 +113,7 @@ allometry = flora.get_allometries(stem_height=stem_height) We can use {mod}`pandas` to visualise those allometric predictions. ```{code-cell} -pandas.DataFrame(allometry) +pd.DataFrame(allometry) ``` We can now use the {meth}`~pyrealm.demography.flora.Flora.get_canopy_profile` method to @@ -151,7 +158,7 @@ vertical profile. For the example PFTs in the `Flora` object, the maximum relati radius values on each stem are: ```{code-cell} -max_relative_crown_radius = canopy_profiles["relative_canopy_radius"].max(axis=0) +max_relative_crown_radius = crown_profiles["relative_canopy_radius"].max(axis=0) print(max_relative_crown_radius) ``` @@ -159,7 +166,7 @@ However the scaled maximum radius values match the expected crown area in the al table above ```{code-cell} -max_crown_radius = canopy_profiles["crown_radius"].max(axis=0) +max_crown_radius = crown_profiles["crown_radius"].max(axis=0) print(max_crown_radius) print(max_crown_radius**2 * np.pi) ``` @@ -180,12 +187,12 @@ stem_max_width = np.maximum(max_crown_radius, max_relative_crown_radius) for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 12), ("r", "g", "b")): # Plot relative radius either side of offset - stem_qz = canopy_profiles["relative_canopy_radius"][:, pft_idx] + stem_qz = crown_profiles["relative_canopy_radius"][:, pft_idx] ax.plot(stem_qz + offset, z, color=colour, linestyle="--", linewidth=1) ax.plot(-stem_qz + offset, z, color=colour, linestyle="--", linewidth=1) # Plot actual crown radius either side of offset - stem_rz = canopy_profiles["crown_radius"][:, pft_idx] + stem_rz = crown_profiles["crown_radius"][:, pft_idx] ax.plot(stem_rz + offset, z, color=colour) ax.plot(-stem_rz + offset, z, color=colour) diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index 059ca146..646601da 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -58,7 +58,7 @@ The returned values in the dictionary are 2 dimensional arrays with each DBH val row and each PFT as a column. This makes them convenient to plot using `matplotlib`. ```{code-cell} -dbh = np.arange(0, 1.6, 0.01) +dbh = np.arange(0, 1.6, 0.01)[:, None] allometries = flora.get_allometries(dbh=dbh) ``` @@ -87,8 +87,8 @@ for ax, (var, ylab) in zip(axes.flatten(), plot_details): ``` ```{code-cell} -potential_gpp = np.repeat(55, dbh.size) -allometries = flora.get_growth(dbh=dbh, potential_gpp=potential_gpp) +potential_gpp = np.repeat(55, dbh.size)[:, None] +allocation = flora.get_allocation(dbh=dbh, potential_gpp=potential_gpp) ``` ```{code-cell} @@ -109,7 +109,7 @@ plot_details = [ axes = axes.flatten() for ax, (var, ylab) in zip(axes, plot_details): - ax.plot(dbh, allometries[var], label=flora.keys()) + ax.plot(dbh, allocation[var], label=flora.keys()) ax.set_xlabel("Diameter at breast height (m)") ax.set_ylabel(ylab) @@ -119,7 +119,3 @@ for ax, (var, ylab) in zip(axes, plot_details): # Delete unused panel in 5 x 2 grid fig.delaxes(axes[-1]) ``` - -```{code-cell} - -``` diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 642b53b5..7b9dc7bd 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -463,7 +463,7 @@ def calculate_canopy_profiles( Args: pft_data: A dictionary of plant functional trait data, as for example returned - from :attr:`Flora.data` attribute. + from :attr:`Flora.data` attribute. z: An array of vertical height values at which to calculate canopy profiles. stem_height: A row array providing expected stem height for each PFT. crown_area: A row array providing expected crown area for each PFT. diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 293d7088..5922759c 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -429,38 +429,29 @@ def get_allocation( raise ValueError("Provide one of either dbh or stem_height") if stem_height is not None: - # Check array dimensions - if stem_height.ndim != 1: - raise ValueError("Stem heights must be a one dimensional array") - - # Convert stem heights back into an array of initial DBH values - # - broadcast to (n_heights, n_pfts) - n_size = stem_height.size - stem_height = np.broadcast_to(stem_height[:, None], (n_size, self.n_pfts)) - dbh_arr = calculate_dbh_from_height( + # TODO: This steals the validation from the canopy functions - this might be + # a general function for the module - see also the + # validate_t_model_args function. + _validate_z_qz_args(z=stem_height, stem_properties=[self.data["h_max"]]) + + dbh = calculate_dbh_from_height( h_max=self.data["h_max"], a_hd=self.data["a_hd"], stem_height=stem_height, ) elif dbh is not None: - # Check array dimensions - if dbh.ndim != 1: - raise ValueError("DBH must be a one dimensional array") - - # Broadcast the dbh to a (n_heights, n_pfts) - n_size = dbh.size - dbh_arr = np.broadcast_to(dbh[:, None], (n_size, self.n_pfts)) - - if not ((potential_gpp.ndim == 1) and (potential_gpp.size == n_size)): - raise ValueError( - "GPP must be a one dimensional array of the same " - "size as DBH or stem height" - ) + # TODO: This steals the validation from the canopy functions - this might be + # a general function for the module - see also the + # validate_t_model_args function. + _validate_z_qz_args(z=dbh, stem_properties=[self.data["h_max"]]) - gpp_arr = np.broadcast_to(potential_gpp[:, None], (n_size, self.n_pfts)) + if potential_gpp.shape != dbh.shape: # type: ignore [union-attr] + raise ValueError("GPP must have the same shape as DBH or stem height") return calculate_t_model_allocation( - pft_data=self.data, dbh=dbh_arr, potential_gpp=gpp_arr + pft_data=self.data, + dbh=dbh, # type: ignore [arg-type] + potential_gpp=potential_gpp, ) def get_canopy_profile( diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 30a36317..f639c877 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -620,7 +620,7 @@ def calculate_t_model_allometry( Args: pft_data: A dictionary of plant functional trait data, as for example returned - from :attr:`Flora.data` attribute. + from :attr:`Flora.data` attribute. dbh: An array of diameter at breast height values for which to predict stem allometry values. """ @@ -705,37 +705,40 @@ def calculate_t_model_allocation( stem_data = calculate_t_model_allometry(pft_data=pft_data, dbh=dbh) - stem_data["whole_crown_gpp"] = calculate_whole_crown_gpp( + # Broadcast potential GPP to match stem data outputs + potential_gpp = np.broadcast_to(potential_gpp, stem_data["dbh"].shape) + + whole_crown_gpp = calculate_whole_crown_gpp( potential_gpp=potential_gpp, crown_area=stem_data["crown_area"], par_ext=pft_data["par_ext"], lai=pft_data["lai"], ) - stem_data["sapwood_respiration"] = calculate_sapwood_respiration( + sapwood_respiration = calculate_sapwood_respiration( resp_s=pft_data["lai"], sapwood_mass=stem_data["sapwood_mass"] ) - stem_data["foliar_respiration"] = calculate_foliar_respiration( - resp_f=pft_data["resp_f"], whole_crown_gpp=stem_data["whole_crown_gpp"] + foliar_respiration = calculate_foliar_respiration( + resp_f=pft_data["resp_f"], whole_crown_gpp=whole_crown_gpp ) - stem_data["fine_root_respiration"] = calculate_fine_root_respiration( + fine_root_respiration = calculate_fine_root_respiration( zeta=pft_data["zeta"], sla=pft_data["sla"], resp_r=pft_data["resp_r"], foliage_mass=stem_data["foliage_mass"], ) - stem_data["npp"] = calculate_net_primary_productivity( + npp = calculate_net_primary_productivity( yld=pft_data["yld"], - whole_crown_gpp=stem_data["whole_crown_gpp"], - foliar_respiration=stem_data["foliar_respiration"], - fine_root_respiration=stem_data["fine_root_respiration"], - sapwood_respiration=stem_data["sapwood_respiration"], + whole_crown_gpp=whole_crown_gpp, + foliar_respiration=foliar_respiration, + fine_root_respiration=fine_root_respiration, + sapwood_respiration=sapwood_respiration, ) - stem_data["turnover"] = calculate_foliage_and_fine_root_turnover( + turnover = calculate_foliage_and_fine_root_turnover( sla=pft_data["sla"], zeta=pft_data["zeta"], tau_f=pft_data["tau_f"], @@ -743,11 +746,7 @@ def calculate_t_model_allocation( foliage_mass=stem_data["foliage_mass"], ) - ( - stem_data["delta_dbh"], - stem_data["delta_stem_mass"], - stem_data["delta_foliage_mass"], - ) = calculate_growth_increments( + (delta_dbh, delta_stem_mass, delta_foliage_mass) = calculate_growth_increments( rho_s=pft_data["rho_s"], a_hd=pft_data["a_hd"], h_max=pft_data["h_max"], @@ -755,10 +754,20 @@ def calculate_t_model_allocation( ca_ratio=pft_data["ca_ratio"], sla=pft_data["sla"], zeta=pft_data["zeta"], - npp=stem_data["npp"], - turnover=stem_data["turnover"], + npp=npp, + turnover=turnover, dbh=stem_data["dbh"], stem_height=stem_data["stem_height"], ) - return stem_data + return dict( + whole_crown_gpp=whole_crown_gpp, + sapwood_respiration=sapwood_respiration, + foliar_respiration=foliar_respiration, + fine_root_respiration=fine_root_respiration, + npp=npp, + turnover=turnover, + delta_dbh=delta_dbh, + delta_stem_mass=delta_stem_mass, + delta_foliage_mass=delta_foliage_mass, + ) From f6d0c57fa8f555be9fddc11009b77b2bb0b948f5 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 17:02:50 +0100 Subject: [PATCH 148/241] Revert "Add Flora helper methods" --- docs/source/_toc.yml | 2 - docs/source/users/demography/crown.md | 268 ------------ docs/source/users/demography/flora.md | 121 ------ .../pmodel/pmodel_details/extreme_values.md | 5 + .../pmodel/pmodel_details/worked_examples.md | 24 + .../subdaily_details/subdaily_calculations.md | 23 + .../pmodel/subdaily_details/worked_example.md | 20 + pyproject.toml | 16 +- pyrealm/demography/canopy_functions.py | 116 +---- pyrealm/demography/flora.py | 180 +------- pyrealm/demography/t_model_functions.py | 227 +--------- tests/unit/demography/conftest.py | 90 ---- tests/unit/demography/test_flora.py | 119 ----- .../unit/demography/test_t_model_functions.py | 410 ++++++++---------- 14 files changed, 277 insertions(+), 1344 deletions(-) delete mode 100644 docs/source/users/demography/crown.md delete mode 100644 docs/source/users/demography/flora.md delete mode 100644 tests/unit/demography/conftest.py diff --git a/docs/source/_toc.yml b/docs/source/_toc.yml index 1674a45f..73c15779 100644 --- a/docs/source/_toc.yml +++ b/docs/source/_toc.yml @@ -27,8 +27,6 @@ subtrees: - file: users/pmodel/subdaily_details/worked_example.md - file: users/pmodel/c3c4model.md - file: users/pmodel/isotopic_discrimination.md - - file: users/demography/flora.md - - file: users/demography/crown.md - file: users/tmodel/tmodel.md - file: users/tmodel/canopy.md - file: users/splash.md diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md deleted file mode 100644 index aa9d15e0..00000000 --- a/docs/source/users/demography/crown.md +++ /dev/null @@ -1,268 +0,0 @@ ---- -jupytext: - formats: md:myst - text_representation: - extension: .md - format_name: myst - format_version: 0.13 -kernelspec: - display_name: Python 3 (ipykernel) - language: python - name: python3 ---- - -# The tree crown model - -:::{admonition} Warning - -This area of `pyrealm` is in active development and this notebook currently contains -notes and initial demonstration code. - -::: - -```{code-cell} -from matplotlib import pyplot as plt -import numpy as np -import pandas as pd - -from pyrealm.demography.canopy_functions import ( - calculate_canopy_q_m, - calculate_canopy_z_max_proportion, -) - -from pyrealm.demography.flora import PlantFunctionalType, Flora -``` - -The {mod}`pyrealm.demography` module uses three-dimensional model of crown shape to -define the vertical distribution of leaf area. This is driven by four parameters within -the {class}`~pyrealm.demography.flora.PlantFunctionalType`: - -* The `m` and `n` parameters that define the vertical shape of the crown profile. -* The `ca_ratio` parameters that defines the size of the crown relative to the stem size. -* The `f_g` parameter that define the crown gap fraction and sets the vertical - distribution of leaves within the crown. - -The code below provides a demonstration of the impacts of each parameter and shows the -use of `pyrealm` tools to visualise the crown model for individual stems. - -## Crown shape parameters - -The `m` and `n` parameters define the vertical profile of the crown but are also define -two further parameters: - -* `q_m`, which is used to scale the size of the crown radius to match the expected crown - area, given the crown shape. -* `z_max_prop`, which sets the height on the stem at which the maximum crown radius is found. - -The code below calculates `q_m` and `z_max_prop` for combinations of `m` and `n` and -then plots the resulting values. - -```{code-cell} -m = n = np.arange(1.0, 5, 0.1) -q_m = calculate_canopy_q_m(m=m, n=n[:, None]) -z_max_prop = calculate_canopy_z_max_proportion(m=m, n=n[:, None]) -``` - -```{code-cell} -fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10.9, 4)) - -# Plot q_m as a function of m and n -cntr_set1 = ax1.contourf(m, n, q_m, levels=10) -fig.colorbar(cntr_set1, ax=ax1, label="q_m") -ax1.set_xlabel("m") -ax1.set_ylabel("n") -ax1.set_aspect("equal") - -# Plot z_max_prop as a function of m and n -cntr_set2 = ax2.contourf(m, n, z_max_prop, levels=10) -fig.colorbar(cntr_set2, ax=ax2, label="z_max_prop") -ax2.set_xlabel("m") -ax2.set_ylabel("n") -ax2.set_aspect("equal") -``` - -## Plotting crown profiles - -The examples below show the calculation of crown profiles for a set of plant functional -types (PFTs) with differing crown trait values. We first need to create a -:class:`~pyrealm.demography.flora.Flora` object that defines those PFTs. - -```{code-cell} -flora = Flora( - [ - PlantFunctionalType(name="short", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=20), - PlantFunctionalType( - name="medium", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=500 - ), - PlantFunctionalType(name="tall", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=2000), - ] -) - -flora -``` - -We then also need to specify the size of a stem of each PFT, along with the resulting -allometric predictions from the T Model. - -```{code-cell} -# Generate the expected stem allometries at a single height for each PFT -stem_height = np.array([18, 18, 18]) -allometry = flora.get_allometries(stem_height=stem_height) -``` - -We can use {mod}`pandas` to visualise those allometric predictions. - -```{code-cell} -pd.DataFrame(allometry) -``` - -We can now use the {meth}`~pyrealm.demography.flora.Flora.get_canopy_profile` method to -calculate the canopy profile for each stem for a set of vertical heights. The heights -need to be defined as a column array, that is with a shape `(N, 1)`, in order to show -that we want the canopy variables to be calculated at each height for each PFT. - -```{code-cell} -# Create a set of vertical heights as a column array. -z = np.linspace(0, 18.0, num=181)[:, None] - -# Calculate the crown profile across those heights for each PFT -crown_profiles = flora.get_canopy_profile( - z=z, - crown_area=allometry["crown_area"], - stem_height=allometry["stem_height"], - r0=allometry["canopy_r0"], - z_max=allometry["canopy_z_max"], -) -``` - -The `crown_profiles` object is a dictionary containing values for four crown profile -variables. - -* The relative crown radius: this value is driven purely by `m`, `n` and the stem height - and defines the vertical profile of the crown. -* The crown radius: this is simply a rescaling of the relative radius so that the - maximum crown radius matches the expected crown area predicted by the allometry of the - T Model. -* The projected crown area: this value shows how crown area accumulates from the top of - the crown to the ground. -* The projected leaf area: this value shows how _leaf_ area accumulates from the top of - the crown to the ground. The difference from the crown area is driven by the crown gap - fraction for a given PFT. - -+++ - -### Crown radius values - -The relative crown radius values are arbitrary - they simply define the shape of the -vertical profile. For the example PFTs in the `Flora` object, the maximum relative -radius values on each stem are: - -```{code-cell} -max_relative_crown_radius = crown_profiles["relative_canopy_radius"].max(axis=0) -print(max_relative_crown_radius) -``` - -However the scaled maximum radius values match the expected crown area in the allometry -table above - -```{code-cell} -max_crown_radius = crown_profiles["crown_radius"].max(axis=0) -print(max_crown_radius) -print(max_crown_radius**2 * np.pi) -``` - -The code below generates a plot of the vertical shape profiles of the crowns for each -stem. For each stem: - -* the dashed line shows how the relative crown radius varies with height, -* the solid line shows the actual crown radius profile with height, and -* the dotted line shows the height at which the maximum crown radius is found. - -```{code-cell} -fig, ax = plt.subplots(ncols=1) - -# Find the maximum of the actual and relative maximum crown widths -stem_max_width = np.maximum(max_crown_radius, max_relative_crown_radius) - -for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 12), ("r", "g", "b")): - - # Plot relative radius either side of offset - stem_qz = crown_profiles["relative_canopy_radius"][:, pft_idx] - ax.plot(stem_qz + offset, z, color=colour, linestyle="--", linewidth=1) - ax.plot(-stem_qz + offset, z, color=colour, linestyle="--", linewidth=1) - - # Plot actual crown radius either side of offset - stem_rz = crown_profiles["crown_radius"][:, pft_idx] - ax.plot(stem_rz + offset, z, color=colour) - ax.plot(-stem_rz + offset, z, color=colour) - - # Add the height of maximum crown radius - stem_rz_max = stem_max_width[pft_idx] - - ax.plot( - [offset - stem_rz_max, offset + stem_rz_max], - [allometry["canopy_z_max"][pft_idx]] * 2, - color=colour, - linewidth=1, - linestyle=":", - ) - -ax.set_aspect(aspect=1) -``` - -### Projected crown and leaf areas - -We can use the crown profile to generate projected area plots, but it is much easier to -compare the effects when comparing stems with similar crown areas. The code below -generates these new predictions for a new set of PFTs. - -```{code-cell} -flora2 = Flora( - [ - PlantFunctionalType(name="short", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=380), - PlantFunctionalType( - name="medium", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=400 - ), - PlantFunctionalType(name="tall", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=420), - ] -) - -allometry2 = flora2.get_allometries(stem_height=stem_height) - - -# Calculate the crown profile across those heights for each PFT -crown_profiles2 = flora2.get_canopy_profile( - z=z, - crown_area=allometry2["crown_area"], - stem_height=allometry2["stem_height"], - r0=allometry2["canopy_r0"], - z_max=allometry2["canopy_z_max"], -) -``` - -The plot below shows how projected crown area (solid lines) and leaf area (dashed lines) -change with height along the stem. - -* The projected crown area increases from zero at the top of the canopy, according to - the canopy profile, until it reaches the maximum crown radius, at which point it - remains constant down to ground level. The total crown areas differs for each stem - because of the slightly different values used for the crown area ratio. - -* The projected leaf area is very similar but leaf area is displaced towards the ground - because of the crown gap fraction (`f_g`). Where `f_g = 0` (the red line), the two - lines are identical, but as `f_g` increases, more of the leaf area is displaced down - within the canopy. - -```{code-cell} -fig, ax = plt.subplots(ncols=1) - -for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 10), ("r", "g", "b")): - - ax.plot(crown_profiles2["projected_crown_area"][:, pft_idx], z, color=colour) - ax.plot( - crown_profiles2["projected_leaf_area"][:, pft_idx], - z, - color=colour, - linestyle="--", - ) -``` diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md deleted file mode 100644 index 646601da..00000000 --- a/docs/source/users/demography/flora.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -jupytext: - formats: md:myst - text_representation: - extension: .md - format_name: myst - format_version: 0.13 -kernelspec: - display_name: Python 3 (ipykernel) - language: python - name: python3 ---- - -# Plant Functional Types and the Flora object - -:::{admonition} Warning - -This area of `pyrealm` is in active development and this notebook currently contains -notes and initial demonstration code. - -::: - -```{code-cell} -from matplotlib import pyplot as plt -import numpy as np - -from pyrealm.demography.flora import PlantFunctionalType, Flora -``` - -The code below creates a simple `Flora` object containing 3 plant functional types with -different maximum stem heights. - -```{code-cell} -flora = Flora( - [ - PlantFunctionalType(name="short", h_max=10), - PlantFunctionalType(name="medium", h_max=20), - PlantFunctionalType(name="tall", h_max=30), - ] -) - -flora -``` - -We can visualise how the stem size, canopy size and various masses of a plant functional -type change with stem diameter by using the `Flora.get_allometries` method. This takes -an array of values for diameter at breast height (metres) and returns a dictionary -containing the predictions of the T Model for: - -* Stem height ('stem_height', m) -* Crown area ('crown_area', m2) -* Crown fraction ('crown_fraction', -) -* Stem mass ('stem_mass', kg) -* Foliage mass ('foliage_mass', kg) -* Sapwood mass ('sapwood_mass', kg) - -The returned values in the dictionary are 2 dimensional arrays with each DBH value as a -row and each PFT as a column. This makes them convenient to plot using `matplotlib`. - -```{code-cell} -dbh = np.arange(0, 1.6, 0.01)[:, None] -allometries = flora.get_allometries(dbh=dbh) -``` - -The code below shows how to use the returned allometries to generate a plot of the -scaling relationships across all of the PFTs in a `Flora` instance. - -```{code-cell} -fig, axes = plt.subplots(ncols=2, nrows=3, sharex=True, figsize=(10, 8)) - -plot_details = [ - ("stem_height", "Stem height (m)"), - ("crown_area", "Crown area (m2)"), - ("crown_fraction", "Crown fraction (-)"), - ("stem_mass", "Stem mass (kg)"), - ("foliage_mass", "Foliage mass (kg)"), - ("sapwood_mass", "Sapwood mass (kg)"), -] - -for ax, (var, ylab) in zip(axes.flatten(), plot_details): - ax.plot(dbh, allometries[var], label=flora.keys()) - ax.set_xlabel("Diameter at breast height (m)") - ax.set_ylabel(ylab) - - if var == "sapwood_mass": - ax.legend(frameon=False) -``` - -```{code-cell} -potential_gpp = np.repeat(55, dbh.size)[:, None] -allocation = flora.get_allocation(dbh=dbh, potential_gpp=potential_gpp) -``` - -```{code-cell} -fig, axes = plt.subplots(ncols=2, nrows=5, sharex=True, figsize=(10, 12)) - -plot_details = [ - ("whole_crown_gpp", "whole_crown_gpp"), - ("sapwood_respiration", "sapwood_respiration"), - ("foliar_respiration", "foliar_respiration"), - ("fine_root_respiration", "fine_root_respiration"), - ("npp", "npp"), - ("turnover", "turnover"), - ("delta_dbh", "delta_dbh"), - ("delta_stem_mass", "delta_stem_mass"), - ("delta_foliage_mass", "delta_foliage_mass"), -] - -axes = axes.flatten() - -for ax, (var, ylab) in zip(axes, plot_details): - ax.plot(dbh, allocation[var], label=flora.keys()) - ax.set_xlabel("Diameter at breast height (m)") - ax.set_ylabel(ylab) - - if var == "whole_crown_gpp": - ax.legend(frameon=False) - -# Delete unused panel in 5 x 2 grid -fig.delaxes(axes[-1]) -``` diff --git a/docs/source/users/pmodel/pmodel_details/extreme_values.md b/docs/source/users/pmodel/pmodel_details/extreme_values.md index 01c92446..7119ac7f 100644 --- a/docs/source/users/pmodel/pmodel_details/extreme_values.md +++ b/docs/source/users/pmodel/pmodel_details/extreme_values.md @@ -53,6 +53,7 @@ Note that the default values for C3 photosynthesis give **non-zero values below ```{code-cell} :tags: [hide-input] +:trusted: true from matplotlib import pyplot import numpy as np @@ -92,6 +93,7 @@ that again, $\Gamma^_$ has non-zero values for sub-zero temperatures. ```{code-cell} :tags: [hide-input] +:trusted: true # Calculate gammastar at different pressures tc_1d = np.linspace(-80, 100, n_pts) @@ -117,6 +119,7 @@ temperature and atmospheric pressure and again behaves smoothly with extreme val ```{code-cell} :tags: [hide-input] +:trusted: true fig, ax = pyplot.subplots(1, 1) @@ -141,6 +144,7 @@ issue with low temperatures arising from the equations for the density of water. ```{code-cell} :tags: [hide-input] +:trusted: true fig, ax = pyplot.subplots(1, 1) @@ -165,6 +169,7 @@ predictions below about -30 °C. ```{code-cell} :tags: [hide-input] +:trusted: true fig, ax = pyplot.subplots(1, 1) diff --git a/docs/source/users/pmodel/pmodel_details/worked_examples.md b/docs/source/users/pmodel/pmodel_details/worked_examples.md index 6e9e2f0e..f3db6947 100644 --- a/docs/source/users/pmodel/pmodel_details/worked_examples.md +++ b/docs/source/users/pmodel/pmodel_details/worked_examples.md @@ -39,6 +39,8 @@ The example shows the steps required using a single site with: ### Estimate photosynthetic environment ```{code-cell} +:trusted: true + from importlib import resources from matplotlib import pyplot as plt @@ -59,10 +61,14 @@ terse - just the shape of the data - but the more detailed summary of the attributes. ```{code-cell} +:trusted: true + env ``` ```{code-cell} +:trusted: true + env.summarize() ``` @@ -72,6 +78,8 @@ Next, the P Model can be fitted to the photosynthetic environment using the ({class}`~pyrealm.pmodel.pmodel.PModel`) class: ```{code-cell} +:trusted: true + model = PModel(env) ``` @@ -79,6 +87,8 @@ The returned model object holds a lot of information. The representation of the model object shows a terse display of the settings used to run the model: ```{code-cell} +:trusted: true + model ``` @@ -89,6 +99,8 @@ photosynthetic efficiency: the intrinsic water use efficiency (``iwue``) and the use efficiency (``lue``). ```{code-cell} +:trusted: true + model.summarize() ``` @@ -101,6 +113,8 @@ This object also has a {meth}`~pyrealm.pmodel.optimal_chi.OptimalChiABC.summariz method: ```{code-cell} +:trusted: true + model.optchi.summarize() ``` @@ -117,6 +131,8 @@ Here we are using: * a PPFD of 834 µmol m-2 s-1. ```{code-cell} +:trusted: true + model.estimate_productivity(fapar=0.91, ppfd=834) model.summarize() ``` @@ -149,6 +165,8 @@ to be the same size so some of the variables have repeated data across dimension * Elevation is constant across months, so the data for each month is repeated. ```{code-cell} +:trusted: true + # Load an example dataset containing the forcing variables. data_path = resources.files("pyrealm_build_data.rpmodel") / "pmodel_global.nc" ds = xarray.load_dataset(data_path) @@ -168,6 +186,8 @@ data to atmospheric pressure, and then this is used to set the photosynthetic environment for the model: ```{code-cell} +:trusted: true + # Convert elevation to atmospheric pressure patm = calc_patm(elev) @@ -186,6 +206,8 @@ That environment can then be run to calculate the P model predictions for light efficiency: ```{code-cell} +:trusted: true + # Run the P model model = PModel(env) @@ -199,6 +221,8 @@ Finally, the light use efficiency can be used to calculate GPP given the photosynthetic photon flux density and fAPAR. ```{code-cell} +:trusted: true + # Scale the outputs from values per unit iabs to realised values model.estimate_productivity(fapar, ppfd) diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md index b4b71cb1..1a134c84 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md @@ -21,6 +21,7 @@ are handled internally by the model fitting in `pyrealm`. ```{code-cell} :tags: [hide-input] +:trusted: true from importlib import resources @@ -47,6 +48,8 @@ site](https://fluxnet.org/doi/FLUXNET2015/BE-Vie), which was also used as a demonstration in {cite:t}`mengoli:2022a`. ```{code-cell} +:trusted: true + data_path = resources.files("pyrealm_build_data.subdaily") / "subdaily_BE_Vie_2014.csv" data = pandas.read_csv(str(data_path)) @@ -68,6 +71,8 @@ subdaily timescale. The code below also estimates GPP under the standard P Model slow responses for comparison. ```{code-cell} +:trusted: true + # Calculate the photosynthetic environment subdaily_env = PModelEnvironment( tc=temp_subdaily, @@ -94,6 +99,8 @@ conditions at the observation closest to noon, or the mean environmental conditi window around noon. ```{code-cell} +:trusted: true + # Create the fast slow scaler fsscaler = SubdailyScaler(datetime_subdaily) @@ -115,6 +122,7 @@ pmodel_subdaily = SubdailyPModel( ```{code-cell} :tags: [hide-input] +:trusted: true idx = np.arange(48 * 120, 48 * 130) plt.figure(figsize=(10, 4)) @@ -138,6 +146,8 @@ inputs to the standard P Model to calculate the optimal behaviour of plants unde conditions. ```{code-cell} +:trusted: true + # Get the daily acclimation conditions for the forcing variables temp_acclim = fsscaler.get_daily_means(temp_subdaily) co2_acclim = fsscaler.get_daily_means(co2_subdaily) @@ -169,6 +179,8 @@ at 25°C. This is acheived by multiplying by the reciprocal of the exponential p the Arrhenius equation ($h^{-1}$ in {cite}`mengoli:2022a`). ```{code-cell} +:trusted: true + # Are these any of the existing values in the constants? ha_vcmax25 = 65330 ha_jmax25 = 43900 @@ -184,6 +196,8 @@ The memory effect can now be applied to the three parameters with slow responses to calculate realised values, here using the default 15 day window. ```{code-cell} +:trusted: true + # Calculation of memory effect in xi, vcmax25 and jmax25 xi_real = memory_effect(pmodel_acclim.optchi.xi, alpha=1 / 15) vcmax25_real = memory_effect(vcmax25_acclim, alpha=1 / 15, allow_holdover=True) @@ -196,6 +210,7 @@ application of the memory effect. ```{code-cell} :tags: [hide-input] +:trusted: true fig, axes = plt.subplots(1, 3, figsize=(16, 5)) @@ -229,6 +244,8 @@ temperature at fast scales: responses of $J_{max}$ and $V_{cmax}$. ```{code-cell} +:trusted: true + tk_subdaily = subdaily_env.tc + pmodel_subdaily.env.core_const.k_CtoK # Fill the realised jmax and vcmax from subdaily to daily @@ -249,6 +266,8 @@ optimal $\chi$, rather than calculating the instantaneously optimal values of $\ as is the case in the standard P Model. ```{code-cell} +:trusted: true + # Interpolate xi to subdaily scale xi_subdaily = fsscaler.fill_daily_to_subdaily(xi_real) @@ -268,6 +287,8 @@ include the slow responses of $V_{cmax25}$ and $J_{max25}$ and fast responses to temperature. ```{code-cell} +:trusted: true + # Calculate Ac Ac_subdaily = ( vcmax_subdaily @@ -298,5 +319,7 @@ print(np.nanmin(diff), np.nanmax(diff)) ``` ```{code-cell} +:trusted: true + ``` diff --git a/docs/source/users/pmodel/subdaily_details/worked_example.md b/docs/source/users/pmodel/subdaily_details/worked_example.md index db699027..fac12b6a 100644 --- a/docs/source/users/pmodel/subdaily_details/worked_example.md +++ b/docs/source/users/pmodel/subdaily_details/worked_example.md @@ -14,6 +14,8 @@ kernelspec: # Worked example of the Subdaily P Model ```{code-cell} +:trusted: true + from importlib import resources import xarray @@ -59,6 +61,8 @@ The test data use some UK WFDE data for three sites in order to compare predicti over a time series. ```{code-cell} +:trusted: true + # Loading the example dataset: dpath = ( resources.files("pyrealm_build_data.uk_data") / "UK_WFDE5_FAPAR_2018_JuneJuly.nc" @@ -80,6 +84,8 @@ The WFDE data need some conversion for use in the PModel, along with the definit the atmospheric CO2 concentration. ```{code-cell} +:trusted: true + # Variable set up # Air temperature in °C from Tair in Kelvin tc = (ds["Tair"] - 273.15).to_numpy() @@ -99,6 +105,8 @@ co2 = np.ones_like(tc) * 400 The code below then calculates the photosynthetic environment. ```{code-cell} +:trusted: true + # Generate and check the PModelEnvironment pm_env = PModelEnvironment(tc=tc, patm=patm, vpd=vpd, co2=co2) pm_env.summarize() @@ -110,6 +118,8 @@ The standard implementation of the P Model used below assumes that plants can instantaneously adopt optimal behaviour. ```{code-cell} +:trusted: true + # Standard PModels pmodC3 = PModel( env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="prentice14" @@ -119,6 +129,8 @@ pmodC3.summarize() ``` ```{code-cell} +:trusted: true + pmodC4 = PModel( env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="c4_no_gamma" ) @@ -135,6 +147,8 @@ calculations: essentially the plant does not acclimate until the optimal values calculated again to update those realised estimates. ```{code-cell} +:trusted: true + # Set the acclimation window to an hour either side of noon fsscaler = SubdailyScaler(datetimes) fsscaler.set_window( @@ -174,6 +188,8 @@ shown above and plots the instantaneous predictions against predictions includin photosynthetic responses. ```{code-cell} +:trusted: true + # Store the predictions in the xarray Dataset to use indexing ds["GPP_pmodC3"] = (ds["Tair"].dims, pmodC3.gpp) ds["GPP_subdailyC3"] = (ds["Tair"].dims, subdailyC3.gpp) @@ -231,6 +247,8 @@ The subdaily models can also be obtained directly from the standard models, usin `convert_pmodel_to_subdaily` method: ```{code-cell} +:trusted: true + # Convert standard C3 model converted_C3 = convert_pmodel_to_subdaily( pmodel=pmodC3, @@ -252,6 +270,8 @@ This produces the same outputs as the `SubdailyPModel` class, but is convenient compact when the two models are going to be compared. ```{code-cell} +:trusted: true + # Models have identical GPP - maximum absolute difference is zero. print(np.nanmax(abs(subdailyC3.gpp.flatten() - converted_C3.gpp.flatten()))) print(np.nanmax(abs(subdailyC4.gpp.flatten() - converted_C4.gpp.flatten()))) diff --git a/pyproject.toml b/pyproject.toml index e72b8031..2823f7cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,15 +31,15 @@ repository = "https://github.com/ImperialCollegeLondon/pyrealm" version = "1.0.0" [tool.poetry.dependencies] -dacite = "^1.6.0" -numpy = "^2.0.0" +dacite = "^1.6.0" +numpy = "^2.0.0" python = ">=3.10" -scipy = "^1.7.3" -tabulate = "^0.8.10" +scipy = "^1.7.3" +tabulate = "^0.8.10" marshmallow = "^3.22.0" -marshmallow-dataclass = "^8.7.0" pandas = "^2.2.2" +marshmallow-dataclass = "^8.7.0" pandas-stubs = "^2.2.2.240909" [tool.poetry.group.types.dependencies] pandas-stubs = "^2.2.0.240218" @@ -132,7 +132,7 @@ select = [ "I", # isort "UP", # pyupgrade "RUF", # RUF specific checks - "NPY201", + "NPY201" ] # On top of the Google convention, disable: @@ -148,5 +148,5 @@ convention = "google" [tool.jupytext] # Stop jupytext from removing mystnb and other settings in MyST Notebook YAML headers notebook_metadata_filter = "-jupytext.text_representation.jupytext_version,settings,mystnb" -# Also stop it from stripping cell metadata except for a few cases. -cell_metadata_filter = "all,-autoscroll,-collapsed,-scrolled,-trusted,-ExecuteTime" +# Also stop it from stripping cell metadata. +cell_metadata_filter = "all" \ No newline at end of file diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 7b9dc7bd..15eae194 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -78,7 +78,7 @@ def calculate_canopy_z_max( def calculate_canopy_r0( q_m: NDArray[np.float32], crown_area: NDArray[np.float32] ) -> NDArray[np.float32]: - r"""Calculate scaling factor width of maximum crown radius. + r"""Calculate scaling factor for height of maximum crown radius. This scaling factor (:math:`r_0`) is derived from the canopy shape parameters (:math:`m,n,q_m`) for plant functional types and the estimated crown area @@ -225,44 +225,9 @@ def calculate_relative_canopy_radius_at_z( z_over_height = z / stem_height - # Remove predictions of canopy radius above stem height - z_over_height = np.where(z > stem_height, np.nan, z_over_height) - return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) -def calculate_canopy_radius( - q_z: NDArray[np.float32], - r0: NDArray[np.float32], - validate: bool = True, -) -> NDArray[np.float32]: - r"""Calculate canopy radius from relative radius and canopy r0. - - The relative canopy radius (:math:`q(z)`) at a given height :math:`z` describes the - vertical profile of the canopy shape, but only varies with the ``m`` and ``n`` shape - parameters and the stem height. The actual crown radius at a given height - (:math:`r(z)`) needs to be scaled using :math:`r_0` such that the maximum crown area - equals the expected crown area given the crown area ratio traiit for the plant - functional type: - - .. math:: - - r(z) = r_0 q(z) - - This function calculates :math:`r(z)` given estimated ``r0`` and an array of - relative radius values. - - Args: - q_z: TODO - r0: TODO - validate: Boolean flag to suppress argument validation. - """ - - # TODO - think about validation here. qz must be row array or 2D (N, n_pft) - - return r0 * q_z - - def calculate_stem_projected_crown_area_at_z( z: NDArray[np.float32], q_z: NDArray[np.float32], @@ -439,73 +404,28 @@ def calculate_stem_projected_leaf_area_at_z( return A_cp -def calculate_canopy_profiles( - pft_data: dict[str, NDArray[np.float32]], - z: NDArray[np.float32], - stem_height: NDArray[np.float32], - crown_area: NDArray[np.float32], - r0: NDArray[np.float32], - z_max: NDArray[np.float32], -) -> dict[str, NDArray[np.float32]]: - """Calculate vertical canopy profiles for stems. +# def calculate_total_canopy_A_cp(z: float, f_g: float, community: Community) -> float: +# """Calculate total leaf area at a given height. - This method calculates canopy profile predictions, given an array of vertical - heights (``z``) for: +# :param f_g: +# :param community: +# :param z: Height above ground. +# :return: Total leaf area in the canopy at a given height. +# """ +# A_cp_for_individuals = calculate_projected_leaf_area_for_individuals( +# z, f_g, community +# ) - * relativate canopy radius, - * actual canopy radius, - * projected crown area, and - * project leaf area. +# A_cp_for_cohorts = A_cp_for_individuals * community.cohort_number_of_individuals - The predictions require a set of plant functional types (PFTs) but also the expected - allometric predictions of stem height, crown area and z_max for an actual stem of a - given size for each PFT. +# return A_cp_for_cohorts.sum() - Args: - pft_data: A dictionary of plant functional trait data, as for example returned - from :attr:`Flora.data` attribute. - z: An array of vertical height values at which to calculate canopy profiles. - stem_height: A row array providing expected stem height for each PFT. - crown_area: A row array providing expected crown area for each PFT. - r0: A row array providing expected r0 for each PFT. - z_max: A row array providing expected z_max height for each PFT. - """ - # Calculate relative radius - relative_canopy_radius = calculate_relative_canopy_radius_at_z( - z=z, - m=pft_data["m"], - n=pft_data["n"], - stem_height=stem_height, - ) +# def calculate_gpp(cell_ppfd: NDArray, lue: NDArray) -> float: +# """Estimate the gross primary productivity. - # Calculate actual radius - crown_radius = calculate_canopy_radius(q_z=relative_canopy_radius, r0=r0) +# Not sure where to place this - need an array of LUE that matches to the - # Calculate projected crown area - projected_crown_area = calculate_stem_projected_crown_area_at_z( - z=z, - q_z=relative_canopy_radius, - crown_area=crown_area, - q_m=pft_data["q_m"], - stem_height=stem_height, - z_max=z_max, - ) - - # Calculate projected leaf area - projected_leaf_area = calculate_stem_projected_leaf_area_at_z( - z=z, - q_z=relative_canopy_radius, - f_g=pft_data["f_g"], - crown_area=crown_area, - q_m=pft_data["q_m"], - stem_height=stem_height, - z_max=z_max, - ) +# """ - return dict( - relative_canopy_radius=relative_canopy_radius, - crown_radius=crown_radius, - projected_crown_area=projected_crown_area, - projected_leaf_area=projected_leaf_area, - ) +# return 100 diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 5922759c..22f00292 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -31,16 +31,9 @@ from numpy.typing import NDArray from pyrealm.demography.canopy_functions import ( - _validate_z_qz_args, - calculate_canopy_profiles, calculate_canopy_q_m, calculate_canopy_z_max_proportion, ) -from pyrealm.demography.t_model_functions import ( - calculate_dbh_from_height, - calculate_t_model_allocation, - calculate_t_model_allometry, -) if sys.version_info[:2] >= (3, 11): import tomllib @@ -241,8 +234,8 @@ def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: for name, pft in zip(pft_names, pfts): self[name] = pft - # Generate a dictionary of arrays of traits across PFTs and an index mapping PFT - # names onto the index of those arrays. + # Generate an dataframe representation to facilitate merging to cohort data. + # - assemble pft fields into arrays data = {} pft_fields = [f.name for f in fields(PlantFunctionalTypeStrict)] @@ -257,14 +250,6 @@ def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: self.pft_indices = {v: k for k, v in enumerate(self.data["name"])} """An dictionary giving the index of each PFT name in the PFT data.""" - self.n_pfts = len(pfts) - """The number of plant functional types in the Flora instance.""" - - def __repr__(self) -> str: - """Simple representation of the Flora instance.""" - - return f"Flora with {self.n_pfts} functional types: {', '.join(self.keys())}" - @classmethod def _from_file_data(cls, file_data: dict) -> Flora: """Create a Flora object from a JSON string. @@ -323,164 +308,3 @@ def from_csv(cls, path: Path) -> Flora: raise excep return cls._from_file_data({"pft": data.to_dict(orient="records")}) - - def get_allometries( - self, - dbh: NDArray[np.float32] | None = None, - stem_height: NDArray[np.float32] | None = None, - ) -> dict[str, NDArray]: - """Calculate T Model scalings for the Flora members. - - This method calculates the allometric predictions of the T Model for all of the - plant functional types within a Flora, given an array of stem sizes at which to - calculate the predictions. The method returns a dictionary of the following - allometric predictions of the T Model: - - * 'dbh' - * 'stem_height' - * 'crown_area' - * 'crown_fraction', - * 'stem_mass' - * 'foliage_mass' - * 'sapwood_mass' - - Each dictionary entry is a 2D array with PFTs as columns and the predictions for - each stem size as rows. - - The T Model uses diameter at breast height (DBH) as the fundamental metric of - stem size but this method will also accept a set of stem heights as an - alternative size metric. Stem heights are converted back into the expected DBH - before calculating the allometric predictions - if any of the stem heights are - higher than the maximum height for a PFT, these will be shown as `np.nan` - values. One of ``dbh`` and ``stem_height`` must be provided as a one-dimensional - array. - - Args: - dbh: An array of diameter at breast height values. - stem_height: An array of stem height values. - """ - - # Need exclusively one of dbh or stem_height - use XOR - if not ((dbh is None) ^ (stem_height is None)): - raise ValueError("Provide one of either dbh or stem_height") - - if stem_height is not None: - # TODO: This steals the validation from the canopy functions - this might be - # a general function for the module - see also the - # validate_t_model_args function. - _validate_z_qz_args(z=stem_height, stem_properties=[self.data["h_max"]]) - - dbh = calculate_dbh_from_height( - h_max=self.data["h_max"], - a_hd=self.data["a_hd"], - stem_height=stem_height, - ) - elif dbh is not None: - # TODO: This steals the validation from the canopy functions - this might be - # a general function for the module - see also the - # validate_t_model_args function. - _validate_z_qz_args(z=dbh, stem_properties=[self.data["h_max"]]) - - # DBH is now always populated so ignore warning that it might be None - return calculate_t_model_allometry(pft_data=self.data, dbh=dbh) # type: ignore [arg-type] - - def get_allocation( - self, - potential_gpp: NDArray[np.float32], - dbh: NDArray[np.float32] | None = None, - stem_height: NDArray[np.float32] | None = None, - ) -> dict[str, NDArray]: - """Calculate T Model scalings for the Flora members. - - This method calculates the predicted allocation of potential gross primary - productivity (GPP) under the T Model for all of the plant functional types - within a Flora, given values for stem size and potential GPP. The method returns - a dictionary of the allocation predictions of the T Model: - - * "whole_crown_gpp" - * "sapwood_respiration" - * "foliar_respiration" - * "fine_root_respiration" - * "npp" - * "turnover" - * "delta_dbh" - * "delta_stem_mass" - * "delta_foliage_mass" - - Each dictionary entry is a 2D array with PFTs as columns and the predictions for - each size value as rows. - - The T Model uses diameter at breast height (DBH) as the fundamental metric of - stem size but this method will also accept a set of stem heights as an - alternative size metric. Stem heights are converted back into the expected DBH - before calculating the allometric predictions - if any of the stem heights are - higher than the maximum height for a PFT, these will be shown as `np.nan` - values. One of ``dbh`` and ``stem_height`` must be provided as a one-dimensional - array, and ``potential_gpp`` must have the same shape. - - Args: - potential_gpp: An array of potential GPP values. - dbh: An array of diameter at breast height values. - stem_height: An array of stem height values. - """ - - # Need exclusively one of dbh or stem_height - use XOR - if not ((dbh is None) ^ (stem_height is None)): - raise ValueError("Provide one of either dbh or stem_height") - - if stem_height is not None: - # TODO: This steals the validation from the canopy functions - this might be - # a general function for the module - see also the - # validate_t_model_args function. - _validate_z_qz_args(z=stem_height, stem_properties=[self.data["h_max"]]) - - dbh = calculate_dbh_from_height( - h_max=self.data["h_max"], - a_hd=self.data["a_hd"], - stem_height=stem_height, - ) - elif dbh is not None: - # TODO: This steals the validation from the canopy functions - this might be - # a general function for the module - see also the - # validate_t_model_args function. - _validate_z_qz_args(z=dbh, stem_properties=[self.data["h_max"]]) - - if potential_gpp.shape != dbh.shape: # type: ignore [union-attr] - raise ValueError("GPP must have the same shape as DBH or stem height") - - return calculate_t_model_allocation( - pft_data=self.data, - dbh=dbh, # type: ignore [arg-type] - potential_gpp=potential_gpp, - ) - - def get_canopy_profile( - self, - z: NDArray[np.float32], - stem_height: NDArray[np.float32], - crown_area: NDArray[np.float32], - r0: NDArray[np.float32], - z_max: NDArray[np.float32], - ) -> dict[str, NDArray]: - """Calculate T Model scalings for the Flora members. - - TODO: Description - - Args: - z: TODO - stem_height: TODO - crown_area: TODO - r0: TODO - z_max: TODO - """ - - # TODO - validation - - return calculate_canopy_profiles( - pft_data=self.data, - z=z, - stem_height=stem_height, - crown_area=crown_area, - r0=r0, - z_max=z_max, - ) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index f639c877..59b18fb7 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -9,10 +9,6 @@ from numpy.typing import NDArray from pyrealm.core.utilities import check_input_shapes -from pyrealm.demography.canopy_functions import ( - calculate_canopy_r0, - calculate_canopy_z_max, -) def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> None: @@ -40,7 +36,8 @@ def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> raise ValueError("Size arrays are not of equal length") # Explicitly check to see if the size arrays are row arrays and - if so - enforce - # that they are the same length. + # that they are the same length.abs + if len(size_args_shape) == 1 and not pft_args_shape == size_args_shape: raise ValueError("Trait and size inputs are row arrays of unequal length.") @@ -81,56 +78,6 @@ def calculate_heights( return h_max * (1 - np.exp(-a_hd * dbh / h_max)) -def calculate_dbh_from_height( - h_max: NDArray[np.float32], - a_hd: NDArray[np.float32], - stem_height: NDArray[np.float32], - validate: bool = True, -) -> NDArray[np.float32]: - r"""Calculate diameter at breast height from stem height under the T Model. - - This function inverts the normal calculation of stem height (:math:`H`) from - diameter at breast height (:math:`D`) in the T Model (see - :meth:`~pyrealm.demography.t_model_functions.calculate_heights`). This is a helper - function to allow users to convert known stem heights for a plant functional type, - with maximum height (:math:`H_{m}`) and initial slope of the height/diameter - relationship (:math:`a`) into the expected :math:`D` values. - - .. math:: - - D = \frac{H \left( \log \left(\frac{H}{H_{m}-H}\right)\right)}{a} - - Warning: - Where the stem height is greater than the maximum height for a PFT, then - :math:`D` is undefined and the return array will contain `np.nan`. Where the - stem height equals the maximum height, the model predicts an infinite stem - diameter: the `h_max` parameter is the asymptotic maximum stem height of an - exponential function. Similarly, heights very close the maximum height may lead - to unrealistically large predictions of DBH. - - Args: - h_max: Maximum height of the PFT - a_hd: Initial slope of the height/diameter relationship of the PFT - stem_height: Stem height of individuals - validate: Boolean flag to suppress argument validation - """ - - if validate: - _validate_t_model_args(pft_args=[h_max, a_hd], size_args=[stem_height]) - - # The equation here blows up in a couple of ways: - # - H > h_max leads to negative logs which generates np.nan with an invalid value - # warning. The np.nan here is what we want to happen, so the warning needs - # suppressing. - # - H = h_max generates a divide by zero which returns inf with a warning. Here the - # answer should be h_max so that needs trapping. - - with np.testing.suppress_warnings() as sup: - sup.filter(RuntimeWarning, "divide by zero encountered in divide") - sup.filter(RuntimeWarning, "invalid value encountered in log") - return (h_max * np.log(h_max / (h_max - stem_height))) / a_hd - - def calculate_crown_areas( ca_ratio: NDArray[np.float32], a_hd: NDArray[np.float32], @@ -514,6 +461,7 @@ def calculate_growth_increments( * the stem mass (:math:`\Delta W_s`), and * the foliar mass (:math:`\Delta W_f`). + The stem diameter increment can be calculated using the available productivity for growth and the rates of change in stem (:math:`\textrm{d}W_s / \textrm{d}t`) and foliar masses (:math:`\textrm{d}W_f / \textrm{d}t`): @@ -575,10 +523,6 @@ def calculate_growth_increments( dbh: Diameter at breast height of individuals stem_height: Stem height of individuals validate: Boolean flag to suppress argument validation - - Returns: - A tuple of arrays containing the calculated increments in stem diameter, stem - mass and foliar mass. """ if validate: _validate_t_model_args( @@ -606,168 +550,3 @@ def calculate_growth_increments( delta_d = (npp - turnover) / (dWsdt + dWfdt) return (delta_d, dWsdt * delta_d, dWfdt * delta_d) - - -def calculate_t_model_allometry( - pft_data: dict[str, NDArray[np.float32]], dbh: NDArray[np.float32] -) -> dict[str, NDArray[np.float32]]: - """Calculate T Model allometric predictions across cohort data. - - This method calculate predictions of stem allometries for stem height, crown area, - crown fraction, stem mass, foliage mass and sapwood mass under the T Model - :cite:`Li:2014bc`, given diameters at breast height for a set of plant functional - traits. - - Args: - pft_data: A dictionary of plant functional trait data, as for example returned - from :attr:`Flora.data` attribute. - dbh: An array of diameter at breast height values for which to predict stem - allometry values. - """ - - stem_height = calculate_heights( - h_max=pft_data["h_max"], - a_hd=pft_data["a_hd"], - dbh=dbh, - ) - - # Broadcast dbh to shape of stem height to get congruent shapes - dbh = np.broadcast_to(dbh, stem_height.shape) - - crown_area = calculate_crown_areas( - ca_ratio=pft_data["ca_ratio"], - a_hd=pft_data["a_hd"], - dbh=dbh, - stem_height=stem_height, - ) - - crown_fraction = calculate_crown_fractions( - a_hd=pft_data["a_hd"], - dbh=dbh, - stem_height=stem_height, - ) - - stem_mass = calculate_stem_masses( - rho_s=pft_data["rho_s"], - dbh=dbh, - stem_height=stem_height, - ) - - foliage_mass = calculate_foliage_masses( - sla=pft_data["sla"], - lai=pft_data["lai"], - crown_area=crown_area, - ) - - sapwood_mass = calculate_sapwood_masses( - rho_s=pft_data["rho_s"], - ca_ratio=pft_data["ca_ratio"], - stem_height=stem_height, - crown_area=crown_area, - crown_fraction=crown_fraction, - ) - - canopy_r0 = calculate_canopy_r0( - q_m=pft_data["q_m"], - crown_area=crown_area, - ) - - canopy_z_max = calculate_canopy_z_max( - z_max_prop=pft_data["z_max_prop"], - stem_height=stem_height, - ) - - return dict( - dbh=dbh, - stem_height=stem_height, - crown_area=crown_area, - crown_fraction=crown_fraction, - stem_mass=stem_mass, - foliage_mass=foliage_mass, - sapwood_mass=sapwood_mass, - canopy_r0=canopy_r0, - canopy_z_max=canopy_z_max, - ) - - -def calculate_t_model_allocation( - pft_data: dict[str, NDArray[np.float32]], - dbh: NDArray[np.float32], - potential_gpp: NDArray[np.float32], -) -> dict[str, NDArray[np.float32]]: - """Calculate T Model predictions across cohort data. - - This method calculate predictions of stem allometries and growth predictions under - the T Model :cite:`Li:2014bc`, given both diameters at breast height for a set of - plant functional traits and potential gross primary productivity estimates for each - height. - """ - - stem_data = calculate_t_model_allometry(pft_data=pft_data, dbh=dbh) - - # Broadcast potential GPP to match stem data outputs - potential_gpp = np.broadcast_to(potential_gpp, stem_data["dbh"].shape) - - whole_crown_gpp = calculate_whole_crown_gpp( - potential_gpp=potential_gpp, - crown_area=stem_data["crown_area"], - par_ext=pft_data["par_ext"], - lai=pft_data["lai"], - ) - - sapwood_respiration = calculate_sapwood_respiration( - resp_s=pft_data["lai"], sapwood_mass=stem_data["sapwood_mass"] - ) - - foliar_respiration = calculate_foliar_respiration( - resp_f=pft_data["resp_f"], whole_crown_gpp=whole_crown_gpp - ) - - fine_root_respiration = calculate_fine_root_respiration( - zeta=pft_data["zeta"], - sla=pft_data["sla"], - resp_r=pft_data["resp_r"], - foliage_mass=stem_data["foliage_mass"], - ) - - npp = calculate_net_primary_productivity( - yld=pft_data["yld"], - whole_crown_gpp=whole_crown_gpp, - foliar_respiration=foliar_respiration, - fine_root_respiration=fine_root_respiration, - sapwood_respiration=sapwood_respiration, - ) - - turnover = calculate_foliage_and_fine_root_turnover( - sla=pft_data["sla"], - zeta=pft_data["zeta"], - tau_f=pft_data["tau_f"], - tau_r=pft_data["tau_r"], - foliage_mass=stem_data["foliage_mass"], - ) - - (delta_dbh, delta_stem_mass, delta_foliage_mass) = calculate_growth_increments( - rho_s=pft_data["rho_s"], - a_hd=pft_data["a_hd"], - h_max=pft_data["h_max"], - lai=pft_data["lai"], - ca_ratio=pft_data["ca_ratio"], - sla=pft_data["sla"], - zeta=pft_data["zeta"], - npp=npp, - turnover=turnover, - dbh=stem_data["dbh"], - stem_height=stem_data["stem_height"], - ) - - return dict( - whole_crown_gpp=whole_crown_gpp, - sapwood_respiration=sapwood_respiration, - foliar_respiration=foliar_respiration, - fine_root_respiration=fine_root_respiration, - npp=npp, - turnover=turnover, - delta_dbh=delta_dbh, - delta_stem_mass=delta_stem_mass, - delta_foliage_mass=delta_foliage_mass, - ) diff --git a/tests/unit/demography/conftest.py b/tests/unit/demography/conftest.py deleted file mode 100644 index 8e77c2d5..00000000 --- a/tests/unit/demography/conftest.py +++ /dev/null @@ -1,90 +0,0 @@ -"""Shared fixtures for testing the demography module.""" - -from importlib import resources - -import numpy as np -import pandas as pd -import pytest - - -@pytest.fixture -def rtmodel_flora(): - """Generates a flora object from the rtmodel test definitions.""" - - from pyrealm.demography.flora import Flora, PlantFunctionalType - - # Load the PFT definitions and rename to pyrealm attributes - pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" - pft_definitions = pd.read_csv(pfts_path) - - # Map the PFT trait args from the R implementation to pyrealm - pft_definitions = pft_definitions.rename( - columns={ - "a": "a_hd", - "cr": "ca_ratio", - "Hm": "h_max", - "rho": "rho_s", - "L": "lai", - "sigma": "sla", - "tf": "tau_f", - "tr": "tau_r", - "K": "par_ext", - "y": "yld", - "rr": "resp_r", - "rs": "resp_s", - } - ) - - pft_definitions = pft_definitions.drop(columns=["d"]) - - return Flora( - pfts=[ - PlantFunctionalType(**args) - for args in pft_definitions.to_dict(orient="records") - ] - ) - - -@pytest.fixture() -def rtmodel_flora_dict(rtmodel_flora): - """Returns the data dictionary attribute of the rtmodel Flora object.""" - return rtmodel_flora.data - - -@pytest.fixture -def rtmodel_data(): - """Loads some simple predictions from the R implementation for testing.""" - - rdata_path = ( - resources.files("pyrealm_build_data.t_model") / "rtmodel_unit_testing.csv" - ) - rdata = pd.read_csv(rdata_path) - - rdata = rdata.rename( - columns={ - "dD": "delta_d", - "D": "dbh", - "H": "stem_height", - "fc": "crown_fraction", - "Ac": "crown_area", - "Wf": "foliage_mass", - "Ws": "stem_mass", - "Wss": "sapwood_mass", - "P0": "potential_gpp", - "GPP": "crown_gpp", - "Rm1": "resp_swd", - "Rm2": "resp_frt", - "dWs": "delta_mass_stm", - "dWfr": "delta_mass_frt", - } - ) - - # Fix some scaling differences: - # The R tmodel implementation rescales reported delta_d as a radial increase in - # millimetres, not diameter increase in metres - rdata["delta_d"] = rdata["delta_d"] / 500 - - # Wrap the return data into arrays with PFT as columns and diameter values as rows - rdata_arrays = {k: np.reshape(v, (3, 6)).T for k, v in rdata.items()} - - return rdata_arrays diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index 04a84e33..76558d94 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -5,7 +5,6 @@ from importlib import resources from json import JSONDecodeError -import numpy as np import pytest from marshmallow.exceptions import ValidationError from pandas.errors import ParserError @@ -265,124 +264,6 @@ def test_flora_from_csv(filename, outcome): assert nm in flora -def test_Flora_get_allometries_dbh_against_rtmodel(rtmodel_data, rtmodel_flora): - """Test the get allometries method against reference values using dbh. - - This test checks that the outcome of running a column array of the rtmodel test data - DBH values (which are the same for each PFT) into get_allometries returns the - correct values. So the shapes go (3,) x (6, 1) -> (6,3) - """ - - result = rtmodel_flora.get_allometries(dbh=rtmodel_data["dbh"][:, [0]]) - - for key, value in result.items(): - # Skip canopy shape allometries that are not in the original T Model - if key not in ("canopy_r0", "canopy_z_max"): - assert np.allclose(value, rtmodel_data[key]) - - -def test_Flora_get_allometries_stem_height_against_rtmodel(rtmodel_data, rtmodel_flora): - """Test the get allometries method against reference values using stem height. - - The stem heights differ for each PFT, so for this to work with stem height as a 1D - input each PFT needs to be run separately. So the test does three iterations of - (1,) x (6, 1) -> (6, 1) and checks each column. - """ - from pyrealm.demography.flora import Flora - - for idx, (name, pft) in enumerate(rtmodel_flora.items()): - single_pft_flora = Flora(pfts=[pft]) - result = single_pft_flora.get_allometries( - stem_height=rtmodel_data["stem_height"][:, [idx]] - ) - - for key, value in result.items(): - # Skip canopy shape allometries that are not in the original T Model - if key not in ("canopy_r0", "canopy_z_max"): - assert np.allclose(value, rtmodel_data[key][:, [idx]]) - - -@pytest.mark.parametrize( - argnames="dbh,stem_height,outcome,excep_msg", - argvalues=[ - pytest.param( - None, - None, - pytest.raises(ValueError), - "Provide one of either dbh or stem_height", - id="fail_no_size_data", - ), - pytest.param( - np.array([0.1, 0.2, 0.3]), - np.array([10, 20, 30]), - pytest.raises(ValueError), - "Provide one of either dbh or stem_height", - id="fail_too_much_size_data", - ), - pytest.param( - np.array([[0.1, 0.2, 0.3]]), - None, - pytest.raises(ValueError), - "The z argument is two dimensional (shape: (1, 3)) " - "but is not a column array.", # TODO - fix to DBH not z - id="fail_dbh_not_1D", - ), - pytest.param( - None, - np.array([[10, 20, 30]]), - pytest.raises(ValueError), - "The z argument is two dimensional (shape: (1, 3)) " - "but is not a column array.", # TODO - fix to stem_height not z - id="fail_stem_height_not_1D", - ), - pytest.param( - np.array([0.1, 0.2, 0.3]), - None, - does_not_raise(), - None, - id="ok_with_dbh_as_row", - ), - pytest.param( - None, - np.array([5, 10, 15]), - does_not_raise(), - None, - id="ok_with_stem_heights_as_row", - ), - pytest.param( - np.array([[0.1], [0.2], [0.3]]), - None, - does_not_raise(), - None, - id="ok_with_dbh_as_col", - ), - pytest.param( - None, - np.array([[5], [10], [15]]), - does_not_raise(), - None, - id="ok_with_stem_heights_as_col", - ), - pytest.param( - None, - np.array([[0], [5], [10], [15], [45.33], [1000]]), - does_not_raise(), - None, - id="ok_with_edgy_stem_heights", - ), # 0, at max height and > max height - ], -) -def test_Flora_get_allometries_setup( - rtmodel_flora, dbh, stem_height, outcome, excep_msg -): - """Test the get allometries input checking.""" - with outcome as excep: - _ = rtmodel_flora.get_allometries(dbh=dbh, stem_height=stem_height) - return - - assert str(excep.value) == excep_msg - - # # Test PlantFunctionalType __post_init__ functions # diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 4fa42ce0..06c15824 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -1,8 +1,10 @@ """test the functions in t_model_functions.py.""" from contextlib import nullcontext as does_not_raise +from importlib import resources import numpy as np +import pandas as pd import pytest @@ -78,6 +80,72 @@ def test__validate_t_model_args(pft_args, size_args, outcome, excep_message): assert str(excep.value).startswith(excep_message) +@pytest.fixture +def rtmodel_data(): + """Loads some simple predictions from the R implementation for testing.""" + + # Load the PFT definitions and rename to pyrealm attributes + pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" + pft_definitions = pd.read_csv(pfts_path) + + # Map the PFT trait args from the R implementation to pyrealm + pft_definitions = pft_definitions.rename( + columns={ + "a": "a_hd", + "cr": "ca_ratio", + "Hm": "h_max", + "rho": "rho_s", + "L": "lai", + "sigma": "sla", + "tf": "tau_f", + "tr": "tau_r", + "K": "par_ext", + "y": "yld", + "rr": "resp_r", + "rs": "resp_s", + } + ) + + # Add foliar respiration rate as 0.1, as this is handled outside of the R + # implementation as a function of GPP. + pft_definitions["resp_f"] = 0.1 + + rdata_path = ( + resources.files("pyrealm_build_data.t_model") / "rtmodel_unit_testing.csv" + ) + rdata = pd.read_csv(rdata_path) + + rdata = rdata.rename( + columns={ + "dD": "delta_d", + "D": "diameter", + "H": "height", + "fc": "crown_fraction", + "Ac": "crown_area", + "Wf": "mass_fol", + "Ws": "mass_stm", + "Wss": "mass_swd", + "P0": "potential_gpp", + "GPP": "crown_gpp", + "Rm1": "resp_swd", + "Rm2": "resp_frt", + "dWs": "delta_mass_stm", + "dWfr": "delta_mass_frt", + } + ) + + # Fix some scaling differences: + # The R tmodel implementation rescales reported delta_d as a radial increase in + # millimetres, not diameter increase in metres + rdata["delta_d"] = rdata["delta_d"] / 500 + + # Wrap the return data into arrays with PFT as columns and diameter values as rows + pft_arrays = {k: v.to_numpy() for k, v in pft_definitions.items()} + rdata_arrays = {k: np.reshape(v, (3, 6)).T for k, v in rdata.items()} + + return pft_arrays, rdata_arrays + + @pytest.mark.parametrize( argnames="data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape", argvalues=[ @@ -250,255 +318,179 @@ class TestTModel: """ def test_calculate_heights( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of heights of tree from diameter.""" from pyrealm.demography.t_model_functions import calculate_heights - with outcome as excep: - result = calculate_heights( - h_max=rtmodel_flora_dict["h_max"][pft_idx], - a_hd=rtmodel_flora_dict["a_hd"][pft_idx], - dbh=rtmodel_data["dbh"][data_idx], - ) - - assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["stem_height"][out_idx]) - return - - assert str(excep.value).startswith(excep_msg) - - def test_calculate_dbh_from_height( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, - ): - """Tests inverted calculation of dbh from height.""" - - from pyrealm.demography.t_model_functions import calculate_dbh_from_height + pfts, data = rtmodel_data with outcome as excep: - result = calculate_dbh_from_height( - h_max=rtmodel_flora_dict["h_max"][pft_idx], - a_hd=rtmodel_flora_dict["a_hd"][pft_idx], - stem_height=rtmodel_data["stem_height"][data_idx], + result = calculate_heights( + h_max=pfts["h_max"][pft_idx], + a_hd=pfts["a_hd"][pft_idx], + dbh=data["diameter"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["dbh"][out_idx]) + assert np.allclose(result, data["height"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_crown_areas( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of crown areas of trees.""" from pyrealm.demography.t_model_functions import calculate_crown_areas + pfts, data = rtmodel_data + with outcome as excep: result = calculate_crown_areas( - ca_ratio=rtmodel_flora_dict["ca_ratio"][pft_idx], - a_hd=rtmodel_flora_dict["a_hd"][pft_idx], - dbh=rtmodel_data["dbh"][data_idx], - stem_height=rtmodel_data["stem_height"][data_idx], + ca_ratio=pfts["ca_ratio"][pft_idx], + a_hd=pfts["a_hd"][pft_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["crown_area"][out_idx]) + assert np.allclose(result, data["crown_area"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_crown_fractions( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of crown fraction of trees.""" from pyrealm.demography.t_model_functions import calculate_crown_fractions + pfts, data = rtmodel_data + with outcome as excep: result = calculate_crown_fractions( - a_hd=rtmodel_flora_dict["a_hd"][pft_idx], - dbh=rtmodel_data["dbh"][data_idx], - stem_height=rtmodel_data["stem_height"][data_idx], + a_hd=pfts["a_hd"][pft_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["crown_fraction"][out_idx]) + assert np.allclose(result, data["crown_fraction"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_stem_masses( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_stem_masses + pfts, data = rtmodel_data + with outcome as excep: result = calculate_stem_masses( - rho_s=rtmodel_flora_dict["rho_s"][pft_idx], - dbh=rtmodel_data["dbh"][data_idx], - stem_height=rtmodel_data["stem_height"][data_idx], + rho_s=pfts["rho_s"][pft_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["stem_mass"][out_idx]) + assert np.allclose(result, data["mass_stm"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_foliage_masses( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_foliage_masses + pfts, data = rtmodel_data + with outcome as excep: result = calculate_foliage_masses( - lai=rtmodel_flora_dict["lai"][pft_idx], - sla=rtmodel_flora_dict["sla"][pft_idx], - crown_area=rtmodel_data["crown_area"][data_idx], + lai=pfts["lai"][pft_idx], + sla=pfts["sla"][pft_idx], + crown_area=data["crown_area"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["foliage_mass"][out_idx]) + assert np.allclose(result, data["mass_fol"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_sapwood_masses( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_sapwood_masses + pfts, data = rtmodel_data + with outcome as excep: result = calculate_sapwood_masses( - rho_s=rtmodel_flora_dict["rho_s"][pft_idx], - ca_ratio=rtmodel_flora_dict["ca_ratio"][pft_idx], - crown_area=rtmodel_data["crown_area"][data_idx], - stem_height=rtmodel_data["stem_height"][data_idx], - crown_fraction=rtmodel_data["crown_fraction"][data_idx], + rho_s=pfts["rho_s"][pft_idx], + ca_ratio=pfts["ca_ratio"][pft_idx], + crown_area=data["crown_area"][data_idx], + stem_height=data["height"][data_idx], + crown_fraction=data["crown_fraction"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["sapwood_mass"][out_idx]) + assert np.allclose(result, data["mass_swd"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_whole_crown_gpp( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of whole crown GPP.""" from pyrealm.demography.t_model_functions import calculate_whole_crown_gpp + pfts, data = rtmodel_data + with outcome as excep: result = calculate_whole_crown_gpp( - lai=rtmodel_flora_dict["lai"][pft_idx], - par_ext=rtmodel_flora_dict["par_ext"][pft_idx], - crown_area=rtmodel_data["crown_area"][data_idx], - potential_gpp=rtmodel_data["potential_gpp"][data_idx], + lai=pfts["lai"][pft_idx], + par_ext=pfts["par_ext"][pft_idx], + crown_area=data["crown_area"][data_idx], + potential_gpp=data["potential_gpp"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["crown_gpp"][out_idx]) + assert np.allclose(result, data["crown_gpp"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_sapwood_respiration( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of sapwood respiration.""" from pyrealm.demography.t_model_functions import calculate_sapwood_respiration + pfts, data = rtmodel_data + with outcome as excep: result = calculate_sapwood_respiration( - resp_s=rtmodel_flora_dict["resp_s"][pft_idx], - sapwood_mass=rtmodel_data["sapwood_mass"][data_idx], + resp_s=pfts["resp_s"][pft_idx], + sapwood_mass=data["mass_swd"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["resp_swd"][out_idx]) + assert np.allclose(result, data["resp_swd"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -507,7 +499,6 @@ def test_calculate_foliar_respiration( self, request, rtmodel_data, - rtmodel_flora_dict, data_idx, pft_idx, outcome, @@ -524,61 +515,47 @@ def test_calculate_foliar_respiration( from pyrealm.demography.t_model_functions import calculate_foliar_respiration + pfts, data = rtmodel_data + with outcome as excep: result = calculate_foliar_respiration( - resp_f=rtmodel_flora_dict["resp_f"][pft_idx], - whole_crown_gpp=rtmodel_data["crown_gpp"][data_idx], + resp_f=pfts["resp_f"][pft_idx], + whole_crown_gpp=data["crown_gpp"][data_idx], ) assert result.shape == exp_shape assert np.allclose( - result, - rtmodel_data["crown_gpp"][data_idx] - * rtmodel_flora_dict["resp_f"][pft_idx], + result, data["crown_gpp"][data_idx] * pfts["resp_f"][pft_idx] ) return assert str(excep.value).startswith(excep_msg) def test_calculate_fine_root_respiration( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of fine root respiration.""" from pyrealm.demography.t_model_functions import calculate_fine_root_respiration + pfts, data = rtmodel_data + with outcome as excep: result = calculate_fine_root_respiration( - zeta=rtmodel_flora_dict["zeta"][pft_idx], - sla=rtmodel_flora_dict["sla"][pft_idx], - resp_r=rtmodel_flora_dict["resp_r"][pft_idx], - foliage_mass=rtmodel_data["foliage_mass"][data_idx], + zeta=pfts["zeta"][pft_idx], + sla=pfts["sla"][pft_idx], + resp_r=pfts["resp_r"][pft_idx], + foliage_mass=data["mass_fol"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["resp_frt"][out_idx]) + assert np.allclose(result, data["resp_frt"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_net_primary_productivity( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of net primary productivity.""" @@ -586,31 +563,25 @@ def test_calculate_net_primary_productivity( calculate_net_primary_productivity, ) + pfts, data = rtmodel_data + with outcome as excep: result = calculate_net_primary_productivity( - yld=rtmodel_flora_dict["yld"][pft_idx], - whole_crown_gpp=rtmodel_data["crown_gpp"][data_idx], + yld=pfts["yld"][pft_idx], + whole_crown_gpp=data["crown_gpp"][data_idx], foliar_respiration=0, # Not included here in the R implementation - fine_root_respiration=rtmodel_data["resp_frt"][data_idx], - sapwood_respiration=rtmodel_data["resp_swd"][data_idx], + fine_root_respiration=data["resp_frt"][data_idx], + sapwood_respiration=data["resp_swd"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["NPP"][out_idx]) + assert np.allclose(result, data["NPP"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_foliage_and_fine_root_turnover( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of foliage and fine root turnover.""" @@ -618,31 +589,25 @@ def test_calculate_foliage_and_fine_root_turnover( calculate_foliage_and_fine_root_turnover, ) + pfts, data = rtmodel_data + with outcome as excep: result = calculate_foliage_and_fine_root_turnover( - sla=rtmodel_flora_dict["sla"][pft_idx], - zeta=rtmodel_flora_dict["zeta"][pft_idx], - tau_f=rtmodel_flora_dict["tau_f"][pft_idx], - tau_r=rtmodel_flora_dict["tau_r"][pft_idx], - foliage_mass=rtmodel_data["foliage_mass"][data_idx], + sla=pfts["sla"][pft_idx], + zeta=pfts["zeta"][pft_idx], + tau_f=pfts["tau_f"][pft_idx], + tau_r=pfts["tau_r"][pft_idx], + foliage_mass=data["mass_fol"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["turnover"][out_idx]) + assert np.allclose(result, data["turnover"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_calculate_growth_increments( - self, - rtmodel_data, - rtmodel_flora_dict, - data_idx, - pft_idx, - outcome, - excep_msg, - out_idx, - exp_shape, + self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape ): """Tests calculation of growth increments.""" @@ -650,58 +615,31 @@ def test_calculate_calculate_growth_increments( calculate_growth_increments, ) + pfts, data = rtmodel_data + with outcome as excep: delta_d, delta_mass_stm, delta_mass_frt = calculate_growth_increments( - rho_s=rtmodel_flora_dict["rho_s"][pft_idx], - a_hd=rtmodel_flora_dict["a_hd"][pft_idx], - h_max=rtmodel_flora_dict["h_max"][pft_idx], - lai=rtmodel_flora_dict["lai"][pft_idx], - ca_ratio=rtmodel_flora_dict["ca_ratio"][pft_idx], - sla=rtmodel_flora_dict["sla"][pft_idx], - zeta=rtmodel_flora_dict["zeta"][pft_idx], - npp=rtmodel_data["NPP"][data_idx], - turnover=rtmodel_data["turnover"][data_idx], - dbh=rtmodel_data["dbh"][data_idx], - stem_height=rtmodel_data["stem_height"][data_idx], + rho_s=pfts["rho_s"][pft_idx], + a_hd=pfts["a_hd"][pft_idx], + h_max=pfts["h_max"][pft_idx], + lai=pfts["lai"][pft_idx], + ca_ratio=pfts["ca_ratio"][pft_idx], + sla=pfts["sla"][pft_idx], + zeta=pfts["zeta"][pft_idx], + npp=data["NPP"][data_idx], + turnover=data["turnover"][data_idx], + dbh=data["diameter"][data_idx], + stem_height=data["height"][data_idx], ) assert delta_d.shape == exp_shape - assert np.allclose(delta_d, rtmodel_data["delta_d"][out_idx]) + assert np.allclose(delta_d, data["delta_d"][out_idx]) assert delta_mass_stm.shape == exp_shape - assert np.allclose(delta_mass_stm, rtmodel_data["delta_mass_stm"][out_idx]) + assert np.allclose(delta_mass_stm, data["delta_mass_stm"][out_idx]) assert delta_mass_frt.shape == exp_shape - assert np.allclose(delta_mass_frt, rtmodel_data["delta_mass_frt"][out_idx]) + assert np.allclose(delta_mass_frt, data["delta_mass_frt"][out_idx]) return assert str(excep.value).startswith(excep_msg) - - -def test_calculate_dbh_from_height_edge_cases(): - """Test inverted calculation of dbh from height handles edges cases. - - * If H > h_max, dbh is not calculable and should be np.nan - * If H = h_max, dbh is infinite. - """ - - from pyrealm.demography.t_model_functions import calculate_dbh_from_height - - pft_h_max_values = np.array([20, 30]) - pft_a_hd_values = np.array([116.0, 116.0]) - stem_heights = np.array([[0], [10], [20], [30], [40]]) - - dbh = calculate_dbh_from_height( - h_max=pft_h_max_values, - a_hd=pft_a_hd_values, - stem_height=stem_heights, - ) - - # first row should be all zeros (zero height gives zero diameter) - assert np.all(dbh[0, :] == 0) - - # Infinite entries - assert np.all(np.isinf(dbh) == np.array([[0, 0], [0, 0], [1, 0], [0, 1], [0, 0]])) - - # Undefined entries - assert np.all(np.isnan(dbh) == np.array([[0, 0], [0, 0], [0, 0], [1, 0], [1, 1]])) From 7c27c8861b96eeaf5558bf10c0c7b22dc7b096d8 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 11:35:45 +0100 Subject: [PATCH 149/241] Restructure of Flora, fixing test_flora.py --- pyrealm/demography/flora.py | 93 +++++++++++++++++++++-------- tests/unit/demography/test_flora.py | 66 ++++++++++---------- 2 files changed, 99 insertions(+), 60 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 22f00292..4262698d 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -21,7 +21,7 @@ import sys from collections import Counter from collections.abc import Sequence -from dataclasses import dataclass, field, fields +from dataclasses import InitVar, dataclass, field, fields from pathlib import Path import marshmallow_dataclass @@ -192,16 +192,18 @@ class PlantFunctionalType(PlantFunctionalTypeStrict): """ -class Flora(dict[str, type[PlantFunctionalTypeStrict]]): - """Defines the flora used in a ``virtual_ecosystem`` model. +@dataclass(frozen=True) +class Flora: + """A dataclass providing trait data on collection of plant functional types. - The flora is the set of plant functional types used within a particular simulation - and this class provides dictionary-like access to a defined set of - :class:`~pyrealm.demography.flora.PlantFunctionalType` or - :class:`~pyrealm.demography.flora.PlantFunctionalTypeStrict` instances. + A flora provides trait data on the complete collection of plant functional types + that will be used within a particular simulation. The dataclass provides access + to trait attributes as row arrays across those plant functional types. - Instances of this class should not be altered during model fitting, at least until - the point where plant evolution is included in the modelling process. + The class is created using a list of + :class:`~pyrealm.demography.flora.PlantFunctionalType` or + :class:`~pyrealm.demography.flora.PlantFunctionalTypeStrict` instances, which must + have unique names. Args: pfts: A sequence of ``PlantFunctionalType`` or ``PlantFunctionalTypeStrict`` @@ -209,10 +211,57 @@ class Flora(dict[str, type[PlantFunctionalTypeStrict]]): :attr:`~pyrealm.demography.flora.PlantFunctionalTypeStrict.name` attributes. """ - def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: - # Initialise the dict superclass to implement dict like behaviour - super().__init__() + pfts: InitVar[Sequence[type[PlantFunctionalTypeStrict]]] + r"""A sequence of plant functional type instances to include in the Flora.""" + name: NDArray[np.str_] = field(init=False) + r"""The name of the plant functional type.""" + a_hd: NDArray[np.float32] = field(init=False) + r"""Initial slope of height-diameter relationship (:math:`a`, -)""" + ca_ratio: NDArray[np.float32] = field(init=False) + r"""Initial ratio of crown area to stem cross-sectional area + (:math:`c`, -)""" + h_max: NDArray[np.float32] = field(init=False) + r"""Maximum tree height (:math:`H_m`, m)""" + rho_s: NDArray[np.float32] = field(init=False) + r"""Sapwood density (:math:`\rho_s`, kg Cm-3)""" + lai: NDArray[np.float32] = field(init=False) + """Leaf area index within the crown (:math:`L`, -)""" + sla: NDArray[np.float32] = field(init=False) + r"""Specific leaf area (:math:`\sigma`, m2 kg-1 C)""" + tau_f: NDArray[np.float32] = field(init=False) + r"""Foliage turnover time (:math:`\tau_f`,years)""" + tau_r: NDArray[np.float32] = field(init=False) + r"""Fine-root turnover time (:math:`\tau_r`, years)""" + par_ext: NDArray[np.float32] = field(init=False) + r"""Extinction coefficient of photosynthetically active radiation (PAR) (:math:`k`, + -)""" + yld: NDArray[np.float32] = field(init=False) + r"""Yield factor (:math:`y`, -)""" + zeta: NDArray[np.float32] = field(init=False) + r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, kg C m-2)""" + resp_r: NDArray[np.float32] = field(init=False) + r"""Fine-root specific respiration rate (:math:`r_r`, year-1)""" + resp_s: NDArray[np.float32] = field(init=False) + r"""Sapwood-specific respiration rate (:math:`r_s`, year-1)""" + resp_f: NDArray[np.float32] = field(init=False) + r"""Foliage maintenance respiration fraction (:math:`r_f`, -)""" + m: NDArray[np.float32] = field(init=False) + r"""Canopy shape parameter (:math:`m`, -)""" + n: NDArray[np.float32] = field(init=False) + r"""Canopy shape parameter (:math:`n`, -)""" + f_g: NDArray[np.float32] = field(init=False) + r"""Crown gap fraction (:math:`f_g`, -)""" + q_m: NDArray[np.float32] = field(init=False) + """Scaling factor to derive maximum crown radius from crown area.""" + z_max_prop: NDArray[np.float32] = field(init=False) + """Proportion of stem height at which maximum crown radius is found.""" + pft_dict: dict[str, type[PlantFunctionalTypeStrict]] = field(init=False) + """A dictionary of the original plant functional type instances, keyed by name.""" + pft_indices: dict[str, int] = field(init=False) + """An dictionary giving the index of each PFT name in the trait array attributes.""" + + def __post_init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: # Check the PFT data if (not isinstance(pfts, Sequence)) or ( not all([isinstance(v, PlantFunctionalTypeStrict) for v in pfts]) @@ -230,25 +279,19 @@ def __init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: f"Duplicated plant functional type names: {','.join(duplicates)}" ) - # Populate the dictionary using the PFT name as key - for name, pft in zip(pft_names, pfts): - self[name] = pft + # Populate the pft dictionary using the PFT name as key + object.__setattr__(self, "pft_dict", {p.name: p for p in pfts}) - # Generate an dataframe representation to facilitate merging to cohort data. - # - assemble pft fields into arrays - data = {} + # Populate the plant functional type attributes with arrays pft_fields = [f.name for f in fields(PlantFunctionalTypeStrict)] for pft_field in pft_fields: - data[pft_field] = np.array( - [getattr(pft, pft_field) for pft in self.values()] + object.__setattr__( + self, pft_field, np.array([getattr(pft, pft_field) for pft in pfts]) ) - self.data: dict[str, NDArray] = data - """A dictionary of trait values as numpy arrays.""" - - self.pft_indices = {v: k for k, v in enumerate(self.data["name"])} - """An dictionary giving the index of each PFT name in the PFT data.""" + # Populate the pft trait indices + object.__setattr__(self, "pft_dict", {v: k for k, v in enumerate(self.name)}) @classmethod def _from_file_data(cls, file_data: dict) -> Flora: diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index 76558d94..31f6783e 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -128,57 +128,53 @@ def flora_inputs(request): match request.param: case "not_sequence": - return "Notasequence" + return "Notasequence", pytest.raises(ValueError) case "sequence_not_all_pfts": - return [1, 2, 3] + return [1, 2, 3], pytest.raises(ValueError) case "single_pft": - return [broadleaf] + return [broadleaf], does_not_raise() case "single_pft_strict": - return [broadleaf_strict] + return [broadleaf_strict], does_not_raise() case "multiple_pfts": - return [broadleaf, conifer] + return [broadleaf, conifer], does_not_raise() case "multiple_pfts_strict": - return [broadleaf_strict, conifer_strict] + return [broadleaf_strict, conifer_strict], does_not_raise() case "multiple_pfts_mixed": - return [broadleaf_strict, conifer] + return [broadleaf_strict, conifer], does_not_raise() case "duplicated_names": - return [broadleaf, broadleaf] + return [broadleaf, broadleaf], pytest.raises(ValueError) case "duplicated_names_mixed": - return [broadleaf_strict, broadleaf] + return [broadleaf_strict, broadleaf], pytest.raises(ValueError) @pytest.mark.parametrize( - argnames="flora_inputs,outcome", + argnames="flora_inputs", argvalues=[ - pytest.param("not_sequence", pytest.raises(ValueError)), - pytest.param("sequence_not_all_pfts", pytest.raises(ValueError)), - pytest.param("single_pft", does_not_raise()), - pytest.param("single_pft_strict", does_not_raise()), - pytest.param("multiple_pfts", does_not_raise()), - pytest.param("multiple_pfts_strict", does_not_raise()), - pytest.param("multiple_pfts_mixed", does_not_raise()), - pytest.param("duplicated_names", pytest.raises(ValueError)), - pytest.param("duplicated_names_mixed", pytest.raises(ValueError)), + "not_sequence", + "sequence_not_all_pfts", + "single_pft", + "single_pft_strict", + "multiple_pfts", + "multiple_pfts_strict", + "multiple_pfts_mixed", + "duplicated_names", + "duplicated_names_mixed", ], indirect=["flora_inputs"], ) -def test_Flora__init__(flora_inputs, outcome): +def test_Flora__init__(flora_inputs): """Test the plant functional type initialisation.""" from pyrealm.demography.flora import Flora + pfts, outcome = flora_inputs + with outcome: - flora = Flora(pfts=flora_inputs) + flora = Flora(pfts=pfts) if isinstance(outcome, does_not_raise): - # Simple check that PFT instances are correctly keyed by name. - for k, v in flora.items(): - assert k == v.name - - # Check data view is correct - assert isinstance(flora.data, dict) - for trait_array in flora.data.values(): - assert trait_array.shape == (len(flora),) + # Really basic check that an array attribute is the right size + assert flora.a_hd.shape == (len(flora.pft_dict),) # @@ -207,9 +203,9 @@ def test_flora_from_json(filename, outcome): if isinstance(outcome, does_not_raise): # Coarse check of what got loaded - assert len(flora) == 2 + assert flora.name.shape == (2,) for nm in ["test1", "test2"]: - assert nm in flora + assert nm in flora.name @pytest.mark.parametrize( @@ -233,9 +229,9 @@ def test_flora_from_toml(filename, outcome): if isinstance(outcome, does_not_raise): # Coarse check of what got loaded - assert len(flora) == 2 + assert flora.name.shape == (2,) for nm in ["test1", "test2"]: - assert nm in flora + assert nm in flora.name @pytest.mark.parametrize( @@ -259,9 +255,9 @@ def test_flora_from_csv(filename, outcome): if isinstance(outcome, does_not_raise): # Coarse check of what got loaded - assert len(flora) == 2 + assert flora.name.shape == (2,) for nm in ["test1", "test2"]: - assert nm in flora + assert nm in flora.name # From cf25bf4fb602ccc8ce86a28a7de643c9d36a6804 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 12:19:52 +0100 Subject: [PATCH 150/241] Adding StemTraits and Flora.get_stem_traits, updating Community --- pyrealm/demography/community.py | 55 +++++----------- pyrealm/demography/flora.py | 109 +++++++++++++++++++++++++++++--- 2 files changed, 117 insertions(+), 47 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index ed041bed..f466493e 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -119,7 +119,7 @@ from pyrealm.core.utilities import check_input_shapes from pyrealm.demography import canopy_functions from pyrealm.demography import t_model_functions as t_model -from pyrealm.demography.flora import Flora +from pyrealm.demography.flora import Flora, StemTraits if sys.version_info[:2] >= (3, 11): import tomllib @@ -355,6 +355,7 @@ class Community: # Post init properties number_of_cohorts: int = field(init=False) + stem_traits: StemTraits = field(init=False) cohort_data: dict[str, NDArray] = field(init=False) def __post_init__( @@ -392,14 +393,6 @@ def __post_init__( except ValueError: raise ValueError("Cohort arrays are of unequal length") - # Check the initial PFT values are known - unknown_pfts = set(cohort_pft_names).difference(self.flora.keys()) - - if unknown_pfts: - raise ValueError( - f"Plant functional types unknown in flora: {','.join(unknown_pfts)}" - ) - # Store as a dictionary self.cohort_data: dict[str, NDArray] = { "name": cohort_pft_names, @@ -407,30 +400,14 @@ def __post_init__( "n_individuals": cohort_n_individuals, } - # Duplicate the pft trait data to match the cohort data and add to the cohort - # data dictionary. - self.cohort_data.update(self._unpack_pft_data(cohort_pft_names)) + # Get the stem traits for the cohorts + self.stem_traits = self.flora.get_stem_traits(cohort_pft_names) self.number_of_cohorts = len(cohort_pft_names) # Populate the T model fields self._calculate_t_model() - def _unpack_pft_data( - self, cohort_pft_names: NDArray[np.str_] - ) -> dict[str, NDArray]: - """Creates a dictionary of PFT data for a set of cohorts. - - Args: - cohort_pft_names: The PFT name for each cohort - """ - # Get the indices for the cohort PFT names in the flora PFT data - pft_index = [self.flora.pft_indices[str(nm)] for nm in cohort_pft_names] - - # Use that index to duplicate the PFT specific data into a per cohort entry for - # each of the PFT traits - return {k: v[pft_index] for k, v in self.flora.data.items()} - def _calculate_t_model(self) -> None: """Calculate T Model predictions across cohort data. @@ -442,39 +419,39 @@ def _calculate_t_model(self) -> None: # Add data to cohort dataframes capturing the T Model geometry # - Classic T Model scaling self.cohort_data["stem_height"] = t_model.calculate_heights( - h_max=self.cohort_data["h_max"], - a_hd=self.cohort_data["a_hd"], + h_max=self.stem_traits.h_max, + a_hd=self.stem_traits.a_hd, dbh=self.cohort_data["dbh"], ) self.cohort_data["crown_area"] = t_model.calculate_crown_areas( - ca_ratio=self.cohort_data["ca_ratio"], - a_hd=self.cohort_data["a_hd"], + ca_ratio=self.stem_traits.ca_ratio, + a_hd=self.stem_traits.a_hd, dbh=self.cohort_data["dbh"], stem_height=self.cohort_data["stem_height"], ) self.cohort_data["crown_fraction"] = t_model.calculate_crown_fractions( - a_hd=self.cohort_data["a_hd"], + a_hd=self.stem_traits.a_hd, dbh=self.cohort_data["dbh"], stem_height=self.cohort_data["stem_height"], ) self.cohort_data["stem_mass"] = t_model.calculate_stem_masses( - rho_s=self.cohort_data["rho_s"], + rho_s=self.stem_traits.rho_s, dbh=self.cohort_data["dbh"], stem_height=self.cohort_data["stem_height"], ) self.cohort_data["foliage_mass"] = t_model.calculate_foliage_masses( - sla=self.cohort_data["sla"], - lai=self.cohort_data["lai"], + sla=self.stem_traits.sla, + lai=self.stem_traits.lai, crown_area=self.cohort_data["crown_area"], ) self.cohort_data["sapwood_mass"] = t_model.calculate_sapwood_masses( - rho_s=self.cohort_data["rho_s"], - ca_ratio=self.cohort_data["ca_ratio"], + rho_s=self.stem_traits.rho_s, + ca_ratio=self.stem_traits.ca_ratio, stem_height=self.cohort_data["stem_height"], crown_area=self.cohort_data["crown_area"], crown_fraction=self.cohort_data["crown_fraction"], @@ -482,11 +459,11 @@ def _calculate_t_model(self) -> None: # Canopy shape extension to T Model from PlantFATE self.cohort_data["canopy_z_max"] = canopy_functions.calculate_canopy_z_max( - z_max_prop=self.cohort_data["z_max_prop"], + z_max_prop=self.stem_traits.z_max_prop, stem_height=self.cohort_data["stem_height"], ) self.cohort_data["canopy_r0"] = canopy_functions.calculate_canopy_r0( - q_m=self.cohort_data["q_m"], + q_m=self.stem_traits.q_m, crown_area=self.cohort_data["crown_area"], ) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 4262698d..33fcd4d8 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -9,10 +9,12 @@ data files. This intentionally enforces a complete description of the traits in the input data. The ``PlantFunctionalType`` is provided as a more convenient API for programmatic use. -* The Flora class, which is simply a dictionary of named plant functional types for use - in describing a plant community in a simulation. The Flora class also defines factory - methods to create instances from plant functional type data stored in JSON, TOML or - CSV formats. +* The Flora class, which is a dataclass representing a collection of plant functional + types for use in describing a plant community in a simulation. It provides the same + trait attributes as the plant functional type classes, but the values are arrays of + trait values across the provided PFTS. The Flora class also defines factory methods to + create instances from plant functional type data stored in JSON, TOML or CSV formats. + """ # noqa: D415 from __future__ import annotations @@ -23,6 +25,7 @@ from collections.abc import Sequence from dataclasses import InitVar, dataclass, field, fields from pathlib import Path +from typing import ClassVar import marshmallow_dataclass import numpy as np @@ -211,9 +214,16 @@ class Flora: :attr:`~pyrealm.demography.flora.PlantFunctionalTypeStrict.name` attributes. """ + # The only init argument. pfts: InitVar[Sequence[type[PlantFunctionalTypeStrict]]] r"""A sequence of plant functional type instances to include in the Flora.""" + # A class variable setting the attribute names of traits. + trait_attrs: ClassVar[list[str]] = [ + f.name for f in fields(PlantFunctionalTypeStrict) + ] + + # Populated post init name: NDArray[np.str_] = field(init=False) r"""The name of the plant functional type.""" a_hd: NDArray[np.float32] = field(init=False) @@ -282,10 +292,8 @@ def __post_init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None # Populate the pft dictionary using the PFT name as key object.__setattr__(self, "pft_dict", {p.name: p for p in pfts}) - # Populate the plant functional type attributes with arrays - pft_fields = [f.name for f in fields(PlantFunctionalTypeStrict)] - - for pft_field in pft_fields: + # Populate the trait attributes with arrays + for pft_field in self.trait_attrs: object.__setattr__( self, pft_field, np.array([getattr(pft, pft_field) for pft in pfts]) ) @@ -351,3 +359,88 @@ def from_csv(cls, path: Path) -> Flora: raise excep return cls._from_file_data({"pft": data.to_dict(orient="records")}) + + def get_stem_traits(self, pft_names: NDArray[np.str_]) -> StemTraits: + """Generates a stem traits object for a set of names. + + Args: + pft_names: An array of PFT names for each stem. + """ + + # Check the initial PFT values are known + unknown_pfts = set(pft_names).difference(self.name) + + if unknown_pfts: + raise ValueError( + f"Plant functional types unknown in flora: {','.join(unknown_pfts)}" + ) + + # Get the indices for the cohort PFT names in the flora PFT data + pft_index = [self.pft_indices[str(nm)] for nm in pft_names] + + # For each trait, get that attribute from the Flora, extract the values + # matching the pft_names and pass that into the StemTraits constructor. + + return StemTraits( + **{trt: getattr(self, trt)[pft_index] for trt in self.trait_attrs} + ) + + +@dataclass() +class StemTraits: + """A dataclass for stem traits. + + This dataclass is used to provide arrays of plant functional type (PFT) traits + across a set of stems. The main use case is to provide stem trait data as arrays + across the cohorts within a community object. + + It provides the same attribute interface as the + :class:`~pyrealm.demography.flora.Flora` class, but unlike that class: + + * is purely a data container, and + * plant functional types can be represented multiple times to represent multiple + stems or cohorts of the same PFT. + """ + + name: NDArray[np.str_] + r"""The name of the plant functional type.""" + a_hd: NDArray[np.float32] + r"""Initial slope of height-diameter relationship (:math:`a`, -)""" + ca_ratio: NDArray[np.float32] + r"""Initial ratio of crown area to stem cross-sectional area + (:math:`c`, -)""" + h_max: NDArray[np.float32] + r"""Maximum tree height (:math:`H_m`, m)""" + rho_s: NDArray[np.float32] + r"""Sapwood density (:math:`\rho_s`, kg Cm-3)""" + lai: NDArray[np.float32] + """Leaf area index within the crown (:math:`L`, -)""" + sla: NDArray[np.float32] + r"""Specific leaf area (:math:`\sigma`, m2 kg-1 C)""" + tau_f: NDArray[np.float32] + r"""Foliage turnover time (:math:`\tau_f`,years)""" + tau_r: NDArray[np.float32] + r"""Fine-root turnover time (:math:`\tau_r`, years)""" + par_ext: NDArray[np.float32] + r"""Extinction coefficient of photosynthetically active radiation (PAR) (:math:`k`, + -)""" + yld: NDArray[np.float32] + r"""Yield factor (:math:`y`, -)""" + zeta: NDArray[np.float32] + r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, kg C m-2)""" + resp_r: NDArray[np.float32] + r"""Fine-root specific respiration rate (:math:`r_r`, year-1)""" + resp_s: NDArray[np.float32] + r"""Sapwood-specific respiration rate (:math:`r_s`, year-1)""" + resp_f: NDArray[np.float32] + r"""Foliage maintenance respiration fraction (:math:`r_f`, -)""" + m: NDArray[np.float32] + r"""Canopy shape parameter (:math:`m`, -)""" + n: NDArray[np.float32] + r"""Canopy shape parameter (:math:`n`, -)""" + f_g: NDArray[np.float32] + r"""Crown gap fraction (:math:`f_g`, -)""" + q_m: NDArray[np.float32] + """Scaling factor to derive maximum crown radius from crown area.""" + z_max_prop: NDArray[np.float32] + """Proportion of stem height at which maximum crown radius is found.""" From 85e49d8cf27dde1c0eef1d5b4a4ec10500955913 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 12:44:29 +0100 Subject: [PATCH 151/241] Adding testing for Flora.get_stem_traits, bug fixes --- pyrealm/demography/flora.py | 8 ++- tests/unit/demography/test_community.py | 14 ---- tests/unit/demography/test_flora.py | 96 +++++++++++++++---------- 3 files changed, 67 insertions(+), 51 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 33fcd4d8..e8ec5c2e 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -299,7 +299,7 @@ def __post_init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None ) # Populate the pft trait indices - object.__setattr__(self, "pft_dict", {v: k for k, v in enumerate(self.name)}) + object.__setattr__(self, "pft_indices", {v: k for k, v in enumerate(self.name)}) @classmethod def _from_file_data(cls, file_data: dict) -> Flora: @@ -402,6 +402,12 @@ class StemTraits: stems or cohorts of the same PFT. """ + # A class variable setting the attribute names of traits. + trait_attrs: ClassVar[list[str]] = [ + f.name for f in fields(PlantFunctionalTypeStrict) + ] + + # Instance trait attributes name: NDArray[np.str_] r"""The name of the plant functional type.""" a_hd: NDArray[np.float32] diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index e5dcd15b..b881257f 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -7,20 +7,6 @@ from marshmallow.exceptions import ValidationError -@pytest.fixture -def fixture_flora(): - """Simple flora object for use in community tests.""" - - from pyrealm.demography.flora import Flora, PlantFunctionalType - - return Flora( - [ - PlantFunctionalType(name="broadleaf", h_max=30), - PlantFunctionalType(name="conifer", h_max=20), - ] - ) - - @pytest.fixture def fixture_expected(fixture_flora): """Expected results for test data. diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index 31f6783e..bf82be7f 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -103,6 +103,47 @@ def test_PlantFunctionalType__init__(args, outcome): assert pft.z_max_prop == calculate_canopy_z_max_proportion(m=2, n=5) +# +# Test PlantFunctionalType __post_init__ functions +# + + +@pytest.mark.parametrize( + argnames="m,n,q_m", + argvalues=[(2, 5, 2.9038988210485766), (3, 4, 2.3953681843215673)], +) +def test_pft_calculate_q_m(m, n, q_m): + """Test calculation of q_m.""" + + from pyrealm.demography.flora import calculate_canopy_q_m + + calculated_q_m = calculate_canopy_q_m(m, n) + assert calculated_q_m == pytest.approx(q_m) + + +def test_calculate_q_m_values_raises_exception_for_invalid_input(): + """Test unhappy path for calculating q_m. + + Test that an exception is raised when invalid arguments are provided to the + function. + """ + + pass + + +@pytest.mark.parametrize( + argnames="m,n,z_max_ratio", + argvalues=[(2, 5, 0.8502830004171938), (3, 4, 0.7226568811456053)], +) +def test_pft_calculate_z_max_ratio(m, n, z_max_ratio): + """Test calculation of z_max proportion.""" + + from pyrealm.demography.flora import calculate_canopy_z_max_proportion + + calculated_zmr = calculate_canopy_z_max_proportion(m, n) + assert calculated_zmr == pytest.approx(z_max_ratio) + + # # Test Flora initialisation # @@ -260,42 +301,25 @@ def test_flora_from_csv(filename, outcome): assert nm in flora.name -# -# Test PlantFunctionalType __post_init__ functions -# - - -@pytest.mark.parametrize( - argnames="m,n,q_m", - argvalues=[(2, 5, 2.9038988210485766), (3, 4, 2.3953681843215673)], -) -def test_calculate_q_m(m, n, q_m): - """Test calculation of q_m.""" - - from pyrealm.demography.flora import calculate_canopy_q_m - - calculated_q_m = calculate_canopy_q_m(m, n) - assert calculated_q_m == pytest.approx(q_m) - - -def test_calculate_q_m_values_raises_exception_for_invalid_input(): - """Test unhappy path for calculating q_m. - - Test that an exception is raised when invalid arguments are provided to the - function. - """ - - pass - - @pytest.mark.parametrize( - argnames="m,n,z_max_ratio", - argvalues=[(2, 5, 0.8502830004171938), (3, 4, 0.7226568811456053)], + argnames="pft_names,outcome", + argvalues=[ + pytest.param( + ["broadleaf", "conifer", "broadleaf", "conifer"], + does_not_raise(), + id="correct", + ), + pytest.param( + ["boredleaf", "conifer", "broadleaf", "conifer"], + pytest.raises(ValueError), + id="unknown_pft", + ), + ], ) -def test_calculate_z_max_ratio(m, n, z_max_ratio): - """Test calculation of z_max proportion.""" - - from pyrealm.demography.flora import calculate_canopy_z_max_proportion +def test_flora_get_stem_traits(fixture_flora, pft_names, outcome): + """Test Flora.get_stem_traits.""" + with outcome: + stem_traits = fixture_flora.get_stem_traits(pft_names=pft_names) - calculated_zmr = calculate_canopy_z_max_proportion(m, n) - assert calculated_zmr == pytest.approx(z_max_ratio) + for trt in stem_traits.trait_attrs: + assert len(getattr(stem_traits, trt)) == len(pft_names) From 29ae69ff47c285343c266436b113b7bbf3d95430 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 12:45:29 +0100 Subject: [PATCH 152/241] Demography unit test shared fixtures --- tests/unit/demography/conftest.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/unit/demography/conftest.py diff --git a/tests/unit/demography/conftest.py b/tests/unit/demography/conftest.py new file mode 100644 index 00000000..f8b34d2f --- /dev/null +++ b/tests/unit/demography/conftest.py @@ -0,0 +1,17 @@ +"""Shared fixtures for demography testing.""" + +import pytest + + +@pytest.fixture +def fixture_flora(): + """Simple flora object for use in demography tests.""" + + from pyrealm.demography.flora import Flora, PlantFunctionalType + + return Flora( + [ + PlantFunctionalType(name="broadleaf", h_max=30), + PlantFunctionalType(name="conifer", h_max=20), + ] + ) From d4df063647ecc7f3f0bd2e56e672d98c8f701930 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 12:50:38 +0100 Subject: [PATCH 153/241] Fixing community tests for StemTraits --- tests/unit/demography/test_community.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index b881257f..80013daf 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -17,15 +17,14 @@ def fixture_expected(fixture_flora): from pyrealm.demography.t_model_functions import calculate_heights - a_hd = np.array([fixture_flora["broadleaf"].a_hd, fixture_flora["conifer"].a_hd]) - h_max = np.array([fixture_flora["broadleaf"].h_max, fixture_flora["conifer"].h_max]) - n_indiv = np.array([6, 1]) dbh = np.array([0.2, 0.5]) expected = { - "n_individuals": n_indiv, - "a_hd": a_hd, - "height": calculate_heights(a_hd=a_hd, h_max=h_max, dbh=dbh), + "n_individuals": np.array([6, 1]), + "a_hd": fixture_flora.a_hd, + "height": calculate_heights( + a_hd=fixture_flora.a_hd, h_max=fixture_flora.h_max, dbh=dbh + ), } return expected @@ -39,7 +38,7 @@ def check_expected(community, expected): expected["n_individuals"], ) assert np.allclose( - community.cohort_data["a_hd"], + community.stem_traits.a_hd, expected["a_hd"], ) assert np.allclose( From 76f66448c1fcfc1246f97d3115f81b23811c4b3b Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 13:04:29 +0100 Subject: [PATCH 154/241] Fix stem traits usage in Canopy and tests --- pyrealm/demography/canopy.py | 16 +++++----- .../unit/demography/test_canopy_functions.py | 32 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index c7a00d5b..0442e37a 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -111,9 +111,9 @@ def _calculate_canopy(self, community: Community) -> None: args=( community.cohort_data["stem_height"], community.cohort_data["crown_area"], - community.cohort_data["m"], - community.cohort_data["n"], - community.cohort_data["q_m"], + community.stem_traits.m, + community.stem_traits.n, + community.stem_traits.q_m, community.cohort_data["canopy_z_max"], community.cohort_data["n_individuals"], target_area, @@ -137,8 +137,8 @@ def _calculate_canopy(self, community: Community) -> None: self.stem_relative_radius = calculate_relative_canopy_radius_at_z( z=self.layer_heights, stem_height=community.cohort_data["stem_height"], - m=community.cohort_data["m"], - n=community.cohort_data["n"], + m=community.stem_traits.m, + n=community.stem_traits.n, validate=False, ) @@ -148,7 +148,7 @@ def _calculate_canopy(self, community: Community) -> None: q_z=self.stem_relative_radius, crown_area=community.cohort_data["crown_area"], stem_height=community.cohort_data["stem_height"], - q_m=community.cohort_data["q_m"], + q_m=community.stem_traits.q_m, z_max=community.cohort_data["canopy_z_max"], validate=False, ) @@ -159,8 +159,8 @@ def _calculate_canopy(self, community: Community) -> None: q_z=self.stem_relative_radius, crown_area=community.cohort_data["crown_area"], stem_height=community.cohort_data["stem_height"], - f_g=community.cohort_data["f_g"], - q_m=community.cohort_data["q_m"], + f_g=community.stem_traits.f_g, + q_m=community.stem_traits.q_m, z_max=community.cohort_data["canopy_z_max"], validate=False, ) diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index e79533c2..e0af9d26 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -402,15 +402,15 @@ def test_calculate_relative_canopy_radius_at_z_values(fixture_community): # Canopy shape model gives the maximum radius at a height z_max z_max = ( fixture_community.cohort_data["stem_height"] - * fixture_community.cohort_data["z_max_prop"] + * fixture_community.stem_traits.z_max_prop ) # Get the relative radius at that height q_z_values = calculate_relative_canopy_radius_at_z( z=z_max, stem_height=fixture_community.cohort_data["stem_height"], - m=fixture_community.cohort_data["m"], - n=fixture_community.cohort_data["n"], + m=fixture_community.stem_traits.m, + n=fixture_community.stem_traits.n, ) # Now test that the circular crown area from that radius is equivalent to the direct @@ -510,8 +510,8 @@ def test_calculate_stem_projected_crown_area_at_z_values( q_z = calculate_relative_canopy_radius_at_z( z=heights, stem_height=fixture_community.cohort_data["stem_height"], - m=fixture_community.cohort_data["m"], - n=fixture_community.cohort_data["n"], + m=fixture_community.stem_traits.m, + n=fixture_community.stem_traits.n, ) # Calculate and test these values @@ -520,7 +520,7 @@ def test_calculate_stem_projected_crown_area_at_z_values( q_z=q_z, stem_height=fixture_community.cohort_data["stem_height"], crown_area=fixture_community.cohort_data["crown_area"], - q_m=fixture_community.cohort_data["q_m"], + q_m=fixture_community.stem_traits.q_m, z_max=fixture_community.cohort_data["canopy_z_max"], ) @@ -556,9 +556,9 @@ def test_solve_community_projected_canopy_area(fixture_community): stem_height=fixture_community.cohort_data["stem_height"], crown_area=fixture_community.cohort_data["crown_area"], n_individuals=fixture_community.cohort_data["n_individuals"], - m=fixture_community.cohort_data["m"], - n=fixture_community.cohort_data["n"], - q_m=fixture_community.cohort_data["q_m"], + m=fixture_community.stem_traits.m, + n=fixture_community.stem_traits.n, + q_m=fixture_community.stem_traits.q_m, z_max=fixture_community.cohort_data["canopy_z_max"], target_area=this_target, ) @@ -628,8 +628,8 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): q_z = calculate_relative_canopy_radius_at_z( z=z_max, stem_height=fixture_community.cohort_data["stem_height"], - m=fixture_community.cohort_data["m"], - n=fixture_community.cohort_data["n"], + m=fixture_community.stem_traits.m, + n=fixture_community.stem_traits.n, ) leaf_area_fg0 = calculate_stem_projected_leaf_area_at_z( @@ -637,8 +637,8 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): q_z=q_z, stem_height=fixture_community.cohort_data["stem_height"], crown_area=fixture_community.cohort_data["crown_area"], - f_g=fixture_community.cohort_data["f_g"], - q_m=fixture_community.cohort_data["q_m"], + f_g=fixture_community.stem_traits.f_g, + q_m=fixture_community.stem_traits.q_m, z_max=fixture_community.cohort_data["canopy_z_max"], ) @@ -664,15 +664,15 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): ) # Introduce some crown gap fraction and recalculate - fixture_community.cohort_data["f_g"] += 0.02 + fixture_community.stem_traits.f_g += 0.02 leaf_area_fg002 = calculate_stem_projected_leaf_area_at_z( z=z_max, q_z=q_z, stem_height=fixture_community.cohort_data["stem_height"], crown_area=fixture_community.cohort_data["crown_area"], - f_g=fixture_community.cohort_data["f_g"], - q_m=fixture_community.cohort_data["q_m"], + f_g=fixture_community.stem_traits.f_g, + q_m=fixture_community.stem_traits.q_m, z_max=fixture_community.cohort_data["canopy_z_max"], ) From e431d0430b2365043c336503221617b1ad311dcf Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 13:27:05 +0100 Subject: [PATCH 155/241] Adding stem_height -> dbh; big overhaul of t model testing against rtmodel predictions --- pyrealm/demography/t_model_functions.py | 50 +++ tests/unit/demography/conftest.py | 81 ++++ .../unit/demography/test_t_model_functions.py | 409 ++++++++++-------- 3 files changed, 366 insertions(+), 174 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 59b18fb7..4323aa2f 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -78,6 +78,56 @@ def calculate_heights( return h_max * (1 - np.exp(-a_hd * dbh / h_max)) +def calculate_dbh_from_height( + h_max: NDArray[np.float32], + a_hd: NDArray[np.float32], + stem_height: NDArray[np.float32], + validate: bool = True, +) -> NDArray[np.float32]: + r"""Calculate diameter at breast height from stem height under the T Model. + + This function inverts the normal calculation of stem height (:math:`H`) from + diameter at breast height (DBH, :math:`D`) in the T Model (see + :meth:`~pyrealm.demography.t_model_functions.calculate_heights`). This is a helper + function to allow users to convert known stem heights for a plant functional type, + with maximum height (:math:`H_{m}`) and initial slope of the height/diameter + relationship (:math:`a`) into the expected DBH values. + + .. math:: + + D = \frac{H \left( \log \left(\frac{H}{H_{m}-H}\right)\right)}{a} + + Warning: + Where the stem height is greater than the maximum height for a PFT, then + DBH is undefined and the return array will contain `np.nan`. Where the + stem height equals the maximum height, the model predicts an infinite stem + diameter: the `h_max` parameter is the asymptotic maximum stem height of an + exponential function. Similarly, heights very close to the maximum height may + lead to unrealistically large predictions of DBH. + + Args: + h_max: Maximum height of the PFT + a_hd: Initial slope of the height/diameter relationship of the PFT + stem_height: Stem height of individuals + validate: Boolean flag to suppress argument validation + """ + + if validate: + _validate_t_model_args(pft_args=[h_max, a_hd], size_args=[stem_height]) + + # The equation here blows up in a couple of ways: + # - H > h_max leads to negative logs which generates np.nan with an invalid value + # warning. The np.nan here is what we want to happen, so the warning needs + # suppressing. + # - H = h_max generates a divide by zero which returns inf with a warning. Here the + # answer should be h_max so that needs trapping. + + with np.testing.suppress_warnings() as sup: + sup.filter(RuntimeWarning, "divide by zero encountered in divide") + sup.filter(RuntimeWarning, "invalid value encountered in log") + return (h_max * np.log(h_max / (h_max - stem_height))) / a_hd + + def calculate_crown_areas( ca_ratio: NDArray[np.float32], a_hd: NDArray[np.float32], diff --git a/tests/unit/demography/conftest.py b/tests/unit/demography/conftest.py index f8b34d2f..0a51f97f 100644 --- a/tests/unit/demography/conftest.py +++ b/tests/unit/demography/conftest.py @@ -1,5 +1,9 @@ """Shared fixtures for demography testing.""" +from importlib import resources + +import numpy as np +import pandas as pd import pytest @@ -15,3 +19,80 @@ def fixture_flora(): PlantFunctionalType(name="conifer", h_max=20), ] ) + + +@pytest.fixture +def rtmodel_flora(): + """Generates a flora object from the rtmodel test definitions.""" + + from pyrealm.demography.flora import Flora, PlantFunctionalType + + # Load the PFT definitions and rename to pyrealm attributes + pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" + pft_definitions = pd.read_csv(pfts_path) + + # Map the PFT trait args from the R implementation to pyrealm + pft_definitions = pft_definitions.rename( + columns={ + "a": "a_hd", + "cr": "ca_ratio", + "Hm": "h_max", + "rho": "rho_s", + "L": "lai", + "sigma": "sla", + "tf": "tau_f", + "tr": "tau_r", + "K": "par_ext", + "y": "yld", + "rr": "resp_r", + "rs": "resp_s", + } + ) + + pft_definitions = pft_definitions.drop(columns=["d"]) + + return Flora( + pfts=[ + PlantFunctionalType(**args) + for args in pft_definitions.to_dict(orient="records") + ] + ) + + +@pytest.fixture +def rtmodel_data(): + """Loads some simple predictions from the R implementation for testing.""" + + rdata_path = ( + resources.files("pyrealm_build_data.t_model") / "rtmodel_unit_testing.csv" + ) + rdata = pd.read_csv(rdata_path) + + rdata = rdata.rename( + columns={ + "dD": "delta_d", + "D": "dbh", + "H": "stem_height", + "fc": "crown_fraction", + "Ac": "crown_area", + "Wf": "foliage_mass", + "Ws": "stem_mass", + "Wss": "sapwood_mass", + "P0": "potential_gpp", + "GPP": "crown_gpp", + "Rm1": "resp_swd", + "Rm2": "resp_frt", + "dWs": "delta_mass_stm", + "dWfr": "delta_mass_frt", + } + ) + + # Fix some scaling differences: + # The R tmodel implementation rescales reported delta_d as a radial increase in + # millimetres, not diameter increase in metres + rdata["delta_d"] = rdata["delta_d"] / 500 + + # Wrap the return data into arrays with PFT as columns and diameter values as rows + rdata_arrays = {k: np.reshape(v, (3, 6)).T for k, v in rdata.items()} + + return rdata_arrays diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 06c15824..19795831 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -1,10 +1,8 @@ """test the functions in t_model_functions.py.""" from contextlib import nullcontext as does_not_raise -from importlib import resources import numpy as np -import pandas as pd import pytest @@ -80,72 +78,6 @@ def test__validate_t_model_args(pft_args, size_args, outcome, excep_message): assert str(excep.value).startswith(excep_message) -@pytest.fixture -def rtmodel_data(): - """Loads some simple predictions from the R implementation for testing.""" - - # Load the PFT definitions and rename to pyrealm attributes - pfts_path = resources.files("pyrealm_build_data.t_model") / "pft_definitions.csv" - pft_definitions = pd.read_csv(pfts_path) - - # Map the PFT trait args from the R implementation to pyrealm - pft_definitions = pft_definitions.rename( - columns={ - "a": "a_hd", - "cr": "ca_ratio", - "Hm": "h_max", - "rho": "rho_s", - "L": "lai", - "sigma": "sla", - "tf": "tau_f", - "tr": "tau_r", - "K": "par_ext", - "y": "yld", - "rr": "resp_r", - "rs": "resp_s", - } - ) - - # Add foliar respiration rate as 0.1, as this is handled outside of the R - # implementation as a function of GPP. - pft_definitions["resp_f"] = 0.1 - - rdata_path = ( - resources.files("pyrealm_build_data.t_model") / "rtmodel_unit_testing.csv" - ) - rdata = pd.read_csv(rdata_path) - - rdata = rdata.rename( - columns={ - "dD": "delta_d", - "D": "diameter", - "H": "height", - "fc": "crown_fraction", - "Ac": "crown_area", - "Wf": "mass_fol", - "Ws": "mass_stm", - "Wss": "mass_swd", - "P0": "potential_gpp", - "GPP": "crown_gpp", - "Rm1": "resp_swd", - "Rm2": "resp_frt", - "dWs": "delta_mass_stm", - "dWfr": "delta_mass_frt", - } - ) - - # Fix some scaling differences: - # The R tmodel implementation rescales reported delta_d as a radial increase in - # millimetres, not diameter increase in metres - rdata["delta_d"] = rdata["delta_d"] / 500 - - # Wrap the return data into arrays with PFT as columns and diameter values as rows - pft_arrays = {k: v.to_numpy() for k, v in pft_definitions.items()} - rdata_arrays = {k: np.reshape(v, (3, 6)).T for k, v in rdata.items()} - - return pft_arrays, rdata_arrays - - @pytest.mark.parametrize( argnames="data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape", argvalues=[ @@ -318,179 +250,255 @@ class TestTModel: """ def test_calculate_heights( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of heights of tree from diameter.""" from pyrealm.demography.t_model_functions import calculate_heights - pfts, data = rtmodel_data - with outcome as excep: result = calculate_heights( - h_max=pfts["h_max"][pft_idx], - a_hd=pfts["a_hd"][pft_idx], - dbh=data["diameter"][data_idx], + h_max=rtmodel_flora.h_max[pft_idx], + a_hd=rtmodel_flora.a_hd[pft_idx], + dbh=rtmodel_data["dbh"][data_idx], + ) + + assert result.shape == exp_shape + assert np.allclose(result, rtmodel_data["stem_height"][out_idx]) + return + + assert str(excep.value).startswith(excep_msg) + + def test_calculate_dbh_from_height( + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, + ): + """Tests inverted calculation of dbh from height.""" + + from pyrealm.demography.t_model_functions import calculate_dbh_from_height + + with outcome as excep: + result = calculate_dbh_from_height( + h_max=rtmodel_flora.h_max[pft_idx], + a_hd=rtmodel_flora.a_hd[pft_idx], + stem_height=rtmodel_data["stem_height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["height"][out_idx]) + assert np.allclose(result, rtmodel_data["dbh"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_crown_areas( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of crown areas of trees.""" from pyrealm.demography.t_model_functions import calculate_crown_areas - pfts, data = rtmodel_data - with outcome as excep: result = calculate_crown_areas( - ca_ratio=pfts["ca_ratio"][pft_idx], - a_hd=pfts["a_hd"][pft_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], + ca_ratio=rtmodel_flora.ca_ratio[pft_idx], + a_hd=rtmodel_flora.a_hd[pft_idx], + dbh=rtmodel_data["dbh"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["crown_area"][out_idx]) + assert np.allclose(result, rtmodel_data["crown_area"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_crown_fractions( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of crown fraction of trees.""" from pyrealm.demography.t_model_functions import calculate_crown_fractions - pfts, data = rtmodel_data - with outcome as excep: result = calculate_crown_fractions( - a_hd=pfts["a_hd"][pft_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], + a_hd=rtmodel_flora.a_hd[pft_idx], + dbh=rtmodel_data["dbh"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["crown_fraction"][out_idx]) + assert np.allclose(result, rtmodel_data["crown_fraction"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_stem_masses( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_stem_masses - pfts, data = rtmodel_data - with outcome as excep: result = calculate_stem_masses( - rho_s=pfts["rho_s"][pft_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], + rho_s=rtmodel_flora.rho_s[pft_idx], + dbh=rtmodel_data["dbh"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["mass_stm"][out_idx]) + assert np.allclose(result, rtmodel_data["stem_mass"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_foliage_masses( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_foliage_masses - pfts, data = rtmodel_data - with outcome as excep: result = calculate_foliage_masses( - lai=pfts["lai"][pft_idx], - sla=pfts["sla"][pft_idx], - crown_area=data["crown_area"][data_idx], + lai=rtmodel_flora.lai[pft_idx], + sla=rtmodel_flora.sla[pft_idx], + crown_area=rtmodel_data["crown_area"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["mass_fol"][out_idx]) + assert np.allclose(result, rtmodel_data["foliage_mass"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_sapwood_masses( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of stem masses of trees.""" from pyrealm.demography.t_model_functions import calculate_sapwood_masses - pfts, data = rtmodel_data - with outcome as excep: result = calculate_sapwood_masses( - rho_s=pfts["rho_s"][pft_idx], - ca_ratio=pfts["ca_ratio"][pft_idx], - crown_area=data["crown_area"][data_idx], - stem_height=data["height"][data_idx], - crown_fraction=data["crown_fraction"][data_idx], + rho_s=rtmodel_flora.rho_s[pft_idx], + ca_ratio=rtmodel_flora.ca_ratio[pft_idx], + crown_area=rtmodel_data["crown_area"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], + crown_fraction=rtmodel_data["crown_fraction"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["mass_swd"][out_idx]) + assert np.allclose(result, rtmodel_data["sapwood_mass"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_whole_crown_gpp( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of whole crown GPP.""" from pyrealm.demography.t_model_functions import calculate_whole_crown_gpp - pfts, data = rtmodel_data - with outcome as excep: result = calculate_whole_crown_gpp( - lai=pfts["lai"][pft_idx], - par_ext=pfts["par_ext"][pft_idx], - crown_area=data["crown_area"][data_idx], - potential_gpp=data["potential_gpp"][data_idx], + lai=rtmodel_flora.lai[pft_idx], + par_ext=rtmodel_flora.par_ext[pft_idx], + crown_area=rtmodel_data["crown_area"][data_idx], + potential_gpp=rtmodel_data["potential_gpp"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["crown_gpp"][out_idx]) + assert np.allclose(result, rtmodel_data["crown_gpp"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_sapwood_respiration( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of sapwood respiration.""" from pyrealm.demography.t_model_functions import calculate_sapwood_respiration - pfts, data = rtmodel_data - with outcome as excep: result = calculate_sapwood_respiration( - resp_s=pfts["resp_s"][pft_idx], - sapwood_mass=data["mass_swd"][data_idx], + resp_s=rtmodel_flora.resp_s[pft_idx], + sapwood_mass=rtmodel_data["sapwood_mass"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["resp_swd"][out_idx]) + assert np.allclose(result, rtmodel_data["resp_swd"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -499,6 +507,7 @@ def test_calculate_foliar_respiration( self, request, rtmodel_data, + rtmodel_flora, data_idx, pft_idx, outcome, @@ -515,47 +524,60 @@ def test_calculate_foliar_respiration( from pyrealm.demography.t_model_functions import calculate_foliar_respiration - pfts, data = rtmodel_data - with outcome as excep: result = calculate_foliar_respiration( - resp_f=pfts["resp_f"][pft_idx], - whole_crown_gpp=data["crown_gpp"][data_idx], + resp_f=rtmodel_flora.resp_f[pft_idx], + whole_crown_gpp=rtmodel_data["crown_gpp"][data_idx], ) assert result.shape == exp_shape assert np.allclose( - result, data["crown_gpp"][data_idx] * pfts["resp_f"][pft_idx] + result, + rtmodel_data["crown_gpp"][data_idx] * rtmodel_flora.resp_f[pft_idx], ) return assert str(excep.value).startswith(excep_msg) def test_calculate_fine_root_respiration( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of fine root respiration.""" from pyrealm.demography.t_model_functions import calculate_fine_root_respiration - pfts, data = rtmodel_data - with outcome as excep: result = calculate_fine_root_respiration( - zeta=pfts["zeta"][pft_idx], - sla=pfts["sla"][pft_idx], - resp_r=pfts["resp_r"][pft_idx], - foliage_mass=data["mass_fol"][data_idx], + zeta=rtmodel_flora.zeta[pft_idx], + sla=rtmodel_flora.sla[pft_idx], + resp_r=rtmodel_flora.resp_r[pft_idx], + foliage_mass=rtmodel_data["foliage_mass"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["resp_frt"][out_idx]) + assert np.allclose(result, rtmodel_data["resp_frt"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_net_primary_productivity( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of net primary productivity.""" @@ -563,25 +585,31 @@ def test_calculate_net_primary_productivity( calculate_net_primary_productivity, ) - pfts, data = rtmodel_data - with outcome as excep: result = calculate_net_primary_productivity( - yld=pfts["yld"][pft_idx], - whole_crown_gpp=data["crown_gpp"][data_idx], + yld=rtmodel_flora.yld[pft_idx], + whole_crown_gpp=rtmodel_data["crown_gpp"][data_idx], foliar_respiration=0, # Not included here in the R implementation - fine_root_respiration=data["resp_frt"][data_idx], - sapwood_respiration=data["resp_swd"][data_idx], + fine_root_respiration=rtmodel_data["resp_frt"][data_idx], + sapwood_respiration=rtmodel_data["resp_swd"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["NPP"][out_idx]) + assert np.allclose(result, rtmodel_data["NPP"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_foliage_and_fine_root_turnover( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of foliage and fine root turnover.""" @@ -589,25 +617,31 @@ def test_calculate_foliage_and_fine_root_turnover( calculate_foliage_and_fine_root_turnover, ) - pfts, data = rtmodel_data - with outcome as excep: result = calculate_foliage_and_fine_root_turnover( - sla=pfts["sla"][pft_idx], - zeta=pfts["zeta"][pft_idx], - tau_f=pfts["tau_f"][pft_idx], - tau_r=pfts["tau_r"][pft_idx], - foliage_mass=data["mass_fol"][data_idx], + sla=rtmodel_flora.sla[pft_idx], + zeta=rtmodel_flora.zeta[pft_idx], + tau_f=rtmodel_flora.tau_f[pft_idx], + tau_r=rtmodel_flora.tau_r[pft_idx], + foliage_mass=rtmodel_data["foliage_mass"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, data["turnover"][out_idx]) + assert np.allclose(result, rtmodel_data["turnover"][out_idx]) return assert str(excep.value).startswith(excep_msg) def test_calculate_calculate_growth_increments( - self, rtmodel_data, data_idx, pft_idx, outcome, excep_msg, out_idx, exp_shape + self, + rtmodel_data, + rtmodel_flora, + data_idx, + pft_idx, + outcome, + excep_msg, + out_idx, + exp_shape, ): """Tests calculation of growth increments.""" @@ -615,31 +649,58 @@ def test_calculate_calculate_growth_increments( calculate_growth_increments, ) - pfts, data = rtmodel_data - with outcome as excep: delta_d, delta_mass_stm, delta_mass_frt = calculate_growth_increments( - rho_s=pfts["rho_s"][pft_idx], - a_hd=pfts["a_hd"][pft_idx], - h_max=pfts["h_max"][pft_idx], - lai=pfts["lai"][pft_idx], - ca_ratio=pfts["ca_ratio"][pft_idx], - sla=pfts["sla"][pft_idx], - zeta=pfts["zeta"][pft_idx], - npp=data["NPP"][data_idx], - turnover=data["turnover"][data_idx], - dbh=data["diameter"][data_idx], - stem_height=data["height"][data_idx], + rho_s=rtmodel_flora.rho_s[pft_idx], + a_hd=rtmodel_flora.a_hd[pft_idx], + h_max=rtmodel_flora.h_max[pft_idx], + lai=rtmodel_flora.lai[pft_idx], + ca_ratio=rtmodel_flora.ca_ratio[pft_idx], + sla=rtmodel_flora.sla[pft_idx], + zeta=rtmodel_flora.zeta[pft_idx], + npp=rtmodel_data["NPP"][data_idx], + turnover=rtmodel_data["turnover"][data_idx], + dbh=rtmodel_data["dbh"][data_idx], + stem_height=rtmodel_data["stem_height"][data_idx], ) assert delta_d.shape == exp_shape - assert np.allclose(delta_d, data["delta_d"][out_idx]) + assert np.allclose(delta_d, rtmodel_data["delta_d"][out_idx]) assert delta_mass_stm.shape == exp_shape - assert np.allclose(delta_mass_stm, data["delta_mass_stm"][out_idx]) + assert np.allclose(delta_mass_stm, rtmodel_data["delta_mass_stm"][out_idx]) assert delta_mass_frt.shape == exp_shape - assert np.allclose(delta_mass_frt, data["delta_mass_frt"][out_idx]) + assert np.allclose(delta_mass_frt, rtmodel_data["delta_mass_frt"][out_idx]) return assert str(excep.value).startswith(excep_msg) + + +def test_calculate_dbh_from_height_edge_cases(): + """Test inverted calculation of dbh from height handles edges cases. + + * If H > h_max, dbh is not calculable and should be np.nan + * If H = h_max, dbh is infinite. + """ + + from pyrealm.demography.t_model_functions import calculate_dbh_from_height + + pft_h_max_values = np.array([20, 30]) + pft_a_hd_values = np.array([116.0, 116.0]) + stem_heights = np.array([[0], [10], [20], [30], [40]]) + + dbh = calculate_dbh_from_height( + h_max=pft_h_max_values, + a_hd=pft_a_hd_values, + stem_height=stem_heights, + ) + + # first row should be all zeros (zero height gives zero diameter) + assert np.all(dbh[0, :] == 0) + + # Infinite entries + assert np.all(np.isinf(dbh) == np.array([[0, 0], [0, 0], [1, 0], [0, 1], [0, 0]])) + + # Undefined entries + assert np.all(np.isnan(dbh) == np.array([[0, 0], [0, 0], [0, 0], [1, 0], [1, 1]])) From f3f62a0a038481e1b7873797920ded30969c8658 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 14:31:31 +0100 Subject: [PATCH 156/241] Added StemAllometry --- pyrealm/demography/t_model_functions.py | 96 +++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 4323aa2f..da2750b1 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -5,10 +5,17 @@ calculate stem growth given net primary productivity. """ # noqa: D205 +from dataclasses import InitVar, dataclass, field + import numpy as np from numpy.typing import NDArray from pyrealm.core.utilities import check_input_shapes +from pyrealm.demography.canopy_functions import ( + calculate_canopy_r0, + calculate_canopy_z_max, +) +from pyrealm.demography.flora import Flora, StemTraits def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> None: @@ -600,3 +607,92 @@ def calculate_growth_increments( delta_d = (npp - turnover) / (dWsdt + dWfdt) return (delta_d, dWsdt * delta_d, dWfdt * delta_d) + + +@dataclass +class StemAllometry: + """Calculate T Model allometric predictions across a set of stems. + + This method calculate predictions of stem allometries for stem height, crown area, + crown fraction, stem mass, foliage mass and sapwood mass under the T Model + :cite:`Li:2014bc`, given diameters at breast height for a set of plant functional + traits. + + Args: + pft_data: A dictionary of plant functional trait data, as for example returned + from :attr:`Flora.data` attribute. + dbh: An array of diameter at breast height values for which to predict stem + allometry values. + """ + + # Init vars + stem_traits: InitVar[Flora | StemTraits] + dbh: InitVar[NDArray[np.float32]] + + # Post init allometry attributes + # dbh: NDArray[np.float32] = field(post_init=False) + stem_height: NDArray[np.float32] = field(init=False) + crown_area: NDArray[np.float32] = field(init=False) + crown_fraction: NDArray[np.float32] = field(init=False) + stem_mass: NDArray[np.float32] = field(init=False) + foliage_mass: NDArray[np.float32] = field(init=False) + sapwood_mass: NDArray[np.float32] = field(init=False) + canopy_r0: NDArray[np.float32] = field(init=False) + canopy_z_max: NDArray[np.float32] = field(init=False) + + def __post_init__( + self, stem_traits: Flora | StemTraits, dbh: NDArray[np.float32] + ) -> None: + """Populate the stem allometry attributes from the traits and size data.""" + + self.stem_height = calculate_heights( + h_max=stem_traits.h_max, + a_hd=stem_traits.a_hd, + dbh=dbh, + ) + + # Broadcast dbh to shape of stem height to get congruent shapes + dbh = np.broadcast_to(dbh, self.stem_height.shape) + + self.crown_area = calculate_crown_areas( + ca_ratio=stem_traits.ca_ratio, + a_hd=stem_traits.a_hd, + dbh=dbh, + stem_height=self.stem_height, + ) + + self.crown_fraction = calculate_crown_fractions( + a_hd=stem_traits.a_hd, + dbh=dbh, + stem_height=self.stem_height, + ) + + self.stem_mass = calculate_stem_masses( + rho_s=stem_traits.rho_s, + dbh=dbh, + stem_height=self.stem_height, + ) + + self.foliage_mass = calculate_foliage_masses( + sla=stem_traits.sla, + lai=stem_traits.lai, + crown_area=self.crown_area, + ) + + self.sapwood_mass = calculate_sapwood_masses( + rho_s=stem_traits.rho_s, + ca_ratio=stem_traits.ca_ratio, + stem_height=self.stem_height, + crown_area=self.crown_area, + crown_fraction=self.crown_fraction, + ) + + self.canopy_r0 = calculate_canopy_r0( + q_m=stem_traits.q_m, + crown_area=self.crown_area, + ) + + self.canopy_z_max = calculate_canopy_z_max( + z_max_prop=stem_traits.z_max_prop, + stem_height=self.stem_height, + ) From c86964c79d5fbd898db35c7e7704735a10865a58 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 14:36:03 +0100 Subject: [PATCH 157/241] Adopt StemAllometry in Community --- pyrealm/demography/community.py | 67 +++------------------------------ 1 file changed, 5 insertions(+), 62 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index f466493e..787afa76 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -117,9 +117,8 @@ from numpy.typing import NDArray from pyrealm.core.utilities import check_input_shapes -from pyrealm.demography import canopy_functions -from pyrealm.demography import t_model_functions as t_model from pyrealm.demography.flora import Flora, StemTraits +from pyrealm.demography.t_model_functions import StemAllometry if sys.version_info[:2] >= (3, 11): import tomllib @@ -356,6 +355,7 @@ class Community: # Post init properties number_of_cohorts: int = field(init=False) stem_traits: StemTraits = field(init=False) + stem_allometry: StemAllometry = field(init=False) cohort_data: dict[str, NDArray] = field(init=False) def __post_init__( @@ -405,66 +405,9 @@ def __post_init__( self.number_of_cohorts = len(cohort_pft_names) - # Populate the T model fields - self._calculate_t_model() - - def _calculate_t_model(self) -> None: - """Calculate T Model predictions across cohort data. - - This method populates or updates the community attributes predicted by the T - Model :cite:`Li:2014bc` and by the canopy shape extensions to the T Model - implemented in PlantFate :cite:`joshi:2022a`. - """ - - # Add data to cohort dataframes capturing the T Model geometry - # - Classic T Model scaling - self.cohort_data["stem_height"] = t_model.calculate_heights( - h_max=self.stem_traits.h_max, - a_hd=self.stem_traits.a_hd, - dbh=self.cohort_data["dbh"], - ) - - self.cohort_data["crown_area"] = t_model.calculate_crown_areas( - ca_ratio=self.stem_traits.ca_ratio, - a_hd=self.stem_traits.a_hd, - dbh=self.cohort_data["dbh"], - stem_height=self.cohort_data["stem_height"], - ) - - self.cohort_data["crown_fraction"] = t_model.calculate_crown_fractions( - a_hd=self.stem_traits.a_hd, - dbh=self.cohort_data["dbh"], - stem_height=self.cohort_data["stem_height"], - ) - - self.cohort_data["stem_mass"] = t_model.calculate_stem_masses( - rho_s=self.stem_traits.rho_s, - dbh=self.cohort_data["dbh"], - stem_height=self.cohort_data["stem_height"], - ) - - self.cohort_data["foliage_mass"] = t_model.calculate_foliage_masses( - sla=self.stem_traits.sla, - lai=self.stem_traits.lai, - crown_area=self.cohort_data["crown_area"], - ) - - self.cohort_data["sapwood_mass"] = t_model.calculate_sapwood_masses( - rho_s=self.stem_traits.rho_s, - ca_ratio=self.stem_traits.ca_ratio, - stem_height=self.cohort_data["stem_height"], - crown_area=self.cohort_data["crown_area"], - crown_fraction=self.cohort_data["crown_fraction"], - ) - - # Canopy shape extension to T Model from PlantFATE - self.cohort_data["canopy_z_max"] = canopy_functions.calculate_canopy_z_max( - z_max_prop=self.stem_traits.z_max_prop, - stem_height=self.cohort_data["stem_height"], - ) - self.cohort_data["canopy_r0"] = canopy_functions.calculate_canopy_r0( - q_m=self.stem_traits.q_m, - crown_area=self.cohort_data["crown_area"], + # Populate the stem allometry + self.stem_allometry = StemAllometry( + stem_traits=self.stem_traits, dbh=cohort_dbh_values ) @classmethod From 2dc486a8f49ea7527d52cb5e1f28f330338cc88c Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 14:39:13 +0100 Subject: [PATCH 158/241] Update Canopy to access StemAllometry attributes --- pyrealm/demography/canopy.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 0442e37a..50958c79 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -79,10 +79,10 @@ def _calculate_canopy(self, community: Community) -> None: # Calculate community wide properties: total crown area, maximum height, crown # area required to fill a layer and total number of canopy layers self.total_community_crown_area = ( - community.cohort_data["crown_area"] * community.cohort_data["n_individuals"] + community.stem_allometry.crown_area * community.cohort_data["n_individuals"] ).sum() - self.max_stem_height = community.cohort_data["stem_height"].max() + self.max_stem_height = community.stem_allometry.stem_height.max() self.crown_area_per_layer = community.cell_area * (1 - self.canopy_gap_fraction) @@ -109,12 +109,12 @@ def _calculate_canopy(self, community: Community) -> None: solution = root_scalar( solve_community_projected_canopy_area, args=( - community.cohort_data["stem_height"], - community.cohort_data["crown_area"], + community.stem_allometry.stem_height, + community.stem_allometry.crown_area, community.stem_traits.m, community.stem_traits.n, community.stem_traits.q_m, - community.cohort_data["canopy_z_max"], + community.stem_allometry.canopy_z_max, community.cohort_data["n_individuals"], target_area, False, # validate @@ -136,7 +136,7 @@ def _calculate_canopy(self, community: Community) -> None: # turning off the validation internally should simply speed up the code. self.stem_relative_radius = calculate_relative_canopy_radius_at_z( z=self.layer_heights, - stem_height=community.cohort_data["stem_height"], + stem_height=community.stem_allometry.stem_height, m=community.stem_traits.m, n=community.stem_traits.n, validate=False, @@ -146,10 +146,10 @@ def _calculate_canopy(self, community: Community) -> None: self.stem_crown_area = calculate_stem_projected_crown_area_at_z( z=self.layer_heights, q_z=self.stem_relative_radius, - crown_area=community.cohort_data["crown_area"], - stem_height=community.cohort_data["stem_height"], + crown_area=community.stem_allometry.crown_area, + stem_height=community.stem_allometry.stem_height, q_m=community.stem_traits.q_m, - z_max=community.cohort_data["canopy_z_max"], + z_max=community.stem_allometry.canopy_z_max, validate=False, ) @@ -157,10 +157,10 @@ def _calculate_canopy(self, community: Community) -> None: self.stem_leaf_area = calculate_stem_projected_leaf_area_at_z( z=self.layer_heights, q_z=self.stem_relative_radius, - crown_area=community.cohort_data["crown_area"], - stem_height=community.cohort_data["stem_height"], + crown_area=community.stem_allometry.crown_area, + stem_height=community.stem_allometry.stem_height, f_g=community.stem_traits.f_g, q_m=community.stem_traits.q_m, - z_max=community.cohort_data["canopy_z_max"], + z_max=community.stem_allometry.canopy_z_max, validate=False, ) From 60878bb855bdb0a6178b295f0fb6a4cfb222b7bd Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 14:56:13 +0100 Subject: [PATCH 159/241] Updating StemAllometry refs in canopy and tests --- pyrealm/demography/community.py | 17 ++++--- tests/unit/demography/test_canopy.py | 2 +- .../unit/demography/test_canopy_functions.py | 48 +++++++++---------- tests/unit/demography/test_community.py | 2 +- 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 787afa76..456088c8 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -89,12 +89,17 @@ ... cohort_pft_names=cohort_pft_names ... ) -Convert the community cohort data to a :class:`pandas.DataFrame` for nicer display and -show some of the calculated T Model predictions: - ->>> pd.DataFrame(community.cohort_data)[ -... ['name', 'dbh', 'n_individuals', 'stem_height', 'crown_area', 'stem_mass'] -... ] +Convert some of the data to a :class:`pandas.DataFrame` for nicer display and show some +of the calculated T Model predictions: + +>>> pd.DataFrame({ +... 'name': community.stem_traits.name, +... 'n_individuals': community.cohort_data["n_individuals"], +... 'dbh': community.stem_allometry.dbh, +... 'stem_height': community.stem_allometry.stem_height, +... 'crown_area': community.stem_allometry.crown_area, +... 'stem_mass': community.stem_allometry.stem_mass, +... }) name dbh n_individuals stem_height crown_area stem_mass 0 Evergreen Tree 0.100 100 9.890399 2.459835 8.156296 1 Deciduous Shrub 0.030 200 2.110534 0.174049 0.134266 diff --git a/tests/unit/demography/test_canopy.py b/tests/unit/demography/test_canopy.py index c937c8eb..615f963a 100644 --- a/tests/unit/demography/test_canopy.py +++ b/tests/unit/demography/test_canopy.py @@ -38,7 +38,7 @@ def test_Canopy__init__(): np.ceil( ( ( - community.cohort_data["crown_area"] + community.stem_allometry.crown_area * community.cohort_data["n_individuals"] ).sum() * (1 + canopy_gap_fraction) diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index e0af9d26..7681fa87 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -401,14 +401,14 @@ def test_calculate_relative_canopy_radius_at_z_values(fixture_community): # Canopy shape model gives the maximum radius at a height z_max z_max = ( - fixture_community.cohort_data["stem_height"] + fixture_community.stem_allometry.stem_height * fixture_community.stem_traits.z_max_prop ) # Get the relative radius at that height q_z_values = calculate_relative_canopy_radius_at_z( z=z_max, - stem_height=fixture_community.cohort_data["stem_height"], + stem_height=fixture_community.stem_allometry.stem_height, m=fixture_community.stem_traits.m, n=fixture_community.stem_traits.n, ) @@ -416,8 +416,8 @@ def test_calculate_relative_canopy_radius_at_z_values(fixture_community): # Now test that the circular crown area from that radius is equivalent to the direct # prediction from the T model allometric equations. assert np.allclose( - fixture_community.cohort_data["crown_area"], - np.pi * (q_z_values * fixture_community.cohort_data["canopy_r0"]) ** 2, + fixture_community.stem_allometry.crown_area, + np.pi * (q_z_values * fixture_community.stem_allometry.canopy_r0) ** 2, ) @@ -509,7 +509,7 @@ def test_calculate_stem_projected_crown_area_at_z_values( # Calculate the required q_z q_z = calculate_relative_canopy_radius_at_z( z=heights, - stem_height=fixture_community.cohort_data["stem_height"], + stem_height=fixture_community.stem_allometry.stem_height, m=fixture_community.stem_traits.m, n=fixture_community.stem_traits.n, ) @@ -518,10 +518,10 @@ def test_calculate_stem_projected_crown_area_at_z_values( Ap_z_values = calculate_stem_projected_crown_area_at_z( z=heights, q_z=q_z, - stem_height=fixture_community.cohort_data["stem_height"], - crown_area=fixture_community.cohort_data["crown_area"], + stem_height=fixture_community.stem_allometry.stem_height, + crown_area=fixture_community.stem_allometry.crown_area, q_m=fixture_community.stem_traits.q_m, - z_max=fixture_community.cohort_data["canopy_z_max"], + z_max=fixture_community.stem_allometry.canopy_z_max, ) assert np.allclose( @@ -548,18 +548,18 @@ def test_solve_community_projected_canopy_area(fixture_community): this_height, this_target, ) in zip( - np.flip(fixture_community.cohort_data["canopy_z_max"]), - np.cumsum(np.flip(fixture_community.cohort_data["crown_area"])), + np.flip(fixture_community.stem_allometry.canopy_z_max), + np.cumsum(np.flip(fixture_community.stem_allometry.crown_area)), ): solved = solve_community_projected_canopy_area( z=this_height, - stem_height=fixture_community.cohort_data["stem_height"], - crown_area=fixture_community.cohort_data["crown_area"], + stem_height=fixture_community.stem_allometry.stem_height, + crown_area=fixture_community.stem_allometry.crown_area, n_individuals=fixture_community.cohort_data["n_individuals"], m=fixture_community.stem_traits.m, n=fixture_community.stem_traits.n, q_m=fixture_community.stem_traits.q_m, - z_max=fixture_community.cohort_data["canopy_z_max"], + z_max=fixture_community.stem_allometry.canopy_z_max, target_area=this_target, ) @@ -623,11 +623,11 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): # Calculate the leaf areas at the locations of z_max for each stem from the lowest # to the highest - z_max = fixture_community.cohort_data["canopy_z_max"][:, None] + z_max = fixture_community.stem_allometry.canopy_z_max[:, None] q_z = calculate_relative_canopy_radius_at_z( z=z_max, - stem_height=fixture_community.cohort_data["stem_height"], + stem_height=fixture_community.stem_allometry.stem_height, m=fixture_community.stem_traits.m, n=fixture_community.stem_traits.n, ) @@ -635,11 +635,11 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): leaf_area_fg0 = calculate_stem_projected_leaf_area_at_z( z=z_max, q_z=q_z, - stem_height=fixture_community.cohort_data["stem_height"], - crown_area=fixture_community.cohort_data["crown_area"], + stem_height=fixture_community.stem_allometry.stem_height, + crown_area=fixture_community.stem_allometry.crown_area, f_g=fixture_community.stem_traits.f_g, q_m=fixture_community.stem_traits.q_m, - z_max=fixture_community.cohort_data["canopy_z_max"], + z_max=fixture_community.stem_allometry.canopy_z_max, ) # Pre-calculated values @@ -656,11 +656,11 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): # More rigourous check - with f_g = 0, the projected leaf area of each stem in the # lowest layer must equal the crown area (all the crown is now accounted for). - assert np.allclose(leaf_area_fg0[0, :], fixture_community.cohort_data["crown_area"]) + assert np.allclose(leaf_area_fg0[0, :], fixture_community.stem_allometry.crown_area) # Also the diagonal of the resulting matrix (4 heights for 4 cohorts) should _also_ # match the crown areas as the leaf area is all accounted for exactly at z_max. assert np.allclose( - np.diag(leaf_area_fg0), fixture_community.cohort_data["crown_area"] + np.diag(leaf_area_fg0), fixture_community.stem_allometry.crown_area ) # Introduce some crown gap fraction and recalculate @@ -669,11 +669,11 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): leaf_area_fg002 = calculate_stem_projected_leaf_area_at_z( z=z_max, q_z=q_z, - stem_height=fixture_community.cohort_data["stem_height"], - crown_area=fixture_community.cohort_data["crown_area"], + stem_height=fixture_community.stem_allometry.stem_height, + crown_area=fixture_community.stem_allometry.crown_area, f_g=fixture_community.stem_traits.f_g, q_m=fixture_community.stem_traits.q_m, - z_max=fixture_community.cohort_data["canopy_z_max"], + z_max=fixture_community.stem_allometry.canopy_z_max, ) expected_leaf_area_fg002 = np.array( @@ -698,5 +698,5 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): # the stem all but the crown gap fraction should be accounted for assert np.allclose( np.diag(leaf_area_fg002), - fixture_community.cohort_data["crown_area"] * 0.98, + fixture_community.stem_allometry.crown_area * 0.98, ) diff --git a/tests/unit/demography/test_community.py b/tests/unit/demography/test_community.py index 80013daf..1e6cdea6 100644 --- a/tests/unit/demography/test_community.py +++ b/tests/unit/demography/test_community.py @@ -42,7 +42,7 @@ def check_expected(community, expected): expected["a_hd"], ) assert np.allclose( - community.cohort_data["stem_height"], + community.stem_allometry.stem_height, expected["height"], ) From ea10d77a9ddf5a7f109ed4ac1517c1a71a655efb Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 18:04:57 +0100 Subject: [PATCH 160/241] Fixing dbh in StemAllometry --- pyrealm/demography/community.py | 4 ++-- pyrealm/demography/t_model_functions.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 456088c8..11502f35 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -94,8 +94,8 @@ >>> pd.DataFrame({ ... 'name': community.stem_traits.name, -... 'n_individuals': community.cohort_data["n_individuals"], ... 'dbh': community.stem_allometry.dbh, +... 'n_individuals': community.cohort_data["n_individuals"], ... 'stem_height': community.stem_allometry.stem_height, ... 'crown_area': community.stem_allometry.crown_area, ... 'stem_mass': community.stem_allometry.stem_mass, @@ -412,7 +412,7 @@ def __post_init__( # Populate the stem allometry self.stem_allometry = StemAllometry( - stem_traits=self.stem_traits, dbh=cohort_dbh_values + stem_traits=self.stem_traits, at_dbh=cohort_dbh_values ) @classmethod diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index da2750b1..4c3a6234 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -621,16 +621,16 @@ class StemAllometry: Args: pft_data: A dictionary of plant functional trait data, as for example returned from :attr:`Flora.data` attribute. - dbh: An array of diameter at breast height values for which to predict stem + at_dbh: An array of diameter at breast height values at which to predict stem allometry values. """ # Init vars stem_traits: InitVar[Flora | StemTraits] - dbh: InitVar[NDArray[np.float32]] + at_dbh: InitVar[NDArray[np.float32]] # Post init allometry attributes - # dbh: NDArray[np.float32] = field(post_init=False) + dbh: NDArray[np.float32] = field(init=False) stem_height: NDArray[np.float32] = field(init=False) crown_area: NDArray[np.float32] = field(init=False) crown_fraction: NDArray[np.float32] = field(init=False) @@ -641,35 +641,35 @@ class StemAllometry: canopy_z_max: NDArray[np.float32] = field(init=False) def __post_init__( - self, stem_traits: Flora | StemTraits, dbh: NDArray[np.float32] + self, stem_traits: Flora | StemTraits, at_dbh: NDArray[np.float32] ) -> None: """Populate the stem allometry attributes from the traits and size data.""" self.stem_height = calculate_heights( h_max=stem_traits.h_max, a_hd=stem_traits.a_hd, - dbh=dbh, + dbh=at_dbh, ) - # Broadcast dbh to shape of stem height to get congruent shapes - dbh = np.broadcast_to(dbh, self.stem_height.shape) + # Broadcast at_dbh to shape of stem height to get congruent shapes + self.dbh = np.broadcast_to(at_dbh, self.stem_height.shape) self.crown_area = calculate_crown_areas( ca_ratio=stem_traits.ca_ratio, a_hd=stem_traits.a_hd, - dbh=dbh, + dbh=self.dbh, stem_height=self.stem_height, ) self.crown_fraction = calculate_crown_fractions( a_hd=stem_traits.a_hd, - dbh=dbh, + dbh=self.dbh, stem_height=self.stem_height, ) self.stem_mass = calculate_stem_masses( rho_s=stem_traits.rho_s, - dbh=dbh, + dbh=self.dbh, stem_height=self.stem_height, ) From 742f02cb68e58b3d6f889cf50540b5863fa77cfe Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 19:12:32 +0100 Subject: [PATCH 161/241] Simple test of StemAllometry --- pyrealm/demography/t_model_functions.py | 13 +++++++++++++ tests/unit/demography/test_t_model_functions.py | 15 +++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 4c3a6234..65641dbc 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -6,6 +6,7 @@ """ # noqa: D205 from dataclasses import InitVar, dataclass, field +from typing import ClassVar import numpy as np from numpy.typing import NDArray @@ -625,6 +626,18 @@ class StemAllometry: allometry values. """ + allometry_attrs: ClassVar[tuple[str, ...]] = ( + "dbh", + "stem_height", + "crown_area", + "crown_fraction", + "stem_mass", + "foliage_mass", + "sapwood_mass", + "canopy_r0", + "canopy_z_max", + ) + # Init vars stem_traits: InitVar[Flora | StemTraits] at_dbh: InitVar[NDArray[np.float32]] diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 19795831..3cc65e2e 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -704,3 +704,18 @@ def test_calculate_dbh_from_height_edge_cases(): # Undefined entries assert np.all(np.isnan(dbh) == np.array([[0, 0], [0, 0], [0, 0], [1, 0], [1, 1]])) + + +def test_StemAllometry(rtmodel_flora, rtmodel_data): + """Test the StemAllometry class.""" + + from pyrealm.demography.t_model_functions import StemAllometry + + stem_allometry = StemAllometry( + stem_traits=rtmodel_flora, at_dbh=rtmodel_data["dbh"][:, [0]] + ) + + # Check the variables provided by the rtmodel implementation + to_check = set(stem_allometry.allometry_attrs) - set(["canopy_r0", "canopy_z_max"]) + for var in to_check: + assert np.allclose(getattr(stem_allometry, var), rtmodel_data[var]) From 44498cf774dc6f8677b82acf79ae93966614da92 Mon Sep 17 00:00:00 2001 From: David Orme Date: Sun, 29 Sep 2024 21:25:50 +0100 Subject: [PATCH 162/241] Fixing missing docstrings and outdated ref --- pyrealm/demography/t_model_functions.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 65641dbc..57a81483 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -620,8 +620,9 @@ class StemAllometry: traits. Args: - pft_data: A dictionary of plant functional trait data, as for example returned - from :attr:`Flora.data` attribute. + stem_traits: An instance of :class:`~pyrealm.demography.flora.Flora` or + :class:`~pyrealm.demography.flora.StemTraits`, providing plant functional + trait data for a set of stems. at_dbh: An array of diameter at breast height values at which to predict stem allometry values. """ @@ -640,18 +641,32 @@ class StemAllometry: # Init vars stem_traits: InitVar[Flora | StemTraits] + """ An instance of :class:`~pyrealm.demography.flora.Flora` or + :class:`~pyrealm.demography.flora.StemTraits`, providing plant functional trait data + for a set of stems.""" at_dbh: InitVar[NDArray[np.float32]] + """An array of diameter at breast height values at which to predict stem allometry + values.""" # Post init allometry attributes dbh: NDArray[np.float32] = field(init=False) + """Diameter at breast height (metres)""" stem_height: NDArray[np.float32] = field(init=False) + """Stem height (metres)""" crown_area: NDArray[np.float32] = field(init=False) + """Crown area (square metres)""" crown_fraction: NDArray[np.float32] = field(init=False) + """Vertical fraction of the stem covered by the crown (-)""" stem_mass: NDArray[np.float32] = field(init=False) + """Stem mass (kg)""" foliage_mass: NDArray[np.float32] = field(init=False) + """Foliage mass (kg)""" sapwood_mass: NDArray[np.float32] = field(init=False) + """Sapwood mass (kg)""" canopy_r0: NDArray[np.float32] = field(init=False) + """Canopy radius scaling factor (-)""" canopy_z_max: NDArray[np.float32] = field(init=False) + """Height of maximum crown radius (metres)""" def __post_init__( self, stem_traits: Flora | StemTraits, at_dbh: NDArray[np.float32] From 8d67c8a418481934a807529c7bebc108d5483016 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 20:24:40 +0100 Subject: [PATCH 163/241] Adding allocation traits class var, simple test --- pyrealm/demography/t_model_functions.py | 122 ++++++++++++++++++ tests/unit/demography/conftest.py | 19 ++- .../unit/demography/test_t_model_functions.py | 60 ++++++--- 3 files changed, 179 insertions(+), 22 deletions(-) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 57a81483..2995652b 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -724,3 +724,125 @@ def __post_init__( z_max_prop=stem_traits.z_max_prop, stem_height=self.stem_height, ) + + +@dataclass() +class StemAllocation: + """Calculate T Model allocation predictions across a set of stems. + + This method calculate predictions of allocation of potential GPP for stems under the + T Model :cite:`Li:2014bc`, given a set of traits for those stems and the stem + allometries given the stem size. + + Args: + stem_traits: An instance of :class:`~pyrealm.demography.flora.Flora` or + :class:`~pyrealm.demography.flora.StemTraits`, providing plant functional + trait data for a set of stems. + stem_allometry: An instance of + :class:`~pyrealm.demography.t_model_functions.StemAllometry` + providing the stem size data for which to calculate allocation. + at_potential_gpp: An array of diameter at breast height values at which to + predict stem allometry values. + """ + + allocation_attrs: ClassVar[tuple[str, ...]] = ( + "potential_gpp", + "whole_crown_gpp", + "sapwood_respiration", + "foliar_respiration", + "fine_root_respiration", + "npp", + "turnover", + "delta_dbh", + "delta_stem_mass", + "delta_foliage_mass", + ) + + # Init vars + stem_traits: InitVar[Flora | StemTraits] + """An instance of :class:`~pyrealm.demography.flora.Flora` or + :class:`~pyrealm.demography.flora.StemTraits`, providing plant functional trait data + for a set of stems.""" + stem_allometry: InitVar[StemAllometry] + """An instance of :class:`~pyrealm.demography.t_model_functions.StemAllometry` + providing the stem size data for which to calculate allocation.""" + at_potential_gpp: InitVar[NDArray[np.float32]] + """An array of potential gross primary productivity for each stem that should be + allocated to respiration, turnover and growth.""" + + # Post init allometry attributes + potential_gpp: NDArray[np.float32] = field(init=False) + whole_crown_gpp: NDArray[np.float32] = field(init=False) + sapwood_respiration: NDArray[np.float32] = field(init=False) + foliar_respiration: NDArray[np.float32] = field(init=False) + fine_root_respiration: NDArray[np.float32] = field(init=False) + npp: NDArray[np.float32] = field(init=False) + turnover: NDArray[np.float32] = field(init=False) + delta_dbh: NDArray[np.float32] = field(init=False) + delta_stem_mass: NDArray[np.float32] = field(init=False) + delta_foliage_mass: NDArray[np.float32] = field(init=False) + + def __post_init__( + self, + stem_traits: Flora | StemTraits, + stem_allometry: StemAllometry, + at_potential_gpp: NDArray[np.float32], + ) -> None: + """Populate stem allocation attributes from the traits, allometry and GPP.""" + + # Broadcast potential GPP to match stem data outputs + self.potential_gpp = np.broadcast_to(at_potential_gpp, stem_allometry.dbh.shape) + + self.whole_crown_gpp = calculate_whole_crown_gpp( + potential_gpp=self.potential_gpp, + crown_area=stem_allometry.crown_area, + par_ext=stem_traits.par_ext, + lai=stem_traits.lai, + ) + + self.sapwood_respiration = calculate_sapwood_respiration( + resp_s=stem_traits.resp_s, sapwood_mass=stem_allometry.sapwood_mass + ) + + self.foliar_respiration = calculate_foliar_respiration( + resp_f=stem_traits.resp_f, whole_crown_gpp=self.whole_crown_gpp + ) + + self.fine_root_respiration = calculate_fine_root_respiration( + zeta=stem_traits.zeta, + sla=stem_traits.sla, + resp_r=stem_traits.resp_r, + foliage_mass=stem_allometry.foliage_mass, + ) + + self.npp = calculate_net_primary_productivity( + yld=stem_traits.yld, + whole_crown_gpp=self.whole_crown_gpp, + foliar_respiration=self.foliar_respiration, + fine_root_respiration=self.fine_root_respiration, + sapwood_respiration=self.sapwood_respiration, + ) + + self.turnover = calculate_foliage_and_fine_root_turnover( + sla=stem_traits.sla, + zeta=stem_traits.zeta, + tau_f=stem_traits.tau_f, + tau_r=stem_traits.tau_r, + foliage_mass=stem_allometry.foliage_mass, + ) + + (self.delta_dbh, self.delta_stem_mass, self.delta_foliage_mass) = ( + calculate_growth_increments( + rho_s=stem_traits.rho_s, + a_hd=stem_traits.a_hd, + h_max=stem_traits.h_max, + lai=stem_traits.lai, + ca_ratio=stem_traits.ca_ratio, + sla=stem_traits.sla, + zeta=stem_traits.zeta, + npp=self.npp, + turnover=self.turnover, + dbh=stem_allometry.dbh, + stem_height=stem_allometry.stem_height, + ) + ) diff --git a/tests/unit/demography/conftest.py b/tests/unit/demography/conftest.py index 0a51f97f..5605db74 100644 --- a/tests/unit/demography/conftest.py +++ b/tests/unit/demography/conftest.py @@ -51,6 +51,10 @@ def rtmodel_flora(): pft_definitions = pft_definitions.drop(columns=["d"]) + # Set foliar respiration to zero to avoid issues with this being applied before + # estimating whole crown gpp in rtmodel + pft_definitions["resp_f"] = 0 + return Flora( pfts=[ PlantFunctionalType(**args) @@ -70,7 +74,6 @@ def rtmodel_data(): rdata = rdata.rename( columns={ - "dD": "delta_d", "D": "dbh", "H": "stem_height", "fc": "crown_fraction", @@ -79,18 +82,20 @@ def rtmodel_data(): "Ws": "stem_mass", "Wss": "sapwood_mass", "P0": "potential_gpp", - "GPP": "crown_gpp", - "Rm1": "resp_swd", - "Rm2": "resp_frt", - "dWs": "delta_mass_stm", - "dWfr": "delta_mass_frt", + "GPP": "whole_crown_gpp", + "Rm1": "sapwood_respiration", + "Rm2": "fine_root_respiration", + "NPP": "npp", + "dD": "delta_dbh", + "dWs": "delta_stem_mass", + "dWfr": "delta_foliage_mass", } ) # Fix some scaling differences: # The R tmodel implementation rescales reported delta_d as a radial increase in # millimetres, not diameter increase in metres - rdata["delta_d"] = rdata["delta_d"] / 500 + rdata["delta_dbh"] = rdata["delta_dbh"] / 500 # Wrap the return data into arrays with PFT as columns and diameter values as rows rdata_arrays = {k: np.reshape(v, (3, 6)).T for k, v in rdata.items()} diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 3cc65e2e..0cb420f8 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -471,7 +471,7 @@ def test_calculate_whole_crown_gpp( ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["crown_gpp"][out_idx]) + assert np.allclose(result, rtmodel_data["whole_crown_gpp"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -498,7 +498,7 @@ def test_calculate_sapwood_respiration( ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["resp_swd"][out_idx]) + assert np.allclose(result, rtmodel_data["sapwood_respiration"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -527,13 +527,14 @@ def test_calculate_foliar_respiration( with outcome as excep: result = calculate_foliar_respiration( resp_f=rtmodel_flora.resp_f[pft_idx], - whole_crown_gpp=rtmodel_data["crown_gpp"][data_idx], + whole_crown_gpp=rtmodel_data["whole_crown_gpp"][data_idx], ) assert result.shape == exp_shape assert np.allclose( result, - rtmodel_data["crown_gpp"][data_idx] * rtmodel_flora.resp_f[pft_idx], + rtmodel_data["whole_crown_gpp"][data_idx] + * rtmodel_flora.resp_f[pft_idx], ) return @@ -563,7 +564,7 @@ def test_calculate_fine_root_respiration( ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["resp_frt"][out_idx]) + assert np.allclose(result, rtmodel_data["fine_root_respiration"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -588,14 +589,14 @@ def test_calculate_net_primary_productivity( with outcome as excep: result = calculate_net_primary_productivity( yld=rtmodel_flora.yld[pft_idx], - whole_crown_gpp=rtmodel_data["crown_gpp"][data_idx], + whole_crown_gpp=rtmodel_data["whole_crown_gpp"][data_idx], foliar_respiration=0, # Not included here in the R implementation - fine_root_respiration=rtmodel_data["resp_frt"][data_idx], - sapwood_respiration=rtmodel_data["resp_swd"][data_idx], + fine_root_respiration=rtmodel_data["fine_root_respiration"][data_idx], + sapwood_respiration=rtmodel_data["sapwood_respiration"][data_idx], ) assert result.shape == exp_shape - assert np.allclose(result, rtmodel_data["NPP"][out_idx]) + assert np.allclose(result, rtmodel_data["npp"][out_idx]) return assert str(excep.value).startswith(excep_msg) @@ -658,20 +659,22 @@ def test_calculate_calculate_growth_increments( ca_ratio=rtmodel_flora.ca_ratio[pft_idx], sla=rtmodel_flora.sla[pft_idx], zeta=rtmodel_flora.zeta[pft_idx], - npp=rtmodel_data["NPP"][data_idx], + npp=rtmodel_data["npp"][data_idx], turnover=rtmodel_data["turnover"][data_idx], dbh=rtmodel_data["dbh"][data_idx], stem_height=rtmodel_data["stem_height"][data_idx], ) assert delta_d.shape == exp_shape - assert np.allclose(delta_d, rtmodel_data["delta_d"][out_idx]) + assert np.allclose(delta_d, rtmodel_data["delta_dbh"][out_idx]) assert delta_mass_stm.shape == exp_shape - assert np.allclose(delta_mass_stm, rtmodel_data["delta_mass_stm"][out_idx]) + assert np.allclose(delta_mass_stm, rtmodel_data["delta_stem_mass"][out_idx]) assert delta_mass_frt.shape == exp_shape - assert np.allclose(delta_mass_frt, rtmodel_data["delta_mass_frt"][out_idx]) + assert np.allclose( + delta_mass_frt, rtmodel_data["delta_foliage_mass"][out_idx] + ) return assert str(excep.value).startswith(excep_msg) @@ -716,6 +719,33 @@ def test_StemAllometry(rtmodel_flora, rtmodel_data): ) # Check the variables provided by the rtmodel implementation - to_check = set(stem_allometry.allometry_attrs) - set(["canopy_r0", "canopy_z_max"]) - for var in to_check: + vars_to_check = ( + v + for v in stem_allometry.allometry_attrs + if v not in ["canopy_r0", "canopy_z_max"] + ) + for var in vars_to_check: assert np.allclose(getattr(stem_allometry, var), rtmodel_data[var]) + + +def test_StemAllocation(rtmodel_flora, rtmodel_data): + """Test the StemAllometry class.""" + + from pyrealm.demography.t_model_functions import StemAllocation, StemAllometry + + stem_allometry = StemAllometry( + stem_traits=rtmodel_flora, at_dbh=rtmodel_data["dbh"][:, [0]] + ) + + stem_allocation = StemAllocation( + stem_traits=rtmodel_flora, + stem_allometry=stem_allometry, + at_potential_gpp=rtmodel_data["potential_gpp"], + ) + + # Check the variables provided by the rtmodel implementation + vars_to_check = ( + v for v in stem_allocation.allocation_attrs if v not in ["foliar_respiration"] + ) + for var in vars_to_check: + assert np.allclose(getattr(stem_allocation, var), rtmodel_data[var]) From fabf312fcd1ff296c0054116d74fdfec68166bad Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 08:36:50 +0100 Subject: [PATCH 164/241] Docstrings on StemAllocation attriubutes --- pyrealm/demography/t_model_functions.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 2995652b..23101d4b 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -772,15 +772,25 @@ class StemAllocation: # Post init allometry attributes potential_gpp: NDArray[np.float32] = field(init=False) + """Potential GPP per unit area (g C m2)""" whole_crown_gpp: NDArray[np.float32] = field(init=False) + """Estimated GPP across the whole crown (g C)""" sapwood_respiration: NDArray[np.float32] = field(init=False) + """Allocation to sapwood respiration (g C)""" foliar_respiration: NDArray[np.float32] = field(init=False) + """Allocation to foliar respiration (g C)""" fine_root_respiration: NDArray[np.float32] = field(init=False) + """Allocation to fine root respiration (g C)""" npp: NDArray[np.float32] = field(init=False) + """Net primary productivity (g C)""" turnover: NDArray[np.float32] = field(init=False) + """Allocation to leaf and fine root turnover (g C)""" delta_dbh: NDArray[np.float32] = field(init=False) + """Predicted increase in stem diameter from growth allocation (g C)""" delta_stem_mass: NDArray[np.float32] = field(init=False) + """Predicted increase in stem mass from growth allocation (g C)""" delta_foliage_mass: NDArray[np.float32] = field(init=False) + """Predicted increase in foliar mass from growth allocation (g C)""" def __post_init__( self, From 9d725f68788ae617b34ac972b151a4e509687f58 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 22:13:00 +0100 Subject: [PATCH 165/241] CrownProfile and calculate_canopy_radius --- pyrealm/demography/canopy_functions.py | 129 +++++++++++++++++++++---- 1 file changed, 111 insertions(+), 18 deletions(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 15eae194..7f22a83f 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -2,10 +2,14 @@ used in PlantFATE :cite:t:`joshi:2022a`. """ # noqa: D205 +from dataclasses import InitVar, dataclass, field + import numpy as np from numpy.typing import NDArray from pyrealm.core.utilities import check_input_shapes +from pyrealm.demography.flora import Flora, StemTraits +from pyrealm.demography.t_model_functions import StemAllometry def calculate_canopy_q_m( @@ -78,7 +82,7 @@ def calculate_canopy_z_max( def calculate_canopy_r0( q_m: NDArray[np.float32], crown_area: NDArray[np.float32] ) -> NDArray[np.float32]: - r"""Calculate scaling factor for height of maximum crown radius. + r"""Calculate scaling factor for width of maximum crown radius. This scaling factor (:math:`r_0`) is derived from the canopy shape parameters (:math:`m,n,q_m`) for plant functional types and the estimated crown area @@ -228,6 +232,38 @@ def calculate_relative_canopy_radius_at_z( return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) +def calculate_canopy_radius( + q_z: NDArray[np.float32], + r0: NDArray[np.float32], + validate: bool = True, +) -> NDArray[np.float32]: + r"""Calculate canopy radius from relative radius and canopy r0. + + The relative canopy radius (:math:`q(z)`) at a given height :math:`z` describes the + vertical profile of the canopy shape, but only varies with the ``m`` and ``n`` shape + parameters and the stem height. The actual crown radius at a given height + (:math:`r(z)`) needs to be scaled using :math:`r_0` such that the maximum crown area + equals the expected crown area given the crown area ratio traiit for the plant + functional type: + + .. math:: + + r(z) = r_0 q(z) + + This function calculates :math:`r(z)` given estimated ``r0`` and an array of + relative radius values. + + Args: + q_z: TODO + r0: TODO + validate: Boolean flag to suppress argument validation. + """ + + # TODO - think about validation here. qz must be row array or 2D (N, n_pft) + + return r0 * q_z + + def calculate_stem_projected_crown_area_at_z( z: NDArray[np.float32], q_z: NDArray[np.float32], @@ -404,28 +440,85 @@ def calculate_stem_projected_leaf_area_at_z( return A_cp -# def calculate_total_canopy_A_cp(z: float, f_g: float, community: Community) -> float: -# """Calculate total leaf area at a given height. +@dataclass +class CrownProfile: + """Calculate vertical crown profiles for stems. -# :param f_g: -# :param community: -# :param z: Height above ground. -# :return: Total leaf area in the canopy at a given height. -# """ -# A_cp_for_individuals = calculate_projected_leaf_area_for_individuals( -# z, f_g, community -# ) + This method calculates canopy profile predictions, given an array of vertical + heights (``z``) for: -# A_cp_for_cohorts = A_cp_for_individuals * community.cohort_number_of_individuals + * relativate canopy radius, + * actual canopy radius, + * projected crown area, and + * project leaf area. -# return A_cp_for_cohorts.sum() + The predictions require a set of plant functional types (PFTs) but also the expected + allometric predictions of stem height, crown area and z_max for an actual stem of a + given size for each PFT. + Args: + stem_traits: + stem_allometry: A Ste + z: An array of vertical height values at which to calculate canopy profiles. + stem_height: A row array providing expected stem height for each PFT. + crown_area: A row array providing expected crown area for each PFT. + r0: A row array providing expected r0 for each PFT. + z_max: A row array providing expected z_max height for each PFT. + """ -# def calculate_gpp(cell_ppfd: NDArray, lue: NDArray) -> float: -# """Estimate the gross primary productivity. + stem_traits: InitVar[StemTraits | Flora] + """A Flora or StemTraits instance providing plant functional trait data.""" + stem_allometry: InitVar[StemAllometry] + """A StemAllometry instance setting the stem allometries for the crown profile.""" + z: InitVar[NDArray[np.float32]] + """An array of vertical height values at which to calculate canopy profiles.""" + + relativate_crown_radius: NDArray[np.float32] = field(init=False) + """An array of the relative crown radius of stems at z heights""" + crown_radius: NDArray[np.float32] = field(init=False) + """An array of the actual crown radius of stems at z heights""" + projected_crown_area: NDArray[np.float32] = field(init=False) + """An array of the projected crown area of stems at z heights""" + project_leaf_area: NDArray[np.float32] = field(init=False) + """An array of the projected leaf area of stems at z heights""" + + def __post_init__( + self, + stem_traits: StemTraits | Flora, + stem_allometry: StemAllometry, + z: NDArray[np.float32], + ) -> None: + """Populate canopy profile attributes from the traits, allometry and height.""" + # Calculate relative crown radius + self.relative_crown_radius = calculate_relative_canopy_radius_at_z( + z=z, + m=stem_traits.m, + n=stem_traits.n, + stem_height=stem_allometry.stem_height, + ) -# Not sure where to place this - need an array of LUE that matches to the + # Calculate actual radius + self.crown_radius = calculate_canopy_radius( + q_z=self.relative_crown_radius, r0=stem_allometry.canopy_r0 + ) -# """ + # Calculate projected crown area + self.projected_crown_area = calculate_stem_projected_crown_area_at_z( + z=z, + q_z=self.relativate_crown_radius, + crown_area=stem_allometry.crown_area, + q_m=stem_traits.q_m, + stem_height=stem_allometry.stem_height, + z_max=stem_allometry.canopy_z_max, + ) -# return 100 + # Calculate projected leaf area + self.projected_leaf_area = calculate_stem_projected_leaf_area_at_z( + z=z, + q_z=self.relative_crown_radius, + f_g=stem_traits.f_g, + q_m=stem_traits.q_m, + crown_area=stem_allometry.crown_area, + stem_height=stem_allometry.stem_height, + z_max=stem_allometry.canopy_z_max, + ) From 8e1076722ded2b479ea88ce3ff653a363667e392 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 22:21:22 +0100 Subject: [PATCH 166/241] Canopy -> crown in functions and docstrings --- pyrealm/demography/canopy.py | 4 +- pyrealm/demography/canopy_functions.py | 94 +++++++++---------- pyrealm/demography/flora.py | 8 +- pyrealm/demography/t_model_functions.py | 8 +- .../unit/demography/test_canopy_functions.py | 44 ++++----- tests/unit/demography/test_flora.py | 24 ++--- 6 files changed, 91 insertions(+), 91 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 50958c79..b6aba29c 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -5,7 +5,7 @@ from scipy.optimize import root_scalar # type: ignore [import-untyped] from pyrealm.demography.canopy_functions import ( - calculate_relative_canopy_radius_at_z, + calculate_relative_crown_radius_at_z, calculate_stem_projected_crown_area_at_z, calculate_stem_projected_leaf_area_at_z, solve_community_projected_canopy_area, @@ -134,7 +134,7 @@ def _calculate_canopy(self, community: Community) -> None: # NOTE - here and in the calls below, validate=False is enforced because the # Community class structures and code should guarantee valid inputs and so # turning off the validation internally should simply speed up the code. - self.stem_relative_radius = calculate_relative_canopy_radius_at_z( + self.stem_relative_radius = calculate_relative_crown_radius_at_z( z=self.layer_heights, stem_height=community.stem_allometry.stem_height, m=community.stem_traits.m, diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 7f22a83f..42cf02a5 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -1,4 +1,4 @@ -"""A set of functions implementing the canopy shape and vertical leaf distribution model +"""A set of functions implementing the crown shape and vertical leaf distribution model used in PlantFATE :cite:t:`joshi:2022a`. """ # noqa: D205 @@ -12,17 +12,17 @@ from pyrealm.demography.t_model_functions import StemAllometry -def calculate_canopy_q_m( +def calculate_crown_q_m( m: float | NDArray[np.float32], n: float | NDArray[np.float32] ) -> float | NDArray[np.float32]: - """Calculate the canopy scaling paramater ``q_m``. + """Calculate the crown scaling paramater ``q_m``. - The value of q_m is a constant canopy scaling parameter derived from the ``m`` and + The value of q_m is a constant crown scaling parameter derived from the ``m`` and ``n`` attributes defined for a plant functional type. Args: - m: Canopy shape parameter - n: Canopy shape parameter + m: Crown shape parameter + n: Crown shape parameter """ return ( m @@ -32,7 +32,7 @@ def calculate_canopy_q_m( ) -def calculate_canopy_z_max_proportion( +def calculate_crown_z_max_proportion( m: float | NDArray[np.float32], n: float | NDArray[np.float32] ) -> float | NDArray[np.float32]: r"""Calculate the z_m proportion. @@ -45,24 +45,24 @@ def calculate_canopy_z_max_proportion( p_{zm} = \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}} Args: - m: Canopy shape parameter - n: Canopy shape parameter + m: Crown shape parameter + n: Crown shape parameter """ return ((n - 1) / (m * n - 1)) ** (1 / n) -def calculate_canopy_z_max( +def calculate_crown_z_max( z_max_prop: NDArray[np.float32], stem_height: NDArray[np.float32] ) -> NDArray[np.float32]: r"""Calculate height of maximum crown radius. - The height of the maximum crown radius (:math:`z_m`) is derived from the canopy + The height of the maximum crown radius (:math:`z_m`) is derived from the crown shape parameters (:math:`m,n`) and the resulting fixed proportion (:math:`p_{zm}`) for plant functional types. These shape parameters are defined as part of the extension of the T Model presented by :cite:t:`joshi:2022a`. - The value :math:`z_m` is the height above ground where the largest canopy radius is + The value :math:`z_m` is the height above ground where the largest crown radius is found, given the proportion and the estimated stem height (:math:`H`) of individuals. @@ -71,7 +71,7 @@ def calculate_canopy_z_max( z_m = p_{zm} H Args: - z_max_prop: Canopy shape parameter of the PFT + z_max_prop: Crown shape parameter of the PFT stem_height: Stem height of individuals """ """Calculate z_m, the height of maximum crown radius.""" @@ -79,12 +79,12 @@ def calculate_canopy_z_max( return stem_height * z_max_prop -def calculate_canopy_r0( +def calculate_crown_r0( q_m: NDArray[np.float32], crown_area: NDArray[np.float32] ) -> NDArray[np.float32]: r"""Calculate scaling factor for width of maximum crown radius. - This scaling factor (:math:`r_0`) is derived from the canopy shape parameters + This scaling factor (:math:`r_0`) is derived from the crown shape parameters (:math:`m,n,q_m`) for plant functional types and the estimated crown area (:math:`A_c`) of individuals. The shape parameters are defined as part of the extension of the T Model presented by :cite:t:`joshi:2022a` and :math:`r_0` is used @@ -96,7 +96,7 @@ def calculate_canopy_r0( r_0 = 1/q_m \sqrt{A_c / \pi} Args: - q_m: Canopy shape parameter of the PFT + q_m: Crown shape parameter of the PFT crown_area: Crown area of individuals """ # Scaling factor to give expected A_c (crown area) at @@ -110,16 +110,16 @@ def _validate_z_qz_args( stem_properties: list[NDArray[np.float32]], q_z: NDArray[np.float32] | None = None, ) -> None: - """Shared validation of for canopy function arguments. + """Shared validation of for crown function arguments. - Several of the canopy functions in this module require a vertical height (``z``) - argument and, in some cases, the relative canopy radius (``q_z``) at that height. + Several of the crown functions in this module require a vertical height (``z``) + argument and, in some cases, the relative crown radius (``q_z``) at that height. These arguments need to have shapes that are congruent with each other and with the arrays providing stem properties for which values are calculated. This function provides the following validation checks (see also the documentation of accepted shapes for ``z`` in - :meth:`~pyrealm.demography.canopy_functions.calculate_relative_canopy_radius_at_z`). + :meth:`~pyrealm.demography.canopy_functions.calculate_relative_crown_radius_at_z`). * Stem properties are identically shaped row (1D) arrays. * The ``z`` argument is then one of: @@ -132,9 +132,9 @@ def _validate_z_qz_args( n_stem_properties``). Args: - z: An array input to the ``z`` argument of a canopy function. + z: An array input to the ``z`` argument of a crown function. stem_properties: A list of array inputs representing stem properties. - q_z: An optional array input to the ``q_z`` argument of a canopy function. + q_z: An optional array input to the ``q_z`` argument of a crown function. """ # Check the stem properties @@ -184,18 +184,18 @@ def _validate_z_qz_args( return -def calculate_relative_canopy_radius_at_z( +def calculate_relative_crown_radius_at_z( z: NDArray[np.float32], stem_height: NDArray[np.float32], m: NDArray[np.float32], n: NDArray[np.float32], validate: bool = True, ) -> NDArray[np.float32]: - r"""Calculate relative canopy radius at a given height. + r"""Calculate relative crown radius at a given height. - The canopy shape parameters ``m`` and ``n`` define the vertical distribution of - canopy along the stem. For a stem of a given total height, this function calculates - the relative canopy radius at a given height :math:`z`: + The crown shape parameters ``m`` and ``n`` define the vertical distribution of + crown along the stem. For a stem of a given total height, this function calculates + the relative crown radius at a given height :math:`z`: .. math:: @@ -232,15 +232,15 @@ def calculate_relative_canopy_radius_at_z( return m * n * z_over_height ** (n - 1) * (1 - z_over_height**n) ** (m - 1) -def calculate_canopy_radius( +def calculate_crown_radius( q_z: NDArray[np.float32], r0: NDArray[np.float32], validate: bool = True, ) -> NDArray[np.float32]: - r"""Calculate canopy radius from relative radius and canopy r0. + r"""Calculate crown radius from relative crown radius and crown r0. - The relative canopy radius (:math:`q(z)`) at a given height :math:`z` describes the - vertical profile of the canopy shape, but only varies with the ``m`` and ``n`` shape + The relative crown radius (:math:`q(z)`) at a given height :math:`z` describes the + vertical profile of the crown shape, but only varies with the ``m`` and ``n`` shape parameters and the stem height. The actual crown radius at a given height (:math:`r(z)`) needs to be scaled using :math:`r_0` such that the maximum crown area equals the expected crown area given the crown area ratio traiit for the plant @@ -280,7 +280,7 @@ def calculate_stem_projected_crown_area_at_z( arguments ``stem_height``,``crown_area``,``q_m`` and ``z_max``, which must be one-dimensional arrays ('row vectors') of equal length. The array of vertical heights ``z`` accepts a range of input shapes (see - :meth:`~pyrealm.demography.canopy_functions.calculate_relative_canopy_radius_at_z` + :meth:`~pyrealm.demography.canopy_functions.calculate_relative_crown_radius_at_z` ) and this function then also requires the expected relative stem radius (``q_z``) calculated from those heights. @@ -322,14 +322,14 @@ def solve_community_projected_canopy_area( target_area: float = 0, validate: bool = True, ) -> NDArray[np.float32]: - """Solver function for community wide projected crown area. + """Solver function for community wide projected canopy area. This function takes the number of individuals in each cohort along with the stem height and crown area and a given vertical height (:math:`z`). It then uses the - canopy shape parameters associated with each cohort to calculate the community wide + crown shape parameters associated with each cohort to calculate the community wide projected crown area above that height (:math:`A_p(z)`). This is simply the sum of - the products of the individual stem projected area at :math:`z` and the number of - individuals in each cohort. + the products of the individual stem crown projected area at :math:`z` and the number + of individuals in each cohort. The return value is the difference between the calculated :math:`A_p(z)` and a user-specified target area, This allows the function to be used with a root solver @@ -346,10 +346,10 @@ def solve_community_projected_canopy_area( n_individuals: Number of individuals in each cohort crown_area: Crown area of each cohort stem_height: Stem height of each cohort - m: Canopy shape parameter ``m``` for each cohort - n: Canopy shape parameter ``n``` for each cohort - q_m: Canopy shape parameter ``q_m``` for each cohort - z_max: Canopy shape parameter ``z_m``` for each cohort + m: Crown shape parameter ``m``` for each cohort + n: Crown shape parameter ``n``` for each cohort + q_m: Crown shape parameter ``q_m``` for each cohort + z_max: Crown shape parameter ``z_m``` for each cohort target_area: A target projected crown area. validate: Boolean flag to suppress argument validation. """ @@ -362,7 +362,7 @@ def solve_community_projected_canopy_area( stem_properties=[n_individuals, crown_area, stem_height, m, n, q_m, z_max], ) - q_z = calculate_relative_canopy_radius_at_z( + q_z = calculate_relative_crown_radius_at_z( z=z_arr, stem_height=stem_height, m=m, n=n, validate=False ) # Calculate A(p) for the stems in each cohort @@ -394,14 +394,14 @@ def calculate_stem_projected_leaf_area_at_z( This function calculates the projected leaf area of a set of stems with given properties at a set of vertical heights. This differs from crown area in allowing for crown openness within the crown of an individual stem that results in the - displacement of leaf area further down into the canopy. The degree of openness is + displacement of leaf area further down into the crown. The degree of openness is controlled by the crown gap fraction property of each stem. The stem properties are given in the arguments ``stem_height``,``crown_area``,``f_g``,``q_m`` and ``z_max``, which must be one-dimensional arrays ('row vectors') of equal length. The array of vertical heights ``z`` accepts a range of input shapes (see - :meth:`~pyrealm.demography.canopy_functions.calculate_relative_canopy_radius_at_z` + :meth:`~pyrealm.demography.canopy_functions.calculate_relative_crown_radius_at_z` ) and this function then also requires the expected relative stem radius (``q_z``) calculated from those heights. @@ -412,13 +412,13 @@ def calculate_stem_projected_leaf_area_at_z( stem_height: Total height of a stem f_g: Within crown gap fraction for each stem. q_m: Canopy shape parameter ``q_m``` for each stem - z_max: Height of maximum canopy radius for each stem + z_max: Height of maximum crown radius for each stem validate: Boolean flag to suppress argument validation. """ # NOTE: Although the internals of this function overlap a lot with # calculate_stem_projected_crown_area_at_z, we want that function to be as - # lean as possible, as it used within solve_community_projected_canopy_area. + # lean as possible, as it used within solve_community_projected_crown_area. if validate: _validate_z_qz_args( @@ -490,7 +490,7 @@ def __post_init__( ) -> None: """Populate canopy profile attributes from the traits, allometry and height.""" # Calculate relative crown radius - self.relative_crown_radius = calculate_relative_canopy_radius_at_z( + self.relative_crown_radius = calculate_relative_crown_radius_at_z( z=z, m=stem_traits.m, n=stem_traits.n, @@ -498,7 +498,7 @@ def __post_init__( ) # Calculate actual radius - self.crown_radius = calculate_canopy_radius( + self.crown_radius = calculate_crown_radius( q_z=self.relative_crown_radius, r0=stem_allometry.canopy_r0 ) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index e8ec5c2e..8dadc788 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -34,8 +34,8 @@ from numpy.typing import NDArray from pyrealm.demography.canopy_functions import ( - calculate_canopy_q_m, - calculate_canopy_z_max_proportion, + calculate_crown_q_m, + calculate_crown_z_max_proportion, ) if sys.version_info[:2] >= (3, 11): @@ -122,9 +122,9 @@ def __post_init__(self) -> None: # Calculate q_m and z_max proportion. Need to use __setattr__ because the # dataclass is frozen. - object.__setattr__(self, "q_m", calculate_canopy_q_m(m=self.m, n=self.n)) + object.__setattr__(self, "q_m", calculate_crown_q_m(m=self.m, n=self.n)) object.__setattr__( - self, "z_max_prop", calculate_canopy_z_max_proportion(m=self.m, n=self.n) + self, "z_max_prop", calculate_crown_z_max_proportion(m=self.m, n=self.n) ) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 23101d4b..096f5ae6 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -13,8 +13,8 @@ from pyrealm.core.utilities import check_input_shapes from pyrealm.demography.canopy_functions import ( - calculate_canopy_r0, - calculate_canopy_z_max, + calculate_crown_r0, + calculate_crown_z_max, ) from pyrealm.demography.flora import Flora, StemTraits @@ -715,12 +715,12 @@ def __post_init__( crown_fraction=self.crown_fraction, ) - self.canopy_r0 = calculate_canopy_r0( + self.canopy_r0 = calculate_crown_r0( q_m=stem_traits.q_m, crown_area=self.crown_area, ) - self.canopy_z_max = calculate_canopy_z_max( + self.canopy_z_max = calculate_crown_z_max( z_max_prop=stem_traits.z_max_prop, stem_height=self.stem_height, ) diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index 7681fa87..0cd178d6 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -41,24 +41,24 @@ def fixture_community(): ) -def test_calculate_canopy_q_m(fixture_canopy_shape): - """Test calculate_canopy_q_m.""" +def test_calculate_crown_q_m(fixture_canopy_shape): + """Test calculate_crown_q_m.""" - from pyrealm.demography.canopy_functions import calculate_canopy_q_m + from pyrealm.demography.canopy_functions import calculate_crown_q_m - actual_q_m_values = calculate_canopy_q_m( + actual_q_m_values = calculate_crown_q_m( m=fixture_canopy_shape["m"], n=fixture_canopy_shape["n"] ) assert np.allclose(actual_q_m_values, fixture_canopy_shape["q_m"]) -def test_calculate_canopy_z_max_proportion(fixture_canopy_shape): - """Test calculate_canopy_z_max_proportion.""" +def test_calculate_crown_z_max_proportion(fixture_canopy_shape): + """Test calculate_crown_z_max_proportion.""" - from pyrealm.demography.canopy_functions import calculate_canopy_z_max_proportion + from pyrealm.demography.canopy_functions import calculate_crown_z_max_proportion - actual_p_zm = calculate_canopy_z_max_proportion( + actual_p_zm = calculate_crown_z_max_proportion( m=fixture_canopy_shape["m"], n=fixture_canopy_shape["n"] ) @@ -75,9 +75,9 @@ def test_calculate_canopy_z_max_proportion(fixture_canopy_shape): def test_calculate_r_0_values(fixture_canopy_shape, crown_areas, expected_r0): """Test happy path for calculating r_0.""" - from pyrealm.demography.canopy_functions import calculate_canopy_r0 + from pyrealm.demography.canopy_functions import calculate_crown_r0 - actual_r0_values = calculate_canopy_r0( + actual_r0_values = calculate_crown_r0( q_m=fixture_canopy_shape["q_m"], crown_area=crown_areas ) @@ -361,14 +361,14 @@ def test__validate_z_qz__args(fixture_z_qz_stem_properties): ], indirect=["fixture_z_qz_stem_properties"], ) -def test_calculate_relative_canopy_radius_at_z_inputs(fixture_z_qz_stem_properties): - """Test calculate_relative_canopy_radius_at_z input and output shapes . +def test_calculate_relative_crown_radius_at_z_inputs(fixture_z_qz_stem_properties): + """Test calculate_relative_crown_radius_at_z input and output shapes . This test checks the function behaviour with different inputs. """ from pyrealm.demography.canopy_functions import ( - calculate_relative_canopy_radius_at_z, + calculate_relative_crown_radius_at_z, ) # Build inputs @@ -377,7 +377,7 @@ def test_calculate_relative_canopy_radius_at_z_inputs(fixture_z_qz_stem_properti with outcome as excep: # Get the relative radius at that height - q_z_values = calculate_relative_canopy_radius_at_z(z, *stem_args) + q_z_values = calculate_relative_crown_radius_at_z(z, *stem_args) if isinstance(outcome, does_not_raise): assert q_z_values.shape == out_shape @@ -387,8 +387,8 @@ def test_calculate_relative_canopy_radius_at_z_inputs(fixture_z_qz_stem_properti assert str(excep.value).startswith(excep_msg) -def test_calculate_relative_canopy_radius_at_z_values(fixture_community): - """Test calculate_relative_canopy_radius_at_z. +def test_calculate_relative_crown_radius_at_z_values(fixture_community): + """Test calculate_relative_crown_radius_at_z. This test validates the expectation that the canopy shape model correctly predicts the crown area from the T Model equations at the predicted height of @@ -396,7 +396,7 @@ def test_calculate_relative_canopy_radius_at_z_values(fixture_community): """ from pyrealm.demography.canopy_functions import ( - calculate_relative_canopy_radius_at_z, + calculate_relative_crown_radius_at_z, ) # Canopy shape model gives the maximum radius at a height z_max @@ -406,7 +406,7 @@ def test_calculate_relative_canopy_radius_at_z_values(fixture_community): ) # Get the relative radius at that height - q_z_values = calculate_relative_canopy_radius_at_z( + q_z_values = calculate_relative_crown_radius_at_z( z=z_max, stem_height=fixture_community.stem_allometry.stem_height, m=fixture_community.stem_traits.m, @@ -502,12 +502,12 @@ def test_calculate_stem_projected_crown_area_at_z_values( """ from pyrealm.demography.canopy_functions import ( - calculate_relative_canopy_radius_at_z, + calculate_relative_crown_radius_at_z, calculate_stem_projected_crown_area_at_z, ) # Calculate the required q_z - q_z = calculate_relative_canopy_radius_at_z( + q_z = calculate_relative_crown_radius_at_z( z=heights, stem_height=fixture_community.stem_allometry.stem_height, m=fixture_community.stem_traits.m, @@ -617,7 +617,7 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): """ from pyrealm.demography.canopy_functions import ( - calculate_relative_canopy_radius_at_z, + calculate_relative_crown_radius_at_z, calculate_stem_projected_leaf_area_at_z, ) @@ -625,7 +625,7 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): # to the highest z_max = fixture_community.stem_allometry.canopy_z_max[:, None] - q_z = calculate_relative_canopy_radius_at_z( + q_z = calculate_relative_crown_radius_at_z( z=z_max, stem_height=fixture_community.stem_allometry.stem_height, m=fixture_community.stem_traits.m, diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index bf82be7f..74e93145 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -56,8 +56,8 @@ def test_PlantFunctionalTypeStrict__init__(args, outcome): from pyrealm.demography.flora import ( PlantFunctionalTypeStrict, - calculate_canopy_q_m, - calculate_canopy_z_max_proportion, + calculate_crown_q_m, + calculate_crown_z_max_proportion, ) with outcome: @@ -67,8 +67,8 @@ def test_PlantFunctionalTypeStrict__init__(args, outcome): if isinstance(outcome, does_not_raise): assert pft.name == "broadleaf" # Expected values from defaults - assert pft.q_m == calculate_canopy_q_m(m=2, n=5) - assert pft.z_max_prop == calculate_canopy_z_max_proportion(m=2, n=5) + assert pft.q_m == calculate_crown_q_m(m=2, n=5) + assert pft.z_max_prop == calculate_crown_z_max_proportion(m=2, n=5) # @@ -88,8 +88,8 @@ def test_PlantFunctionalType__init__(args, outcome): from pyrealm.demography.flora import ( PlantFunctionalType, - calculate_canopy_q_m, - calculate_canopy_z_max_proportion, + calculate_crown_q_m, + calculate_crown_z_max_proportion, ) with outcome: @@ -99,8 +99,8 @@ def test_PlantFunctionalType__init__(args, outcome): if isinstance(outcome, does_not_raise): assert pft.name == "broadleaf" # Expected values from defaults - assert pft.q_m == calculate_canopy_q_m(m=2, n=5) - assert pft.z_max_prop == calculate_canopy_z_max_proportion(m=2, n=5) + assert pft.q_m == calculate_crown_q_m(m=2, n=5) + assert pft.z_max_prop == calculate_crown_z_max_proportion(m=2, n=5) # @@ -115,9 +115,9 @@ def test_PlantFunctionalType__init__(args, outcome): def test_pft_calculate_q_m(m, n, q_m): """Test calculation of q_m.""" - from pyrealm.demography.flora import calculate_canopy_q_m + from pyrealm.demography.flora import calculate_crown_q_m - calculated_q_m = calculate_canopy_q_m(m, n) + calculated_q_m = calculate_crown_q_m(m, n) assert calculated_q_m == pytest.approx(q_m) @@ -138,9 +138,9 @@ def test_calculate_q_m_values_raises_exception_for_invalid_input(): def test_pft_calculate_z_max_ratio(m, n, z_max_ratio): """Test calculation of z_max proportion.""" - from pyrealm.demography.flora import calculate_canopy_z_max_proportion + from pyrealm.demography.flora import calculate_crown_z_max_proportion - calculated_zmr = calculate_canopy_z_max_proportion(m, n) + calculated_zmr = calculate_crown_z_max_proportion(m, n) assert calculated_zmr == pytest.approx(z_max_ratio) From 8dfdfd528d92cfd791a2b4412e9aac035aa1b760 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 22:23:04 +0100 Subject: [PATCH 167/241] More canopy -> crown --- pyrealm/demography/canopy.py | 6 +++--- pyrealm/demography/canopy_functions.py | 18 +++++++++--------- pyrealm/demography/t_model_functions.py | 14 +++++++------- tests/unit/demography/test_canopy_functions.py | 14 +++++++------- .../unit/demography/test_t_model_functions.py | 2 +- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index b6aba29c..91694326 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -114,7 +114,7 @@ def _calculate_canopy(self, community: Community) -> None: community.stem_traits.m, community.stem_traits.n, community.stem_traits.q_m, - community.stem_allometry.canopy_z_max, + community.stem_allometry.crown_z_max, community.cohort_data["n_individuals"], target_area, False, # validate @@ -149,7 +149,7 @@ def _calculate_canopy(self, community: Community) -> None: crown_area=community.stem_allometry.crown_area, stem_height=community.stem_allometry.stem_height, q_m=community.stem_traits.q_m, - z_max=community.stem_allometry.canopy_z_max, + z_max=community.stem_allometry.crown_z_max, validate=False, ) @@ -161,6 +161,6 @@ def _calculate_canopy(self, community: Community) -> None: stem_height=community.stem_allometry.stem_height, f_g=community.stem_traits.f_g, q_m=community.stem_traits.q_m, - z_max=community.stem_allometry.canopy_z_max, + z_max=community.stem_allometry.crown_z_max, validate=False, ) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 42cf02a5..65cf2d38 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -444,11 +444,11 @@ def calculate_stem_projected_leaf_area_at_z( class CrownProfile: """Calculate vertical crown profiles for stems. - This method calculates canopy profile predictions, given an array of vertical + This method calculates crown profile predictions, given an array of vertical heights (``z``) for: - * relativate canopy radius, - * actual canopy radius, + * relativate crown radius, + * actual crown radius, * projected crown area, and * project leaf area. @@ -459,7 +459,7 @@ class CrownProfile: Args: stem_traits: stem_allometry: A Ste - z: An array of vertical height values at which to calculate canopy profiles. + z: An array of vertical height values at which to calculate crown profiles. stem_height: A row array providing expected stem height for each PFT. crown_area: A row array providing expected crown area for each PFT. r0: A row array providing expected r0 for each PFT. @@ -471,7 +471,7 @@ class CrownProfile: stem_allometry: InitVar[StemAllometry] """A StemAllometry instance setting the stem allometries for the crown profile.""" z: InitVar[NDArray[np.float32]] - """An array of vertical height values at which to calculate canopy profiles.""" + """An array of vertical height values at which to calculate crown profiles.""" relativate_crown_radius: NDArray[np.float32] = field(init=False) """An array of the relative crown radius of stems at z heights""" @@ -488,7 +488,7 @@ def __post_init__( stem_allometry: StemAllometry, z: NDArray[np.float32], ) -> None: - """Populate canopy profile attributes from the traits, allometry and height.""" + """Populate crown profile attributes from the traits, allometry and height.""" # Calculate relative crown radius self.relative_crown_radius = calculate_relative_crown_radius_at_z( z=z, @@ -499,7 +499,7 @@ def __post_init__( # Calculate actual radius self.crown_radius = calculate_crown_radius( - q_z=self.relative_crown_radius, r0=stem_allometry.canopy_r0 + q_z=self.relative_crown_radius, r0=stem_allometry.crown_r0 ) # Calculate projected crown area @@ -509,7 +509,7 @@ def __post_init__( crown_area=stem_allometry.crown_area, q_m=stem_traits.q_m, stem_height=stem_allometry.stem_height, - z_max=stem_allometry.canopy_z_max, + z_max=stem_allometry.crown_z_max, ) # Calculate projected leaf area @@ -520,5 +520,5 @@ def __post_init__( q_m=stem_traits.q_m, crown_area=stem_allometry.crown_area, stem_height=stem_allometry.stem_height, - z_max=stem_allometry.canopy_z_max, + z_max=stem_allometry.crown_z_max, ) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index 096f5ae6..b4a78f4d 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -635,8 +635,8 @@ class StemAllometry: "stem_mass", "foliage_mass", "sapwood_mass", - "canopy_r0", - "canopy_z_max", + "crown_r0", + "crown_z_max", ) # Init vars @@ -663,9 +663,9 @@ class StemAllometry: """Foliage mass (kg)""" sapwood_mass: NDArray[np.float32] = field(init=False) """Sapwood mass (kg)""" - canopy_r0: NDArray[np.float32] = field(init=False) - """Canopy radius scaling factor (-)""" - canopy_z_max: NDArray[np.float32] = field(init=False) + crown_r0: NDArray[np.float32] = field(init=False) + """Crown radius scaling factor (-)""" + crown_z_max: NDArray[np.float32] = field(init=False) """Height of maximum crown radius (metres)""" def __post_init__( @@ -715,12 +715,12 @@ def __post_init__( crown_fraction=self.crown_fraction, ) - self.canopy_r0 = calculate_crown_r0( + self.crown_r0 = calculate_crown_r0( q_m=stem_traits.q_m, crown_area=self.crown_area, ) - self.canopy_z_max = calculate_crown_z_max( + self.crown_z_max = calculate_crown_z_max( z_max_prop=stem_traits.z_max_prop, stem_height=self.stem_height, ) diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index 0cd178d6..2d93576f 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -417,7 +417,7 @@ def test_calculate_relative_crown_radius_at_z_values(fixture_community): # prediction from the T model allometric equations. assert np.allclose( fixture_community.stem_allometry.crown_area, - np.pi * (q_z_values * fixture_community.stem_allometry.canopy_r0) ** 2, + np.pi * (q_z_values * fixture_community.stem_allometry.crown_r0) ** 2, ) @@ -521,7 +521,7 @@ def test_calculate_stem_projected_crown_area_at_z_values( stem_height=fixture_community.stem_allometry.stem_height, crown_area=fixture_community.stem_allometry.crown_area, q_m=fixture_community.stem_traits.q_m, - z_max=fixture_community.stem_allometry.canopy_z_max, + z_max=fixture_community.stem_allometry.crown_z_max, ) assert np.allclose( @@ -548,7 +548,7 @@ def test_solve_community_projected_canopy_area(fixture_community): this_height, this_target, ) in zip( - np.flip(fixture_community.stem_allometry.canopy_z_max), + np.flip(fixture_community.stem_allometry.crown_z_max), np.cumsum(np.flip(fixture_community.stem_allometry.crown_area)), ): solved = solve_community_projected_canopy_area( @@ -559,7 +559,7 @@ def test_solve_community_projected_canopy_area(fixture_community): m=fixture_community.stem_traits.m, n=fixture_community.stem_traits.n, q_m=fixture_community.stem_traits.q_m, - z_max=fixture_community.stem_allometry.canopy_z_max, + z_max=fixture_community.stem_allometry.crown_z_max, target_area=this_target, ) @@ -623,7 +623,7 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): # Calculate the leaf areas at the locations of z_max for each stem from the lowest # to the highest - z_max = fixture_community.stem_allometry.canopy_z_max[:, None] + z_max = fixture_community.stem_allometry.crown_z_max[:, None] q_z = calculate_relative_crown_radius_at_z( z=z_max, @@ -639,7 +639,7 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): crown_area=fixture_community.stem_allometry.crown_area, f_g=fixture_community.stem_traits.f_g, q_m=fixture_community.stem_traits.q_m, - z_max=fixture_community.stem_allometry.canopy_z_max, + z_max=fixture_community.stem_allometry.crown_z_max, ) # Pre-calculated values @@ -673,7 +673,7 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): crown_area=fixture_community.stem_allometry.crown_area, f_g=fixture_community.stem_traits.f_g, q_m=fixture_community.stem_traits.q_m, - z_max=fixture_community.stem_allometry.canopy_z_max, + z_max=fixture_community.stem_allometry.crown_z_max, ) expected_leaf_area_fg002 = np.array( diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index 0cb420f8..f183662a 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -722,7 +722,7 @@ def test_StemAllometry(rtmodel_flora, rtmodel_data): vars_to_check = ( v for v in stem_allometry.allometry_attrs - if v not in ["canopy_r0", "canopy_z_max"] + if v not in ["crown_r0", "crown_z_max"] ) for var in vars_to_check: assert np.allclose(getattr(stem_allometry, var), rtmodel_data[var]) From de412677f96ef542eec65459e2cefca1f75e8fac Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 22:28:17 +0100 Subject: [PATCH 168/241] Move crown trait functions for crown_qm and crown_z_max into flora module --- pyrealm/demography/canopy_functions.py | 40 ----------------------- pyrealm/demography/flora.py | 45 +++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 45 deletions(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 65cf2d38..18face46 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -12,46 +12,6 @@ from pyrealm.demography.t_model_functions import StemAllometry -def calculate_crown_q_m( - m: float | NDArray[np.float32], n: float | NDArray[np.float32] -) -> float | NDArray[np.float32]: - """Calculate the crown scaling paramater ``q_m``. - - The value of q_m is a constant crown scaling parameter derived from the ``m`` and - ``n`` attributes defined for a plant functional type. - - Args: - m: Crown shape parameter - n: Crown shape parameter - """ - return ( - m - * n - * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) - * (((m - 1) * n) / (m * n - 1)) ** (m - 1) - ) - - -def calculate_crown_z_max_proportion( - m: float | NDArray[np.float32], n: float | NDArray[np.float32] -) -> float | NDArray[np.float32]: - r"""Calculate the z_m proportion. - - The z_m proportion (:math:`p_{zm}`) is the constant proportion of stem height at - which the maximum crown radius is found for a given plant functional type. - - .. math:: - - p_{zm} = \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}} - - Args: - m: Crown shape parameter - n: Crown shape parameter - """ - - return ((n - 1) / (m * n - 1)) ** (1 / n) - - def calculate_crown_z_max( z_max_prop: NDArray[np.float32], stem_height: NDArray[np.float32] ) -> NDArray[np.float32]: diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 8dadc788..b77d4ea8 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -33,11 +33,6 @@ from marshmallow.exceptions import ValidationError from numpy.typing import NDArray -from pyrealm.demography.canopy_functions import ( - calculate_crown_q_m, - calculate_crown_z_max_proportion, -) - if sys.version_info[:2] >= (3, 11): import tomllib from tomllib import TOMLDecodeError @@ -46,6 +41,46 @@ from tomli import TOMLDecodeError +def calculate_crown_q_m( + m: float | NDArray[np.float32], n: float | NDArray[np.float32] +) -> float | NDArray[np.float32]: + """Calculate the crown scaling trait ``q_m``. + + The value of q_m is a constant crown scaling parameter derived from the ``m`` and + ``n`` attributes defined for a plant functional type. + + Args: + m: Crown shape parameter + n: Crown shape parameter + """ + return ( + m + * n + * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) + * (((m - 1) * n) / (m * n - 1)) ** (m - 1) + ) + + +def calculate_crown_z_max_proportion( + m: float | NDArray[np.float32], n: float | NDArray[np.float32] +) -> float | NDArray[np.float32]: + r"""Calculate the z_m trait. + + The z_m proportion (:math:`p_{zm}`) is the constant proportion of stem height at + which the maximum crown radius is found for a given plant functional type. + + .. math:: + + p_{zm} = \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}} + + Args: + m: Crown shape parameter + n: Crown shape parameter + """ + + return ((n - 1) / (m * n - 1)) ** (1 / n) + + @dataclass(frozen=True) class PlantFunctionalTypeStrict: """The PlantFunctionalTypeStrict dataclass. From e3800db31996ffbc3b6cb90105587e84f53eeee4 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 22:31:18 +0100 Subject: [PATCH 169/241] Move crown_r0 and crown_zmax allometry functions into t_model_functions --- pyrealm/demography/canopy_functions.py | 53 ----------------------- pyrealm/demography/t_model_functions.py | 57 +++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 57 deletions(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 18face46..7461cff2 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -12,59 +12,6 @@ from pyrealm.demography.t_model_functions import StemAllometry -def calculate_crown_z_max( - z_max_prop: NDArray[np.float32], stem_height: NDArray[np.float32] -) -> NDArray[np.float32]: - r"""Calculate height of maximum crown radius. - - The height of the maximum crown radius (:math:`z_m`) is derived from the crown - shape parameters (:math:`m,n`) and the resulting fixed proportion (:math:`p_{zm}`) - for plant functional types. These shape parameters are defined as part of the - extension of the T Model presented by :cite:t:`joshi:2022a`. - - The value :math:`z_m` is the height above ground where the largest crown radius is - found, given the proportion and the estimated stem height (:math:`H`) of - individuals. - - .. math:: - - z_m = p_{zm} H - - Args: - z_max_prop: Crown shape parameter of the PFT - stem_height: Stem height of individuals - """ - """Calculate z_m, the height of maximum crown radius.""" - - return stem_height * z_max_prop - - -def calculate_crown_r0( - q_m: NDArray[np.float32], crown_area: NDArray[np.float32] -) -> NDArray[np.float32]: - r"""Calculate scaling factor for width of maximum crown radius. - - This scaling factor (:math:`r_0`) is derived from the crown shape parameters - (:math:`m,n,q_m`) for plant functional types and the estimated crown area - (:math:`A_c`) of individuals. The shape parameters are defined as part of the - extension of the T Model presented by :cite:t:`joshi:2022a` and :math:`r_0` is used - to scale the crown area such that the crown area at the maximum crown radius fits - the expectations of the T Model. - - .. math:: - - r_0 = 1/q_m \sqrt{A_c / \pi} - - Args: - q_m: Crown shape parameter of the PFT - crown_area: Crown area of individuals - """ - # Scaling factor to give expected A_c (crown area) at - # z_m (height of maximum crown radius) - - return 1 / q_m * np.sqrt(crown_area / np.pi) - - def _validate_z_qz_args( z: NDArray[np.float32], stem_properties: list[NDArray[np.float32]], diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index b4a78f4d..fa1be81d 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -12,10 +12,6 @@ from numpy.typing import NDArray from pyrealm.core.utilities import check_input_shapes -from pyrealm.demography.canopy_functions import ( - calculate_crown_r0, - calculate_crown_z_max, -) from pyrealm.demography.flora import Flora, StemTraits @@ -290,6 +286,59 @@ def calculate_sapwood_masses( return crown_area * rho_s * stem_height * (1 - crown_fraction / 2) / ca_ratio +def calculate_crown_z_max( + z_max_prop: NDArray[np.float32], stem_height: NDArray[np.float32] +) -> NDArray[np.float32]: + r"""Calculate height of maximum crown radius. + + The height of the maximum crown radius (:math:`z_m`) is derived from the crown + shape parameters (:math:`m,n`) and the resulting fixed proportion (:math:`p_{zm}`) + for plant functional types. These shape parameters are defined as part of the + extension of the T Model presented by :cite:t:`joshi:2022a`. + + The value :math:`z_m` is the height above ground where the largest crown radius is + found, given the proportion and the estimated stem height (:math:`H`) of + individuals. + + .. math:: + + z_m = p_{zm} H + + Args: + z_max_prop: Crown shape parameter of the PFT + stem_height: Stem height of individuals + """ + """Calculate z_m, the height of maximum crown radius.""" + + return stem_height * z_max_prop + + +def calculate_crown_r0( + q_m: NDArray[np.float32], crown_area: NDArray[np.float32] +) -> NDArray[np.float32]: + r"""Calculate scaling factor for width of maximum crown radius. + + This scaling factor (:math:`r_0`) is derived from the crown shape parameters + (:math:`m,n,q_m`) for plant functional types and the estimated crown area + (:math:`A_c`) of individuals. The shape parameters are defined as part of the + extension of the T Model presented by :cite:t:`joshi:2022a` and :math:`r_0` is used + to scale the crown area such that the crown area at the maximum crown radius fits + the expectations of the T Model. + + .. math:: + + r_0 = 1/q_m \sqrt{A_c / \pi} + + Args: + q_m: Crown shape parameter of the PFT + crown_area: Crown area of individuals + """ + # Scaling factor to give expected A_c (crown area) at + # z_m (height of maximum crown radius) + + return 1 / q_m * np.sqrt(crown_area / np.pi) + + def calculate_whole_crown_gpp( potential_gpp: NDArray[np.float32], crown_area: NDArray[np.float32], From 9073becbb2de47dc9f3fe4589ddc17af7167dcc4 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 27 Sep 2024 22:47:47 +0100 Subject: [PATCH 170/241] Fixing tests --- .../unit/demography/test_canopy_functions.py | 58 ------------------- tests/unit/demography/test_flora.py | 35 +++++++---- .../unit/demography/test_t_model_functions.py | 18 ++++++ 3 files changed, 41 insertions(+), 70 deletions(-) diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index 2d93576f..49e51b96 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -7,21 +7,6 @@ import pytest -@pytest.fixture -def fixture_canopy_shape(): - """Fixture providing input and expected values for shape parameter calculations. - - These are hand calculated and only really test that the calculations haven't changed - from the initial implementation. - """ - return { - "m": np.array([2, 3]), - "n": np.array([5, 4]), - "q_m": np.array([2.9038988210485766, 2.3953681843215673]), - "p_zm": np.array([0.850283, 0.72265688]), - } - - @pytest.fixture def fixture_community(): """A fixture providing a simple community.""" @@ -41,49 +26,6 @@ def fixture_community(): ) -def test_calculate_crown_q_m(fixture_canopy_shape): - """Test calculate_crown_q_m.""" - - from pyrealm.demography.canopy_functions import calculate_crown_q_m - - actual_q_m_values = calculate_crown_q_m( - m=fixture_canopy_shape["m"], n=fixture_canopy_shape["n"] - ) - - assert np.allclose(actual_q_m_values, fixture_canopy_shape["q_m"]) - - -def test_calculate_crown_z_max_proportion(fixture_canopy_shape): - """Test calculate_crown_z_max_proportion.""" - - from pyrealm.demography.canopy_functions import calculate_crown_z_max_proportion - - actual_p_zm = calculate_crown_z_max_proportion( - m=fixture_canopy_shape["m"], n=fixture_canopy_shape["n"] - ) - - assert np.allclose(actual_p_zm, fixture_canopy_shape["p_zm"]) - - -@pytest.mark.parametrize( - argnames="crown_areas, expected_r0", - argvalues=( - (np.array([20, 30]), np.array([0.86887756, 1.29007041])), - (np.array([30, 40]), np.array([1.06415334, 1.489645])), - ), -) -def test_calculate_r_0_values(fixture_canopy_shape, crown_areas, expected_r0): - """Test happy path for calculating r_0.""" - - from pyrealm.demography.canopy_functions import calculate_crown_r0 - - actual_r0_values = calculate_crown_r0( - q_m=fixture_canopy_shape["q_m"], crown_area=crown_areas - ) - - assert np.allclose(actual_r0_values, expected_r0) - - ZQZInput = namedtuple( "ZQZInput", ["z", "stem", "more_stem", "q_z", "outcome", "excep_msg", "output_shape"], diff --git a/tests/unit/demography/test_flora.py b/tests/unit/demography/test_flora.py index 74e93145..d9959350 100644 --- a/tests/unit/demography/test_flora.py +++ b/tests/unit/demography/test_flora.py @@ -5,6 +5,7 @@ from importlib import resources from json import JSONDecodeError +import numpy as np import pytest from marshmallow.exceptions import ValidationError from pandas.errors import ParserError @@ -104,17 +105,29 @@ def test_PlantFunctionalType__init__(args, outcome): # -# Test PlantFunctionalType __post_init__ functions +# Test PlantFunctionalType __post_init__ trait calculation functions # -@pytest.mark.parametrize( - argnames="m,n,q_m", - argvalues=[(2, 5, 2.9038988210485766), (3, 4, 2.3953681843215673)], -) -def test_pft_calculate_q_m(m, n, q_m): +@pytest.fixture +def fixture_crown_shape(): + """Fixture of input and expected values for crown shape parameter calculations. + + These are hand calculated and only really test that the calculations haven't changed + from the initial implementation. + """ + return ( + np.array([2, 3]), # m + np.array([5, 4]), # n + np.array([2.9038988210485766, 2.3953681843215673]), # q_m + np.array([0.850283, 0.72265688]), # p_zm + ) + + +def test_pft_calculate_q_m(fixture_crown_shape): """Test calculation of q_m.""" + m, n, q_m, _ = fixture_crown_shape from pyrealm.demography.flora import calculate_crown_q_m calculated_q_m = calculate_crown_q_m(m, n) @@ -131,17 +144,15 @@ def test_calculate_q_m_values_raises_exception_for_invalid_input(): pass -@pytest.mark.parametrize( - argnames="m,n,z_max_ratio", - argvalues=[(2, 5, 0.8502830004171938), (3, 4, 0.7226568811456053)], -) -def test_pft_calculate_z_max_ratio(m, n, z_max_ratio): +def test_pft_calculate_z_max_ratio(fixture_crown_shape): """Test calculation of z_max proportion.""" from pyrealm.demography.flora import calculate_crown_z_max_proportion + m, n, _, p_zm = fixture_crown_shape + calculated_zmr = calculate_crown_z_max_proportion(m, n) - assert calculated_zmr == pytest.approx(z_max_ratio) + assert calculated_zmr == pytest.approx(p_zm) # diff --git a/tests/unit/demography/test_t_model_functions.py b/tests/unit/demography/test_t_model_functions.py index f183662a..661a8bf3 100644 --- a/tests/unit/demography/test_t_model_functions.py +++ b/tests/unit/demography/test_t_model_functions.py @@ -6,6 +6,24 @@ import pytest +@pytest.mark.parametrize( + argnames="crown_areas, expected_r0", + argvalues=( + (np.array([20, 30]), np.array([0.86887756, 1.29007041])), + (np.array([30, 40]), np.array([1.06415334, 1.489645])), + ), +) +def test_calculate_crown_r_0_values(crown_areas, expected_r0): + """Test happy path for calculating r_0.""" + + from pyrealm.demography.t_model_functions import calculate_crown_r0 + + q_m = np.array([2.9038988210485766, 2.3953681843215673]) + actual_r0_values = calculate_crown_r0(q_m=q_m, crown_area=crown_areas) + + assert np.allclose(actual_r0_values, expected_r0) + + @pytest.mark.parametrize( argnames="pft_args, size_args, outcome, excep_message", argvalues=[ From e8afa7797e7119d3b06b24c43d9ca206f9089a6f Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 11:05:32 +0100 Subject: [PATCH 171/241] Typo in crown radius attribute --- pyrealm/demography/canopy_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 7461cff2..8808596e 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -412,7 +412,7 @@ def __post_init__( # Calculate projected crown area self.projected_crown_area = calculate_stem_projected_crown_area_at_z( z=z, - q_z=self.relativate_crown_radius, + q_z=self.relative_crown_radius, crown_area=stem_allometry.crown_area, q_m=stem_traits.q_m, stem_height=stem_allometry.stem_height, From d28afeeb43168f440540b6c663aa337e2ac6fb66 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 11:12:28 +0100 Subject: [PATCH 172/241] Moar typos --- pyrealm/demography/canopy_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 8808596e..4957554d 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -354,7 +354,7 @@ class CrownProfile: This method calculates crown profile predictions, given an array of vertical heights (``z``) for: - * relativate crown radius, + * relative crown radius, * actual crown radius, * projected crown area, and * project leaf area. @@ -380,7 +380,7 @@ class CrownProfile: z: InitVar[NDArray[np.float32]] """An array of vertical height values at which to calculate crown profiles.""" - relativate_crown_radius: NDArray[np.float32] = field(init=False) + relative_crown_radius: NDArray[np.float32] = field(init=False) """An array of the relative crown radius of stems at z heights""" crown_radius: NDArray[np.float32] = field(init=False) """An array of the actual crown radius of stems at z heights""" From b2a5edd8de8857ccdf2c4d1fbb315e9790df38f2 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 11:16:12 +0100 Subject: [PATCH 173/241] Yet moar typos --- pyrealm/demography/canopy_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/canopy_functions.py index 4957554d..68b41c61 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/canopy_functions.py @@ -357,7 +357,7 @@ class CrownProfile: * relative crown radius, * actual crown radius, * projected crown area, and - * project leaf area. + * projected leaf area. The predictions require a set of plant functional types (PFTs) but also the expected allometric predictions of stem height, crown area and z_max for an actual stem of a @@ -386,7 +386,7 @@ class CrownProfile: """An array of the actual crown radius of stems at z heights""" projected_crown_area: NDArray[np.float32] = field(init=False) """An array of the projected crown area of stems at z heights""" - project_leaf_area: NDArray[np.float32] = field(init=False) + projected_leaf_area: NDArray[np.float32] = field(init=False) """An array of the projected leaf area of stems at z heights""" def __post_init__( From deae51907bd35513fbcc7307df76c4063dd0f44f Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 12:36:11 +0100 Subject: [PATCH 174/241] Added a simple validation that CanopyProfile gets the same answers as more detailed tests --- .../unit/demography/test_canopy_functions.py | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_canopy_functions.py index 49e51b96..db3bc370 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_canopy_functions.py @@ -341,15 +341,9 @@ def test_calculate_relative_crown_radius_at_z_values(fixture_community): calculate_relative_crown_radius_at_z, ) - # Canopy shape model gives the maximum radius at a height z_max - z_max = ( - fixture_community.stem_allometry.stem_height - * fixture_community.stem_traits.z_max_prop - ) - - # Get the relative radius at that height + # Get the relative radius at that heights of the crown z_max values q_z_values = calculate_relative_crown_radius_at_z( - z=z_max, + z=fixture_community.stem_allometry.crown_z_max, stem_height=fixture_community.stem_allometry.stem_height, m=fixture_community.stem_traits.m, n=fixture_community.stem_traits.n, @@ -642,3 +636,38 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): np.diag(leaf_area_fg002), fixture_community.stem_allometry.crown_area * 0.98, ) + + +def test_CrownProfile(fixture_community): + """Test the CrownProfile class. + + This implements a subset of the tests in the more detailed function checks above to + validate that this wrapper class works as intended. + """ + + from pyrealm.demography.canopy_functions import CrownProfile + + # Estimate the profile at the heights of the maximum crown radii for each cohort + crown_profile = CrownProfile( + stem_traits=fixture_community.stem_traits, + stem_allometry=fixture_community.stem_allometry, + z=fixture_community.stem_allometry.crown_z_max[:, None], + ) + + # Crown radius on diagonal predicts crown area accurately + assert np.allclose( + np.diag(crown_profile.crown_radius) ** 2 * np.pi, + fixture_community.stem_allometry.crown_area, + ) + + # Same is true for projected crown area at z_max heights + assert np.allclose( + np.diag(crown_profile.projected_crown_area), + fixture_community.stem_allometry.crown_area, + ) + + # And since f_g=0, so is projected leaf area + assert np.allclose( + np.diag(crown_profile.projected_leaf_area), + fixture_community.stem_allometry.crown_area, + ) From 062d8207ab1672963309e90e6d9077c14c800c20 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 13:00:43 +0100 Subject: [PATCH 175/241] Renaming canopy_functions to crown --- pyrealm/demography/canopy.py | 4 ++-- .../{canopy_functions.py => crown.py} | 6 +++--- ...{test_canopy_functions.py => test_crown.py} | 18 +++++++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) rename pyrealm/demography/{canopy_functions.py => crown.py} (98%) rename tests/unit/demography/{test_canopy_functions.py => test_crown.py} (97%) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 91694326..05c35631 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -4,13 +4,13 @@ from numpy.typing import NDArray from scipy.optimize import root_scalar # type: ignore [import-untyped] -from pyrealm.demography.canopy_functions import ( +from pyrealm.demography.community import Community +from pyrealm.demography.crown import ( calculate_relative_crown_radius_at_z, calculate_stem_projected_crown_area_at_z, calculate_stem_projected_leaf_area_at_z, solve_community_projected_canopy_area, ) -from pyrealm.demography.community import Community class Canopy: diff --git a/pyrealm/demography/canopy_functions.py b/pyrealm/demography/crown.py similarity index 98% rename from pyrealm/demography/canopy_functions.py rename to pyrealm/demography/crown.py index 68b41c61..2f945996 100644 --- a/pyrealm/demography/canopy_functions.py +++ b/pyrealm/demography/crown.py @@ -26,7 +26,7 @@ def _validate_z_qz_args( This function provides the following validation checks (see also the documentation of accepted shapes for ``z`` in - :meth:`~pyrealm.demography.canopy_functions.calculate_relative_crown_radius_at_z`). + :meth:`~pyrealm.demography.crown.calculate_relative_crown_radius_at_z`). * Stem properties are identically shaped row (1D) arrays. * The ``z`` argument is then one of: @@ -187,7 +187,7 @@ def calculate_stem_projected_crown_area_at_z( arguments ``stem_height``,``crown_area``,``q_m`` and ``z_max``, which must be one-dimensional arrays ('row vectors') of equal length. The array of vertical heights ``z`` accepts a range of input shapes (see - :meth:`~pyrealm.demography.canopy_functions.calculate_relative_crown_radius_at_z` + :meth:`~pyrealm.demography.crown.calculate_relative_crown_radius_at_z` ) and this function then also requires the expected relative stem radius (``q_z``) calculated from those heights. @@ -308,7 +308,7 @@ def calculate_stem_projected_leaf_area_at_z( ``stem_height``,``crown_area``,``f_g``,``q_m`` and ``z_max``, which must be one-dimensional arrays ('row vectors') of equal length. The array of vertical heights ``z`` accepts a range of input shapes (see - :meth:`~pyrealm.demography.canopy_functions.calculate_relative_crown_radius_at_z` + :meth:`~pyrealm.demography.crown.calculate_relative_crown_radius_at_z` ) and this function then also requires the expected relative stem radius (``q_z``) calculated from those heights. diff --git a/tests/unit/demography/test_canopy_functions.py b/tests/unit/demography/test_crown.py similarity index 97% rename from tests/unit/demography/test_canopy_functions.py rename to tests/unit/demography/test_crown.py index db3bc370..221eac2c 100644 --- a/tests/unit/demography/test_canopy_functions.py +++ b/tests/unit/demography/test_crown.py @@ -275,7 +275,7 @@ def fixture_z_qz_stem_properties(request): def test__validate_z_qz__args(fixture_z_qz_stem_properties): """Tests the validation function for arguments to canopy functions.""" - from pyrealm.demography.canopy_functions import _validate_z_qz_args + from pyrealm.demography.crown import _validate_z_qz_args # Unpack the input arguments for the test case - not testing outputs here z, stem, more_stem, q_z, outcome, excep_msg, _ = fixture_z_qz_stem_properties @@ -309,7 +309,7 @@ def test_calculate_relative_crown_radius_at_z_inputs(fixture_z_qz_stem_propertie This test checks the function behaviour with different inputs. """ - from pyrealm.demography.canopy_functions import ( + from pyrealm.demography.crown import ( calculate_relative_crown_radius_at_z, ) @@ -337,7 +337,7 @@ def test_calculate_relative_crown_radius_at_z_values(fixture_community): maximum crown radius. """ - from pyrealm.demography.canopy_functions import ( + from pyrealm.demography.crown import ( calculate_relative_crown_radius_at_z, ) @@ -378,7 +378,7 @@ def test_calculate_relative_crown_radius_at_z_values(fixture_community): ) def test_calculate_stem_projected_crown_area_at_z_inputs(fixture_z_qz_stem_properties): """Tests the validation of inputs to calculate_stem_projected_crown_area_at_z.""" - from pyrealm.demography.canopy_functions import ( + from pyrealm.demography.crown import ( calculate_stem_projected_crown_area_at_z, ) @@ -437,7 +437,7 @@ def test_calculate_stem_projected_crown_area_at_z_values( * 1 metre below z_max - all values should be equal to crown area """ - from pyrealm.demography.canopy_functions import ( + from pyrealm.demography.crown import ( calculate_relative_crown_radius_at_z, calculate_stem_projected_crown_area_at_z, ) @@ -476,7 +476,7 @@ def test_solve_community_projected_canopy_area(fixture_community): 2 and so on. """ - from pyrealm.demography.canopy_functions import ( + from pyrealm.demography.crown import ( solve_community_projected_canopy_area, ) @@ -523,7 +523,7 @@ def test_solve_community_projected_canopy_area(fixture_community): ) def test_calculate_stem_projected_leaf_area_at_z_inputs(fixture_z_qz_stem_properties): """Tests the validation of inputs to calculate_stem_projected_crown_area_at_z.""" - from pyrealm.demography.canopy_functions import ( + from pyrealm.demography.crown import ( calculate_stem_projected_leaf_area_at_z, ) @@ -552,7 +552,7 @@ def test_calculate_stem_projected_leaf_area_at_z_values(fixture_community): robust theoretical checks about the expectations and crown area. """ - from pyrealm.demography.canopy_functions import ( + from pyrealm.demography.crown import ( calculate_relative_crown_radius_at_z, calculate_stem_projected_leaf_area_at_z, ) @@ -645,7 +645,7 @@ def test_CrownProfile(fixture_community): validate that this wrapper class works as intended. """ - from pyrealm.demography.canopy_functions import CrownProfile + from pyrealm.demography.crown import CrownProfile # Estimate the profile at the heights of the maximum crown radii for each cohort crown_profile = CrownProfile( From f5539ccbcd778c92a8abbff127d9ed6265089d8a Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 13:57:42 +0100 Subject: [PATCH 176/241] Draft user docs --- docs/source/users/demography/crown.md | 282 ++++++++++++++++++++++++++ docs/source/users/demography/flora.md | 121 +++++++++++ 2 files changed, 403 insertions(+) create mode 100644 docs/source/users/demography/crown.md create mode 100644 docs/source/users/demography/flora.md diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md new file mode 100644 index 00000000..4d3cf0b7 --- /dev/null +++ b/docs/source/users/demography/crown.md @@ -0,0 +1,282 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# The tree crown model + +:::{admonition} Warning + +This area of `pyrealm` is in active development and this notebook currently contains +notes and initial demonstration code. + +::: + +```{code-cell} +from matplotlib import pyplot as plt +import numpy as np +import pandas as pd + +from pyrealm.demography.flora import ( + calculate_crown_q_m, + calculate_crown_z_max_proportion, + PlantFunctionalType, + Flora, +) + +from pyrealm.demography.t_model_functions import ( + calculate_dbh_from_height, + StemAllometry, +) + +from pyrealm.demography.crown import ( + CrownProfile, +) +``` + +The {mod}`pyrealm.demography` module uses three-dimensional model of crown shape to +define the vertical distribution of leaf area. This is driven by four parameters within +the {class}`~pyrealm.demography.flora.PlantFunctionalType`: + +* The `m` and `n` parameters that define the vertical shape of the crown profile. +* The `ca_ratio` parameters that defines the size of the crown relative to the stem size. +* The `f_g` parameter that define the crown gap fraction and sets the vertical + distribution of leaves within the crown. + +The code below provides a demonstration of the impacts of each parameter and shows the +use of `pyrealm` tools to visualise the crown model for individual stems. + +## Crown shape parameters + +The `m` and `n` parameters define the vertical profile of the crown but are also define +two further parameters: + +* `q_m`, which is used to scale the size of the crown radius to match the expected crown + area, given the crown shape. +* `z_max_prop`, which sets the height on the stem at which the maximum crown radius is found. + +The code below calculates `q_m` and `z_max_prop` for combinations of `m` and `n` and +then plots the resulting values. + +```{code-cell} +m = n = np.arange(1.0, 5, 0.1) +q_m = calculate_crown_q_m(m=m, n=n[:, None]) +z_max_prop = calculate_crown_z_max_proportion(m=m, n=n[:, None]) +``` + +```{code-cell} +fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10.9, 4)) + +# Plot q_m as a function of m and n +cntr_set1 = ax1.contourf(m, n, q_m, levels=10) +fig.colorbar(cntr_set1, ax=ax1, label="q_m") +ax1.set_xlabel("m") +ax1.set_ylabel("n") +ax1.set_aspect("equal") + +# Plot z_max_prop as a function of m and n +cntr_set2 = ax2.contourf(m, n, z_max_prop, levels=10) +fig.colorbar(cntr_set2, ax=ax2, label="z_max_prop") +ax2.set_xlabel("m") +ax2.set_ylabel("n") +ax2.set_aspect("equal") +``` + +## Plotting crown profiles + +The examples below show the calculation of crown profiles for a set of plant functional +types (PFTs) with differing crown trait values. We first need to create a +:class:`~pyrealm.demography.flora.Flora` object that defines those PFTs. + +```{code-cell} +flora = Flora( + [ + PlantFunctionalType(name="short", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=20), + PlantFunctionalType( + name="medium", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=500 + ), + PlantFunctionalType(name="tall", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=2000), + ] +) + +flora +``` + +```{code-cell} +pd.DataFrame({k: getattr(flora, k) for k in flora.trait_attrs}) +``` + +We then also need to specify the size of a stem of each PFT, along with the resulting +allometric predictions from the T Model. + +```{code-cell} +# Generate the expected stem allometries at a single height for each PFT +stem_height = np.array([18, 18, 18]) +stem_dbh = calculate_dbh_from_height( + a_hd=flora.a_hd, h_max=flora.h_max, stem_height=stem_height +) +stem_dbh +``` + +```{code-cell} +allometry = StemAllometry(stem_traits=flora, at_dbh=stem_dbh) +``` + +We can use {mod}`pandas` to visualise those allometric predictions. + +```{code-cell} +pd.DataFrame({k: getattr(allometry, k) for k in allometry.allometry_attrs}) +``` + +We can now use the {meth}`~pyrealm.demography.flora.Flora.get_canopy_profile` method to +calculate the canopy profile for each stem for a set of vertical heights. The heights +need to be defined as a column array, that is with a shape `(N, 1)`, in order to show +that we want the canopy variables to be calculated at each height for each PFT. + +```{code-cell} +# Create a set of vertical heights as a column array. +z = np.linspace(0, 18.0, num=181)[:, None] + +# Calculate the crown profile across those heights for each PFT +crown_profiles = CrownProfile(stem_traits=flora, stem_allometry=allometry, z=z) +``` + +The `crown_profiles` object is a dictionary containing values for four crown profile +variables. + +* The relative crown radius: this value is driven purely by `m`, `n` and the stem height + and defines the vertical profile of the crown. +* The crown radius: this is simply a rescaling of the relative radius so that the + maximum crown radius matches the expected crown area predicted by the allometry of the + T Model. +* The projected crown area: this value shows how crown area accumulates from the top of + the crown to the ground. +* The projected leaf area: this value shows how _leaf_ area accumulates from the top of + the crown to the ground. The difference from the crown area is driven by the crown gap + fraction for a given PFT. + +```{code-cell} +crown_profiles +``` + +### Crown radius values + +The relative crown radius values are arbitrary - they simply define the shape of the +vertical profile. For the example PFTs in the `Flora` object, the maximum relative +radius values on each stem are: + +```{code-cell} +max_relative_crown_radius = crown_profiles.relative_crown_radius.max(axis=0) +print(max_relative_crown_radius) +``` + +However the scaled maximum radius values match the expected crown area in the allometry +table above + +```{code-cell} +max_crown_radius = crown_profiles.crown_radius.max(axis=0) +print(max_crown_radius) +print(max_crown_radius**2 * np.pi) +``` + +The code below generates a plot of the vertical shape profiles of the crowns for each +stem. For each stem: + +* the dashed line shows how the relative crown radius varies with height, +* the solid line shows the actual crown radius profile with height, and +* the dotted line shows the height at which the maximum crown radius is found. + +```{code-cell} +fig, ax = plt.subplots(ncols=1) + +# Find the maximum of the actual and relative maximum crown widths +stem_max_width = np.maximum(max_crown_radius, max_relative_crown_radius) + +for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 12), ("r", "g", "b")): + + # Plot relative radius either side of offset + stem_qz = crown_profiles.relative_crown_radius[:, pft_idx] + ax.plot(stem_qz + offset, z, color=colour, linestyle="--", linewidth=1) + ax.plot(-stem_qz + offset, z, color=colour, linestyle="--", linewidth=1) + + # Plot actual crown radius either side of offset + stem_rz = crown_profiles.crown_radius[:, pft_idx] + ax.plot(stem_rz + offset, z, color=colour) + ax.plot(-stem_rz + offset, z, color=colour) + + # Add the height of maximum crown radius + stem_rz_max = stem_max_width[pft_idx] + + ax.plot( + [offset - stem_rz_max, offset + stem_rz_max], + [allometry.crown_z_max[pft_idx]] * 2, + color=colour, + linewidth=1, + linestyle=":", + ) + +ax.set_aspect(aspect=1) +``` + +### Projected crown and leaf areas + +We can use the crown profile to generate projected area plots, but it is much easier to +compare the effects when comparing stems with similar crown areas. The code below +generates these new predictions for a new set of PFTs. + +```{code-cell} +flora2 = Flora( + [ + PlantFunctionalType(name="short", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=380), + PlantFunctionalType( + name="medium", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=400 + ), + PlantFunctionalType(name="tall", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=420), + ] +) + +allometry2 = StemAllometry(stem_traits=flora2, at_dbh=stem_dbh) + + +# Calculate the crown profile across those heights for each PFT +crown_profiles2 = CrownProfile(stem_traits=flora2, stem_allometry=allometry2, z=z) +``` + +The plot below shows how projected crown area (solid lines) and leaf area (dashed lines) +change with height along the stem. + +* The projected crown area increases from zero at the top of the canopy, according to + the canopy profile, until it reaches the maximum crown radius, at which point it + remains constant down to ground level. The total crown areas differs for each stem + because of the slightly different values used for the crown area ratio. + +* The projected leaf area is very similar but leaf area is displaced towards the ground + because of the crown gap fraction (`f_g`). Where `f_g = 0` (the red line), the two + lines are identical, but as `f_g` increases, more of the leaf area is displaced down + within the canopy. + +```{code-cell} +fig, ax = plt.subplots(ncols=1) + +for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 10), ("r", "g", "b")): + + ax.plot(crown_profiles2.projected_crown_area[:, pft_idx], z, color=colour) + ax.plot( + crown_profiles2.projected_leaf_area[:, pft_idx], + z, + color=colour, + linestyle="--", + ) +``` + +```{code-cell} + +``` diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md new file mode 100644 index 00000000..646601da --- /dev/null +++ b/docs/source/users/demography/flora.md @@ -0,0 +1,121 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Plant Functional Types and the Flora object + +:::{admonition} Warning + +This area of `pyrealm` is in active development and this notebook currently contains +notes and initial demonstration code. + +::: + +```{code-cell} +from matplotlib import pyplot as plt +import numpy as np + +from pyrealm.demography.flora import PlantFunctionalType, Flora +``` + +The code below creates a simple `Flora` object containing 3 plant functional types with +different maximum stem heights. + +```{code-cell} +flora = Flora( + [ + PlantFunctionalType(name="short", h_max=10), + PlantFunctionalType(name="medium", h_max=20), + PlantFunctionalType(name="tall", h_max=30), + ] +) + +flora +``` + +We can visualise how the stem size, canopy size and various masses of a plant functional +type change with stem diameter by using the `Flora.get_allometries` method. This takes +an array of values for diameter at breast height (metres) and returns a dictionary +containing the predictions of the T Model for: + +* Stem height ('stem_height', m) +* Crown area ('crown_area', m2) +* Crown fraction ('crown_fraction', -) +* Stem mass ('stem_mass', kg) +* Foliage mass ('foliage_mass', kg) +* Sapwood mass ('sapwood_mass', kg) + +The returned values in the dictionary are 2 dimensional arrays with each DBH value as a +row and each PFT as a column. This makes them convenient to plot using `matplotlib`. + +```{code-cell} +dbh = np.arange(0, 1.6, 0.01)[:, None] +allometries = flora.get_allometries(dbh=dbh) +``` + +The code below shows how to use the returned allometries to generate a plot of the +scaling relationships across all of the PFTs in a `Flora` instance. + +```{code-cell} +fig, axes = plt.subplots(ncols=2, nrows=3, sharex=True, figsize=(10, 8)) + +plot_details = [ + ("stem_height", "Stem height (m)"), + ("crown_area", "Crown area (m2)"), + ("crown_fraction", "Crown fraction (-)"), + ("stem_mass", "Stem mass (kg)"), + ("foliage_mass", "Foliage mass (kg)"), + ("sapwood_mass", "Sapwood mass (kg)"), +] + +for ax, (var, ylab) in zip(axes.flatten(), plot_details): + ax.plot(dbh, allometries[var], label=flora.keys()) + ax.set_xlabel("Diameter at breast height (m)") + ax.set_ylabel(ylab) + + if var == "sapwood_mass": + ax.legend(frameon=False) +``` + +```{code-cell} +potential_gpp = np.repeat(55, dbh.size)[:, None] +allocation = flora.get_allocation(dbh=dbh, potential_gpp=potential_gpp) +``` + +```{code-cell} +fig, axes = plt.subplots(ncols=2, nrows=5, sharex=True, figsize=(10, 12)) + +plot_details = [ + ("whole_crown_gpp", "whole_crown_gpp"), + ("sapwood_respiration", "sapwood_respiration"), + ("foliar_respiration", "foliar_respiration"), + ("fine_root_respiration", "fine_root_respiration"), + ("npp", "npp"), + ("turnover", "turnover"), + ("delta_dbh", "delta_dbh"), + ("delta_stem_mass", "delta_stem_mass"), + ("delta_foliage_mass", "delta_foliage_mass"), +] + +axes = axes.flatten() + +for ax, (var, ylab) in zip(axes, plot_details): + ax.plot(dbh, allocation[var], label=flora.keys()) + ax.set_xlabel("Diameter at breast height (m)") + ax.set_ylabel(ylab) + + if var == "whole_crown_gpp": + ax.legend(frameon=False) + +# Delete unused panel in 5 x 2 grid +fig.delaxes(axes[-1]) +``` From d7e8d634500a9f5b22340088e8b259e2e87bdf1b Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 14:04:23 +0100 Subject: [PATCH 177/241] Added a Flora.__repr__ --- pyrealm/demography/flora.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index b77d4ea8..69a8a29e 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -259,6 +259,7 @@ class Flora: ] # Populated post init + # - trait arrays name: NDArray[np.str_] = field(init=False) r"""The name of the plant functional type.""" a_hd: NDArray[np.float32] = field(init=False) @@ -301,10 +302,14 @@ class Flora: """Scaling factor to derive maximum crown radius from crown area.""" z_max_prop: NDArray[np.float32] = field(init=False) """Proportion of stem height at which maximum crown radius is found.""" + + # - other instance attributes pft_dict: dict[str, type[PlantFunctionalTypeStrict]] = field(init=False) """A dictionary of the original plant functional type instances, keyed by name.""" pft_indices: dict[str, int] = field(init=False) """An dictionary giving the index of each PFT name in the trait array attributes.""" + n_pfts: int = field(init=False) + """The number of plant functional types in the Flora instance.""" def __post_init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: # Check the PFT data @@ -324,8 +329,9 @@ def __post_init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None f"Duplicated plant functional type names: {','.join(duplicates)}" ) - # Populate the pft dictionary using the PFT name as key + # Populate the pft dictionary using the PFT name as key and the number of PFTs object.__setattr__(self, "pft_dict", {p.name: p for p in pfts}) + object.__setattr__(self, "n_pfts", len(pfts)) # Populate the trait attributes with arrays for pft_field in self.trait_attrs: @@ -336,6 +342,11 @@ def __post_init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None # Populate the pft trait indices object.__setattr__(self, "pft_indices", {v: k for k, v in enumerate(self.name)}) + def __repr__(self) -> str: + """Simple representation of the Flora instance.""" + + return f"Flora with {self.n_pfts} functional types: {', '.join(self.name)}" + @classmethod def _from_file_data(cls, file_data: dict) -> Flora: """Create a Flora object from a JSON string. From c6ac276b058ada5c17a7b1d0d6d7b5f86a397226 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 14:51:20 +0100 Subject: [PATCH 178/241] Docstring updates --- pyrealm/demography/flora.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 69a8a29e..e9e9196f 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -9,12 +9,16 @@ data files. This intentionally enforces a complete description of the traits in the input data. The ``PlantFunctionalType`` is provided as a more convenient API for programmatic use. -* The Flora class, which is a dataclass representing a collection of plant functional - types for use in describing a plant community in a simulation. It provides the same - trait attributes as the plant functional type classes, but the values are arrays of - trait values across the provided PFTS. The Flora class also defines factory methods to - create instances from plant functional type data stored in JSON, TOML or CSV formats. - +* The Flora dataclass, which represents a collection of plant functional types for use + in describing a plant community in a simulation. It provides the same trait attributes + as the plant functional type classes, but the values are arrays of trait values across + the provided PFTS. The Flora class also defines factory methods to create instances + from plant functional type data stored in JSON, TOML or CSV formats. +* The StemTraits dataclass, which represents a collection of stems used in a simulation. + It again provides the same trait attributes as the plant functional type classes, but + as arrays. This differs from the Flora class in allowing multiple stems of the same + plant functional type and is primarily used to broadcast PFT traits into arrays for + use in calculating demography across the stems in plant cohorts. """ # noqa: D415 from __future__ import annotations @@ -137,9 +141,9 @@ class PlantFunctionalTypeStrict: resp_f: float r"""Foliage maintenance respiration fraction (:math:`r_f`, -)""" m: float - r"""Canopy shape parameter (:math:`m`, -)""" + r"""Crown shape parameter (:math:`m`, -)""" n: float - r"""Canopy shape parameter (:math:`n`, -)""" + r"""Crown shape parameter (:math:`n`, -)""" f_g: float r"""Crown gap fraction (:math:`f_g`, -)""" @@ -200,6 +204,7 @@ class PlantFunctionalType(PlantFunctionalTypeStrict): f_g, 0.05, - """ + name: str a_hd: float = 116.0 ca_ratio: float = 390.43 h_max: float = 25.33 @@ -293,9 +298,9 @@ class Flora: resp_f: NDArray[np.float32] = field(init=False) r"""Foliage maintenance respiration fraction (:math:`r_f`, -)""" m: NDArray[np.float32] = field(init=False) - r"""Canopy shape parameter (:math:`m`, -)""" + r"""Crown shape parameter (:math:`m`, -)""" n: NDArray[np.float32] = field(init=False) - r"""Canopy shape parameter (:math:`n`, -)""" + r"""Crown shape parameter (:math:`n`, -)""" f_g: NDArray[np.float32] = field(init=False) r"""Crown gap fraction (:math:`f_g`, -)""" q_m: NDArray[np.float32] = field(init=False) @@ -487,9 +492,9 @@ class StemTraits: resp_f: NDArray[np.float32] r"""Foliage maintenance respiration fraction (:math:`r_f`, -)""" m: NDArray[np.float32] - r"""Canopy shape parameter (:math:`m`, -)""" + r"""Crown shape parameter (:math:`m`, -)""" n: NDArray[np.float32] - r"""Canopy shape parameter (:math:`n`, -)""" + r"""Crown shape parameter (:math:`n`, -)""" f_g: NDArray[np.float32] r"""Crown gap fraction (:math:`f_g`, -)""" q_m: NDArray[np.float32] From 8ed8aa0dd5da1edb7f55582fc6db9dafc67ca912 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 14:51:49 +0100 Subject: [PATCH 179/241] Docstring updates --- pyrealm/demography/flora.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index e9e9196f..4c78e5ea 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -97,11 +97,11 @@ class PlantFunctionalTypeStrict: * The foliage maintenance respiration fraction was not explicitly included in :cite:t:`Li:2014bc` - there was assumed to be a 10% penalty on GPP before calculating the other component - but has been explicitly included here. - * This implementation adds two further canopy shape parameters (``m`` and ``n`` and + * This implementation adds two further crown shape parameters (``m`` and ``n`` and ``f_g``). The first two are then used to calculate two constant derived attributes (``q_m`` and ``z_max_ratio``) that define the vertical distribution of the crown. The last parameter (``f_g``) is the crown gap fraction, that defines the vertical - distribution of leaves within the crown. This canopy model parameterisation + distribution of leaves within the crown. This crown model parameterisation follows the implementation developed in the PlantFATE model :cite:`joshi:2022a`. See also :class:`~pyrealm.demography.flora.PlantFunctionalType` for the default From 6effa3a0168f2f88a154437e31a328682d60fe9c Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 15:43:35 +0100 Subject: [PATCH 180/241] StemAllocation.__repr__ and user doc update --- docs/source/users/demography/flora.md | 165 ++++++++++++++++++++---- pyrealm/demography/t_model_functions.py | 17 +++ 2 files changed, 154 insertions(+), 28 deletions(-) diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index 646601da..631473f8 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -11,7 +11,7 @@ kernelspec: name: python3 --- -# Plant Functional Types and the Flora object +# Plant Functional Types and Traits :::{admonition} Warning @@ -20,53 +20,155 @@ notes and initial demonstration code. ::: +This page introduces the main components of the {mod}`~pyrealm.demography` module that +describe plant functional types (PFTs) and their traits. + ```{code-cell} from matplotlib import pyplot as plt import numpy as np from pyrealm.demography.flora import PlantFunctionalType, Flora + +from pyrealm.demography.t_model_functions import StemAllocation, StemAllometry ``` -The code below creates a simple `Flora` object containing 3 plant functional types with -different maximum stem heights. +## Plant traits + +The table below shows the traits used to define the behaviour of different PFTs in +demographic simulations. These traits mostly consist of the parameters defined in the T +Model {cite}`Li:2014bc` to govern the allometric scaling and carbon allocation of trees, +but also include parameters for crown shape that follow the implementation developed in +the PlantFATE model {cite}`joshi:2022a`. + +:::{list-table} +:widths: 10 30 +:header-rows: 1 + +* * Trait name + * Description +* * `a_hd` + * Initial slope of height-diameter relationship ($a$, -) +* * `ca_ratio` + * Initial ratio of crown area to stem cross-sectional area ($c$, -) +* * `h_max` + * Maximum tree height ($H_m$, m) +* * `rho_s` + * Sapwood density ($\rho_s$, kg Cm-3) +* * `lai` + * Leaf area index within the crown ($L$, -) +* * `sla` + * Specific leaf area ($\sigma$, m2 kg-1 C) +* * `tau_f` + * Foliage turnover time ($\tau_f$,years) +* * `tau_r` + * Fine-root turnover time ($\tau_r$, years) +* * `par_ext` + * Extinction coefficient of photosynthetically active radiation (PAR) ($k$, -) +* * `yld` + * Yield factor ($y$, -) +* * `zeta` + * Ratio of fine-root mass to foliage area ($\zeta$, kg C m-2) +* * `resp_r` + * Fine-root specific respiration rate ($r_r$, year-1) +* * `resp_s` + * Sapwood-specific respiration rate ($r_s$, year-1) +* * `resp_f` + * Foliage maintenance respiration fraction ($r_f$, -) +* * `m` + * Crown shape parameter ($m$, -) +* * `n` + * Crown shape parameter ($n$, -) +* * `f_g` + * Crown gap fraction ($f_g$, -) +* * `q_m` + * Scaling factor to derive maximum crown radius from crown area. +* * `z_max_prop` + * Proportion of stem height at which maximum crown radius is found. +::: + ++++ + +## Plant Functional Types + +The {class}`~pyrealm.demography.flora.PlantFunctionalType` class is used define a PFT +with a given name, along with the trait values associated with the PFT. By default, +values for each trait are taken from Table 1 of {cite}`Li:2014bc`, but these can be +adjusted for different PFTs. The code below contains three examples that just differ in +their maximum height. + +Note that the `q_m` and `z_max_prop` traits are calculated from the `m` and `n` traits +and cannot be set directly. ```{code-cell} -flora = Flora( - [ - PlantFunctionalType(name="short", h_max=10), - PlantFunctionalType(name="medium", h_max=20), - PlantFunctionalType(name="tall", h_max=30), - ] -) +short_pft = PlantFunctionalType(name="short", h_max=10) +medium_pft = PlantFunctionalType(name="medium", h_max=20) +tall_pft = PlantFunctionalType(name="tall", h_max=30) +``` + +The traits values set for a PFT instance can then be shown: + +```{code-cell} +short_pft +``` + +## The Flora class + +The {class}`~pyrealm.demography.flora.Flora` class is used to collect a list of PFTs +that will be used in a demographic simulation. It can be created directly by providing +the list of {class}`~pyrealm.demography.flora.PlantFunctionalType` instances. The only +requirement is that each PFT instance uses a different name. + +```{code-cell} +flora = Flora([short_pft, medium_pft, tall_pft]) flora ``` -We can visualise how the stem size, canopy size and various masses of a plant functional -type change with stem diameter by using the `Flora.get_allometries` method. This takes -an array of values for diameter at breast height (metres) and returns a dictionary -containing the predictions of the T Model for: +You can also create `Flora` instances using PFT data stored TOML, JSON and CSV file formats. -* Stem height ('stem_height', m) -* Crown area ('crown_area', m2) -* Crown fraction ('crown_fraction', -) -* Stem mass ('stem_mass', kg) -* Foliage mass ('foliage_mass', kg) -* Sapwood mass ('sapwood_mass', kg) +## Stem allometry -The returned values in the dictionary are 2 dimensional arrays with each DBH value as a -row and each PFT as a column. This makes them convenient to plot using `matplotlib`. +We can visualise how the stem size, canopy size and various masses of PFTs change with +stem diameter by using the {class}`~pyrealm.demography.t_model_functions.StemAllometry` +class. Creating a `StemAllometry` instance needs an existing `Flora` instance and an +array of values for diameter at breast height (DBH, metres). The returned class contains +the predictions of the T Model for: + +* Stem height (`stem_height`, m), +* Crown area (`crown_area`, m2), +* Crown fraction (`crown_fraction`, -), +* Stem mass (`stem_mass`, kg), +* Foliage mass (`foliage_mass`, kg), +* Sapwood mass (`sapwood_mass`, kg), +* Crown radius scaling factor (`crown_r0`, -), and +* Height of maximum crown radius (`crown_z_max`, m). + +The DBH input can be a scalar array or a one dimensional array providing a single value +for each PFT. This then calculates a single estimate for a specific stem size. ```{code-cell} -dbh = np.arange(0, 1.6, 0.01)[:, None] -allometries = flora.get_allometries(dbh=dbh) +# Calculate a single prediction +single_allometry = StemAllometry(stem_traits=flora, at_dbh=np.array([0.1, 0.1, 0.1])) +single_allometry.stem_height +``` + +However, the DBH values can also be a column array (an `N` x 1 array). In this case, the +predictions are made at each DBH value for each PFT and the allometry attributes with +predictions arranged with each PFT as a column and each DBH prediction as a row. This +makes them convenient to plot using `matplotlib`. + +```{code-cell} +# Column array of DBH values from 0 to 1.6 metres +dbh_col = np.arange(0, 1.6, 0.01)[:, None] +# Get the predictions +allometries = StemAllometry(stem_traits=flora, at_dbh=dbh_col) ``` The code below shows how to use the returned allometries to generate a plot of the scaling relationships across all of the PFTs in a `Flora` instance. ```{code-cell} -fig, axes = plt.subplots(ncols=2, nrows=3, sharex=True, figsize=(10, 8)) +fig, axes = plt.subplots(ncols=2, nrows=4, sharex=True, figsize=(10, 10)) plot_details = [ ("stem_height", "Stem height (m)"), @@ -75,10 +177,12 @@ plot_details = [ ("stem_mass", "Stem mass (kg)"), ("foliage_mass", "Foliage mass (kg)"), ("sapwood_mass", "Sapwood mass (kg)"), + ("crown_r0", "Crown scaling factor (-)"), + ("crown_z_max", "Height of maximum\ncrown radius (m)"), ] for ax, (var, ylab) in zip(axes.flatten(), plot_details): - ax.plot(dbh, allometries[var], label=flora.keys()) + ax.plot(dbh_col, getattr(allometries, var), label=flora.name) ax.set_xlabel("Diameter at breast height (m)") ax.set_ylabel(ylab) @@ -87,8 +191,13 @@ for ax, (var, ylab) in zip(axes.flatten(), plot_details): ``` ```{code-cell} -potential_gpp = np.repeat(55, dbh.size)[:, None] -allocation = flora.get_allocation(dbh=dbh, potential_gpp=potential_gpp) +potential_gpp = np.repeat(55, dbh_col.size)[:, None] +print(potential_gpp) + + +allocation = StemAllocation( + stem_traits=flora, stem_allometry=single_allometry, at_potential_gpp=potential_gpp +) ``` ```{code-cell} diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index fa1be81d..d7df585a 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -716,6 +716,9 @@ class StemAllometry: """Crown radius scaling factor (-)""" crown_z_max: NDArray[np.float32] = field(init=False) """Height of maximum crown radius (metres)""" + # Information attributes + _n_z_obs: int = field(init=False) + """The number of calculated height values per stem.""" def __post_init__( self, stem_traits: Flora | StemTraits, at_dbh: NDArray[np.float32] @@ -774,6 +777,20 @@ def __post_init__( stem_height=self.stem_height, ) + if self.dbh.ndim == 1: + self._n_z_obs = 1 + else: + self._n_z_obs = self.dbh.shape[0] + + def __repr__(self) -> str: + if self._n_z_obs == 1: + return f"StemAllometry: Single prediction for {len(self.dbh)} stems" + else: + return ( + f"StemAllometry: Prediction for {len(self.dbh)} stems " + f"at {self._n_z_obs} DBH values." + ) + @dataclass() class StemAllocation: From 502968dada8303e6581d27acdd544974250236d8 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 16:01:12 +0100 Subject: [PATCH 181/241] Docstring fixes from @j-emberton --- pyrealm/demography/crown.py | 10 ++++++---- pyrealm/demography/t_model_functions.py | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index 2f945996..ed93fa32 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -161,8 +161,8 @@ def calculate_crown_radius( relative radius values. Args: - q_z: TODO - r0: TODO + q_z: An array of relative crown radius values + r0: An array of crown radius scaling factor values validate: Boolean flag to suppress argument validation. """ @@ -364,8 +364,10 @@ class CrownProfile: given size for each PFT. Args: - stem_traits: - stem_allometry: A Ste + stem_traits: A Flora or StemTraits instance providing plant functional trait + data. + stem_allometry: A StemAllometry instance setting the stem allometries for the + crown profile. z: An array of vertical height values at which to calculate crown profiles. stem_height: A row array providing expected stem height for each PFT. crown_area: A row array providing expected crown area for each PFT. diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index fa1be81d..122aeb8e 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -308,7 +308,6 @@ def calculate_crown_z_max( z_max_prop: Crown shape parameter of the PFT stem_height: Stem height of individuals """ - """Calculate z_m, the height of maximum crown radius.""" return stem_height * z_max_prop From 74b6eb4606eba7630e78d3977a2d68c800ce2778 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 17:09:03 +0100 Subject: [PATCH 182/241] Updated user docs --- docs/source/users/demography/flora.md | 167 ++++++++++++++++++-------- 1 file changed, 120 insertions(+), 47 deletions(-) diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index 631473f8..cb3605c8 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -26,6 +26,7 @@ describe plant functional types (PFTs) and their traits. ```{code-cell} from matplotlib import pyplot as plt import numpy as np +import pandas as pd from pyrealm.demography.flora import PlantFunctionalType, Flora @@ -40,53 +41,55 @@ Model {cite}`Li:2014bc` to govern the allometric scaling and carbon allocation o but also include parameters for crown shape that follow the implementation developed in the PlantFATE model {cite}`joshi:2022a`. + + :::{list-table} :widths: 10 30 :header-rows: 1 -* * Trait name - * Description -* * `a_hd` - * Initial slope of height-diameter relationship ($a$, -) -* * `ca_ratio` - * Initial ratio of crown area to stem cross-sectional area ($c$, -) -* * `h_max` - * Maximum tree height ($H_m$, m) -* * `rho_s` - * Sapwood density ($\rho_s$, kg Cm-3) -* * `lai` - * Leaf area index within the crown ($L$, -) -* * `sla` - * Specific leaf area ($\sigma$, m2 kg-1 C) -* * `tau_f` - * Foliage turnover time ($\tau_f$,years) -* * `tau_r` - * Fine-root turnover time ($\tau_r$, years) -* * `par_ext` - * Extinction coefficient of photosynthetically active radiation (PAR) ($k$, -) -* * `yld` - * Yield factor ($y$, -) -* * `zeta` - * Ratio of fine-root mass to foliage area ($\zeta$, kg C m-2) -* * `resp_r` - * Fine-root specific respiration rate ($r_r$, year-1) -* * `resp_s` - * Sapwood-specific respiration rate ($r_s$, year-1) -* * `resp_f` - * Foliage maintenance respiration fraction ($r_f$, -) -* * `m` - * Crown shape parameter ($m$, -) -* * `n` - * Crown shape parameter ($n$, -) -* * `f_g` - * Crown gap fraction ($f_g$, -) -* * `q_m` - * Scaling factor to derive maximum crown radius from crown area. -* * `z_max_prop` - * Proportion of stem height at which maximum crown radius is found. +* - Trait name + - Description +* - `a_hd` + - Initial slope of height-diameter relationship ($a$, -) +* - `ca_ratio` + - Initial ratio of crown area to stem cross-sectional area ($c$, -) +* - `h_max` + - Maximum tree height ($H_m$, m) +* - `rho_s` + - Sapwood density ($\rho_s$, kg Cm-3) +* - `lai` + - Leaf area index within the crown ($L$, -) +* - `sla` + - Specific leaf area ($\sigma$, m2 kg-1 C) +* - `tau_f` + - Foliage turnover time ($\tau_f$,years) +* - `tau_r` + - Fine-root turnover time ($\tau_r$, years) +* - `par_ext` + - Extinction coefficient of photosynthetically active radiation (PAR) ($k$, -) +* - `yld` + - Yield factor ($y$, -) +* - `zeta` + - Ratio of fine-root mass to foliage area ($\zeta$, kg C m-2) +* - `resp_r` + - Fine-root specific respiration rate ($r_r$, year-1) +* - `resp_s` + - Sapwood-specific respiration rate ($r_s$, year-1) +* - `resp_f` + - Foliage maintenance respiration fraction ($r_f$, -) +* - `m` + - Crown shape parameter ($m$, -) +* - `n` + - Crown shape parameter ($n$, -) +* - `f_g` + - Crown gap fraction ($f_g$, -) +* - `q_m` + - Scaling factor to derive maximum crown radius from crown area. +* - `z_max_prop` + - Proportion of stem height at which maximum crown radius is found. ::: -+++ + ## Plant Functional Types @@ -124,6 +127,10 @@ flora = Flora([short_pft, medium_pft, tall_pft]) flora ``` +```{code-cell} +pd.DataFrame({k: getattr(flora, k) for k in flora.trait_attrs}) +``` + You can also create `Flora` instances using PFT data stored TOML, JSON and CSV file formats. ## Stem allometry @@ -144,12 +151,19 @@ the predictions of the T Model for: * Height of maximum crown radius (`crown_z_max`, m). The DBH input can be a scalar array or a one dimensional array providing a single value -for each PFT. This then calculates a single estimate for a specific stem size. +for each PFT. This then calculates a single estimate at the given size for each stem. ```{code-cell} # Calculate a single prediction single_allometry = StemAllometry(stem_traits=flora, at_dbh=np.array([0.1, 0.1, 0.1])) -single_allometry.stem_height +``` + +We can display those predictions as a `pandas.DataFrame`: + +```{code-cell} +pd.DataFrame( + {k: getattr(single_allometry, k) for k in single_allometry.allometry_attrs} +) ``` However, the DBH values can also be a column array (an `N` x 1 array). In this case, the @@ -190,13 +204,34 @@ for ax, (var, ylab) in zip(axes.flatten(), plot_details): ax.legend(frameon=False) ``` +## Productivity allocation + +The T Model also predicts how potential GPP will be allocated to respiration, turnover +and growth for stems with a given PFT and allometry. Again, a single value can be +provided to get a single estimate of the allocation model for each stem: + +```{code-cell} +single_allocation = StemAllocation( + stem_traits=flora, stem_allometry=single_allometry, at_potential_gpp=np.array([55]) +) +single_allocation +``` + ```{code-cell} -potential_gpp = np.repeat(55, dbh_col.size)[:, None] -print(potential_gpp) +pd.DataFrame( + {k: getattr(single_allocation, k) for k in single_allocation.allocation_attrs} +) +``` +Using a column array of potential GPP values can be used predict multiple estimates of +allocation per stem. In the first example, the code takes the allometric predictions +from above and calculates the GPP allocation for stems of varying size with the same +potential GPP: +```{code-cell} +potential_gpp = np.repeat(5, dbh_col.size)[:, None] allocation = StemAllocation( - stem_traits=flora, stem_allometry=single_allometry, at_potential_gpp=potential_gpp + stem_traits=flora, stem_allometry=allometries, at_potential_gpp=potential_gpp ) ``` @@ -218,7 +253,7 @@ plot_details = [ axes = axes.flatten() for ax, (var, ylab) in zip(axes, plot_details): - ax.plot(dbh, allocation[var], label=flora.keys()) + ax.plot(dbh_col, getattr(allocation, var), label=flora.name) ax.set_xlabel("Diameter at breast height (m)") ax.set_ylabel(ylab) @@ -228,3 +263,41 @@ for ax, (var, ylab) in zip(axes, plot_details): # Delete unused panel in 5 x 2 grid fig.delaxes(axes[-1]) ``` + +An alternative calculation is to make allocation predictions for varying potential GPP +for constant allometries: + +```{code-cell} +# Column array of DBH values from 0 to 1.6 metres +dbh_constant = np.repeat(0.2, 50)[:, None] +# Get the allometric predictions +constant_allometries = StemAllometry(stem_traits=flora, at_dbh=dbh_constant) + +potential_gpp_varying = np.linspace(1, 10, num=50)[:, None] +allocation_2 = StemAllocation( + stem_traits=flora, + stem_allometry=constant_allometries, + at_potential_gpp=potential_gpp_varying, +) +``` + +```{code-cell} +fig, axes = plt.subplots(ncols=2, nrows=5, sharex=True, figsize=(10, 12)) + +axes = axes.flatten() + +for ax, (var, ylab) in zip(axes, plot_details): + ax.plot(potential_gpp_varying, getattr(allocation_2, var), label=flora.name) + ax.set_xlabel("Potential GPP") + ax.set_ylabel(ylab) + + if var == "whole_crown_gpp": + ax.legend(frameon=False) + +# Delete unused panel in 5 x 2 grid +fig.delaxes(axes[-1]) +``` + +```{code-cell} + +``` From 6eea057b8f2f68c246fbc623cd5cbcf6eba90003 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 17:10:42 +0100 Subject: [PATCH 183/241] Adding simple info attributes and __repr__ methods --- pyrealm/demography/flora.py | 12 +++++++- pyrealm/demography/t_model_functions.py | 40 ++++++++++++++++++------- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 4c78e5ea..41767d5f 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -315,6 +315,8 @@ class Flora: """An dictionary giving the index of each PFT name in the trait array attributes.""" n_pfts: int = field(init=False) """The number of plant functional types in the Flora instance.""" + _n_stems: int = field(init=False) + """Private attribute for compatibility with StemTraits API.""" def __post_init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None: # Check the PFT data @@ -337,6 +339,7 @@ def __post_init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None # Populate the pft dictionary using the PFT name as key and the number of PFTs object.__setattr__(self, "pft_dict", {p.name: p for p in pfts}) object.__setattr__(self, "n_pfts", len(pfts)) + object.__setattr__(self, "_n_stems", len(pfts)) # Populate the trait attributes with arrays for pft_field in self.trait_attrs: @@ -350,7 +353,7 @@ def __post_init__(self, pfts: Sequence[type[PlantFunctionalTypeStrict]]) -> None def __repr__(self) -> str: """Simple representation of the Flora instance.""" - return f"Flora with {self.n_pfts} functional types: {', '.join(self.name)}" + return f"Flora with {self._n_stems} functional types: {', '.join(self.name)}" @classmethod def _from_file_data(cls, file_data: dict) -> Flora: @@ -501,3 +504,10 @@ class StemTraits: """Scaling factor to derive maximum crown radius from crown area.""" z_max_prop: NDArray[np.float32] """Proportion of stem height at which maximum crown radius is found.""" + + # Post init attributes + _n_stems: int = field(init=False) + + def __post_init__(self) -> None: + """Post init validation and attribute setting.""" + self._n_stems = len(self.a_hd) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index df818c67..ecdbdf17 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -716,8 +716,10 @@ class StemAllometry: crown_z_max: NDArray[np.float32] = field(init=False) """Height of maximum crown radius (metres)""" # Information attributes - _n_z_obs: int = field(init=False) - """The number of calculated height values per stem.""" + _n_pred: int = field(init=False) + """The number of predictions per stem.""" + _n_stems: int = field(init=False) + """The number of stems.""" def __post_init__( self, stem_traits: Flora | StemTraits, at_dbh: NDArray[np.float32] @@ -776,19 +778,20 @@ def __post_init__( stem_height=self.stem_height, ) + # Set the number of observations per stem (one if dbh is 1D, otherwise size of + # the first axis) if self.dbh.ndim == 1: - self._n_z_obs = 1 + self._n_pred = 1 else: - self._n_z_obs = self.dbh.shape[0] + self._n_pred = self.dbh.shape[0] + + self._n_stems = stem_traits._n_stems def __repr__(self) -> str: - if self._n_z_obs == 1: - return f"StemAllometry: Single prediction for {len(self.dbh)} stems" - else: - return ( - f"StemAllometry: Prediction for {len(self.dbh)} stems " - f"at {self._n_z_obs} DBH values." - ) + return ( + f"StemAllometry: Prediction for {self._n_stems} stems at se" + f"at {self._n_pred} DBH values." + ) @dataclass() @@ -921,3 +924,18 @@ def __post_init__( stem_height=stem_allometry.stem_height, ) ) + + # Set the number of observations per stem (one if dbh is 1D, otherwise size of + # the first axis) + if self.potential_gpp.ndim == 1: + self._n_pred = 1 + else: + self._n_pred = self.potential_gpp.shape[0] + + self._n_stems = stem_traits._n_stems + + def __repr__(self) -> str: + return ( + f"StemAllocation: Prediction for {self._n_stems} stems" + f"at {self._n_pred} observations." + ) From 8d034fa9c3f88e93507dfd34e3356646fd284c4e Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 17:26:41 +0100 Subject: [PATCH 184/241] Adding demography docs to TOC --- docs/source/_toc.yml | 6 ++++++ docs/source/users/demography/module_overview.md | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 docs/source/users/demography/module_overview.md diff --git a/docs/source/_toc.yml b/docs/source/_toc.yml index 73c15779..c243c1d8 100644 --- a/docs/source/_toc.yml +++ b/docs/source/_toc.yml @@ -1,6 +1,7 @@ root: index subtrees: + - caption: Users entries: - file: users/pmodel/module_overview.md @@ -27,6 +28,11 @@ subtrees: - file: users/pmodel/subdaily_details/worked_example.md - file: users/pmodel/c3c4model.md - file: users/pmodel/isotopic_discrimination.md + - file: users/demography/module_overview.md + subtrees: + - entries: + - file: users/demography/flora.md + - file: users/demography/crown.md - file: users/tmodel/tmodel.md - file: users/tmodel/canopy.md - file: users/splash.md diff --git a/docs/source/users/demography/module_overview.md b/docs/source/users/demography/module_overview.md new file mode 100644 index 00000000..2d399c9e --- /dev/null +++ b/docs/source/users/demography/module_overview.md @@ -0,0 +1,16 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# The demography module + +This is placeholder text for a broader introduction to the demography module. From 89a2960cff7c04c45576f0525154c13e410bb5d0 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 17:32:05 +0100 Subject: [PATCH 185/241] Typos and broken link --- docs/source/users/demography/crown.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md index 4d3cf0b7..3e8d8a3a 100644 --- a/docs/source/users/demography/crown.md +++ b/docs/source/users/demography/crown.md @@ -136,10 +136,10 @@ We can use {mod}`pandas` to visualise those allometric predictions. pd.DataFrame({k: getattr(allometry, k) for k in allometry.allometry_attrs}) ``` -We can now use the {meth}`~pyrealm.demography.flora.Flora.get_canopy_profile` method to -calculate the canopy profile for each stem for a set of vertical heights. The heights +We can now use the {class}`~pyrealm.demography.crown.CrownProfile` class to +calculate the crown profile for each stem for a set of vertical heights. The heights need to be defined as a column array, that is with a shape `(N, 1)`, in order to show -that we want the canopy variables to be calculated at each height for each PFT. +that we want the crown variables to be calculated at each height for each PFT. ```{code-cell} # Create a set of vertical heights as a column array. @@ -253,15 +253,15 @@ crown_profiles2 = CrownProfile(stem_traits=flora2, stem_allometry=allometry2, z= The plot below shows how projected crown area (solid lines) and leaf area (dashed lines) change with height along the stem. -* The projected crown area increases from zero at the top of the canopy, according to - the canopy profile, until it reaches the maximum crown radius, at which point it - remains constant down to ground level. The total crown areas differs for each stem - because of the slightly different values used for the crown area ratio. +* The projected crown area increases from zero at the top of the crown until it reaches + the maximum crown radius, at which point it remains constant down to ground level. The + total crown areas differs for each stem because of the slightly different values used + for the crown area ratio. * The projected leaf area is very similar but leaf area is displaced towards the ground because of the crown gap fraction (`f_g`). Where `f_g = 0` (the red line), the two lines are identical, but as `f_g` increases, more of the leaf area is displaced down - within the canopy. + within the crown. ```{code-cell} fig, ax = plt.subplots(ncols=1) From d4a21af7eb52d6fc3b199c77fba2e6e35c8bbc3a Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 30 Sep 2024 17:51:32 +0100 Subject: [PATCH 186/241] Tidying up repr methods --- docs/source/api/demography_api.md | 16 ++++++++++++---- docs/source/users/demography/crown.md | 11 ++++++----- pyrealm/demography/crown.py | 21 +++++++++++++++++++++ pyrealm/demography/t_model_functions.py | 11 +++++++++-- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/docs/source/api/demography_api.md b/docs/source/api/demography_api.md index c327e76b..459345c4 100644 --- a/docs/source/api/demography_api.md +++ b/docs/source/api/demography_api.md @@ -27,18 +27,26 @@ kernelspec: :members: ``` -## The {mod}`~pyrealm.demography.community` module +## The {mod}`~pyrealm.demography.t_model_functions` module ```{eval-rst} -.. automodule:: pyrealm.demography.community +.. automodule:: pyrealm.demography.t_model_functions :autosummary: :members: ``` -## The {mod}`~pyrealm.demography.t_model_functions` module +## The {mod}`~pyrealm.demography.crown` module ```{eval-rst} -.. automodule:: pyrealm.demography.t_model_functions +.. automodule:: pyrealm.demography.crown + :autosummary: + :members: +``` + +## The {mod}`~pyrealm.demography.community` module + +```{eval-rst} +.. automodule:: pyrealm.demography.community :autosummary: :members: ``` diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md index 3e8d8a3a..a107675e 100644 --- a/docs/source/users/demography/crown.md +++ b/docs/source/users/demography/crown.md @@ -94,7 +94,7 @@ ax2.set_aspect("equal") The examples below show the calculation of crown profiles for a set of plant functional types (PFTs) with differing crown trait values. We first need to create a -:class:`~pyrealm.demography.flora.Flora` object that defines those PFTs. +{class}`~pyrealm.demography.flora.Flora` object that defines those PFTs. ```{code-cell} flora = Flora( @@ -223,6 +223,9 @@ for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 12), ("r", "g", "b")): linestyle=":", ) + ax.set_xlabel("Crown profile") + ax.set_ylabel("Height above ground (m)") + ax.set_aspect(aspect=1) ``` @@ -275,8 +278,6 @@ for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 10), ("r", "g", "b")): color=colour, linestyle="--", ) -``` - -```{code-cell} - + ax.set_xlabel("Projected area (m2)") + ax.set_ylabel("Height above ground (m)") ``` diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index ed93fa32..61a60ce1 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -391,6 +391,12 @@ class CrownProfile: projected_leaf_area: NDArray[np.float32] = field(init=False) """An array of the projected leaf area of stems at z heights""" + # Information attributes + _n_pred: int = field(init=False) + """The number of predictions per stem.""" + _n_stems: int = field(init=False) + """The number of stems.""" + def __post_init__( self, stem_traits: StemTraits | Flora, @@ -431,3 +437,18 @@ def __post_init__( stem_height=stem_allometry.stem_height, z_max=stem_allometry.crown_z_max, ) + + # Set the number of observations per stem (one if dbh is 1D, otherwise size of + # the first axis) + if self.relative_crown_radius.ndim == 1: + self._n_pred = 1 + else: + self._n_pred = self.relative_crown_radius.shape[0] + + self._n_stems = stem_traits._n_stems + + def __repr__(self) -> str: + return ( + f"CrownProfile: Prediction for {self._n_stems} stems " + f"at {self._n_pred} observations." + ) diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index ecdbdf17..dbedb70f 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -715,6 +715,7 @@ class StemAllometry: """Crown radius scaling factor (-)""" crown_z_max: NDArray[np.float32] = field(init=False) """Height of maximum crown radius (metres)""" + # Information attributes _n_pred: int = field(init=False) """The number of predictions per stem.""" @@ -789,7 +790,7 @@ def __post_init__( def __repr__(self) -> str: return ( - f"StemAllometry: Prediction for {self._n_stems} stems at se" + f"StemAllometry: Prediction for {self._n_stems} stems " f"at {self._n_pred} DBH values." ) @@ -860,6 +861,12 @@ class StemAllocation: delta_foliage_mass: NDArray[np.float32] = field(init=False) """Predicted increase in foliar mass from growth allocation (g C)""" + # Information attributes + _n_pred: int = field(init=False) + """The number of predictions per stem.""" + _n_stems: int = field(init=False) + """The number of stems.""" + def __post_init__( self, stem_traits: Flora | StemTraits, @@ -936,6 +943,6 @@ def __post_init__( def __repr__(self) -> str: return ( - f"StemAllocation: Prediction for {self._n_stems} stems" + f"StemAllocation: Prediction for {self._n_stems} stems " f"at {self._n_pred} observations." ) From 4c5776ca458222ab420177fbe1cac12f411a082f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:50:50 +0000 Subject: [PATCH 187/241] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.5 → v0.6.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.5...v0.6.8) - [github.com/igorshubovych/markdownlint-cli: v0.41.0 → v0.42.0](https://github.com/igorshubovych/markdownlint-cli/compare/v0.41.0...v0.42.0) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 327eeef8..969a879d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ repos: - id: debug-statements - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.5 + rev: v0.6.8 hooks: # Run the linter. - id: ruff @@ -21,7 +21,7 @@ repos: exclude: "pyrealm_build_data/splash/splash_py_version/.*\\.py" # https://stackoverflow.com/a/75447331/3401916 - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.41.0 + rev: v0.42.0 hooks: - id: markdownlint - repo: https://github.com/mwouts/jupytext From decba0d48f51be4b44cde3d73527ba7fccca1f6e Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 1 Oct 2024 13:21:02 +0100 Subject: [PATCH 188/241] Working in old canopy demo using actual code --- .../users/{tmodel => demography}/canopy.md | 9 +- docs/source/users/demography/crown.md | 304 ++++++++++++------ docs/source/users/demography/flora.md | 2 +- 3 files changed, 215 insertions(+), 100 deletions(-) rename docs/source/users/{tmodel => demography}/canopy.md (99%) diff --git a/docs/source/users/tmodel/canopy.md b/docs/source/users/demography/canopy.md similarity index 99% rename from docs/source/users/tmodel/canopy.md rename to docs/source/users/demography/canopy.md index b0911b87..a285909b 100644 --- a/docs/source/users/tmodel/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -6,13 +6,20 @@ jupytext: format_name: myst format_version: 0.13 kernelspec: - display_name: python3 + display_name: Python 3 (ipykernel) language: python name: python3 --- # Canopy model +:::{admonition} Warning + +This area of `pyrealm` is in active development and this notebook currently contains +notes and initial demonstration code. + +::: + This notebook walks through the steps in generating the canopy model as (hopefully) used in Plant-FATE. diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md index a107675e..1eba4486 100644 --- a/docs/source/users/demography/crown.md +++ b/docs/source/users/demography/crown.md @@ -43,31 +43,114 @@ from pyrealm.demography.crown import ( ``` The {mod}`pyrealm.demography` module uses three-dimensional model of crown shape to -define the vertical distribution of leaf area. This is driven by four parameters within -the {class}`~pyrealm.demography.flora.PlantFunctionalType`: +define the vertical distribution of leaf area, following the implementation of crown +shape in the Plant-FATE model {cite}`joshi:2022a`. -* The `m` and `n` parameters that define the vertical shape of the crown profile. -* The `ca_ratio` parameters that defines the size of the crown relative to the stem size. -* The `f_g` parameter that define the crown gap fraction and sets the vertical - distribution of leaves within the crown. - -The code below provides a demonstration of the impacts of each parameter and shows the -use of `pyrealm` tools to visualise the crown model for individual stems. - -## Crown shape parameters +## Crown traits -The `m` and `n` parameters define the vertical profile of the crown but are also define -two further parameters: +The crown model for a plant functional type (PFT) is driven by four traits within +the {class}`~pyrealm.demography.flora.PlantFunctionalType` class: -* `q_m`, which is used to scale the size of the crown radius to match the expected crown - area, given the crown shape. -* `z_max_prop`, which sets the height on the stem at which the maximum crown radius is found. +* The `m` and `n` ($m, n$) traits set the vertical shape of the crown profile. +* The `ca_ratio` trait sets the area of the crown ($A_c$) relative to the stem size. +* The `f_g` ($f_g$) trait sets the crown gap fraction and sets the vertical + distribution of leaves within the crown. -The code below calculates `q_m` and `z_max_prop` for combinations of `m` and `n` and -then plots the resulting values. +### Canopy shape + +For a stem of height $H$, the $m$ and $n$ traits are used to calculate the *relative* +crown radius $q(z)$ at a height $z$ of as: + +$$ +q(z)= m n \left(\dfrac{z}{H}\right) ^ {n -1} + \left( 1 - \left(\dfrac{z}{H}\right) ^ n \right)^{m-1} +$$ + +In order to align the arbitrary relative radius values with the predictions of the +T Model for the stem, we then need to find the height at which the relative radius +is at its maximum and a scaling factor that will convert the relative area at this +height to the expected crown area under the T Model. These can be calculated using +the following two additional traits, which are invariant for a PFT. + +* `z_max_prop` ($p_{zm}$) sets the proportion of the height of the stem at which + the maximum relative crown radius is found. +* `q_m` ($q_m$) is used to scale the size of the crown radius at $z_{max}$ to match + the expected crown area. + +$$ +\begin{align} +p_{zm} &= \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}}\\[8pt] +q_m &= m n \left(\dfrac{n-1}{m n -1}\right)^ {1 - \tfrac{1}{n}} + \left(\dfrac{\left(m-1\right) n}{m n -1}\right)^ {m-1} +\end{align} +$$ + +For individual stems, with expected height $H$ and crown area $A_c$, we can then +calculate: + +* the height $z_m$ at which the maximum crown radius $r_m$ is found, +* a height-specific scaling factor $r_0$ such that $\pi q(z_m)^2 = A_c$, +* the actual crown radius $r(z)$ at a given height $z$. + +$$ +\begin{align} +z_m &= H p_{zm}\\[8pt] +r_0 &= \frac{1}{q_m}\sqrt{\frac{A_c}{\pi}}\\[8pt] +r(z) &= r_0 \; q(z) +\end{align} +$$ + +### Projected crown and leaf area + +From the crown radius profile, the model can then be used to calculate how crown area +and leaf area accumulates from the top of the crown towards the ground, giving +functions given height $z$ for: + +* the projected crown area $A_p(z)$, and +* the projected leaf area $\tilde{A}_{cp}(z)$. + +The projected crown area is calculated for a stem of known height and crown area is: + +$$ +A_p(z)= +\begin{cases} +A_c, & z \le z_m \\ +A_c \left(\dfrac{q(z)}{q_m}\right)^2, & H > z > z_m \\ +0, & z > H +\end{cases} +$$ + +That is, the projected crown area is zero above the top of the stem, increases to the +expected crown area at $z_max$ and is then constant to ground level. + +The projected leaf area $\tilde{A}_{cp}(z)$ models how the vertical distribution of +leaf area within the crown is modified by the crown gap fraction $f_g$. This trait +models how leaf gaps higher in the crown are filled by leaf area at lower heights: +it does not change the profile of the crown but allows leaf area in the crown to be +displaced downwards. When $f_g = 0$, the projected crown and leaf areas are identical, +but as $f_g \to 1$ the projected leaf area is pushed downwards. +The calculation of $\tilde{A}_{cp}(z)$ is defined as: + +$$ +\tilde{A}_{cp}(z)= +\begin{cases} +0, & z \gt H \\ +A_c \left(\dfrac{q(z)}{q_m}\right)^2 \left(1 - f_g\right), & H \gt z \gt z_m \\ +Ac - A_c \left(\dfrac{q(z)}{q_m}\right)^2 f_g, & zm \gt z +\end{cases} +$$ + +## Calculating crown model traits in `pyrealm` + +The {class}`~pyrealm.demography.flora.PlantFunctionalType` class is typically +used to set specific PFTs, but the functions to calculate $q_m$ and $p_{zm}$ +are used directly below to provides a demonstration of the impacts of each trait. ```{code-cell} +# Set a range of values for m and n traits m = n = np.arange(1.0, 5, 0.1) + +# Calculate the invariant q_m and z_max_prop traits q_m = calculate_crown_q_m(m=m, n=n[:, None]) z_max_prop = calculate_crown_z_max_proportion(m=m, n=n[:, None]) ``` @@ -90,36 +173,53 @@ ax2.set_ylabel("n") ax2.set_aspect("equal") ``` -## Plotting crown profiles +## Crown calculations in `pyrealm` -The examples below show the calculation of crown profiles for a set of plant functional -types (PFTs) with differing crown trait values. We first need to create a -{class}`~pyrealm.demography.flora.Flora` object that defines those PFTs. +The examples below show the calculation of crown variables in `pyrealm`. -```{code-cell} -flora = Flora( - [ - PlantFunctionalType(name="short", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=20), - PlantFunctionalType( - name="medium", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=500 - ), - PlantFunctionalType(name="tall", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=2000), - ] -) +### Calculting crown profiles + +The {class}`~pyrealm.demography.crown.CrownProfile` class is used to calculate crown +profiles for PFTs. It requires: + +* a {class}`~pyrealm.demography.flora.Flora` instance providing a set of PFTs to be + compared, +* a {class}`~pyrealm.demography.t_model_functions.StemAllometry` instance setting the + specific stem sizes for the profile, and +* a set of heights at which to estimate the profile variables + +The code below creates a set of PFTS with differing crown trait values and then creates +a `Flora` object using the PFTs. +```{code-cell} +# A PFT with a small crown area and equal m and n values +narrow_pft = PlantFunctionalType(name="narrow", h_max=20, m=1.5, n=1.5, ca_ratio=20) +# A PFT with an intermediate crown area and m < n +medium_pft = PlantFunctionalType(name="medium", h_max=20, m=1.5, n=4, ca_ratio=500) +# A PFT with a wide crown area and m > n +wide_pft = PlantFunctionalType(name="wide", h_max=20, m=4, n=1.5, ca_ratio=2000) + +# Generate a Flora instance using those PFTs +flora = Flora([narrow_pft, medium_pft, wide_pft]) flora ``` +The Flora object can also be used to show a table of canopy variables: + ```{code-cell} -pd.DataFrame({k: getattr(flora, k) for k in flora.trait_attrs}) +# TODO - add a Flora.to_pandas() method +flora_data = pd.DataFrame({k: getattr(flora, k) for k in flora.trait_attrs}) +flora_data[["name", "ca_ratio", "m", "n", "f_g", "q_m", "z_max_prop"]] ``` -We then also need to specify the size of a stem of each PFT, along with the resulting -allometric predictions from the T Model. +The next section of code generates the `StemAllometry` to use for the profiles. +The T Model uses DBH to define stem size - here the the code is being used to +back-calculate the required DBH values to give three stems with similar heights +near the maximum height for each PFT. ```{code-cell} -# Generate the expected stem allometries at a single height for each PFT -stem_height = np.array([18, 18, 18]) +# Generate the expected stem allometries at similar heights for each PFT +stem_height = np.array([19, 17, 15]) stem_dbh = calculate_dbh_from_height( a_hd=flora.a_hd, h_max=flora.h_max, stem_height=stem_height ) @@ -127,79 +227,64 @@ stem_dbh ``` ```{code-cell} +# Calculate the stem allometries allometry = StemAllometry(stem_traits=flora, at_dbh=stem_dbh) ``` -We can use {mod}`pandas` to visualise those allometric predictions. +We can again use {mod}`pandas` to get a table of those allometric predictions: ```{code-cell} pd.DataFrame({k: getattr(allometry, k) for k in allometry.allometry_attrs}) ``` -We can now use the {class}`~pyrealm.demography.crown.CrownProfile` class to -calculate the crown profile for each stem for a set of vertical heights. The heights -need to be defined as a column array, that is with a shape `(N, 1)`, in order to show -that we want the crown variables to be calculated at each height for each PFT. +Finally, we can define a set of vertical heights. In order to calculate the +variables for each PFT at each height, this needs to be provided as a column array, +that is with a shape `(N, 1)`. + +We can then calculate the crown profiles. ```{code-cell} # Create a set of vertical heights as a column array. -z = np.linspace(0, 18.0, num=181)[:, None] +z = np.linspace(-1, 20.0, num=211)[:, None] # Calculate the crown profile across those heights for each PFT crown_profiles = CrownProfile(stem_traits=flora, stem_allometry=allometry, z=z) ``` -The `crown_profiles` object is a dictionary containing values for four crown profile -variables. +The `crown_profiles` object then provides the four crown profile attributes describe +above calculated at each height $z$: -* The relative crown radius: this value is driven purely by `m`, `n` and the stem height - and defines the vertical profile of the crown. -* The crown radius: this is simply a rescaling of the relative radius so that the - maximum crown radius matches the expected crown area predicted by the allometry of the - T Model. -* The projected crown area: this value shows how crown area accumulates from the top of - the crown to the ground. -* The projected leaf area: this value shows how _leaf_ area accumulates from the top of - the crown to the ground. The difference from the crown area is driven by the crown gap - fraction for a given PFT. +* The relative crown radius $q(z)$ +* The crown radius $r(z)$ +* The projected crown area +* The projected leaf area ```{code-cell} crown_profiles ``` -### Crown radius values - -The relative crown radius values are arbitrary - they simply define the shape of the -vertical profile. For the example PFTs in the `Flora` object, the maximum relative -radius values on each stem are: - -```{code-cell} -max_relative_crown_radius = crown_profiles.relative_crown_radius.max(axis=0) -print(max_relative_crown_radius) -``` - -However the scaled maximum radius values match the expected crown area in the allometry -table above - -```{code-cell} -max_crown_radius = crown_profiles.crown_radius.max(axis=0) -print(max_crown_radius) -print(max_crown_radius**2 * np.pi) -``` +### Visualising crown profiles The code below generates a plot of the vertical shape profiles of the crowns for each stem. For each stem: -* the dashed line shows how the relative crown radius varies with height, -* the solid line shows the actual crown radius profile with height, and -* the dotted line shows the height at which the maximum crown radius is found. +* the dashed line shows how the relative crown radius $q(z)$ varies with height $z$, +* the solid line shows the actual crown radius $r)z)$ varies with height, and +* the dotted horizontal line shows the height at which the maximum crown radius is + found ($z_max$). + +Note that the equation for the relative radius $q(z)$ does define values where +$z <0$ or $z > H$. ```{code-cell} fig, ax = plt.subplots(ncols=1) # Find the maximum of the actual and relative maximum crown widths +max_relative_crown_radius = np.nanmax(crown_profiles.relative_crown_radius, axis=0) +max_crown_radius = np.nanmax(crown_profiles.crown_radius, axis=0) stem_max_width = np.maximum(max_crown_radius, max_relative_crown_radius) + for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 12), ("r", "g", "b")): # Plot relative radius either side of offset @@ -229,32 +314,51 @@ for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 12), ("r", "g", "b")): ax.set_aspect(aspect=1) ``` -### Projected crown and leaf areas +We can also use the `CanopyProfile` class with a single row of heights to calculate +the crown profile at the expected $z_max$ and show that this matches the expected +crown area from the T Model allometry. + +```{code-cell} +# Calculate the crown profile across those heights for each PFT +z_max = flora.z_max_prop * stem_height +profile_at_zmax = CrownProfile(stem_traits=flora, stem_allometry=allometry, z=z_max) + +print(profile_at_zmax.crown_radius**2 * np.pi) +print(allometry.crown_area) +``` + +### Visualising crown and leaf projected areas -We can use the crown profile to generate projected area plots, but it is much easier to -compare the effects when comparing stems with similar crown areas. The code below -generates these new predictions for a new set of PFTs. +We can also use the crown profile to generate projected area plots. This is hard to see +using the PFTs defined above because they have very different crown areas, so the code +below generates new profiles for a new set of PFTs that have similar crown area ratios +but different shapes and gap fractions. ```{code-cell} -flora2 = Flora( - [ - PlantFunctionalType(name="short", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=380), - PlantFunctionalType( - name="medium", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=400 - ), - PlantFunctionalType(name="tall", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=420), - ] +no_gaps_pft = PlantFunctionalType( + name="no_gaps", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=380 +) +few_gaps_pft = PlantFunctionalType( + name="few_gaps", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=400 +) +many_gaps_pft = PlantFunctionalType( + name="many_gaps", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=420 ) -allometry2 = StemAllometry(stem_traits=flora2, at_dbh=stem_dbh) - +# Calculate allometries for each PFT at the same stem DBH +area_stem_dbh = np.array([0.4, 0.4, 0.4]) +area_flora = Flora([no_gaps_pft, few_gaps_pft, many_gaps_pft]) +area_allometry = StemAllometry(stem_traits=area_flora, at_dbh=area_stem_dbh) -# Calculate the crown profile across those heights for each PFT -crown_profiles2 = CrownProfile(stem_traits=flora2, stem_allometry=allometry2, z=z) +# Calculate the crown profiles across those heights for each PFT +area_z = np.linspace(0, area_allometry.stem_height.max(), 201)[:, None] +area_crown_profiles = CrownProfile( + stem_traits=area_flora, stem_allometry=area_allometry, z=area_z +) ``` -The plot below shows how projected crown area (solid lines) and leaf area (dashed lines) -change with height along the stem. +The plot below then shows how projected crown area (solid lines) and leaf area (dashed +lines) change with height along the stem. * The projected crown area increases from zero at the top of the crown until it reaches the maximum crown radius, at which point it remains constant down to ground level. The @@ -271,13 +375,17 @@ fig, ax = plt.subplots(ncols=1) for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 10), ("r", "g", "b")): - ax.plot(crown_profiles2.projected_crown_area[:, pft_idx], z, color=colour) + ax.plot(area_crown_profiles.projected_crown_area[:, pft_idx], area_z, color=colour) ax.plot( - crown_profiles2.projected_leaf_area[:, pft_idx], - z, + area_crown_profiles.projected_leaf_area[:, pft_idx], + area_z, color=colour, linestyle="--", ) ax.set_xlabel("Projected area (m2)") ax.set_ylabel("Height above ground (m)") ``` + +```{code-cell} + +``` diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index cb3605c8..dfe4f4e2 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -95,7 +95,7 @@ the PlantFATE model {cite}`joshi:2022a`. The {class}`~pyrealm.demography.flora.PlantFunctionalType` class is used define a PFT with a given name, along with the trait values associated with the PFT. By default, -values for each trait are taken from Table 1 of {cite}`Li:2014bc`, but these can be +values for each trait are taken from Table 1 of {cite:t}`Li:2014bc`, but these can be adjusted for different PFTs. The code below contains three examples that just differ in their maximum height. From 9756e30c8341e1ced7afe40b46185043d1fd2ea2 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 1 Oct 2024 13:42:30 +0100 Subject: [PATCH 189/241] Separating flora and t model user docs --- docs/source/users/demography/flora.md | 192 +++------------------ docs/source/users/demography/t_model.md | 211 ++++++++++++++++++++++++ 2 files changed, 237 insertions(+), 166 deletions(-) create mode 100644 docs/source/users/demography/t_model.md diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index dfe4f4e2..4b9bf3f7 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -28,9 +28,7 @@ from matplotlib import pyplot as plt import numpy as np import pandas as pd -from pyrealm.demography.flora import PlantFunctionalType, Flora - -from pyrealm.demography.t_model_functions import StemAllocation, StemAllometry +from pyrealm.demography.flora import PlantFunctionalType, Flora, StemTraits ``` ## Plant traits @@ -114,6 +112,16 @@ The traits values set for a PFT instance can then be shown: short_pft ``` +:::{admonition} Info + +In addition, `pyrealm` also defines the +{class}`~pyrealm.demography.flora.PlantFunctionalTypeStrict` class. This version of the +class requires that all trait values be provided when creating an instance, rather than +falling back to the default values as above. This is mostly used within the `pyrealm` +code for loading PFT data from files. + +::: + ## The Flora class The {class}`~pyrealm.demography.flora.Flora` class is used to collect a list of PFTs @@ -131,173 +139,25 @@ flora pd.DataFrame({k: getattr(flora, k) for k in flora.trait_attrs}) ``` -You can also create `Flora` instances using PFT data stored TOML, JSON and CSV file formats. - -## Stem allometry - -We can visualise how the stem size, canopy size and various masses of PFTs change with -stem diameter by using the {class}`~pyrealm.demography.t_model_functions.StemAllometry` -class. Creating a `StemAllometry` instance needs an existing `Flora` instance and an -array of values for diameter at breast height (DBH, metres). The returned class contains -the predictions of the T Model for: - -* Stem height (`stem_height`, m), -* Crown area (`crown_area`, m2), -* Crown fraction (`crown_fraction`, -), -* Stem mass (`stem_mass`, kg), -* Foliage mass (`foliage_mass`, kg), -* Sapwood mass (`sapwood_mass`, kg), -* Crown radius scaling factor (`crown_r0`, -), and -* Height of maximum crown radius (`crown_z_max`, m). - -The DBH input can be a scalar array or a one dimensional array providing a single value -for each PFT. This then calculates a single estimate at the given size for each stem. - -```{code-cell} -# Calculate a single prediction -single_allometry = StemAllometry(stem_traits=flora, at_dbh=np.array([0.1, 0.1, 0.1])) -``` - -We can display those predictions as a `pandas.DataFrame`: - -```{code-cell} -pd.DataFrame( - {k: getattr(single_allometry, k) for k in single_allometry.allometry_attrs} -) -``` - -However, the DBH values can also be a column array (an `N` x 1 array). In this case, the -predictions are made at each DBH value for each PFT and the allometry attributes with -predictions arranged with each PFT as a column and each DBH prediction as a row. This -makes them convenient to plot using `matplotlib`. - -```{code-cell} -# Column array of DBH values from 0 to 1.6 metres -dbh_col = np.arange(0, 1.6, 0.01)[:, None] -# Get the predictions -allometries = StemAllometry(stem_traits=flora, at_dbh=dbh_col) -``` - -The code below shows how to use the returned allometries to generate a plot of the -scaling relationships across all of the PFTs in a `Flora` instance. - -```{code-cell} -fig, axes = plt.subplots(ncols=2, nrows=4, sharex=True, figsize=(10, 10)) - -plot_details = [ - ("stem_height", "Stem height (m)"), - ("crown_area", "Crown area (m2)"), - ("crown_fraction", "Crown fraction (-)"), - ("stem_mass", "Stem mass (kg)"), - ("foliage_mass", "Foliage mass (kg)"), - ("sapwood_mass", "Sapwood mass (kg)"), - ("crown_r0", "Crown scaling factor (-)"), - ("crown_z_max", "Height of maximum\ncrown radius (m)"), -] - -for ax, (var, ylab) in zip(axes.flatten(), plot_details): - ax.plot(dbh_col, getattr(allometries, var), label=flora.name) - ax.set_xlabel("Diameter at breast height (m)") - ax.set_ylabel(ylab) - - if var == "sapwood_mass": - ax.legend(frameon=False) -``` +You can also create `Flora` instances using PFT data stored TOML, JSON and CSV file +formats. -## Productivity allocation +## The StemTraits class -The T Model also predicts how potential GPP will be allocated to respiration, turnover -and growth for stems with a given PFT and allometry. Again, a single value can be -provided to get a single estimate of the allocation model for each stem: +The {class}`~pyrealm.demography.flora.StemTraits` class is used to hold arrays of the +same PFT traits across any number of stems. Unlike the +{class}`~pyrealm.demography.flora.Flora` class, the `name` attribute does not need to be +unique. It is mostly used within `pyrealm` to represent the stem traits of plant cohorts +within {class}`~pyrealm.demography.community.Community` objects. -```{code-cell} -single_allocation = StemAllocation( - stem_traits=flora, stem_allometry=single_allometry, at_potential_gpp=np.array([55]) -) -single_allocation -``` - -```{code-cell} -pd.DataFrame( - {k: getattr(single_allocation, k) for k in single_allocation.allocation_attrs} -) -``` - -Using a column array of potential GPP values can be used predict multiple estimates of -allocation per stem. In the first example, the code takes the allometric predictions -from above and calculates the GPP allocation for stems of varying size with the same -potential GPP: - -```{code-cell} -potential_gpp = np.repeat(5, dbh_col.size)[:, None] -allocation = StemAllocation( - stem_traits=flora, stem_allometry=allometries, at_potential_gpp=potential_gpp -) -``` - -```{code-cell} -fig, axes = plt.subplots(ncols=2, nrows=5, sharex=True, figsize=(10, 12)) - -plot_details = [ - ("whole_crown_gpp", "whole_crown_gpp"), - ("sapwood_respiration", "sapwood_respiration"), - ("foliar_respiration", "foliar_respiration"), - ("fine_root_respiration", "fine_root_respiration"), - ("npp", "npp"), - ("turnover", "turnover"), - ("delta_dbh", "delta_dbh"), - ("delta_stem_mass", "delta_stem_mass"), - ("delta_foliage_mass", "delta_foliage_mass"), -] - -axes = axes.flatten() - -for ax, (var, ylab) in zip(axes, plot_details): - ax.plot(dbh_col, getattr(allocation, var), label=flora.name) - ax.set_xlabel("Diameter at breast height (m)") - ax.set_ylabel(ylab) - - if var == "whole_crown_gpp": - ax.legend(frameon=False) - -# Delete unused panel in 5 x 2 grid -fig.delaxes(axes[-1]) -``` - -An alternative calculation is to make allocation predictions for varying potential GPP -for constant allometries: - -```{code-cell} -# Column array of DBH values from 0 to 1.6 metres -dbh_constant = np.repeat(0.2, 50)[:, None] -# Get the allometric predictions -constant_allometries = StemAllometry(stem_traits=flora, at_dbh=dbh_constant) - -potential_gpp_varying = np.linspace(1, 10, num=50)[:, None] -allocation_2 = StemAllocation( - stem_traits=flora, - stem_allometry=constant_allometries, - at_potential_gpp=potential_gpp_varying, -) -``` - -```{code-cell} -fig, axes = plt.subplots(ncols=2, nrows=5, sharex=True, figsize=(10, 12)) - -axes = axes.flatten() - -for ax, (var, ylab) in zip(axes, plot_details): - ax.plot(potential_gpp_varying, getattr(allocation_2, var), label=flora.name) - ax.set_xlabel("Potential GPP") - ax.set_ylabel(ylab) - - if var == "whole_crown_gpp": - ax.legend(frameon=False) - -# Delete unused panel in 5 x 2 grid -fig.delaxes(axes[-1]) -``` +A `StemTraits` instance can be created directly by providing arrays for each trait, but is +more easily created from a `Flora` object by providing a list of PFT names: ```{code-cell} +# Get stem traits for a range of stems +stem_pfts = ["short", "short", "short", "medium", "medium", "tall"] +stem_traits = flora.get_stem_traits(pft_names=stem_pfts) +# Show the repeated values +stem_traits.h_max ``` diff --git a/docs/source/users/demography/t_model.md b/docs/source/users/demography/t_model.md new file mode 100644 index 00000000..72be1d0d --- /dev/null +++ b/docs/source/users/demography/t_model.md @@ -0,0 +1,211 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# The T Model module + +The T Model {cite}`Li:2014bc` provides a model of both: + +* stem allometry, given a set of [stem traits](./flora.md) for a plant functional type + (PFT), and +* a carbon allocation model, given stem allometry and potential GPP. + +```{code-cell} +from matplotlib import pyplot as plt +import numpy as np +import pandas as pd + +from pyrealm.demography.flora import PlantFunctionalType, Flora +from pyrealm.demography.t_model_functions import StemAllocation, StemAllometry +``` + +To generate predictions under the T Model, we need a Flora object providing the +[trait values](./flora.md) for each of the PFTsto be modelled: + +```{code-cell} +# Three PFTS +short_pft = PlantFunctionalType(name="short", h_max=10) +medium_pft = PlantFunctionalType(name="medium", h_max=20) +tall_pft = PlantFunctionalType(name="tall", h_max=30) + +# Combine into a Flora instance +flora = Flora([short_pft, medium_pft, tall_pft]) +``` + +## Stem allometry + +We can visualise how the stem size, canopy size and various masses of PFTs change with +stem diameter by using the {class}`~pyrealm.demography.t_model_functions.StemAllometry` +class. Creating a `StemAllometry` instance needs an existing `Flora` instance and an +array of values for diameter at breast height (DBH, metres). The returned class contains +the predictions of the T Model for: + +* Stem height (`stem_height`, m), +* Crown area (`crown_area`, m2), +* Crown fraction (`crown_fraction`, -), +* Stem mass (`stem_mass`, kg), +* Foliage mass (`foliage_mass`, kg), +* Sapwood mass (`sapwood_mass`, kg), +* Crown radius scaling factor (`crown_r0`, -), and +* Height of maximum crown radius (`crown_z_max`, m). + +The DBH input can be a scalar array or a one dimensional array providing a single value +for each PFT. This then calculates a single estimate at the given size for each stem. + +```{code-cell} +# Calculate a single prediction +single_allometry = StemAllometry(stem_traits=flora, at_dbh=np.array([0.1, 0.1, 0.1])) +``` + +We can display those predictions as a `pandas.DataFrame`: + +```{code-cell} +pd.DataFrame( + {k: getattr(single_allometry, k) for k in single_allometry.allometry_attrs} +) +``` + +However, the DBH values can also be a column array (an `N` x 1 array). In this case, the +predictions are made at each DBH value for each PFT and the allometry attributes with +predictions arranged with each PFT as a column and each DBH prediction as a row. This +makes them convenient to plot using `matplotlib`. + +```{code-cell} +# Column array of DBH values from 0 to 1.6 metres +dbh_col = np.arange(0, 1.6, 0.01)[:, None] +# Get the predictions +allometries = StemAllometry(stem_traits=flora, at_dbh=dbh_col) +``` + +The code below shows how to use the returned allometries to generate a plot of the +scaling relationships across all of the PFTs in a `Flora` instance. + +```{code-cell} +fig, axes = plt.subplots(ncols=2, nrows=4, sharex=True, figsize=(10, 10)) + +plot_details = [ + ("stem_height", "Stem height (m)"), + ("crown_area", "Crown area (m2)"), + ("crown_fraction", "Crown fraction (-)"), + ("stem_mass", "Stem mass (kg)"), + ("foliage_mass", "Foliage mass (kg)"), + ("sapwood_mass", "Sapwood mass (kg)"), + ("crown_r0", "Crown scaling factor (-)"), + ("crown_z_max", "Height of maximum\ncrown radius (m)"), +] + +for ax, (var, ylab) in zip(axes.flatten(), plot_details): + ax.plot(dbh_col, getattr(allometries, var), label=flora.name) + ax.set_xlabel("Diameter at breast height (m)") + ax.set_ylabel(ylab) + + if var == "sapwood_mass": + ax.legend(frameon=False) +``` + +## Productivity allocation + +The T Model also predicts how potential GPP will be allocated to respiration, turnover +and growth for stems with a given PFT and allometry. Again, a single value can be +provided to get a single estimate of the allocation model for each stem: + +```{code-cell} +single_allocation = StemAllocation( + stem_traits=flora, stem_allometry=single_allometry, at_potential_gpp=np.array([55]) +) +single_allocation +``` + +```{code-cell} +pd.DataFrame( + {k: getattr(single_allocation, k) for k in single_allocation.allocation_attrs} +) +``` + +Using a column array of potential GPP values can be used predict multiple estimates of +allocation per stem. In the first example, the code takes the allometric predictions +from above and calculates the GPP allocation for stems of varying size with the same +potential GPP: + +```{code-cell} +potential_gpp = np.repeat(5, dbh_col.size)[:, None] +allocation = StemAllocation( + stem_traits=flora, stem_allometry=allometries, at_potential_gpp=potential_gpp +) +``` + +```{code-cell} +fig, axes = plt.subplots(ncols=2, nrows=5, sharex=True, figsize=(10, 12)) + +plot_details = [ + ("whole_crown_gpp", "whole_crown_gpp"), + ("sapwood_respiration", "sapwood_respiration"), + ("foliar_respiration", "foliar_respiration"), + ("fine_root_respiration", "fine_root_respiration"), + ("npp", "npp"), + ("turnover", "turnover"), + ("delta_dbh", "delta_dbh"), + ("delta_stem_mass", "delta_stem_mass"), + ("delta_foliage_mass", "delta_foliage_mass"), +] + +axes = axes.flatten() + +for ax, (var, ylab) in zip(axes, plot_details): + ax.plot(dbh_col, getattr(allocation, var), label=flora.name) + ax.set_xlabel("Diameter at breast height (m)") + ax.set_ylabel(ylab) + + if var == "whole_crown_gpp": + ax.legend(frameon=False) + +# Delete unused panel in 5 x 2 grid +fig.delaxes(axes[-1]) +``` + +An alternative calculation is to make allocation predictions for varying potential GPP +for constant allometries: + +```{code-cell} +# Column array of DBH values from 0 to 1.6 metres +dbh_constant = np.repeat(0.2, 50)[:, None] +# Get the allometric predictions +constant_allometries = StemAllometry(stem_traits=flora, at_dbh=dbh_constant) + +potential_gpp_varying = np.linspace(1, 10, num=50)[:, None] +allocation_2 = StemAllocation( + stem_traits=flora, + stem_allometry=constant_allometries, + at_potential_gpp=potential_gpp_varying, +) +``` + +```{code-cell} +fig, axes = plt.subplots(ncols=2, nrows=5, sharex=True, figsize=(10, 12)) + +axes = axes.flatten() + +for ax, (var, ylab) in zip(axes, plot_details): + ax.plot(potential_gpp_varying, getattr(allocation_2, var), label=flora.name) + ax.set_xlabel("Potential GPP") + ax.set_ylabel(ylab) + + if var == "whole_crown_gpp": + ax.legend(frameon=False) + +# Delete unused panel in 5 x 2 grid +fig.delaxes(axes[-1]) +``` + +```{code-cell} + +``` From 539e435ce05ce1d8352e22805cebedf2e28faecb Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 1 Oct 2024 13:52:07 +0100 Subject: [PATCH 190/241] Update overview and TOC --- docs/source/_toc.yml | 2 ++ docs/source/users/demography/community.md | 20 +++++++++++++++++++ .../users/demography/module_overview.md | 13 +++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 docs/source/users/demography/community.md diff --git a/docs/source/_toc.yml b/docs/source/_toc.yml index c243c1d8..592b04fa 100644 --- a/docs/source/_toc.yml +++ b/docs/source/_toc.yml @@ -32,7 +32,9 @@ subtrees: subtrees: - entries: - file: users/demography/flora.md + - file: users/demography/t_model.md - file: users/demography/crown.md + - file: users/demography/canopy.md - file: users/tmodel/tmodel.md - file: users/tmodel/canopy.md - file: users/splash.md diff --git a/docs/source/users/demography/community.md b/docs/source/users/demography/community.md new file mode 100644 index 00000000..d7caf0f8 --- /dev/null +++ b/docs/source/users/demography/community.md @@ -0,0 +1,20 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: python3 + language: python + name: python3 +--- + +# Plant Communities + +:::{admonition} Warning + +This area of `pyrealm` is in active development. + +::: diff --git a/docs/source/users/demography/module_overview.md b/docs/source/users/demography/module_overview.md index 2d399c9e..fffdd77f 100644 --- a/docs/source/users/demography/module_overview.md +++ b/docs/source/users/demography/module_overview.md @@ -13,4 +13,15 @@ kernelspec: # The demography module -This is placeholder text for a broader introduction to the demography module. +The functionality of the demography module is split into the following submodules + +* The [`flora` module](./flora.md) that defines the set of plant functional traits used + in demographic modelling and the classes used to represent those traits. +* The [`t_model` module](./t_model.md) module that implements the allometric and + allocation equations of the T Model {cite}`Li:2014bc`. +* The [`crown` module](./crown.md) that implements a three dimensional model of crown + shape taken from the Plant-FATE model {cite}`joshi:2022a`. +* The [`community` module](./community.md) that implements a plant community model using + size-structured cohorts. +* The [`canopy` module](./canopy.md) that generates a model of the canopy structure for + a community, based on the Perfect Plasticity Approximation model :cite:`purves:2008a`. From ff9d4ad834d2abf87a14b23b1a857019c8fd8403 Mon Sep 17 00:00:00 2001 From: MarionBWeinzierl Date: Tue, 1 Oct 2024 14:45:03 +0100 Subject: [PATCH 191/241] check shape of init_realised, add initial_values argument to memory_effect --- pyrealm/pmodel/subdaily.py | 39 +++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index fd3b2447..bb48ef1e 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -38,7 +38,10 @@ def memory_effect( - values: NDArray, alpha: float = 0.067, allow_holdover: bool = False + values: NDArray, + initial_values: NDArray | None = None, + alpha: float = 0.067, + allow_holdover: bool = False, ) -> NDArray: r"""Apply a memory effect to a variable. @@ -86,6 +89,8 @@ def memory_effect( Args: values: The values to apply the memory effect to. + initial_values: Last available realised value used if model is fitted in + chunks and value at t=0 is not optimal. alpha: The relative weight applied to the most recent observation. allow_holdover: Allow missing values to be filled by holding over earlier values. @@ -102,7 +107,10 @@ def memory_effect( # Initialise the output storage and set the first values to be a slice along the # first axis of the input values memory_values = np.empty_like(values, dtype=np.float32) - memory_values[0] = values[0] + if initial_values is None: + memory_values[0] = values[0] + else: + memory_values[0] = initial_values # Handle the data if there are no missing data, if not nan_present: @@ -365,23 +373,36 @@ def __init__( """Instantaneous optimal :math:`x_{i}`, :math:`V_{cmax}` and :math:`J_{max}`""" if init_realised is not None: - self.init_xi_real, self.init_vcmax_real, self.init_jmax_real = init_realised + if not ( + (init_realised[0].shape() == self.xi_real.shape()) + and (init_realised[1].shape() == self.vcmax25_real.shape()) + and (init_realised[2].shape() == self.jmax25_real.shape()) + ): + raise Exception("`init_realised` has wrong shape in Subdaily PModel") + else: + init_xi_real, init_vcmax_real, init_jmax_real = init_realised else: - self.init_xi_real = self.pmodel_acclim.optchi.xi - self.init_vcmax_real = self.vcmax25_opt - self.init_jmax_real = self.jmax25_opt + init_xi_real = self.pmodel_acclim.optchi.xi + init_vcmax_real = self.vcmax25_opt + init_jmax_real = self.jmax25_opt # 5) Calculate the realised daily values from the instantaneous optimal values self.xi_real: NDArray = memory_effect( - self.pmodel_acclim.optchi.xi, alpha=alpha, allow_holdover=allow_holdover + self.pmodel_acclim.optchi.xi, + init_xi_real, + alpha=alpha, + allow_holdover=allow_holdover, ) r"""Realised daily slow responses in :math:`\xi`""" self.vcmax25_real: NDArray = memory_effect( - self.vcmax25_opt, alpha=alpha, allow_holdover=allow_holdover + self.vcmax25_opt, + init_vcmax_real, + alpha=alpha, + allow_holdover=allow_holdover, ) r"""Realised daily slow responses in :math:`V_{cmax25}`""" self.jmax25_real: NDArray = memory_effect( - self.jmax25_opt, alpha=alpha, allow_holdover=allow_holdover + self.jmax25_opt, init_jmax_real, alpha=alpha, allow_holdover=allow_holdover ) r"""Realised daily slow responses in :math:`J_{max25}`""" From d030112ff68e923ad159cbc490473fbd6ebd51a5 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 1 Oct 2024 15:25:35 +0100 Subject: [PATCH 192/241] More user doc updates --- docs/source/users/demography/canopy.md | 432 ++++-------------- .../users/demography/module_overview.md | 2 +- 2 files changed, 93 insertions(+), 341 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index a285909b..2f2da88a 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -20,398 +20,150 @@ notes and initial demonstration code. ::: -This notebook walks through the steps in generating the canopy model as (hopefully) used -in Plant-FATE. +The canopy model uses the perfect plasticity approximation (PPA) {cite}`purves:2008a`, +which assumes that plants are always able to plastically arrange their crown within the +broader canopy of the community to maximise their crown size and fill the available +space $A$. When the area $A$ is filled, a new lower canopy layer is formed until all +of the individual crown area has been distributed across within the canopy. -## The T Model - -The T Model provides a numerical description of how tree geometry scales with stem -diameter, and an allocation model of how GPP predicts changes in stem diameter. - -The implementation in `pyrealm` provides a class representing a particular plant -functional type, using a set of traits. The code below creates a PFT with the default -set of trait values. - -```{warning} -This sketch: - -* Assumes a single individual of each stem diameter, but in practice - we are going to want to include a number of individuals to capture cohorts. -* Assumes a single PFT, where we will need to provide a mixed community. -* Consequently handles forest inventory properties in a muddled way: we will - likely package all of the stem data into a single class, probably a community - object. -``` +The key variables in calculating the canopy model are the crown projected area $A_p$ +and leaf projected projected area $\tilde{A}_{cp}(z)$, which are calculated for a stem +of a given size using the [crown model](./crown.md). ```{code-cell} +from matplotlib import pyplot as plt import numpy as np -import matplotlib.pyplot as plt -from scipy.optimize import root_scalar +import pandas as pd -from pyrealm.tmodel import TTree - -np.set_printoptions(precision=3) - -# Plant functional type with default parameterization -pft = TTree(diameters=np.array([0.1, 0.15, 0.2, 0.25, 0.38, 0.4, 1.0])) -pft.traits +from pyrealm.demography.flora import PlantFunctionalType, Flora +from pyrealm.demography.community import Community +from pyrealm.demography.canopy import Canopy ``` -The scaling of a set of trees is automatically calculated using the initial diameters to -the `TTree` instance. This automatically calculates the other dimensions, such as -height, using the underlying scaling equations of the T Model. +## Canopy closure and canopy gap fraction -```{code-cell} -pft.height -``` - -```{code-cell} -:lines_to_next_cell: 2 - -pft.crown_area -``` - -+++ {"lines_to_next_cell": 2} - -### Crown shape - -Jaideep's extension of the T Model adds a crown shape model, driven by two parameters -($m$ and $n$) that provide a very flexible description of the vertical crown profile. -These are used to derive two further invariant parameters: $q_m$ scales the canopy -radius to match the predictions of crown area under the T model and $p_{zm}$ is the -proportion of the total stem height at which the maximum crown radius occurs. Both these -values are constant for a plant functional type. +A simple method for finding the first canopy closure height is to find a height $z^*_1$ +at which the sum of crown projected area across all stems $N_s$ in a community equals $A$: $$ -\begin{align} -q_m &= m n \left(\dfrac{n-1}{m n -1}\right)^ {1 - \tfrac{1}{n}} - \left(\dfrac{\left(m-1\right) n}{m n -1}\right)^ {m-1} \\[8pt] -p_{zm} &= \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}} -\end{align} +\sum_1^{N_s}{ A_p(z^*_1)} = A $$ -For individual stems, with expected height $H$ and crown area $A_c$, we can then -estimate: - -* the height $z_m$ at which the maximum crown radius $r_m$ is found, and -* a slope $r_0$ that scales the relative canopy radius so that the $r_m$ matches - the allometric prediction of $A_c$ from the T Model. +However, the canopy model is modified by a community-level +**canopy gap fraction** ($f_G$) that captures the overall proportion of the canopy area +that is left unfilled by canopy. This gap fraction, capturing processes such as crown +shyness, describes the proportion of open sky visible from the forest floor. This +gives the following definition of the height of canopy layer closure ($z^*_l$) for a +given canopy layer $l = 1, ..., l_m$: $$ -\begin{align} -z_m &= H p_{zm}\\[8pt] -r_0 &= \frac{1}{q_m}\sqrt{\frac{A_c}{\pi}} -\end{align} +\sum_1^{N_s}{ A_p(z^*_l)} = l A(1 - f_G) $$ -```{code-cell} -:lines_to_next_cell: 2 - -def calculate_qm(m, n): - - # Constant q_m - return ( - m - * n - * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) - * (((m - 1) * n) / (m * n - 1)) ** (m - 1) - ) - - -def calculate_stem_canopy_factors(pft, m, n): - - # Height of maximum crown radius - zm = pft.height * ((n - 1) / (m * n - 1)) ** (1 / n) +The set of heights $z^*$ can be found numerically by using a root solver to find +values of $z^*_l$ for $l = 1, ..., l_m$ that satisfy: - # Slope to give Ac at zm - r0 = 1 / qm * np.sqrt(pft.crown_area / np.pi) - - return zm, r0 - - -# Shape parameters for a fairly top heavy crown profile -m = 2 -n = 5 -qm = calculate_qm(m=m, n=n) -zm, r0 = calculate_stem_canopy_factors(pft=pft, m=m, n=n) - -print("qm = ", np.round(qm, 4)) -print("zm = ", zm) -print("r0 = ", r0) -``` - -+++ {"lines_to_next_cell": 2} +$$ +\sum_1^{N_s}{ A_p(z^*_l)} - l A(1 - f_G) = 0 +$$ -The following functions then provide the value at height $z$ of relative $q(z)$ and -actual $r(z)$ canopy radius: +The total number of layers $l_m$ in a canopy, where the final layer may not be fully +closed, can be found given the total crown area across stems as: $$ -\begin{align} -q(z) &= m n \left(\dfrac{z}{H}\right) ^ {n -1} - \left( 1 - \left(\dfrac{z}{H}\right) ^ n \right)^{m-1}\\[8pt] -r(z) &= r_0 \; q(z) -\end{align} +l_m = \left\lceil \frac{\sum_1^{N_s}{A_c}}{ A(1 - f_G)}\right\rceil $$ -```{code-cell} -def calculate_relative_canopy_radius_at_z(z, H, m, n): - """Calculate q(z)""" ++++ - z_over_H = z / H +## Implementation in `pyrealm` - return m * n * z_over_H ** (n - 1) * (1 - z_over_H**n) ** (m - 1) -``` +The {class}`~pyrealm.demography.canopy.Canopy` class automatically finds the canopy +closure heights, given a {class}`~pyrealm.demography.community.Community` instance +and the required canopy gap fraction. -```{code-cell} -# Validate that zm and r0 generate the predicted maximum crown area -q_zm = calculate_relative_canopy_radius_at_z(zm, pft.height, m, n) -rm = r0 * q_zm -print("rm = ", rm) -``` +The code below creates a simple community and then fits the canopy model: ```{code-cell} -np.allclose(rm**2 * np.pi, pft.crown_area) +# Two PFTs +# - a shorter understory tree with a columnar canopy and no crown gaps +# - a taller canopy tree with a top heavy canopy and more crown gaps + +short_pft = PlantFunctionalType( + name="short", h_max=15, m=1.5, n=1.5, f_g=0, ca_ratio=380 +) +tall_pft = PlantFunctionalType(name="tall", h_max=30, m=1.5, n=4, f_g=0.2, ca_ratio=500) + +# Create the flora +flora = Flora([short_pft, tall_pft]) + +# Create a simply community with three cohorts +# - 15 saplings of the short PFT +# - 5 larger stems of the short PFT +# - 2 large stems of tall PFT + +community = Community( + flora=flora, + cell_area=32, + cell_id=1, + cohort_dbh_values=np.array([0.02, 0.20, 0.5]), + cohort_n_individuals=np.array([15, 5, 2]), + cohort_pft_names=np.array(["short", "short", "tall"]), +) ``` -Vertical crown radius profiles can now be calculated for each stem: +We can then look at the expected allometries for the stems in each cohort: ```{code-cell} -# Create an interpolation from ground to maximum stem height, with 5 cm resolution. -# Also append a set of values _fractionally_ less than the exact height of stems -# so that the height at the top of each stem is included but to avoid floating -# point issues with exact heights. - -zres = 0.05 -z = np.arange(0, pft.height.max() + 1, zres) -z = np.sort(np.concatenate([z, pft.height - 0.00001])) - -# Convert the heights into a column matrix to broadcast against the stems -# and then calculate r(z) = r0 * q(z) -rz = r0 * calculate_relative_canopy_radius_at_z(z[:, None], pft.height, m, n) - -# When z > H, rz < 0, so set radius to 0 where rz < 0 -rz[np.where(rz < 0)] = 0 - -np.cumsum(np.convolve(rm, np.ones(2), "valid") + 0.1) +print("H = ", community.stem_allometry.stem_height) +print("Ac = ", community.stem_allometry.crown_area) ``` -Those can be plotted out to show the vertical crown radius profiles +We can now calculate the canopy model for the community: ```{code-cell} -# Separate the stems along the x axis for plotting -stem_x = np.concatenate( - [np.array([0]), np.cumsum(np.convolve(rm, np.ones(2), "valid") + 0.4)] -) - -# Get the canopy sections above and below zm -rz_above_zm = np.where(np.logical_and(rz > 0, np.greater.outer(z, zm)), rz, np.nan) -rz_below_zm = np.where(np.logical_and(rz > 0, np.less_equal.outer(z, zm)), rz, np.nan) - -# Plot the canopy parts -plt.plot(stem_x + rz_below_zm, z, color="khaki") -plt.plot(stem_x - rz_below_zm, z, color="khaki") -plt.plot(stem_x + rz_above_zm, z, color="forestgreen") -plt.plot(stem_x - rz_above_zm, z, color="forestgreen") - -# Add the maximum radius -plt.plot(np.vstack((stem_x - rm, stem_x + rm)), np.vstack((zm, zm)), color="firebrick") - -# Plot the stem centre lines -plt.vlines(stem_x, 0, pft.height, linestyles="-", color="grey") - -plt.gca().set_aspect("equal") +canopy = Canopy(community=community, canopy_gap_fraction=2 / 32) ``` -## Canopy structure - -The canopy structure model uses the perfect plasticity approximation (PPA), which -assumes that plants can arrange their canopies to fill the available space $A$. -It takes the **projected area of stems** $Ap(z)$ within the canopy and finds the heights -at which each canopy layer closes ($z^*_l$ for $l = 1, 2, 3 ...$) where the total projected -area of the canopy equals $lA$. - -### Canopy projected area - -The projected area $A_p$ for a stem with height $H$, a maximum crown area $A_c$ at a -height $z_m$ and $m$, $n$ and $q_m$ for the associated plant functional type is +We can then look at three key properties of the canopy model: the layer closure +heights ($z^*_l$) and the projected crown areas and leaf areas at each of those +heights for each stem in the three cohorts. -$$ -A_p(z)= -\begin{cases} -A_c, & z \le z_m \\ -A_c \left(\dfrac{q(z)}{q_m}\right)^2, & H > z > z_m \\ -0, & z > H -\end{cases} -$$ +There are four canopy layers, with the top two very close together because of the +large crown area in the two stems in the cohort of `tall` trees. ```{code-cell} -Stems = float | np.ndarray - - -def calculate_projected_area( - z: float, - pft, - m: Stems, - n: Stems, - qm: Stems, - zm: Stems, -) -> np.ndarray: - """Calculate projected crown area above a given height. - - This function takes PFT specific parameters (shape parameters) and stem specific - sizes and estimates the projected crown area above a given height $z$. The inputs - can either be scalars describing a single stem or arrays representing a community - of stems. If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can - be scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that - PFT. - - Args: - z: Canopy height - m, n, qm : PFT specific shape parameters - pft, qm, zm: stem data - - """ - - # Calculate q(z) - qz = calculate_relative_canopy_radius_at_z(z, pft.height, m, n) - - # Calculate Ap given z > zm - Ap = pft.crown_area * (qz / qm) ** 2 - # Set Ap = Ac where z <= zm - Ap = np.where(z <= zm, pft.crown_area, Ap) - # Set Ap = 0 where z > H - Ap = np.where(z > pft.height, 0, Ap) - - return Ap +canopy.layer_heights ``` -The code below calculates the projected crown area for each stem and then plots the -vertical profile for individual stems and across the community. +The `stem_crown_area` attribute then provides the crown area of each stem found in each +layer. ```{code-cell} -:lines_to_next_cell: 2 - -# Calculate the projected area for each stem -Ap_z = calculate_projected_area(z=z[:, None], pft=pft, m=m, n=n, qm=qm, zm=zm) - -# Plot the calculated values for each stem and across the community -fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(10, 5)) - -# Plot the individual stem projected area -ax1.set_ylabel("Height above ground ($z$, m)") -ax1.plot(Ap_z, z) -ax1.set_xlabel("Stem $A_p(z)$ (m2)") - -# Plot the individual stem projected area -ax2.plot(np.nansum(Ap_z, axis=1), z) -ax2.set_xlabel("Total community $A_p(z)$ (m2)") - -plt.tight_layout() +canopy.stem_crown_area ``` -+++ {"lines_to_next_cell": 2} - -### Canopy closure and canopy gap fraction - -The total cumulative projected area shown above is modified by a community-level -**canopy gap fraction** ($f_G$) that captures the overall proportion of the canopy area -that is left unfilled by canopy. This gap fraction, capturing processes such as crown -shyness, describes the proportion of open sky visible from the forest floor. - -The definition of the height of canopy layer closure ($z^*_l$) for a given canopy -layer $l = 1, ..., l_m$ is then: - -$$ -\sum_1^{N_s}{ A_p(z^*_l)} = l A(1 - f_G) -$$ - -This can be found numerically using a root solver as: - -$$ -\sum_1^{N_s}{ A_p(z^*_l)} - l A(1 - f_G) = 0 -$$ - -The total number of layers $l_m$ in a canopy, where the final layer may not be fully closed, -can be found given the total crown area across stems as: - -$$ -l_m = \left\lceil \frac{\sum_1^{N_s}{ A_c}}{ A(1 - f_G)}\right\rceil -$$ +Given the canopy gap fraction, the available crown area per layer is 30 m2, so +the first two layers are taken up entirely by the two stems in the cohort of large +trees. We can confirm that the calculation is correct by calculating the total crown area +across the cohorts at each height: ```{code-cell} -def solve_canopy_closure_height( - z: float, - l: int, - A: float, - fG: float, - m: Stems, - n: Stems, - qm: Stems, - pft: Stems, - zm: Stems, -) -> np.ndarray: - """Solver function for canopy closure height. - - This function returns the difference between the total community projected area - at a height $z$ and the total available canopy space for canopy layer $l$, given - the community gap fraction for a given height. It is used with a root solver to - find canopy layer closure heights $z^*_l* for a community. - - Args: - m, n, qm : PFT specific shape parameters - H, Ac, zm: stem specific sizes - A, l: cell area and layer index - fG: community gap fraction - """ - - # Calculate Ap(z) - Ap_z = calculate_projected_area(z=z, pft=pft, m=m, n=n, qm=qm, zm=zm) - - # Return the difference between the projected area and the available space - return Ap_z.sum() - (A * l) * (1 - fG) - - -def calculate_canopy_heights( - A: float, - fG: float, - m: Stems, - n: Stems, - qm: Stems, - pft, - zm: Stems, -): - - # Calculate the number of layers - total_community_ca = pft.crown_area.sum() - n_layers = int(np.ceil(total_community_ca / (A * (1 - fG)))) - - # Data store for z* - z_star = np.zeros(n_layers) - - # Loop over the layers TODO - edge case of completely filled final layer - for lyr in np.arange(n_layers - 1): - z_star[lyr] = root_scalar( - solve_canopy_closure_height, - args=(lyr + 1, A, fG, m, n, qm, pft, zm), - bracket=(0, pft.height.max()), - ).root - - return z_star +np.sum(canopy.stem_crown_area * community.cohort_data["n_individuals"], axis=1) ``` -The example below calculates the projected crown area above ground level for the example -stems. These should be identical to the crown area of the stems. +Those are equal to the layer closure areas of 30, 60 and 90 m2 and the last layer does +not quite close. The slight numerical differences result from the precision of the root +solver for finding $z^*_l$ and this can be adjusted by using the `layer_tolerance` +argument to the `Canopy` class -```{code-cell} -# Set the total available canopy space and community gap fraction -canopy_area = 32 -community_gap_fraction = 2 / 32 - -z_star = calculate_canopy_heights( - A=canopy_area, fG=community_gap_fraction, m=m, n=n, qm=qm, pft=pft, zm=zm -) +The projected leaf area per stem is reported in the `stem_leaf_area` attribute. This is +identical to the projected crown area for the first two cohorts because the crown gap +fraction $f_g$ is zero for this PFT. The projected leaf area is however displaced +towards the ground in the last cohort, because the `tall` PFT has a large gap fraction. -print("z_star = ", z_star) +```{code-cell} +canopy.stem_leaf_area ``` We can now plot the canopy stems alongside the community $A_p(z)$ profile, and diff --git a/docs/source/users/demography/module_overview.md b/docs/source/users/demography/module_overview.md index fffdd77f..e2aaceab 100644 --- a/docs/source/users/demography/module_overview.md +++ b/docs/source/users/demography/module_overview.md @@ -24,4 +24,4 @@ The functionality of the demography module is split into the following submodule * The [`community` module](./community.md) that implements a plant community model using size-structured cohorts. * The [`canopy` module](./canopy.md) that generates a model of the canopy structure for - a community, based on the Perfect Plasticity Approximation model :cite:`purves:2008a`. + a community, based on the Perfect Plasticity Approximation model {cite}`purves:2008a`. From eab4927193da94bee8b25ec4f2f20581861015c1 Mon Sep 17 00:00:00 2001 From: Marion <56403724+MarionBWeinzierl@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:29:25 +0100 Subject: [PATCH 193/241] Update poetry.lock --- poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index cf1c4476..5090ba12 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2447,7 +2447,7 @@ xml = ["lxml (>=4.9.2)"] [[package]] name = "pandas-stubs" -version = "2.2.2.240807" +version = "2.2.2.240909" description = "Type annotations for pandas" optional = false python-versions = ">=3.10" From a74e10564699269ff32cc307f54fba6186dc3a9e Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 1 Oct 2024 15:35:37 +0100 Subject: [PATCH 194/241] Temporarily restore original canopy doc to pirate ideas from --- docs/source/users/tmodel/canopy.md | 677 +++++++++++++++++++++++++++++ 1 file changed, 677 insertions(+) create mode 100644 docs/source/users/tmodel/canopy.md diff --git a/docs/source/users/tmodel/canopy.md b/docs/source/users/tmodel/canopy.md new file mode 100644 index 00000000..3fab2df8 --- /dev/null +++ b/docs/source/users/tmodel/canopy.md @@ -0,0 +1,677 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Canopy model + +This notebook walks through the steps in generating the canopy model as (hopefully) used +in Plant-FATE. + +## The T Model + +The T Model provides a numerical description of how tree geometry scales with stem +diameter, and an allocation model of how GPP predicts changes in stem diameter. + +The implementation in `pyrealm` provides a class representing a particular plant +functional type, using a set of traits. The code below creates a PFT with the default +set of trait values. + +```{warning} +This sketch: + +* Assumes a single individual of each stem diameter, but in practice + we are going to want to include a number of individuals to capture cohorts. +* Assumes a single PFT, where we will need to provide a mixed community. +* Consequently handles forest inventory properties in a muddled way: we will + likely package all of the stem data into a single class, probably a community + object. +``` + +```{code-cell} +import numpy as np +import matplotlib.pyplot as plt +from scipy.optimize import root_scalar + +from pyrealm.tmodel import TTree + +np.set_printoptions(precision=3) + +# Plant functional type with default parameterization +pft = TTree(diameters=np.array([0.1, 0.15, 0.2, 0.25, 0.38, 0.4, 1.0])) +pft.traits +``` + +The scaling of a set of trees is automatically calculated using the initial diameters to +the `TTree` instance. This automatically calculates the other dimensions, such as +height, using the underlying scaling equations of the T Model. + +```{code-cell} +pft.height +``` + +```{code-cell} +:lines_to_next_cell: 2 + +pft.crown_area +``` + ++++ {"lines_to_next_cell": 2} + +### Crown shape + +Jaideep's extension of the T Model adds a crown shape model, driven by two parameters +($m$ and $n$) that provide a very flexible description of the vertical crown profile. +These are used to derive two further invariant parameters: $q_m$ scales the canopy +radius to match the predictions of crown area under the T model and $p_{zm}$ is the +proportion of the total stem height at which the maximum crown radius occurs. Both these +values are constant for a plant functional type. + +$$ +\begin{align} +q_m &= m n \left(\dfrac{n-1}{m n -1}\right)^ {1 - \tfrac{1}{n}} + \left(\dfrac{\left(m-1\right) n}{m n -1}\right)^ {m-1} \\[8pt] +p_{zm} &= \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}} +\end{align} +$$ + +For individual stems, with expected height $H$ and crown area $A_c$, we can then +estimate: + +* the height $z_m$ at which the maximum crown radius $r_m$ is found, and +* a slope $r_0$ that scales the relative canopy radius so that the $r_m$ matches + the allometric prediction of $A_c$ from the T Model. + +$$ +\begin{align} +z_m &= H p_{zm}\\[8pt] +r_0 &= \frac{1}{q_m}\sqrt{\frac{A_c}{\pi}} +\end{align} +$$ + +```{code-cell} +:lines_to_next_cell: 2 + +def calculate_qm(m, n): + + # Constant q_m + return ( + m + * n + * ((n - 1) / (m * n - 1)) ** (1 - 1 / n) + * (((m - 1) * n) / (m * n - 1)) ** (m - 1) + ) + + +def calculate_stem_canopy_factors(pft, m, n): + + # Height of maximum crown radius + zm = pft.height * ((n - 1) / (m * n - 1)) ** (1 / n) + + # Slope to give Ac at zm + r0 = 1 / qm * np.sqrt(pft.crown_area / np.pi) + + return zm, r0 + + +# Shape parameters for a fairly top heavy crown profile +m = 2 +n = 5 +qm = calculate_qm(m=m, n=n) +zm, r0 = calculate_stem_canopy_factors(pft=pft, m=m, n=n) + +print("qm = ", np.round(qm, 4)) +print("zm = ", zm) +print("r0 = ", r0) +``` + ++++ {"lines_to_next_cell": 2} + +The following functions then provide the value at height $z$ of relative $q(z)$ and +actual $r(z)$ canopy radius: + +$$ +\begin{align} +q(z) &= m n \left(\dfrac{z}{H}\right) ^ {n -1} + \left( 1 - \left(\dfrac{z}{H}\right) ^ n \right)^{m-1}\\[8pt] +r(z) &= r_0 \; q(z) +\end{align} +$$ + +```{code-cell} +def calculate_relative_canopy_radius_at_z(z, H, m, n): + """Calculate q(z)""" + + z_over_H = z / H + + return m * n * z_over_H ** (n - 1) * (1 - z_over_H**n) ** (m - 1) +``` + +```{code-cell} +# Validate that zm and r0 generate the predicted maximum crown area +q_zm = calculate_relative_canopy_radius_at_z(zm, pft.height, m, n) +rm = r0 * q_zm +print("rm = ", rm) +``` + +```{code-cell} +np.allclose(rm**2 * np.pi, pft.crown_area) +``` + +Vertical crown radius profiles can now be calculated for each stem: + +```{code-cell} +# Create an interpolation from ground to maximum stem height, with 5 cm resolution. +# Also append a set of values _fractionally_ less than the exact height of stems +# so that the height at the top of each stem is included but to avoid floating +# point issues with exact heights. + +zres = 0.05 +z = np.arange(0, pft.height.max() + 1, zres) +z = np.sort(np.concatenate([z, pft.height - 0.00001])) + +# Convert the heights into a column matrix to broadcast against the stems +# and then calculate r(z) = r0 * q(z) +rz = r0 * calculate_relative_canopy_radius_at_z(z[:, None], pft.height, m, n) + +# When z > H, rz < 0, so set radius to 0 where rz < 0 +rz[np.where(rz < 0)] = 0 + +np.cumsum(np.convolve(rm, np.ones(2), "valid") + 0.1) +``` + +Those can be plotted out to show the vertical crown radius profiles + +```{code-cell} +# Separate the stems along the x axis for plotting +stem_x = np.concatenate( + [np.array([0]), np.cumsum(np.convolve(rm, np.ones(2), "valid") + 0.4)] +) + +# Get the canopy sections above and below zm +rz_above_zm = np.where(np.logical_and(rz > 0, np.greater.outer(z, zm)), rz, np.nan) +rz_below_zm = np.where(np.logical_and(rz > 0, np.less_equal.outer(z, zm)), rz, np.nan) + +# Plot the canopy parts +plt.plot(stem_x + rz_below_zm, z, color="khaki") +plt.plot(stem_x - rz_below_zm, z, color="khaki") +plt.plot(stem_x + rz_above_zm, z, color="forestgreen") +plt.plot(stem_x - rz_above_zm, z, color="forestgreen") + +# Add the maximum radius +plt.plot(np.vstack((stem_x - rm, stem_x + rm)), np.vstack((zm, zm)), color="firebrick") + +# Plot the stem centre lines +plt.vlines(stem_x, 0, pft.height, linestyles="-", color="grey") + +plt.gca().set_aspect("equal") +``` + +## Canopy structure + +The canopy structure model uses the perfect plasticity approximation (PPA), which +assumes that plants can arrange their canopies to fill the available space $A$. +It takes the **projected area of stems** $Ap(z)$ within the canopy and finds the heights +at which each canopy layer closes ($z^*_l$ for $l = 1, 2, 3 ...$) where the total projected +area of the canopy equals $lA$. + +### Canopy projected area + +The projected area $A_p$ for a stem with height $H$, a maximum crown area $A_c$ at a +height $z_m$ and $m$, $n$ and $q_m$ for the associated plant functional type is + +$$ +A_p(z)= +\begin{cases} +A_c, & z \le z_m \\ +A_c \left(\dfrac{q(z)}{q_m}\right)^2, & H > z > z_m \\ +0, & z > H +\end{cases} +$$ + +```{code-cell} +Stems = float | np.ndarray + + +def calculate_projected_area( + z: float, + pft, + m: Stems, + n: Stems, + qm: Stems, + zm: Stems, +) -> np.ndarray: + """Calculate projected crown area above a given height. + + This function takes PFT specific parameters (shape parameters) and stem specific + sizes and estimates the projected crown area above a given height $z$. The inputs + can either be scalars describing a single stem or arrays representing a community + of stems. If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can + be scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that + PFT. + + Args: + z: Canopy height + m, n, qm : PFT specific shape parameters + pft, qm, zm: stem data + + """ + + # Calculate q(z) + qz = calculate_relative_canopy_radius_at_z(z, pft.height, m, n) + + # Calculate Ap given z > zm + Ap = pft.crown_area * (qz / qm) ** 2 + # Set Ap = Ac where z <= zm + Ap = np.where(z <= zm, pft.crown_area, Ap) + # Set Ap = 0 where z > H + Ap = np.where(z > pft.height, 0, Ap) + + return Ap +``` + +The code below calculates the projected crown area for each stem and then plots the +vertical profile for individual stems and across the community. + +```{code-cell} +:lines_to_next_cell: 2 + +# Calculate the projected area for each stem +Ap_z = calculate_projected_area(z=z[:, None], pft=pft, m=m, n=n, qm=qm, zm=zm) + +# Plot the calculated values for each stem and across the community +fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(10, 5)) + +# Plot the individual stem projected area +ax1.set_ylabel("Height above ground ($z$, m)") +ax1.plot(Ap_z, z) +ax1.set_xlabel("Stem $A_p(z)$ (m2)") + +# Plot the individual stem projected area +ax2.plot(np.nansum(Ap_z, axis=1), z) +ax2.set_xlabel("Total community $A_p(z)$ (m2)") + +plt.tight_layout() +``` + ++++ {"lines_to_next_cell": 2} + +### Canopy closure and canopy gap fraction + +The total cumulative projected area shown above is modified by a community-level +**canopy gap fraction** ($f_G$) that captures the overall proportion of the canopy area +that is left unfilled by canopy. This gap fraction, capturing processes such as crown +shyness, describes the proportion of open sky visible from the forest floor. + +The definition of the height of canopy layer closure ($z^*_l$) for a given canopy +layer $l = 1, ..., l_m$ is then: + +$$ +\sum_1^{N_s}{ A_p(z^*_l)} = l A(1 - f_G) +$$ + +This can be found numerically using a root solver as: + +$$ +\sum_1^{N_s}{ A_p(z^*_l)} - l A(1 - f_G) = 0 +$$ + +The total number of layers $l_m$ in a canopy, where the final layer may not be fully closed, +can be found given the total crown area across stems as: + +$$ +l_m = \left\lceil \frac{\sum_1^{N_s}{ A_c}}{ A(1 - f_G)}\right\rceil +$$ + +```{code-cell} +def solve_canopy_closure_height( + z: float, + l: int, + A: float, + fG: float, + m: Stems, + n: Stems, + qm: Stems, + pft: Stems, + zm: Stems, +) -> np.ndarray: + """Solver function for canopy closure height. + + This function returns the difference between the total community projected area + at a height $z$ and the total available canopy space for canopy layer $l$, given + the community gap fraction for a given height. It is used with a root solver to + find canopy layer closure heights $z^*_l* for a community. + + Args: + m, n, qm : PFT specific shape parameters + H, Ac, zm: stem specific sizes + A, l: cell area and layer index + fG: community gap fraction + """ + + # Calculate Ap(z) + Ap_z = calculate_projected_area(z=z, pft=pft, m=m, n=n, qm=qm, zm=zm) + + # Return the difference between the projected area and the available space + return Ap_z.sum() - (A * l) * (1 - fG) + + +def calculate_canopy_heights( + A: float, + fG: float, + m: Stems, + n: Stems, + qm: Stems, + pft, + zm: Stems, +): + + # Calculate the number of layers + total_community_ca = pft.crown_area.sum() + n_layers = int(np.ceil(total_community_ca / (A * (1 - fG)))) + + # Data store for z* + z_star = np.zeros(n_layers) + + # Loop over the layers TODO - edge case of completely filled final layer + for lyr in np.arange(n_layers - 1): + z_star[lyr] = root_scalar( + solve_canopy_closure_height, + args=(lyr + 1, A, fG, m, n, qm, pft, zm), + bracket=(0, pft.height.max()), + ).root + + return z_star +``` + +The example below calculates the projected crown area above ground level for the example +stems. These should be identical to the crown area of the stems. + +```{code-cell} +# Set the total available canopy space and community gap fraction +canopy_area = 32 +community_gap_fraction = 2 / 32 + +z_star = calculate_canopy_heights( + A=canopy_area, fG=community_gap_fraction, m=m, n=n, qm=qm, pft=pft, zm=zm +) + +print("z_star = ", z_star) +``` + +We can now plot the canopy stems alongside the community $A_p(z)$ profile, and +superimpose the calculated $z^*_l$ values and the cumulative canopy area for each layer +to confirm that the calculated values coincide with the profile. Note here that the +total area at each closed layer height is omitting the community gap fraction. + +```{code-cell} +community_Ap_z = np.nansum(Ap_z, axis=1) + +fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(10, 5)) + +zcol = "red" + +# Plot the canopy parts +ax1.plot(stem_x + rz_below_zm, z, color="khaki") +ax1.plot(stem_x - rz_below_zm, z, color="khaki") +ax1.plot(stem_x + rz_above_zm, z, color="forestgreen") +ax1.plot(stem_x - rz_above_zm, z, color="forestgreen") + +# Add the maximum radius +ax1.plot(np.vstack((stem_x - rm, stem_x + rm)), np.vstack((zm, zm)), color="firebrick") + +# Plot the stem centre lines +ax1.vlines(stem_x, 0, pft.height, linestyles="-", color="grey") + +ax1.set_ylabel("Height above ground ($z$, m)") +ax1.set_xlabel("Arbitrary stem position") +ax1.hlines(z_star, 0, (stem_x + rm).max(), color=zcol, linewidth=0.5) + +# Plot the projected community crown area by height along with the heights +# at which different canopy layers close +ax2.hlines(z_star, 0, community_Ap_z.max(), color=zcol, linewidth=0.5) +ax2.vlines( + canopy_area * np.arange(1, len(z_star)) * (1 - community_gap_fraction), + 0, + pft.height.max(), + color=zcol, + linewidth=0.5, +) + +ax2.plot(community_Ap_z, z) +ax2.set_xlabel("Projected crown area above height $z$ ($A_p(z)$, m2)") + +# Add z* values on the righthand axis +ax3 = ax2.twinx() + + +def z_star_labels(X): + return [f"$z^*_{l + 1}$ = {z:.2f}" for l, z in enumerate(X)] + + +ax3.set_ylim(ax2.get_ylim()) +ax3.set_yticks(z_star) +ax3.set_yticklabels(z_star_labels(z_star)) + +ax4 = ax2.twiny() + +# Add canopy layer closure areas on top axis +cum_area = np.arange(1, len(z_star)) * canopy_area * (1 - community_gap_fraction) + + +def cum_area_labels(X): + return [f"$A_{l + 1}$ = {z:.1f}" for l, z in enumerate(X)] + + +ax4.set_xlim(ax2.get_xlim()) +ax4.set_xticks(cum_area) +ax4.set_xticklabels(cum_area_labels(cum_area)) + +plt.tight_layout() +``` + +The projected area from individual stems to each canopy layer can then be calculated at +$z^*_l$ and hence the projected area of canopy **within each layer**. + +```{code-cell} +# Calculate the canopy area above z_star for each stem +Ap_z_star = calculate_projected_area(z=z_star[:, None], pft=pft, m=m, n=n, qm=qm, zm=zm) + +print(Ap_z_star) +``` + +```{code-cell} +:lines_to_next_cell: 2 + +# Calculate the contribution _within_ each layer per stem +Ap_within_layer = np.diff(Ap_z_star, axis=0, prepend=0) + +print(Ap_within_layer) +``` + ++++ {"lines_to_next_cell": 2} + +### Leaf area within canopy layers + +The projected area occupied by leaves at a given height $\tilde{A}_{cp}(z)$ is +needed to calculate light transmission through those layers. This differs from the +projected area $A_p(z)$ because, although a tree occupies an area in the canopy +following the PPA, a **crown gap fraction** ($f_g$) reduces the actual leaf area +at a given height $z$. + +The crown gap fraction does not affect the overall projected canopy area at ground +level or the community gap fraction: the amount of clear sky at ground level is +governed purely by $f_G$. Instead it models how leaf gaps in the upper canopy are +filled by leaf area at lower heights. It captures the vertical distribution of +leaf area within the canopy: a higher $f_g$ will give fewer leaves at the top of +the canopy and more leaves further down within the canopy. + +The calculation of $\tilde{A}_{cp}(z)$ is defined as: + +$$ +\tilde{A}_{cp}(z)= +\begin{cases} +0, & z \gt H \\ +A_c \left(\dfrac{q(z)}{q_m}\right)^2 \left(1 - f_g\right), & H \gt z \gt z_m \\ +Ac - A_c \left(\dfrac{q(z)}{q_m}\right)^2 f_g, & zm \gt z +\end{cases} +$$ + +The function below calculates $\tilde{A}_{cp}(z)$. + +```{code-cell} +def calculate_leaf_area( + z: float, + fg: float, + pft, + m: Stems, + n: Stems, + qm: Stems, + zm: Stems, +) -> np.ndarray: + """Calculate leaf area above a given height. + + This function takes PFT specific parameters (shape parameters) and stem specific + sizes and estimates the projected crown area above a given height $z$. The inputs + can either be scalars describing a single stem or arrays representing a community + of stems. If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can + be scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that + PFT. + + Args: + z: Canopy height + fg: crown gap fraction + m, n, qm : PFT specific shape parameters + pft, qm, zm: stem data + """ + + # Calculate q(z) + qz = calculate_relative_canopy_radius_at_z(z, pft.height, m, n) + + # Calculate Ac term + Ac_term = pft.crown_area * (qz / qm) ** 2 + # Set Acp either side of zm + Acp = np.where(z <= zm, pft.crown_area - Ac_term * fg, Ac_term * (1 - fg)) + # Set Ap = 0 where z > H + Acp = np.where(z > pft.height, 0, Acp) + + return Acp +``` + +The plot below shows how the vertical leaf area profile for the community changes for +different values of $f_g$. When $f_g = 0$, then $A_cp(z) = A_p(z)$ (red line) because +there are no crown gaps and hence all of the leaf area is within the crown surface. As +$f_g \to 1$, more of the leaf area is displaced deeper into the canopy, leaves in the +lower crown intercepting light coming through holes in the upper canopy. + +```{code-cell} +fig, ax1 = plt.subplots(1, 1, figsize=(6, 5)) + +for fg in np.arange(0, 1.01, 0.05): + + if fg == 0: + color = "red" + label = "$f_g = 0$" + lwd = 0.5 + elif fg == 1: + color = "blue" + label = "$f_g = 1$" + lwd = 0.5 + else: + color = "black" + label = None + lwd = 0.25 + + Acp_z = calculate_leaf_area(z=z[:, None], fg=fg, pft=pft, m=m, n=n, qm=qm, zm=zm) + ax1.plot(np.nansum(Acp_z, axis=1), z, color=color, linewidth=lwd, label=label) + +ax1.set_xlabel(r"Projected leaf area above height $z$ ($\tilde{A}_{cp}(z)$, m2)") +ax1.legend(frameon=False) +``` + +We can now calculate the crown area occupied by leaves above the height of each closed +layer $z^*_l$: + +```{code-cell} +# Calculate the leaf area above z_star for each stem +crown_gap_fraction = 0.05 +Acp_z_star = calculate_leaf_area( + z=z_star[:, None], fg=crown_gap_fraction, pft=pft, m=m, n=n, qm=qm, zm=zm +) + +print(Acp_z_star) +``` + +And from that, the area occupied by leaves **within each layer**. These values are +similar to the projected crown area within layers (`Ap_within_layer`, above) but +leaf area is displaced into lower layers because $f_g > 0$. + +```{code-cell} +# Calculate the contribution _within_ each layer per stem +Acp_within_layer = np.diff(Acp_z_star, axis=0, prepend=0) + +print(Acp_within_layer) +``` + +### Light transmission through the canopy + +Now we can use the leaf area by layer and the Beer-Lambert equation to calculate light +attenuation through the canopy layers. + +$f_{abs} = 1 - e ^ {-kL}$, + +where $k$ is the light extinction coefficient ($k$) and $L$ is the leaf area index +(LAI). The LAI can be calculated for each stem and layer: + +```{code-cell} +LAI = Acp_within_layer / canopy_area +print(LAI) +``` + +This can be used to calculate the LAI of individual stems but also the LAI of each layer +in the canopy: + +```{code-cell} +LAI_stem = LAI.sum(axis=0) +LAI_layer = LAI.sum(axis=1) + +print("LAI stem = ", LAI_stem) +print("LAI layer = ", LAI_layer) +``` + +The layer LAI values can now be used to calculate the light transmission of each layer and +hence the cumulative light extinction profile through the canopy. + +```{code-cell} +f_abs = 1 - np.exp(-pft.traits.par_ext * LAI_layer) +ext = np.cumprod(f_abs) + +print("f_abs = ", f_abs) +print("extinction = ", ext) +``` + +One issue that needs to be resolved is that the T Model implementation in `pyrealm` +follows the original implementation of the T Model in having LAI as a fixed trait of +a given plant functional type, so is constant for all stems of that PFT. + +```{code-cell} +print("f_abs = ", (1 - np.exp(-pft.traits.par_ext * pft.traits.lai))) +``` + +## Things to worry about later + +Herbivory - leaf fall (transmission increases, truncate at 0, replace from NSCs) vs leaf +turnover (transmission constant, increased GPP penalty) + +Leaf area dynamics in PlantFATE - acclimation to herbivory and transitory decreases in +transimission, need non-structural carbohydrates to recover from total defoliation. + +Leaf economics. From b8cde9d758525796e66d50f1eb8129238b650a84 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 1 Oct 2024 15:58:03 +0100 Subject: [PATCH 195/241] Extra projected leaf area demo --- docs/source/users/demography/crown.md | 48 +++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md index 1eba4486..dcf41bc7 100644 --- a/docs/source/users/demography/crown.md +++ b/docs/source/users/demography/crown.md @@ -386,6 +386,54 @@ for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 10), ("r", "g", "b")): ax.set_ylabel("Height above ground (m)") ``` +We can also generate predictions for a single PFT with varying crown gap fraction. In +the plot below, note that all leaf area is above $z_{max}$ when $f_g=1$ and all leaf +area is *below* + +```{code-cell} +fig, ax = plt.subplots(ncols=1) + +# Loop over f_g values +for f_g in np.linspace(0, 1, num=11): + + label = None + colour = "gray" + + if f_g == 0: + label = "$f_g=0$" + colour = "red" + elif f_g == 1: + label = "$f_g=1$" + colour = "blue" + + # Create a flora with a single PFT with current f_g and then generate a + # stem allometry and crown profile + flora_f_g = Flora( + [PlantFunctionalType(name="example", h_max=20, m=2, n=2, f_g=f_g)] + ) + allometry_f_g = StemAllometry(stem_traits=flora_f_g, at_dbh=np.array([0.4])) + profile = CrownProfile( + stem_traits=flora_f_g, stem_allometry=allometry_f_g, z=area_z + ) + + # Plot the projected leaf area with height + ax.plot(profile.projected_leaf_area, area_z, color=colour, label=label, linewidth=1) + +# Add a horizontal line for z_max +ax.plot( + [-1, allometry_f_g.crown_area[0] + 1], + [allometry_f_g.crown_z_max, allometry_f_g.crown_z_max], + linestyle="--", + color="black", + label="$z_{max}$", + linewidth=1, +) + +ax.set_ylabel(r"Vertical height ($z$, m)") +ax.set_xlabel(r"Projected leaf area ($\tilde{A}_{cp}(z)$, m2)") +ax.legend(frameon=False) +``` + ```{code-cell} ``` From 2b9d02f15093125218e9f0c4e697cacc971b508d Mon Sep 17 00:00:00 2001 From: Marion <56403724+MarionBWeinzierl@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:20:05 +0100 Subject: [PATCH 196/241] Update poetry.lock --- poetry.lock | 1220 ++++++++++++++++++++++++--------------------------- 1 file changed, 572 insertions(+), 648 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5090ba12..7481dbd5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "alabaster" @@ -154,46 +154,46 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} [[package]] name = "attrs" -version = "24.2.0" +version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, - {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] [package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "autodocsumm" -version = "0.2.13" +version = "0.2.12" description = "Extended sphinx autodoc including automatic autosummaries" optional = false python-versions = ">=3.7" files = [ - {file = "autodocsumm-0.2.13-py3-none-any.whl", hash = "sha256:bf4d82ea7acb3e7d9a3ad8c135e097eca1d3f0bd00800d7804127e848e66741d"}, - {file = "autodocsumm-0.2.13.tar.gz", hash = "sha256:ac5f0cf1adbe957acb136fe0d9e16c38fb74fcaefb45c148204aba26dbb12ee2"}, + {file = "autodocsumm-0.2.12-py3-none-any.whl", hash = "sha256:b842b53c686c07a4f174721ca4e729b027367703dbf42e2508863a3c6d6c049c"}, + {file = "autodocsumm-0.2.12.tar.gz", hash = "sha256:848fe8c38df433c6635489499b969cb47cc389ed3d7b6e75c8ccbc94d4b3bf9e"}, ] [package.dependencies] -Sphinx = ">=2.2,<9.0" +Sphinx = ">=2.2,<8.0" [[package]] name = "babel" -version = "2.16.0" +version = "2.15.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" files = [ - {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, - {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, ] [package.extras] @@ -251,78 +251,63 @@ files = [ [[package]] name = "cffi" -version = "1.17.0" +version = "1.16.0" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"}, - {file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"}, - {file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"}, - {file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"}, - {file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"}, - {file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"}, - {file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"}, - {file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"}, - {file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"}, - {file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"}, - {file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"}, - {file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"}, - {file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"}, - {file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"}, - {file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"}, - {file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"}, - {file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"}, - {file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"}, - {file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"}, - {file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] [package.dependencies] @@ -590,83 +575,63 @@ test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" -version = "7.6.1" +version = "7.6.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, - {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, - {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, - {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, - {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, - {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, - {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, - {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, - {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, - {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, - {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, - {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, - {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, - {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, - {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, - {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, - {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, - {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, + {file = "coverage-7.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd"}, + {file = "coverage-7.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb"}, + {file = "coverage-7.6.0-cp310-cp310-win32.whl", hash = "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c"}, + {file = "coverage-7.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169"}, + {file = "coverage-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933"}, + {file = "coverage-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63"}, + {file = "coverage-7.6.0-cp311-cp311-win32.whl", hash = "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713"}, + {file = "coverage-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1"}, + {file = "coverage-7.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"}, + {file = "coverage-7.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605"}, + {file = "coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da"}, + {file = "coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67"}, + {file = "coverage-7.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b"}, + {file = "coverage-7.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b"}, + {file = "coverage-7.6.0-cp38-cp38-win32.whl", hash = "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428"}, + {file = "coverage-7.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8"}, + {file = "coverage-7.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c"}, + {file = "coverage-7.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd"}, + {file = "coverage-7.6.0-cp39-cp39-win32.whl", hash = "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2"}, + {file = "coverage-7.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca"}, + {file = "coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6"}, + {file = "coverage-7.6.0.tar.gz", hash = "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51"}, ] [package.dependencies] @@ -705,33 +670,33 @@ dev = ["black", "coveralls", "mypy", "pre-commit", "pylint", "pytest (>=5)", "py [[package]] name = "debugpy" -version = "1.8.5" +version = "1.8.2" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" files = [ - {file = "debugpy-1.8.5-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:7e4d594367d6407a120b76bdaa03886e9eb652c05ba7f87e37418426ad2079f7"}, - {file = "debugpy-1.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4413b7a3ede757dc33a273a17d685ea2b0c09dbd312cc03f5534a0fd4d40750a"}, - {file = "debugpy-1.8.5-cp310-cp310-win32.whl", hash = "sha256:dd3811bd63632bb25eda6bd73bea8e0521794cda02be41fa3160eb26fc29e7ed"}, - {file = "debugpy-1.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:b78c1250441ce893cb5035dd6f5fc12db968cc07f91cc06996b2087f7cefdd8e"}, - {file = "debugpy-1.8.5-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:606bccba19f7188b6ea9579c8a4f5a5364ecd0bf5a0659c8a5d0e10dcee3032a"}, - {file = "debugpy-1.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db9fb642938a7a609a6c865c32ecd0d795d56c1aaa7a7a5722d77855d5e77f2b"}, - {file = "debugpy-1.8.5-cp311-cp311-win32.whl", hash = "sha256:4fbb3b39ae1aa3e5ad578f37a48a7a303dad9a3d018d369bc9ec629c1cfa7408"}, - {file = "debugpy-1.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:345d6a0206e81eb68b1493ce2fbffd57c3088e2ce4b46592077a943d2b968ca3"}, - {file = "debugpy-1.8.5-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:5b5c770977c8ec6c40c60d6f58cacc7f7fe5a45960363d6974ddb9b62dbee156"}, - {file = "debugpy-1.8.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a65b00b7cdd2ee0c2cf4c7335fef31e15f1b7056c7fdbce9e90193e1a8c8cb"}, - {file = "debugpy-1.8.5-cp312-cp312-win32.whl", hash = "sha256:c9f7c15ea1da18d2fcc2709e9f3d6de98b69a5b0fff1807fb80bc55f906691f7"}, - {file = "debugpy-1.8.5-cp312-cp312-win_amd64.whl", hash = "sha256:28ced650c974aaf179231668a293ecd5c63c0a671ae6d56b8795ecc5d2f48d3c"}, - {file = "debugpy-1.8.5-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:3df6692351172a42af7558daa5019651f898fc67450bf091335aa8a18fbf6f3a"}, - {file = "debugpy-1.8.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cd04a73eb2769eb0bfe43f5bfde1215c5923d6924b9b90f94d15f207a402226"}, - {file = "debugpy-1.8.5-cp38-cp38-win32.whl", hash = "sha256:8f913ee8e9fcf9d38a751f56e6de12a297ae7832749d35de26d960f14280750a"}, - {file = "debugpy-1.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:a697beca97dad3780b89a7fb525d5e79f33821a8bc0c06faf1f1289e549743cf"}, - {file = "debugpy-1.8.5-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:0a1029a2869d01cb777216af8c53cda0476875ef02a2b6ff8b2f2c9a4b04176c"}, - {file = "debugpy-1.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84c276489e141ed0b93b0af648eef891546143d6a48f610945416453a8ad406"}, - {file = "debugpy-1.8.5-cp39-cp39-win32.whl", hash = "sha256:ad84b7cde7fd96cf6eea34ff6c4a1b7887e0fe2ea46e099e53234856f9d99a34"}, - {file = "debugpy-1.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:7b0fe36ed9d26cb6836b0a51453653f8f2e347ba7348f2bbfe76bfeb670bfb1c"}, - {file = "debugpy-1.8.5-py2.py3-none-any.whl", hash = "sha256:55919dce65b471eff25901acf82d328bbd5b833526b6c1364bd5133754777a44"}, - {file = "debugpy-1.8.5.zip", hash = "sha256:b2112cfeb34b4507399d298fe7023a16656fc553ed5246536060ca7bd0e668d0"}, + {file = "debugpy-1.8.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7ee2e1afbf44b138c005e4380097d92532e1001580853a7cb40ed84e0ef1c3d2"}, + {file = "debugpy-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f8c3f7c53130a070f0fc845a0f2cee8ed88d220d6b04595897b66605df1edd6"}, + {file = "debugpy-1.8.2-cp310-cp310-win32.whl", hash = "sha256:f179af1e1bd4c88b0b9f0fa153569b24f6b6f3de33f94703336363ae62f4bf47"}, + {file = "debugpy-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:0600faef1d0b8d0e85c816b8bb0cb90ed94fc611f308d5fde28cb8b3d2ff0fe3"}, + {file = "debugpy-1.8.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:8a13417ccd5978a642e91fb79b871baded925d4fadd4dfafec1928196292aa0a"}, + {file = "debugpy-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acdf39855f65c48ac9667b2801234fc64d46778021efac2de7e50907ab90c634"}, + {file = "debugpy-1.8.2-cp311-cp311-win32.whl", hash = "sha256:2cbd4d9a2fc5e7f583ff9bf11f3b7d78dfda8401e8bb6856ad1ed190be4281ad"}, + {file = "debugpy-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:d3408fddd76414034c02880e891ea434e9a9cf3a69842098ef92f6e809d09afa"}, + {file = "debugpy-1.8.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:5d3ccd39e4021f2eb86b8d748a96c766058b39443c1f18b2dc52c10ac2757835"}, + {file = "debugpy-1.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62658aefe289598680193ff655ff3940e2a601765259b123dc7f89c0239b8cd3"}, + {file = "debugpy-1.8.2-cp312-cp312-win32.whl", hash = "sha256:bd11fe35d6fd3431f1546d94121322c0ac572e1bfb1f6be0e9b8655fb4ea941e"}, + {file = "debugpy-1.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:15bc2f4b0f5e99bf86c162c91a74c0631dbd9cef3c6a1d1329c946586255e859"}, + {file = "debugpy-1.8.2-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:5a019d4574afedc6ead1daa22736c530712465c0c4cd44f820d803d937531b2d"}, + {file = "debugpy-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40f062d6877d2e45b112c0bbade9a17aac507445fd638922b1a5434df34aed02"}, + {file = "debugpy-1.8.2-cp38-cp38-win32.whl", hash = "sha256:c78ba1680f1015c0ca7115671fe347b28b446081dada3fedf54138f44e4ba031"}, + {file = "debugpy-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:cf327316ae0c0e7dd81eb92d24ba8b5e88bb4d1b585b5c0d32929274a66a5210"}, + {file = "debugpy-1.8.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1523bc551e28e15147815d1397afc150ac99dbd3a8e64641d53425dba57b0ff9"}, + {file = "debugpy-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e24ccb0cd6f8bfaec68d577cb49e9c680621c336f347479b3fce060ba7c09ec1"}, + {file = "debugpy-1.8.2-cp39-cp39-win32.whl", hash = "sha256:7f8d57a98c5a486c5c7824bc0b9f2f11189d08d73635c326abef268f83950326"}, + {file = "debugpy-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:16c8dcab02617b75697a0a925a62943e26a0330da076e2a10437edd9f0bf3755"}, + {file = "debugpy-1.8.2-py2.py3-none-any.whl", hash = "sha256:16e16df3a98a35c63c3ab1e4d19be4cbc7fdda92d9ddc059294f18910928e0ca"}, + {file = "debugpy-1.8.2.zip", hash = "sha256:95378ed08ed2089221896b9b3a8d021e642c24edc8fef20e5d4342ca8be65c00"}, ] [[package]] @@ -1119,13 +1084,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "8.3.0" +version = "8.2.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-8.3.0-py3-none-any.whl", hash = "sha256:42817a4a0be5845d22c6e212db66a94ad261e2318d80b3e0d363894a79df2b67"}, - {file = "importlib_metadata-8.3.0.tar.gz", hash = "sha256:9c8fa6e8ea0f9516ad5c8db9246a731c948193c7754d3babb0114a05b27dd364"}, + {file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"}, + {file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"}, ] [package.dependencies] @@ -1873,51 +1838,40 @@ tests = ["pytest (>=5.4)", "pytest-mypy-plugins (>=1.2.0)"] [[package]] name = "matplotlib" -version = "3.9.2" +version = "3.9.1" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.9.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9d78bbc0cbc891ad55b4f39a48c22182e9bdaea7fc0e5dbd364f49f729ca1bbb"}, - {file = "matplotlib-3.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c375cc72229614632c87355366bdf2570c2dac01ac66b8ad048d2dabadf2d0d4"}, - {file = "matplotlib-3.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d94ff717eb2bd0b58fe66380bd8b14ac35f48a98e7c6765117fe67fb7684e64"}, - {file = "matplotlib-3.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab68d50c06938ef28681073327795c5db99bb4666214d2d5f880ed11aeaded66"}, - {file = "matplotlib-3.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:65aacf95b62272d568044531e41de26285d54aec8cb859031f511f84bd8b495a"}, - {file = "matplotlib-3.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:3fd595f34aa8a55b7fc8bf9ebea8aa665a84c82d275190a61118d33fbc82ccae"}, - {file = "matplotlib-3.9.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8dd059447824eec055e829258ab092b56bb0579fc3164fa09c64f3acd478772"}, - {file = "matplotlib-3.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c797dac8bb9c7a3fd3382b16fe8f215b4cf0f22adccea36f1545a6d7be310b41"}, - {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d719465db13267bcef19ea8954a971db03b9f48b4647e3860e4bc8e6ed86610f"}, - {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8912ef7c2362f7193b5819d17dae8629b34a95c58603d781329712ada83f9447"}, - {file = "matplotlib-3.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7741f26a58a240f43bee74965c4882b6c93df3e7eb3de160126d8c8f53a6ae6e"}, - {file = "matplotlib-3.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae82a14dab96fbfad7965403c643cafe6515e386de723e498cf3eeb1e0b70cc7"}, - {file = "matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9"}, - {file = "matplotlib-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d"}, - {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7"}, - {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c"}, - {file = "matplotlib-3.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e"}, - {file = "matplotlib-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3"}, - {file = "matplotlib-3.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9"}, - {file = "matplotlib-3.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa"}, - {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b"}, - {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413"}, - {file = "matplotlib-3.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b"}, - {file = "matplotlib-3.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49"}, - {file = "matplotlib-3.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03"}, - {file = "matplotlib-3.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30"}, - {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51"}, - {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c"}, - {file = "matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e"}, - {file = "matplotlib-3.9.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:cef2a73d06601437be399908cf13aee74e86932a5ccc6ccdf173408ebc5f6bb2"}, - {file = "matplotlib-3.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e0830e188029c14e891fadd99702fd90d317df294c3298aad682739c5533721a"}, - {file = "matplotlib-3.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ba9c1299c920964e8d3857ba27173b4dbb51ca4bab47ffc2c2ba0eb5e2cbc5"}, - {file = "matplotlib-3.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cd93b91ab47a3616b4d3c42b52f8363b88ca021e340804c6ab2536344fad9ca"}, - {file = "matplotlib-3.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6d1ce5ed2aefcdce11904fc5bbea7d9c21fff3d5f543841edf3dea84451a09ea"}, - {file = "matplotlib-3.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:b2696efdc08648536efd4e1601b5fd491fd47f4db97a5fbfd175549a7365c1b2"}, - {file = "matplotlib-3.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d52a3b618cb1cbb769ce2ee1dcdb333c3ab6e823944e9a2d36e37253815f9556"}, - {file = "matplotlib-3.9.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:039082812cacd6c6bec8e17a9c1e6baca230d4116d522e81e1f63a74d01d2e21"}, - {file = "matplotlib-3.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6758baae2ed64f2331d4fd19be38b7b4eae3ecec210049a26b6a4f3ae1c85dcc"}, - {file = "matplotlib-3.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:050598c2b29e0b9832cde72bcf97627bf00262adbc4a54e2b856426bb2ef0697"}, - {file = "matplotlib-3.9.2.tar.gz", hash = "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92"}, + {file = "matplotlib-3.9.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7ccd6270066feb9a9d8e0705aa027f1ff39f354c72a87efe8fa07632f30fc6bb"}, + {file = "matplotlib-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:591d3a88903a30a6d23b040c1e44d1afdd0d778758d07110eb7596f811f31842"}, + {file = "matplotlib-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd2a59ff4b83d33bca3b5ec58203cc65985367812cb8c257f3e101632be86d92"}, + {file = "matplotlib-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fc001516ffcf1a221beb51198b194d9230199d6842c540108e4ce109ac05cc0"}, + {file = "matplotlib-3.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:83c6a792f1465d174c86d06f3ae85a8fe36e6f5964633ae8106312ec0921fdf5"}, + {file = "matplotlib-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:421851f4f57350bcf0811edd754a708d2275533e84f52f6760b740766c6747a7"}, + {file = "matplotlib-3.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b3fce58971b465e01b5c538f9d44915640c20ec5ff31346e963c9e1cd66fa812"}, + {file = "matplotlib-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a973c53ad0668c53e0ed76b27d2eeeae8799836fd0d0caaa4ecc66bf4e6676c0"}, + {file = "matplotlib-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd5acf8f3ef43f7532c2f230249720f5dc5dd40ecafaf1c60ac8200d46d7eb"}, + {file = "matplotlib-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab38a4f3772523179b2f772103d8030215b318fef6360cb40558f585bf3d017f"}, + {file = "matplotlib-3.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2315837485ca6188a4b632c5199900e28d33b481eb083663f6a44cfc8987ded3"}, + {file = "matplotlib-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:a0c977c5c382f6696caf0bd277ef4f936da7e2aa202ff66cad5f0ac1428ee15b"}, + {file = "matplotlib-3.9.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:565d572efea2b94f264dd86ef27919515aa6d629252a169b42ce5f570db7f37b"}, + {file = "matplotlib-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d397fd8ccc64af2ec0af1f0efc3bacd745ebfb9d507f3f552e8adb689ed730a"}, + {file = "matplotlib-3.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26040c8f5121cd1ad712abffcd4b5222a8aec3a0fe40bc8542c94331deb8780d"}, + {file = "matplotlib-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12cb1837cffaac087ad6b44399d5e22b78c729de3cdae4629e252067b705e2b"}, + {file = "matplotlib-3.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0e835c6988edc3d2d08794f73c323cc62483e13df0194719ecb0723b564e0b5c"}, + {file = "matplotlib-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:44a21d922f78ce40435cb35b43dd7d573cf2a30138d5c4b709d19f00e3907fd7"}, + {file = "matplotlib-3.9.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0c584210c755ae921283d21d01f03a49ef46d1afa184134dd0f95b0202ee6f03"}, + {file = "matplotlib-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11fed08f34fa682c2b792942f8902e7aefeed400da71f9e5816bea40a7ce28fe"}, + {file = "matplotlib-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0000354e32efcfd86bda75729716b92f5c2edd5b947200be9881f0a671565c33"}, + {file = "matplotlib-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4db17fea0ae3aceb8e9ac69c7e3051bae0b3d083bfec932240f9bf5d0197a049"}, + {file = "matplotlib-3.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:208cbce658b72bf6a8e675058fbbf59f67814057ae78165d8a2f87c45b48d0ff"}, + {file = "matplotlib-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:dc23f48ab630474264276be156d0d7710ac6c5a09648ccdf49fef9200d8cbe80"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3fda72d4d472e2ccd1be0e9ccb6bf0d2eaf635e7f8f51d737ed7e465ac020cb3"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:84b3ba8429935a444f1fdc80ed930babbe06725bcf09fbeb5c8757a2cd74af04"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b918770bf3e07845408716e5bbda17eadfc3fcbd9307dc67f37d6cf834bb3d98"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f1f2e5d29e9435c97ad4c36fb6668e89aee13d48c75893e25cef064675038ac9"}, + {file = "matplotlib-3.9.1.tar.gz", hash = "sha256:de06b19b8db95dd33d0dc17c926c7c9ebed9f572074b6fac4f65068a6814d010"}, ] [package.dependencies] @@ -2104,22 +2058,22 @@ testing = ["beautifulsoup4", "coverage (>=6.4,<8.0)", "ipykernel (>=5.5,<7.0)", [[package]] name = "myst-parser" -version = "4.0.0" +version = "3.0.1" description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," optional = false -python-versions = ">=3.10" +python-versions = ">=3.8" files = [ - {file = "myst_parser-4.0.0-py3-none-any.whl", hash = "sha256:b9317997552424448c6096c2558872fdb6f81d3ecb3a40ce84a7518798f3f28d"}, - {file = "myst_parser-4.0.0.tar.gz", hash = "sha256:851c9dfb44e36e56d15d05e72f02b80da21a9e0d07cba96baf5e2d476bb91531"}, + {file = "myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1"}, + {file = "myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87"}, ] [package.dependencies] -docutils = ">=0.19,<0.22" +docutils = ">=0.18,<0.22" jinja2 = "*" markdown-it-py = ">=3.0,<4.0" -mdit-py-plugins = ">=0.4.1,<1.0" +mdit-py-plugins = ">=0.4,<1.0" pyyaml = "*" -sphinx = ">=7,<9" +sphinx = ">=6,<8" [package.extras] code-style = ["pre-commit (>=3.0,<4.0)"] @@ -2221,36 +2175,36 @@ files = [ [[package]] name = "netcdf4" -version = "1.7.1.post2" +version = "1.7.1.post1" description = "Provides an object-oriented python interface to the netCDF version 4 library" optional = false python-versions = ">=3.8" files = [ - {file = "netCDF4-1.7.1.post2-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:a1006ae117a754e3cf41a9e704032bf3837cbf53a695cd71deaad3e02e93d570"}, - {file = "netCDF4-1.7.1.post2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:7530d60cf6450d997ea0607f8b68b9b088f2382c42648cddf5e66e6f1280b692"}, - {file = "netCDF4-1.7.1.post2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:756a54cb212c9fc5d0ea74f7c661621821138ab8f63e818317330330cfd6165c"}, - {file = "netCDF4-1.7.1.post2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:156428fc63e2280e8bcab7f49531cde19fbba192c2ffdfb352c6a3f5e813a80b"}, - {file = "netCDF4-1.7.1.post2-cp310-cp310-win_amd64.whl", hash = "sha256:79d890ade8b8646bb2833c2b9565392cdf5e97e016cf0319693d13bd8c2dd511"}, - {file = "netCDF4-1.7.1.post2-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:b2700bd0a188637b740aa6ad09dbf9d21337fb1e0336f9859c2c6e9525404cc0"}, - {file = "netCDF4-1.7.1.post2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:914e210f76c4ce016aed32ba7dfad57e6316a38502bdcbd071fc74ee8fec73ec"}, - {file = "netCDF4-1.7.1.post2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a98731d88889e41e9a92d67cad8ac9d9c4acba612a999db803bd082384462dea"}, - {file = "netCDF4-1.7.1.post2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6369ed38ffd094fce44e066d0823b6420205d5825a715fe048146052b299754c"}, - {file = "netCDF4-1.7.1.post2-cp311-cp311-win_amd64.whl", hash = "sha256:9fe939ad543371b5ea46864ba6ac88532b2189ce139804b3187c241eb89a02a6"}, - {file = "netCDF4-1.7.1.post2-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:658f38ceb74bb127e293a47fa36f949babba0c872cf3091e2fdafa73caacc7e4"}, - {file = "netCDF4-1.7.1.post2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5f396f150f97831229e47f449fe6acbca8ff9d08b2166560c46790aa6f11b56b"}, - {file = "netCDF4-1.7.1.post2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d5216369a0a4a868dadb5c4137d854810a309b9f9ef1d16786269fbeb244101"}, - {file = "netCDF4-1.7.1.post2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12f8ab560320e879763b7837d6f8f5eb285195271f47fc5c18362e5b097ee67c"}, - {file = "netCDF4-1.7.1.post2-cp312-cp312-win_amd64.whl", hash = "sha256:2cbca7dcd92075aebe7c242e16f51f20bc5073b6f0f1449394dadc3c17e44b29"}, - {file = "netCDF4-1.7.1.post2-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:13dc0d3fa4d46e531f32fa0bb4068bdac35513114b9548ea49f92e85d9702afb"}, - {file = "netCDF4-1.7.1.post2-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:f040aecec09a44388e1469725d471e8f1d491d4b70b27c8b2d45fd47db4e8abc"}, - {file = "netCDF4-1.7.1.post2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0691d20fcc2d41cd0a15ef335a4f038ccaf07c013c4c79ad3e39993cac3c9bbb"}, - {file = "netCDF4-1.7.1.post2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa22721d9860181c03506c6d718b3a9daf8d07dcb35a466b376760f8eddfffe5"}, - {file = "netCDF4-1.7.1.post2-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:d92bd60dc2b4beba293d81912f3094b2854e9f492ce5e9b4a3ad4fbd725a29e8"}, - {file = "netCDF4-1.7.1.post2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:d8c015cd8c8582b351d715aed4c17da2e68493edaa59e91f6cf12756479fbd53"}, - {file = "netCDF4-1.7.1.post2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bc8ca705e39ac9f4d3950c908867d377f789e5bcc6f94e0a2bdadc4c4612f94"}, - {file = "netCDF4-1.7.1.post2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fef5b27a2325a50ec59793c96e5b1e9945061a390c1ea33d403ed91b7a2fb4"}, - {file = "netCDF4-1.7.1.post2-cp39-cp39-win_amd64.whl", hash = "sha256:294b24234fb71ee30640a451ed1428da3569f23383d35f905558093795f3609a"}, - {file = "netcdf4-1.7.1.post2.tar.gz", hash = "sha256:37d557e36654889d7020192bfb56f9d5f93894cb32997eb837ae586c538fd7b6"}, + {file = "netCDF4-1.7.1.post1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5abdc8ab27bcb11325547841311717a0ba8f5b73a5fc5e93b933bc23285d0c03"}, + {file = "netCDF4-1.7.1.post1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:33f5d66ee9cedf43d3932d0e5447eb471f9c53332f93476133b4bfc6b682f790"}, + {file = "netCDF4-1.7.1.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d649fad9d1f63e25a191576c7de158c8c3afa8d4b4001e8683e20da90b49b939"}, + {file = "netCDF4-1.7.1.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:860222bc57bbc714e55705f263162be2c935129dcb700a944bda61aee785ff03"}, + {file = "netCDF4-1.7.1.post1-cp310-cp310-win_amd64.whl", hash = "sha256:d5420155ca6c768c070922d80acd9f4088a913afd25a9fd2f429e7af626374eb"}, + {file = "netCDF4-1.7.1.post1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:a8d3209516aa8c58d70863ab1059af4ec82ef8ecb1c6b8cb4842d7825a6f64da"}, + {file = "netCDF4-1.7.1.post1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:7a10da9b60d3358876d53a0cd691d2c900c2b39903bf25ad5235fd321d59eb2f"}, + {file = "netCDF4-1.7.1.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac99e03d6e28419b206444fd6dc80a5e21d0ae8e53ff37d756fbc16c5d3775"}, + {file = "netCDF4-1.7.1.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e15f3afa4e6910fc158a318ea73fdc6f9e41058c71bf98a99fd63994334d16b0"}, + {file = "netCDF4-1.7.1.post1-cp311-cp311-win_amd64.whl", hash = "sha256:115160fc8e09333754542c33d721d42625a7bd62381a74f2f759297e3e38810b"}, + {file = "netCDF4-1.7.1.post1-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:75bba24ef0354fb6913bc3acdcb3790534e86bf329bbeaaf54122b18e5fd05ea"}, + {file = "netCDF4-1.7.1.post1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ce7f89b98dbb3acd9582db30e6478ce7a7003b2cb70dc20d85fe9506e65ab001"}, + {file = "netCDF4-1.7.1.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac4e30a0d5a8e227d6a890502cfa201388acf606c0c73a5a7594232f3a74e67e"}, + {file = "netCDF4-1.7.1.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:988c45f9122337a12267fb158953c0609e3ea50a557335a3105f104416a4821a"}, + {file = "netCDF4-1.7.1.post1-cp312-cp312-win_amd64.whl", hash = "sha256:8fb3ed3541fa1b5b46e9d92d7e803734a1a3f37d8f5adf5fdf7957c7750cb20e"}, + {file = "netCDF4-1.7.1.post1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:a4d05cc4c3628a7b88d623cb1a02908100a4938335a0289fa79c19016c21d7f9"}, + {file = "netCDF4-1.7.1.post1-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:3a9ba8dc93f3d9019db921e42d40fa6791e7e244f3bb3a874bf2bfb96aea7380"}, + {file = "netCDF4-1.7.1.post1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fbbca82a822ba74b605254f7a267d258f13d67f8a4156a09e26322bfa002a82d"}, + {file = "netCDF4-1.7.1.post1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a09da245f4784421fb4d5740dae0367cdbb270d0a931a33474ec17a9433314d"}, + {file = "netCDF4-1.7.1.post1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:fdcec3a3150f9248e76301ad723f51955efc770edf015dfb61a6480cc7c04a70"}, + {file = "netCDF4-1.7.1.post1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:0fed0eb65a7751a99a0cee08c6df383737d46d17c73cabae81d113f1b4fa3643"}, + {file = "netCDF4-1.7.1.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daa6169fe6617a4612cb75a8ef61ee14011a012633ad1ace1b629a1ff87bf5cf"}, + {file = "netCDF4-1.7.1.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcad21e965978cc5530131bd7e73dcabe7dda1f681f9e4ebf940a65a176d25fe"}, + {file = "netCDF4-1.7.1.post1-cp39-cp39-win_amd64.whl", hash = "sha256:f24027ae19b68cc1274aad8b00d6d81879d506ddca011a080dff2117014398b9"}, + {file = "netcdf4-1.7.1.post1.tar.gz", hash = "sha256:797f0b25d87827fc6821e415d9e15a2068604b18c3be62563e72682bcba76548"}, ] [package.dependencies] @@ -2291,63 +2245,56 @@ test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync" [[package]] name = "numpy" -version = "2.1.0" +version = "2.0.1" description = "Fundamental package for array computing in Python" optional = false -python-versions = ">=3.10" +python-versions = ">=3.9" files = [ - {file = "numpy-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6326ab99b52fafdcdeccf602d6286191a79fe2fda0ae90573c5814cd2b0bc1b8"}, - {file = "numpy-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0937e54c09f7a9a68da6889362ddd2ff584c02d015ec92672c099b61555f8911"}, - {file = "numpy-2.1.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:30014b234f07b5fec20f4146f69e13cfb1e33ee9a18a1879a0142fbb00d47673"}, - {file = "numpy-2.1.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:899da829b362ade41e1e7eccad2cf274035e1cb36ba73034946fccd4afd8606b"}, - {file = "numpy-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08801848a40aea24ce16c2ecde3b756f9ad756586fb2d13210939eb69b023f5b"}, - {file = "numpy-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:398049e237d1aae53d82a416dade04defed1a47f87d18d5bd615b6e7d7e41d1f"}, - {file = "numpy-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0abb3916a35d9090088a748636b2c06dc9a6542f99cd476979fb156a18192b84"}, - {file = "numpy-2.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10e2350aea18d04832319aac0f887d5fcec1b36abd485d14f173e3e900b83e33"}, - {file = "numpy-2.1.0-cp310-cp310-win32.whl", hash = "sha256:f6b26e6c3b98adb648243670fddc8cab6ae17473f9dc58c51574af3e64d61211"}, - {file = "numpy-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:f505264735ee074250a9c78247ee8618292091d9d1fcc023290e9ac67e8f1afa"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:76368c788ccb4f4782cf9c842b316140142b4cbf22ff8db82724e82fe1205dce"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f8e93a01a35be08d31ae33021e5268f157a2d60ebd643cfc15de6ab8e4722eb1"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9523f8b46485db6939bd069b28b642fec86c30909cea90ef550373787f79530e"}, - {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54139e0eb219f52f60656d163cbe67c31ede51d13236c950145473504fa208cb"}, - {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebbf9fbdabed208d4ecd2e1dfd2c0741af2f876e7ae522c2537d404ca895c3"}, - {file = "numpy-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:378cb4f24c7d93066ee4103204f73ed046eb88f9ad5bb2275bb9fa0f6a02bd36"}, - {file = "numpy-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f699a709120b220dfe173f79c73cb2a2cab2c0b88dd59d7b49407d032b8ebd"}, - {file = "numpy-2.1.0-cp311-cp311-win32.whl", hash = "sha256:ffbd6faeb190aaf2b5e9024bac9622d2ee549b7ec89ef3a9373fa35313d44e0e"}, - {file = "numpy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0af3a5987f59d9c529c022c8c2a64805b339b7ef506509fba7d0556649b9714b"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fe76d75b345dc045acdbc006adcb197cc680754afd6c259de60d358d60c93736"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f358ea9e47eb3c2d6eba121ab512dfff38a88db719c38d1e67349af210bc7529"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:dd94ce596bda40a9618324547cfaaf6650b1a24f5390350142499aa4e34e53d1"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b47c551c6724960479cefd7353656498b86e7232429e3a41ab83be4da1b109e8"}, - {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0756a179afa766ad7cb6f036de622e8a8f16ffdd55aa31f296c870b5679d745"}, - {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24003ba8ff22ea29a8c306e61d316ac74111cebf942afbf692df65509a05f111"}, - {file = "numpy-2.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b34fa5e3b5d6dc7e0a4243fa0f81367027cb6f4a7215a17852979634b5544ee0"}, - {file = "numpy-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4f982715e65036c34897eb598d64aef15150c447be2cfc6643ec7a11af06574"}, - {file = "numpy-2.1.0-cp312-cp312-win32.whl", hash = "sha256:c4cd94dfefbefec3f8b544f61286584292d740e6e9d4677769bc76b8f41deb02"}, - {file = "numpy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0cdef204199278f5c461a0bed6ed2e052998276e6d8ab2963d5b5c39a0500bc"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8ab81ccd753859ab89e67199b9da62c543850f819993761c1e94a75a814ed667"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:442596f01913656d579309edcd179a2a2f9977d9a14ff41d042475280fc7f34e"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:848c6b5cad9898e4b9ef251b6f934fa34630371f2e916261070a4eb9092ffd33"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:54c6a63e9d81efe64bfb7bcb0ec64332a87d0b87575f6009c8ba67ea6374770b"}, - {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652e92fc409e278abdd61e9505649e3938f6d04ce7ef1953f2ec598a50e7c195"}, - {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab32eb9170bf8ffcbb14f11613f4a0b108d3ffee0832457c5d4808233ba8977"}, - {file = "numpy-2.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:8fb49a0ba4d8f41198ae2d52118b050fd34dace4b8f3fb0ee34e23eb4ae775b1"}, - {file = "numpy-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44e44973262dc3ae79e9063a1284a73e09d01b894b534a769732ccd46c28cc62"}, - {file = "numpy-2.1.0-cp313-cp313-win32.whl", hash = "sha256:ab83adc099ec62e044b1fbb3a05499fa1e99f6d53a1dde102b2d85eff66ed324"}, - {file = "numpy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:de844aaa4815b78f6023832590d77da0e3b6805c644c33ce94a1e449f16d6ab5"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:343e3e152bf5a087511cd325e3b7ecfd5b92d369e80e74c12cd87826e263ec06"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f07fa2f15dabe91259828ce7d71b5ca9e2eb7c8c26baa822c825ce43552f4883"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5474dad8c86ee9ba9bb776f4b99ef2d41b3b8f4e0d199d4f7304728ed34d0300"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1f817c71683fd1bb5cff1529a1d085a57f02ccd2ebc5cd2c566f9a01118e3b7d"}, - {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a3336fbfa0d38d3deacd3fe7f3d07e13597f29c13abf4d15c3b6dc2291cbbdd"}, - {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a894c51fd8c4e834f00ac742abad73fc485df1062f1b875661a3c1e1fb1c2f6"}, - {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:9156ca1f79fc4acc226696e95bfcc2b486f165a6a59ebe22b2c1f82ab190384a"}, - {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:624884b572dff8ca8f60fab591413f077471de64e376b17d291b19f56504b2bb"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:15ef8b2177eeb7e37dd5ef4016f30b7659c57c2c0b57a779f1d537ff33a72c7b"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:e5f0642cdf4636198a4990de7a71b693d824c56a757862230454629cf62e323d"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15976718c004466406342789f31b6673776360f3b1e3c575f25302d7e789575"}, - {file = "numpy-2.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6c1de77ded79fef664d5098a66810d4d27ca0224e9051906e634b3f7ead134c2"}, - {file = "numpy-2.1.0.tar.gz", hash = "sha256:7dc90da0081f7e1da49ec4e398ede6a8e9cc4f5ebe5f9e06b443ed889ee9aaa2"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fbb536eac80e27a2793ffd787895242b7f18ef792563d742c2d673bfcb75134"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:69ff563d43c69b1baba77af455dd0a839df8d25e8590e79c90fcbe1499ebde42"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:1b902ce0e0a5bb7704556a217c4f63a7974f8f43e090aff03fcf262e0b135e02"}, + {file = "numpy-2.0.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:f1659887361a7151f89e79b276ed8dff3d75877df906328f14d8bb40bb4f5101"}, + {file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4658c398d65d1b25e1760de3157011a80375da861709abd7cef3bad65d6543f9"}, + {file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4127d4303b9ac9f94ca0441138acead39928938660ca58329fe156f84b9f3015"}, + {file = "numpy-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e5eeca8067ad04bc8a2a8731183d51d7cbaac66d86085d5f4766ee6bf19c7f87"}, + {file = "numpy-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9adbd9bb520c866e1bfd7e10e1880a1f7749f1f6e5017686a5fbb9b72cf69f82"}, + {file = "numpy-2.0.1-cp310-cp310-win32.whl", hash = "sha256:7b9853803278db3bdcc6cd5beca37815b133e9e77ff3d4733c247414e78eb8d1"}, + {file = "numpy-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81b0893a39bc5b865b8bf89e9ad7807e16717f19868e9d234bdaf9b1f1393868"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75b4e316c5902d8163ef9d423b1c3f2f6252226d1aa5cd8a0a03a7d01ffc6268"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6e4eeb6eb2fced786e32e6d8df9e755ce5be920d17f7ce00bc38fcde8ccdbf9e"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a1e01dcaab205fbece13c1410253a9eea1b1c9b61d237b6fa59bcc46e8e89343"}, + {file = "numpy-2.0.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8fc2de81ad835d999113ddf87d1ea2b0f4704cbd947c948d2f5513deafe5a7b"}, + {file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3d94942c331dd4e0e1147f7a8699a4aa47dffc11bf8a1523c12af8b2e91bbe"}, + {file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15eb4eca47d36ec3f78cde0a3a2ee24cf05ca7396ef808dda2c0ddad7c2bde67"}, + {file = "numpy-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b83e16a5511d1b1f8a88cbabb1a6f6a499f82c062a4251892d9ad5d609863fb7"}, + {file = "numpy-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f87fec1f9bc1efd23f4227becff04bd0e979e23ca50cc92ec88b38489db3b55"}, + {file = "numpy-2.0.1-cp311-cp311-win32.whl", hash = "sha256:36d3a9405fd7c511804dc56fc32974fa5533bdeb3cd1604d6b8ff1d292b819c4"}, + {file = "numpy-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:08458fbf403bff5e2b45f08eda195d4b0c9b35682311da5a5a0a0925b11b9bd8"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bf4e6f4a2a2e26655717a1983ef6324f2664d7011f6ef7482e8c0b3d51e82ac"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6fddc5fe258d3328cd8e3d7d3e02234c5d70e01ebe377a6ab92adb14039cb4"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5daab361be6ddeb299a918a7c0864fa8618af66019138263247af405018b04e1"}, + {file = "numpy-2.0.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:ea2326a4dca88e4a274ba3a4405eb6c6467d3ffbd8c7d38632502eaae3820587"}, + {file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529af13c5f4b7a932fb0e1911d3a75da204eff023ee5e0e79c1751564221a5c8"}, + {file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6790654cb13eab303d8402354fabd47472b24635700f631f041bd0b65e37298a"}, + {file = "numpy-2.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cbab9fc9c391700e3e1287666dfd82d8666d10e69a6c4a09ab97574c0b7ee0a7"}, + {file = "numpy-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99d0d92a5e3613c33a5f01db206a33f8fdf3d71f2912b0de1739894668b7a93b"}, + {file = "numpy-2.0.1-cp312-cp312-win32.whl", hash = "sha256:173a00b9995f73b79eb0191129f2455f1e34c203f559dd118636858cc452a1bf"}, + {file = "numpy-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:bb2124fdc6e62baae159ebcfa368708867eb56806804d005860b6007388df171"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc085b28d62ff4009364e7ca34b80a9a080cbd97c2c0630bb5f7f770dae9414"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fae4ebbf95a179c1156fab0b142b74e4ba4204c87bde8d3d8b6f9c34c5825ef"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:72dc22e9ec8f6eaa206deb1b1355eb2e253899d7347f5e2fae5f0af613741d06"}, + {file = "numpy-2.0.1-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:ec87f5f8aca726117a1c9b7083e7656a9d0d606eec7299cc067bb83d26f16e0c"}, + {file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f682ea61a88479d9498bf2091fdcd722b090724b08b31d63e022adc063bad59"}, + {file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8efc84f01c1cd7e34b3fb310183e72fcdf55293ee736d679b6d35b35d80bba26"}, + {file = "numpy-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3fdabe3e2a52bc4eff8dc7a5044342f8bd9f11ef0934fcd3289a788c0eb10018"}, + {file = "numpy-2.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:24a0e1befbfa14615b49ba9659d3d8818a0f4d8a1c5822af8696706fbda7310c"}, + {file = "numpy-2.0.1-cp39-cp39-win32.whl", hash = "sha256:f9cf5ea551aec449206954b075db819f52adc1638d46a6738253a712d553c7b4"}, + {file = "numpy-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:e9e81fa9017eaa416c056e5d9e71be93d05e2c3c2ab308d23307a8bc4443c368"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61728fba1e464f789b11deb78a57805c70b2ed02343560456190d0501ba37b0f"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:12f5d865d60fb9734e60a60f1d5afa6d962d8d4467c120a1c0cda6eb2964437d"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eacf3291e263d5a67d8c1a581a8ebbcfd6447204ef58828caf69a5e3e8c75990"}, + {file = "numpy-2.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2c3a346ae20cfd80b6cfd3e60dc179963ef2ea58da5ec074fd3d9e7a1e7ba97f"}, + {file = "numpy-2.0.1.tar.gz", hash = "sha256:485b87235796410c3519a699cfe1faab097e509e90ebb05dcd098db2ae87e7b3"}, ] [[package]] @@ -2452,8 +2399,8 @@ description = "Type annotations for pandas" optional = false python-versions = ">=3.10" files = [ - {file = "pandas_stubs-2.2.2.240807-py3-none-any.whl", hash = "sha256:893919ad82be4275f0d07bb47a95d08bae580d3fdea308a7acfcb3f02e76186e"}, - {file = "pandas_stubs-2.2.2.240807.tar.gz", hash = "sha256:64a559725a57a449f46225fbafc422520b7410bff9252b661a225b5559192a93"}, + {file = "pandas_stubs-2.2.2.240909-py3-none-any.whl", hash = "sha256:e230f5fa4065f9417804f4d65cd98f86c002efcc07933e8abcd48c3fad9c30a2"}, + {file = "pandas_stubs-2.2.2.240909.tar.gz", hash = "sha256:3c0951a2c3e45e3475aed9d80b7147ae82f176b9e42e9fb321cfdebf3d411b3d"}, ] [package.dependencies] @@ -2970,182 +2917,159 @@ files = [ [[package]] name = "pyyaml" -version = "6.0.2" +version = "6.0.1" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, - {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, - {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, - {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, - {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, - {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, - {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, - {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, - {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, - {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, - {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, - {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, - {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, - {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, - {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] [[package]] name = "pyzmq" -version = "26.1.1" +version = "26.0.3" description = "Python bindings for 0MQ" optional = false python-versions = ">=3.7" files = [ - {file = "pyzmq-26.1.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:b1bb952d1e407463c9333ea7e0c0600001e54e08ce836d4f0aff1fb3f902cf63"}, - {file = "pyzmq-26.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:65e2a18e845c6ea7ab849c70db932eaeadee5edede9e379eb21c0a44cf523b2e"}, - {file = "pyzmq-26.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:def7ae3006924b8a0c146a89ab4008310913fa903beedb95e25dea749642528e"}, - {file = "pyzmq-26.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8234571df7816f99dde89c3403cb396d70c6554120b795853a8ea56fcc26cd3"}, - {file = "pyzmq-26.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18da8e84dbc30688fd2baefd41df7190607511f916be34f9a24b0e007551822e"}, - {file = "pyzmq-26.1.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c70dab93d98b2bf3f0ac1265edbf6e7f83acbf71dabcc4611889bb0dea45bed7"}, - {file = "pyzmq-26.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fcb90592c5d5c562e1b1a1ceccf6f00036d73c51db0271bf4d352b8d6b31d468"}, - {file = "pyzmq-26.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cf4be7460a0c1bc71e9b0e64ecdd75a86386ca6afaa36641686f5542d0314e9d"}, - {file = "pyzmq-26.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4cbecda4ddbfc1e309c3be04d333f9be3fc6178b8b6592b309676f929767a15"}, - {file = "pyzmq-26.1.1-cp310-cp310-win32.whl", hash = "sha256:583f73b113b8165713b6ce028d221402b1b69483055b5aa3f991937e34dd1ead"}, - {file = "pyzmq-26.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5e6f39ecb8eb7bfcb976c49262e8cf83ff76e082b77ca23ba90c9b6691a345be"}, - {file = "pyzmq-26.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:8d042d6446cab3a1388b38596f5acabb9926b0b95c3894c519356b577a549458"}, - {file = "pyzmq-26.1.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:362cac2423e36966d336d79d3ec3eafeabc153ee3e7a5cf580d7e74a34b3d912"}, - {file = "pyzmq-26.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0841633446cb1539a832a19bb24c03a20c00887d0cedd1d891b495b07e5c5cb5"}, - {file = "pyzmq-26.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e1fcdc333afbf9918d0a614a6e10858aede7da49a60f6705a77e343fe86a317"}, - {file = "pyzmq-26.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc8d655627d775475eafdcf0e49e74bcc1e5e90afd9ab813b4da98f092ed7b93"}, - {file = "pyzmq-26.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32de51744820857a6f7c3077e620ab3f607d0e4388dfead885d5124ab9bcdc5e"}, - {file = "pyzmq-26.1.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a880240597010914ffb1d6edd04d3deb7ce6a2abf79a0012751438d13630a671"}, - {file = "pyzmq-26.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:26131b1cec02f941ed2d2b4b8cc051662b1c248b044eff5069df1f500bbced56"}, - {file = "pyzmq-26.1.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ce05841322b58510607f9508a573138d995a46c7928887bc433de9cb760fd2ad"}, - {file = "pyzmq-26.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:32123ff0a6db521aadf2b95201e967a4e0d11fb89f73663a99d2f54881c07214"}, - {file = "pyzmq-26.1.1-cp311-cp311-win32.whl", hash = "sha256:e790602d7ea1d6c7d8713d571226d67de7ffe47b1e22ae2c043ebd537de1bccb"}, - {file = "pyzmq-26.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:717960855f2d6fdc2dba9df49dff31c414187bb11c76af36343a57d1f7083d9a"}, - {file = "pyzmq-26.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:08956c26dbcd4fd8835cb777a16e21958ed2412317630e19f0018d49dbeeb470"}, - {file = "pyzmq-26.1.1-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:e80345900ae241c2c51bead7c9fa247bba6d4b2a83423e9791bae8b0a7f12c52"}, - {file = "pyzmq-26.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ec8fe214fcc45dfb0c32e4a7ad1db20244ba2d2fecbf0cbf9d5242d81ca0a375"}, - {file = "pyzmq-26.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf4e283f97688d993cb7a8acbc22889effbbb7cbaa19ee9709751f44be928f5d"}, - {file = "pyzmq-26.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2508bdc8ab246e5ed7c92023d4352aaad63020ca3b098a4e3f1822db202f703d"}, - {file = "pyzmq-26.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:741bdb4d96efe8192616abdc3671931d51a8bcd38c71da2d53fb3127149265d1"}, - {file = "pyzmq-26.1.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:76154943e4c4054b2591792eb3484ef1dd23d59805759f9cebd2f010aa30ee8c"}, - {file = "pyzmq-26.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9498ac427d20d0e0ef0e4bbd6200841e91640dfdf619f544ceec7f464cfb6070"}, - {file = "pyzmq-26.1.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f34453ef3496ca3462f30435bf85f535f9550392987341f9ccc92c102825a79"}, - {file = "pyzmq-26.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:50f0669324e27cc2091ef6ab76ca7112f364b6249691790b4cffce31e73fda28"}, - {file = "pyzmq-26.1.1-cp312-cp312-win32.whl", hash = "sha256:3ee5cbf2625b94de21c68d0cefd35327c8dfdbd6a98fcc41682b4e8bb00d841f"}, - {file = "pyzmq-26.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:75bd448a28b1001b6928679015bc95dd5f172703ed30135bb9e34fc9cda0a3e7"}, - {file = "pyzmq-26.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:4350233569b4bbef88595c5e77ee38995a6f1f1790fae148b578941bfffd1c24"}, - {file = "pyzmq-26.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8087a3281c20b1d11042d372ed5a47734af05975d78e4d1d6e7bd1018535f3"}, - {file = "pyzmq-26.1.1-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:ebef7d3fe11fe4c688f08bc0211a976c3318c097057f258428200737b9fff4da"}, - {file = "pyzmq-26.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a5342110510045a47de1e87f5f1dcc1d9d90109522316dc9830cfc6157c800f"}, - {file = "pyzmq-26.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af690ea4be6ca92a67c2b44a779a023bf0838e92d48497a2268175dc4a505691"}, - {file = "pyzmq-26.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc994e220c1403ae087d7f0fa45129d583e46668a019e389060da811a5a9320e"}, - {file = "pyzmq-26.1.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:b8e153f5dffb0310af71fc6fc9cd8174f4c8ea312c415adcb815d786fee78179"}, - {file = "pyzmq-26.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0065026e624052a51033857e5cd45a94b52946b44533f965f0bdf182460e965d"}, - {file = "pyzmq-26.1.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:63351392f948b5d50b9f55161994bc4feedbfb3f3cfe393d2f503dea2c3ec445"}, - {file = "pyzmq-26.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ffecc43b3c18e36b62fcec995761829b6ac325d8dd74a4f2c5c1653afbb4495a"}, - {file = "pyzmq-26.1.1-cp313-cp313-win32.whl", hash = "sha256:6ff14c2fae6c0c2c1c02590c5c5d75aa1db35b859971b3ca2fcd28f983d9f2b6"}, - {file = "pyzmq-26.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:85f2d2ee5ea9a8f1de86a300e1062fbab044f45b5ce34d20580c0198a8196db0"}, - {file = "pyzmq-26.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:cc09b1de8b985ca5a0ca343dd7fb007267c6b329347a74e200f4654268084239"}, - {file = "pyzmq-26.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:bc904e86de98f8fc5bd41597da5d61232d2d6d60c4397f26efffabb961b2b245"}, - {file = "pyzmq-26.1.1-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:00f39c367bbd6aa8e4bc36af6510561944c619b58eb36199fa334b594a18f615"}, - {file = "pyzmq-26.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de6f384864a959866b782e6a3896538d1424d183f2d3c7ef079f71dcecde7284"}, - {file = "pyzmq-26.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3abb15df0c763339edb27a644c19381b2425ddd1aea3dbd77c1601a3b31867b8"}, - {file = "pyzmq-26.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40908ec2dd3b29bbadc0916a0d3c87f8dbeebbd8fead8e618539f09e0506dec4"}, - {file = "pyzmq-26.1.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:c11a95d3f6fc7e714ccd1066f68f9c1abd764a8b3596158be92f46dd49f41e03"}, - {file = "pyzmq-26.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:4437af9fee7a58302dbd511cc49f0cc2b35c112a33a1111fb123cf0be45205ca"}, - {file = "pyzmq-26.1.1-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:76390d3d66406cb01b9681c382874400e9dfd77f30ecdea4bd1bf5226dd4aff0"}, - {file = "pyzmq-26.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:4d4c7fe5e50e269f9c63a260638488fec194a73993008618a59b54c47ef6ae72"}, - {file = "pyzmq-26.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:25d128524207f53f7aae7c5abdc2b63f8957a060b00521af5ffcd20986b5d8f4"}, - {file = "pyzmq-26.1.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d74b925d997e4f92b042bdd7085cd0a309ee0fd7cb4dc376059bbff6b32ff34f"}, - {file = "pyzmq-26.1.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:732f957441e5b1c65a7509395e6b6cafee9e12df9aa5f4bf92ed266fe0ba70ee"}, - {file = "pyzmq-26.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0a45102ad7ed9f9ddf2bd699cc5df37742cf7301111cba06001b927efecb120"}, - {file = "pyzmq-26.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9f380d5333fc7cd17423f486125dcc073918676e33db70a6a8172b19fc78d23d"}, - {file = "pyzmq-26.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8eaffcd6bf6a9d00b66a2052a33fa7e6a6575427e9644395f13c3d070f2918dc"}, - {file = "pyzmq-26.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f1483d4975ae1b387b39bb8e23d1ff32fe5621aa9e4ed3055d05e9c5613fea53"}, - {file = "pyzmq-26.1.1-cp37-cp37m-win32.whl", hash = "sha256:a83653c6bbe5887caea55e49fbd2909c14b73acf43bcc051eb60b2d514bbd46e"}, - {file = "pyzmq-26.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9763a8d3f5f74ef679989b373c37cc22e8d07e56d26439205cb83edb7722357f"}, - {file = "pyzmq-26.1.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2b045647caf620ce0ed6c8fd9fb6a73116f99aceed966b152a5ba1b416d25311"}, - {file = "pyzmq-26.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f66dcb6625c002f209cdc12cae1a1fec926493cd2262efe37dc6b25a30cea863"}, - {file = "pyzmq-26.1.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0cf1d980c969fb9e538f52abd2227f09e015096bc5c3ef7aa26e0d64051c1db8"}, - {file = "pyzmq-26.1.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:443ebf5e261a95ee9725693f2a5a71401f89b89df0e0ea58844b074067aac2f1"}, - {file = "pyzmq-26.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29de77ba1b1877fe7defc1b9140e65cbd35f72a63bc501e56c2eae55bde5fff4"}, - {file = "pyzmq-26.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f6071ec95af145d7b659dae6786871cd85f0acc599286b6f8ba0c74592d83dd"}, - {file = "pyzmq-26.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f0512fc87629ad968889176bf2165d721cd817401a281504329e2a2ed0ca6a3"}, - {file = "pyzmq-26.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5ccfcf13e80719f6a2d9c0a021d9e47d4550907a29253554be2c09582f6d7963"}, - {file = "pyzmq-26.1.1-cp38-cp38-win32.whl", hash = "sha256:809673947e95752e407aaaaf03f205ee86ebfff9ca51db6d4003dfd87b8428d1"}, - {file = "pyzmq-26.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:62b5180e23e6f581600459cd983473cd723fdc64350f606d21407c99832aaf5f"}, - {file = "pyzmq-26.1.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:fe73d7c89d6f803bed122135ff5783364e8cdb479cf6fe2d764a44b6349e7e0f"}, - {file = "pyzmq-26.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db1b7e2b50ef21f398036786da4c153db63203a402396d9f21e08ea61f3f8dba"}, - {file = "pyzmq-26.1.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7c506a51cb01bb997a3f6440db0d121e5e7a32396e9948b1fdb6a7bfa67243f4"}, - {file = "pyzmq-26.1.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:92eca4f80e8a748d880e55d3cf57ef487692e439f12d5c5a2e1cce84aaa7f6cb"}, - {file = "pyzmq-26.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14bdbae02f72f4716b0ffe7500e9da303d719ddde1f3dcfb4c4f6cc1cf73bb02"}, - {file = "pyzmq-26.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e03be7ed17836c9434cce0668ac1e2cc9143d7169f90f46a0167f6155e176e32"}, - {file = "pyzmq-26.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc5df31e36e4fddd4c8b5c42daee8d54d7b529e898ac984be97bf5517de166a7"}, - {file = "pyzmq-26.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f218179c90a12d660906e04b25a340dd63e9743000ba16232ddaf46888f269da"}, - {file = "pyzmq-26.1.1-cp39-cp39-win32.whl", hash = "sha256:7dfabc180a4da422a4b349c63077347392463a75fa07aa3be96712ed6d42c547"}, - {file = "pyzmq-26.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c5248e6e0fcbbbc912982e99cdd51c342601f495b0fa5bd667f3bdbdbf3e170f"}, - {file = "pyzmq-26.1.1-cp39-cp39-win_arm64.whl", hash = "sha256:2ae7aa1408778dc74582a1226052b930f9083b54b64d7e6ef6ec0466cfdcdec2"}, - {file = "pyzmq-26.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:be3fc2b11c0c384949cf1f01f9a48555039408b0f3e877863b1754225635953e"}, - {file = "pyzmq-26.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48dee75c2a9fa4f4a583d4028d564a0453447ee1277a29b07acc3743c092e259"}, - {file = "pyzmq-26.1.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23f2fe4fb567e8098ebaa7204819658195b10ddd86958a97a6058eed2901eed3"}, - {file = "pyzmq-26.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:472cacd16f627c06d3c8b2d374345ab74446bae913584a6245e2aa935336d929"}, - {file = "pyzmq-26.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8285b25aa20fcc46f1ca4afbc39fd3d5f2fe4c4bbf7f2c7f907a214e87a70024"}, - {file = "pyzmq-26.1.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2067e63fd9d5c13cfe12624dab0366053e523b37a7a01678ce4321f839398939"}, - {file = "pyzmq-26.1.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cc109be2ee3638035d276e18eaf66a1e1f44201c0c4bea4ee0c692766bbd3570"}, - {file = "pyzmq-26.1.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0da97e65ee73261dba70469cc8f63d8da3a8a825337a2e3d246b9e95141cdd0"}, - {file = "pyzmq-26.1.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa79c528706561306938b275f89bb2c6985ce08469c27e5de05bc680df5e826f"}, - {file = "pyzmq-26.1.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3ddbd851a3a2651fdc5065a2804d50cf2f4b13b1bcd66de8e9e855d0217d4fcd"}, - {file = "pyzmq-26.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d3df226ab7464684ae6706e20a5cbab717c3735a7e409b3fa598b754d49f1946"}, - {file = "pyzmq-26.1.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abad7b897e960d577eb4a0f3f789c1780bc3ffe2e7c27cf317e7c90ad26acf12"}, - {file = "pyzmq-26.1.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c513d829a548c2d5c88983167be2b3aa537f6d1191edcdc6fcd8999e18bdd994"}, - {file = "pyzmq-26.1.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70af4c9c991714ef1c65957605a8de42ef0d0620dd5f125953c8e682281bdb80"}, - {file = "pyzmq-26.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8d4234f335b0d0842f7d661d8cd50cbad0729be58f1c4deb85cd96b38fe95025"}, - {file = "pyzmq-26.1.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2c0fdb7b758e0e1605157e480b00b3a599073068a37091a1c75ec65bf7498645"}, - {file = "pyzmq-26.1.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc657577f057d60dd3642c9f95f28b432889b73143140061f7c1331d02f03df6"}, - {file = "pyzmq-26.1.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e3b66fe6131b4f33d239f7d4c3bfb2f8532d8644bae3b3da4f3987073edac55"}, - {file = "pyzmq-26.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59b57e912feef6951aec8bb03fe0faa5ad5f36962883c72a30a9c965e6d988fd"}, - {file = "pyzmq-26.1.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:146956aec7d947c5afc5e7da0841423d7a53f84fd160fff25e682361dcfb32cb"}, - {file = "pyzmq-26.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9521b874fd489495865172f344e46e0159095d1f161858e3fc6e28e43ca15160"}, - {file = "pyzmq-26.1.1.tar.gz", hash = "sha256:a7db05d8b7cd1a8c6610e9e9aa55d525baae7a44a43e18bc3260eb3f92de96c6"}, + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8"}, + {file = "pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83"}, + {file = "pyzmq-26.0.3-cp311-cp311-win32.whl", hash = "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798"}, + {file = "pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97"}, + {file = "pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc"}, + {file = "pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920"}, + {file = "pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad"}, + {file = "pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a"}, ] [package.dependencies] @@ -3214,114 +3138,114 @@ files = [ [[package]] name = "rpds-py" -version = "0.20.0" +version = "0.19.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2"}, - {file = "rpds_py-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf"}, - {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce"}, - {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94"}, - {file = "rpds_py-0.20.0-cp310-none-win32.whl", hash = "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee"}, - {file = "rpds_py-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399"}, - {file = "rpds_py-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489"}, - {file = "rpds_py-0.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58"}, - {file = "rpds_py-0.20.0-cp311-none-win32.whl", hash = "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0"}, - {file = "rpds_py-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c"}, - {file = "rpds_py-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6"}, - {file = "rpds_py-0.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4"}, - {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940"}, - {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174"}, - {file = "rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139"}, - {file = "rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585"}, - {file = "rpds_py-0.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29"}, - {file = "rpds_py-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879"}, - {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2"}, - {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57"}, - {file = "rpds_py-0.20.0-cp313-none-win32.whl", hash = "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a"}, - {file = "rpds_py-0.20.0-cp313-none-win_amd64.whl", hash = "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2"}, - {file = "rpds_py-0.20.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24"}, - {file = "rpds_py-0.20.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751"}, - {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253"}, - {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a"}, - {file = "rpds_py-0.20.0-cp38-none-win32.whl", hash = "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5"}, - {file = "rpds_py-0.20.0-cp38-none-win_amd64.whl", hash = "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232"}, - {file = "rpds_py-0.20.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22"}, - {file = "rpds_py-0.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda"}, - {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420"}, - {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b"}, - {file = "rpds_py-0.20.0-cp39-none-win32.whl", hash = "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7"}, - {file = "rpds_py-0.20.0-cp39-none-win_amd64.whl", hash = "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344"}, - {file = "rpds_py-0.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec"}, - {file = "rpds_py-0.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8"}, - {file = "rpds_py-0.20.0.tar.gz", hash = "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121"}, + {file = "rpds_py-0.19.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:aaf71f95b21f9dc708123335df22e5a2fef6307e3e6f9ed773b2e0938cc4d491"}, + {file = "rpds_py-0.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca0dda0c5715efe2ab35bb83f813f681ebcd2840d8b1b92bfc6fe3ab382fae4a"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81db2e7282cc0487f500d4db203edc57da81acde9e35f061d69ed983228ffe3b"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1a8dfa125b60ec00c7c9baef945bb04abf8ac772d8ebefd79dae2a5f316d7850"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:271accf41b02687cef26367c775ab220372ee0f4925591c6796e7c148c50cab5"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9bc4161bd3b970cd6a6fcda70583ad4afd10f2750609fb1f3ca9505050d4ef3"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0cf2a0dbb5987da4bd92a7ca727eadb225581dd9681365beba9accbe5308f7d"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b5e28e56143750808c1c79c70a16519e9bc0a68b623197b96292b21b62d6055c"}, + {file = "rpds_py-0.19.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c7af6f7b80f687b33a4cdb0a785a5d4de1fb027a44c9a049d8eb67d5bfe8a687"}, + {file = "rpds_py-0.19.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e429fc517a1c5e2a70d576077231538a98d59a45dfc552d1ac45a132844e6dfb"}, + {file = "rpds_py-0.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d2dbd8f4990d4788cb122f63bf000357533f34860d269c1a8e90ae362090ff3a"}, + {file = "rpds_py-0.19.1-cp310-none-win32.whl", hash = "sha256:e0f9d268b19e8f61bf42a1da48276bcd05f7ab5560311f541d22557f8227b866"}, + {file = "rpds_py-0.19.1-cp310-none-win_amd64.whl", hash = "sha256:df7c841813f6265e636fe548a49664c77af31ddfa0085515326342a751a6ba51"}, + {file = "rpds_py-0.19.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:902cf4739458852fe917104365ec0efbea7d29a15e4276c96a8d33e6ed8ec137"}, + {file = "rpds_py-0.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f3d73022990ab0c8b172cce57c69fd9a89c24fd473a5e79cbce92df87e3d9c48"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3837c63dd6918a24de6c526277910e3766d8c2b1627c500b155f3eecad8fad65"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cdb7eb3cf3deb3dd9e7b8749323b5d970052711f9e1e9f36364163627f96da58"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26ab43b6d65d25b1a333c8d1b1c2f8399385ff683a35ab5e274ba7b8bb7dc61c"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75130df05aae7a7ac171b3b5b24714cffeabd054ad2ebc18870b3aa4526eba23"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c34f751bf67cab69638564eee34023909380ba3e0d8ee7f6fe473079bf93f09b"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f2671cb47e50a97f419a02cd1e0c339b31de017b033186358db92f4d8e2e17d8"}, + {file = "rpds_py-0.19.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c73254c256081704dba0a333457e2fb815364018788f9b501efe7c5e0ada401"}, + {file = "rpds_py-0.19.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4383beb4a29935b8fa28aca8fa84c956bf545cb0c46307b091b8d312a9150e6a"}, + {file = "rpds_py-0.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dbceedcf4a9329cc665452db1aaf0845b85c666e4885b92ee0cddb1dbf7e052a"}, + {file = "rpds_py-0.19.1-cp311-none-win32.whl", hash = "sha256:f0a6d4a93d2a05daec7cb885157c97bbb0be4da739d6f9dfb02e101eb40921cd"}, + {file = "rpds_py-0.19.1-cp311-none-win_amd64.whl", hash = "sha256:c149a652aeac4902ecff2dd93c3b2681c608bd5208c793c4a99404b3e1afc87c"}, + {file = "rpds_py-0.19.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:56313be667a837ff1ea3508cebb1ef6681d418fa2913a0635386cf29cff35165"}, + {file = "rpds_py-0.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d1d7539043b2b31307f2c6c72957a97c839a88b2629a348ebabe5aa8b626d6b"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1dc59a5e7bc7f44bd0c048681f5e05356e479c50be4f2c1a7089103f1621d5"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8f78398e67a7227aefa95f876481485403eb974b29e9dc38b307bb6eb2315ea"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef07a0a1d254eeb16455d839cef6e8c2ed127f47f014bbda64a58b5482b6c836"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8124101e92c56827bebef084ff106e8ea11c743256149a95b9fd860d3a4f331f"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08ce9c95a0b093b7aec75676b356a27879901488abc27e9d029273d280438505"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b02dd77a2de6e49078c8937aadabe933ceac04b41c5dde5eca13a69f3cf144e"}, + {file = "rpds_py-0.19.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4dd02e29c8cbed21a1875330b07246b71121a1c08e29f0ee3db5b4cfe16980c4"}, + {file = "rpds_py-0.19.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9c7042488165f7251dc7894cd533a875d2875af6d3b0e09eda9c4b334627ad1c"}, + {file = "rpds_py-0.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f809a17cc78bd331e137caa25262b507225854073fd319e987bd216bed911b7c"}, + {file = "rpds_py-0.19.1-cp312-none-win32.whl", hash = "sha256:3ddab996807c6b4227967fe1587febade4e48ac47bb0e2d3e7858bc621b1cace"}, + {file = "rpds_py-0.19.1-cp312-none-win_amd64.whl", hash = "sha256:32e0db3d6e4f45601b58e4ac75c6f24afbf99818c647cc2066f3e4b192dabb1f"}, + {file = "rpds_py-0.19.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:747251e428406b05fc86fee3904ee19550c4d2d19258cef274e2151f31ae9d38"}, + {file = "rpds_py-0.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dc733d35f861f8d78abfaf54035461e10423422999b360966bf1c443cbc42705"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbda75f245caecff8faa7e32ee94dfaa8312a3367397975527f29654cd17a6ed"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd04d8cab16cab5b0a9ffc7d10f0779cf1120ab16c3925404428f74a0a43205a"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2d66eb41ffca6cc3c91d8387509d27ba73ad28371ef90255c50cb51f8953301"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdf4890cda3b59170009d012fca3294c00140e7f2abe1910e6a730809d0f3f9b"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1fa67ef839bad3815124f5f57e48cd50ff392f4911a9f3cf449d66fa3df62a5"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b82c9514c6d74b89a370c4060bdb80d2299bc6857e462e4a215b4ef7aa7b090e"}, + {file = "rpds_py-0.19.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c7b07959866a6afb019abb9564d8a55046feb7a84506c74a6f197cbcdf8a208e"}, + {file = "rpds_py-0.19.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4f580ae79d0b861dfd912494ab9d477bea535bfb4756a2269130b6607a21802e"}, + {file = "rpds_py-0.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c6d20c8896c00775e6f62d8373aba32956aa0b850d02b5ec493f486c88e12859"}, + {file = "rpds_py-0.19.1-cp313-none-win32.whl", hash = "sha256:afedc35fe4b9e30ab240b208bb9dc8938cb4afe9187589e8d8d085e1aacb8309"}, + {file = "rpds_py-0.19.1-cp313-none-win_amd64.whl", hash = "sha256:1d4af2eb520d759f48f1073ad3caef997d1bfd910dc34e41261a595d3f038a94"}, + {file = "rpds_py-0.19.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:34bca66e2e3eabc8a19e9afe0d3e77789733c702c7c43cd008e953d5d1463fde"}, + {file = "rpds_py-0.19.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:24f8ae92c7fae7c28d0fae9b52829235df83f34847aa8160a47eb229d9666c7b"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71157f9db7f6bc6599a852852f3389343bea34315b4e6f109e5cbc97c1fb2963"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d494887d40dc4dd0d5a71e9d07324e5c09c4383d93942d391727e7a40ff810b"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b3661e6d4ba63a094138032c1356d557de5b3ea6fd3cca62a195f623e381c76"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97fbb77eaeb97591efdc654b8b5f3ccc066406ccfb3175b41382f221ecc216e8"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cc4bc73e53af8e7a42c8fd7923bbe35babacfa7394ae9240b3430b5dcf16b2a"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:35af5e4d5448fa179fd7fff0bba0fba51f876cd55212f96c8bbcecc5c684ae5c"}, + {file = "rpds_py-0.19.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3511f6baf8438326e351097cecd137eb45c5f019944fe0fd0ae2fea2fd26be39"}, + {file = "rpds_py-0.19.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:57863d16187995c10fe9cf911b897ed443ac68189179541734502353af33e693"}, + {file = "rpds_py-0.19.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9e318e6786b1e750a62f90c6f7fa8b542102bdcf97c7c4de2a48b50b61bd36ec"}, + {file = "rpds_py-0.19.1-cp38-none-win32.whl", hash = "sha256:53dbc35808c6faa2ce3e48571f8f74ef70802218554884787b86a30947842a14"}, + {file = "rpds_py-0.19.1-cp38-none-win_amd64.whl", hash = "sha256:8df1c283e57c9cb4d271fdc1875f4a58a143a2d1698eb0d6b7c0d7d5f49c53a1"}, + {file = "rpds_py-0.19.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e76c902d229a3aa9d5ceb813e1cbcc69bf5bda44c80d574ff1ac1fa3136dea71"}, + {file = "rpds_py-0.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de1f7cd5b6b351e1afd7568bdab94934d656abe273d66cda0ceea43bbc02a0c2"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fc5a84777cb61692d17988989690d6f34f7f95968ac81398d67c0d0994a897"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:74129d5ffc4cde992d89d345f7f7d6758320e5d44a369d74d83493429dad2de5"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e360188b72f8080fefa3adfdcf3618604cc8173651c9754f189fece068d2a45"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13e6d4840897d4e4e6b2aa1443e3a8eca92b0402182aafc5f4ca1f5e24f9270a"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f09529d2332264a902688031a83c19de8fda5eb5881e44233286b9c9ec91856d"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0d4b52811dcbc1aba08fd88d475f75b4f6db0984ba12275d9bed1a04b2cae9b5"}, + {file = "rpds_py-0.19.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd635c2c4043222d80d80ca1ac4530a633102a9f2ad12252183bcf338c1b9474"}, + {file = "rpds_py-0.19.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f35b34a5184d5e0cc360b61664c1c06e866aab077b5a7c538a3e20c8fcdbf90b"}, + {file = "rpds_py-0.19.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d4ec0046facab83012d821b33cead742a35b54575c4edfb7ed7445f63441835f"}, + {file = "rpds_py-0.19.1-cp39-none-win32.whl", hash = "sha256:f5b8353ea1a4d7dfb59a7f45c04df66ecfd363bb5b35f33b11ea579111d4655f"}, + {file = "rpds_py-0.19.1-cp39-none-win_amd64.whl", hash = "sha256:1fb93d3486f793d54a094e2bfd9cd97031f63fcb5bc18faeb3dd4b49a1c06523"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7d5c7e32f3ee42f77d8ff1a10384b5cdcc2d37035e2e3320ded909aa192d32c3"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:89cc8921a4a5028d6dd388c399fcd2eef232e7040345af3d5b16c04b91cf3c7e"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca34e913d27401bda2a6f390d0614049f5a95b3b11cd8eff80fe4ec340a1208"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5953391af1405f968eb5701ebbb577ebc5ced8d0041406f9052638bafe52209d"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:840e18c38098221ea6201f091fc5d4de6128961d2930fbbc96806fb43f69aec1"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d8b735c4d162dc7d86a9cf3d717f14b6c73637a1f9cd57fe7e61002d9cb1972"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce757c7c90d35719b38fa3d4ca55654a76a40716ee299b0865f2de21c146801c"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9421b23c85f361a133aa7c5e8ec757668f70343f4ed8fdb5a4a14abd5437244"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3b823be829407393d84ee56dc849dbe3b31b6a326f388e171555b262e8456cc1"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:5e58b61dcbb483a442c6239c3836696b79f2cd8e7eec11e12155d3f6f2d886d1"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39d67896f7235b2c886fb1ee77b1491b77049dcef6fbf0f401e7b4cbed86bbd4"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8b32cd4ab6db50c875001ba4f5a6b30c0f42151aa1fbf9c2e7e3674893fb1dc4"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1c32e41de995f39b6b315d66c27dea3ef7f7c937c06caab4c6a79a5e09e2c415"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1a129c02b42d46758c87faeea21a9f574e1c858b9f358b6dd0bbd71d17713175"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:346557f5b1d8fd9966059b7a748fd79ac59f5752cd0e9498d6a40e3ac1c1875f"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:31e450840f2f27699d014cfc8865cc747184286b26d945bcea6042bb6aa4d26e"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01227f8b3e6c8961490d869aa65c99653df80d2f0a7fde8c64ebddab2b9b02fd"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69084fd29bfeff14816666c93a466e85414fe6b7d236cfc108a9c11afa6f7301"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d2b88efe65544a7d5121b0c3b003ebba92bfede2ea3577ce548b69c5235185"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ea961a674172ed2235d990d7edf85d15d8dfa23ab8575e48306371c070cda67"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:5beffdbe766cfe4fb04f30644d822a1080b5359df7db3a63d30fa928375b2720"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:720f3108fb1bfa32e51db58b832898372eb5891e8472a8093008010911e324c5"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c2087dbb76a87ec2c619253e021e4fb20d1a72580feeaa6892b0b3d955175a71"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ddd50f18ebc05ec29a0d9271e9dbe93997536da3546677f8ca00b76d477680c"}, + {file = "rpds_py-0.19.1.tar.gz", hash = "sha256:31dd5794837f00b46f4096aa8ccaa5972f73a938982e32ed817bb520c465e520"}, ] [[package]] @@ -3410,19 +3334,19 @@ win32 = ["pywin32"] [[package]] name = "setuptools" -version = "73.0.0" +version = "72.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-73.0.0-py3-none-any.whl", hash = "sha256:f2bfcce7ae1784d90b04c57c2802e8649e1976530bb25dc72c2b078d3ecf4864"}, - {file = "setuptools-73.0.0.tar.gz", hash = "sha256:3c08705fadfc8c7c445cf4d98078f0fafb9225775b2b4e8447e40348f82597c0"}, + {file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"}, + {file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"}, ] [package.extras] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -3459,13 +3383,13 @@ files = [ [[package]] name = "soupsieve" -version = "2.6" +version = "2.5" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" files = [ - {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, - {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, ] [[package]] @@ -3670,60 +3594,60 @@ test = ["pytest"] [[package]] name = "sqlalchemy" -version = "2.0.32" +version = "2.0.31" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.32-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0c9045ecc2e4db59bfc97b20516dfdf8e41d910ac6fb667ebd3a79ea54084619"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1467940318e4a860afd546ef61fefb98a14d935cd6817ed07a228c7f7c62f389"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5954463675cb15db8d4b521f3566a017c8789222b8316b1e6934c811018ee08b"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:167e7497035c303ae50651b351c28dc22a40bb98fbdb8468cdc971821b1ae533"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b27dfb676ac02529fb6e343b3a482303f16e6bc3a4d868b73935b8792edb52d0"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bf2360a5e0f7bd75fa80431bf8ebcfb920c9f885e7956c7efde89031695cafb8"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-win32.whl", hash = "sha256:306fe44e754a91cd9d600a6b070c1f2fadbb4a1a257b8781ccf33c7067fd3e4d"}, - {file = "SQLAlchemy-2.0.32-cp310-cp310-win_amd64.whl", hash = "sha256:99db65e6f3ab42e06c318f15c98f59a436f1c78179e6a6f40f529c8cc7100b22"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21b053be28a8a414f2ddd401f1be8361e41032d2ef5884b2f31d31cb723e559f"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b178e875a7a25b5938b53b006598ee7645172fccafe1c291a706e93f48499ff5"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723a40ee2cc7ea653645bd4cf024326dea2076673fc9d3d33f20f6c81db83e1d"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:295ff8689544f7ee7e819529633d058bd458c1fd7f7e3eebd0f9268ebc56c2a0"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49496b68cd190a147118af585173ee624114dfb2e0297558c460ad7495f9dfe2"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:acd9b73c5c15f0ec5ce18128b1fe9157ddd0044abc373e6ecd5ba376a7e5d961"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-win32.whl", hash = "sha256:9365a3da32dabd3e69e06b972b1ffb0c89668994c7e8e75ce21d3e5e69ddef28"}, - {file = "SQLAlchemy-2.0.32-cp311-cp311-win_amd64.whl", hash = "sha256:8bd63d051f4f313b102a2af1cbc8b80f061bf78f3d5bd0843ff70b5859e27924"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bab3db192a0c35e3c9d1560eb8332463e29e5507dbd822e29a0a3c48c0a8d92"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:19d98f4f58b13900d8dec4ed09dd09ef292208ee44cc9c2fe01c1f0a2fe440e9"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd33c61513cb1b7371fd40cf221256456d26a56284e7d19d1f0b9f1eb7dd7e8"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6ba0497c1d066dd004e0f02a92426ca2df20fac08728d03f67f6960271feec"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2b6be53e4fde0065524f1a0a7929b10e9280987b320716c1509478b712a7688c"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:916a798f62f410c0b80b63683c8061f5ebe237b0f4ad778739304253353bc1cb"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-win32.whl", hash = "sha256:31983018b74908ebc6c996a16ad3690301a23befb643093fcfe85efd292e384d"}, - {file = "SQLAlchemy-2.0.32-cp312-cp312-win_amd64.whl", hash = "sha256:4363ed245a6231f2e2957cccdda3c776265a75851f4753c60f3004b90e69bfeb"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b8afd5b26570bf41c35c0121801479958b4446751a3971fb9a480c1afd85558e"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c750987fc876813f27b60d619b987b057eb4896b81117f73bb8d9918c14f1cad"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ada0102afff4890f651ed91120c1120065663506b760da4e7823913ebd3258be"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:78c03d0f8a5ab4f3034c0e8482cfcc415a3ec6193491cfa1c643ed707d476f16"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:3bd1cae7519283ff525e64645ebd7a3e0283f3c038f461ecc1c7b040a0c932a1"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-win32.whl", hash = "sha256:01438ebcdc566d58c93af0171c74ec28efe6a29184b773e378a385e6215389da"}, - {file = "SQLAlchemy-2.0.32-cp37-cp37m-win_amd64.whl", hash = "sha256:4979dc80fbbc9d2ef569e71e0896990bc94df2b9fdbd878290bd129b65ab579c"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c742be912f57586ac43af38b3848f7688863a403dfb220193a882ea60e1ec3a"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:62e23d0ac103bcf1c5555b6c88c114089587bc64d048fef5bbdb58dfd26f96da"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:251f0d1108aab8ea7b9aadbd07fb47fb8e3a5838dde34aa95a3349876b5a1f1d"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef18a84e5116340e38eca3e7f9eeaaef62738891422e7c2a0b80feab165905f"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3eb6a97a1d39976f360b10ff208c73afb6a4de86dd2a6212ddf65c4a6a2347d5"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0c1c9b673d21477cec17ab10bc4decb1322843ba35b481585facd88203754fc5"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-win32.whl", hash = "sha256:c41a2b9ca80ee555decc605bd3c4520cc6fef9abde8fd66b1cf65126a6922d65"}, - {file = "SQLAlchemy-2.0.32-cp38-cp38-win_amd64.whl", hash = "sha256:8a37e4d265033c897892279e8adf505c8b6b4075f2b40d77afb31f7185cd6ecd"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:52fec964fba2ef46476312a03ec8c425956b05c20220a1a03703537824b5e8e1"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:328429aecaba2aee3d71e11f2477c14eec5990fb6d0e884107935f7fb6001632"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85a01b5599e790e76ac3fe3aa2f26e1feba56270023d6afd5550ed63c68552b3"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaf04784797dcdf4c0aa952c8d234fa01974c4729db55c45732520ce12dd95b4"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4488120becf9b71b3ac718f4138269a6be99a42fe023ec457896ba4f80749525"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:14e09e083a5796d513918a66f3d6aedbc131e39e80875afe81d98a03312889e6"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-win32.whl", hash = "sha256:0d322cc9c9b2154ba7e82f7bf25ecc7c36fbe2d82e2933b3642fc095a52cfc78"}, - {file = "SQLAlchemy-2.0.32-cp39-cp39-win_amd64.whl", hash = "sha256:7dd8583df2f98dea28b5cd53a1beac963f4f9d087888d75f22fcc93a07cf8d84"}, - {file = "SQLAlchemy-2.0.32-py3-none-any.whl", hash = "sha256:e567a8793a692451f706b363ccf3c45e056b67d90ead58c3bc9471af5d212202"}, - {file = "SQLAlchemy-2.0.32.tar.gz", hash = "sha256:c1b88cc8b02b6a5f0efb0345a03672d4c897dc7d92585176f88c67346f565ea8"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2a213c1b699d3f5768a7272de720387ae0122f1becf0901ed6eaa1abd1baf6c"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9fea3d0884e82d1e33226935dac990b967bef21315cbcc894605db3441347443"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ad7f221d8a69d32d197e5968d798217a4feebe30144986af71ada8c548e9fa"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2bee229715b6366f86a95d497c347c22ddffa2c7c96143b59a2aa5cc9eebbc"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cd5b94d4819c0c89280b7c6109c7b788a576084bf0a480ae17c227b0bc41e109"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:750900a471d39a7eeba57580b11983030517a1f512c2cb287d5ad0fcf3aebd58"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-win32.whl", hash = "sha256:7bd112be780928c7f493c1a192cd8c5fc2a2a7b52b790bc5a84203fb4381c6be"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-win_amd64.whl", hash = "sha256:5a48ac4d359f058474fadc2115f78a5cdac9988d4f99eae44917f36aa1476327"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f68470edd70c3ac3b6cd5c2a22a8daf18415203ca1b036aaeb9b0fb6f54e8298"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e2c38c2a4c5c634fe6c3c58a789712719fa1bf9b9d6ff5ebfce9a9e5b89c1ca"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd15026f77420eb2b324dcb93551ad9c5f22fab2c150c286ef1dc1160f110203"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2196208432deebdfe3b22185d46b08f00ac9d7b01284e168c212919891289396"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:352b2770097f41bff6029b280c0e03b217c2dcaddc40726f8f53ed58d8a85da4"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56d51ae825d20d604583f82c9527d285e9e6d14f9a5516463d9705dab20c3740"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-win32.whl", hash = "sha256:6e2622844551945db81c26a02f27d94145b561f9d4b0c39ce7bfd2fda5776dac"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-win_amd64.whl", hash = "sha256:ccaf1b0c90435b6e430f5dd30a5aede4764942a695552eb3a4ab74ed63c5b8d3"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3b74570d99126992d4b0f91fb87c586a574a5872651185de8297c6f90055ae42"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f77c4f042ad493cb8595e2f503c7a4fe44cd7bd59c7582fd6d78d7e7b8ec52c"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd1591329333daf94467e699e11015d9c944f44c94d2091f4ac493ced0119449"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74afabeeff415e35525bf7a4ecdab015f00e06456166a2eba7590e49f8db940e"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b9c01990d9015df2c6f818aa8f4297d42ee71c9502026bb074e713d496e26b67"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66f63278db425838b3c2b1c596654b31939427016ba030e951b292e32b99553e"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-win32.whl", hash = "sha256:0b0f658414ee4e4b8cbcd4a9bb0fd743c5eeb81fc858ca517217a8013d282c96"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-win_amd64.whl", hash = "sha256:fa4b1af3e619b5b0b435e333f3967612db06351217c58bfb50cee5f003db2a5a"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f43e93057cf52a227eda401251c72b6fbe4756f35fa6bfebb5d73b86881e59b0"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d337bf94052856d1b330d5fcad44582a30c532a2463776e1651bd3294ee7e58b"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c06fb43a51ccdff3b4006aafee9fcf15f63f23c580675f7734245ceb6b6a9e05"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:b6e22630e89f0e8c12332b2b4c282cb01cf4da0d26795b7eae16702a608e7ca1"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:79a40771363c5e9f3a77f0e28b3302801db08040928146e6808b5b7a40749c88"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-win32.whl", hash = "sha256:501ff052229cb79dd4c49c402f6cb03b5a40ae4771efc8bb2bfac9f6c3d3508f"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-win_amd64.whl", hash = "sha256:597fec37c382a5442ffd471f66ce12d07d91b281fd474289356b1a0041bdf31d"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dc6d69f8829712a4fd799d2ac8d79bdeff651c2301b081fd5d3fe697bd5b4ab9"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:23b9fbb2f5dd9e630db70fbe47d963c7779e9c81830869bd7d137c2dc1ad05fb"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21c97efcbb9f255d5c12a96ae14da873233597dfd00a3a0c4ce5b3e5e79704"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a6a9837589c42b16693cf7bf836f5d42218f44d198f9343dd71d3164ceeeac"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc251477eae03c20fae8db9c1c23ea2ebc47331bcd73927cdcaecd02af98d3c3"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2fd17e3bb8058359fa61248c52c7b09a97cf3c820e54207a50af529876451808"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-win32.whl", hash = "sha256:c76c81c52e1e08f12f4b6a07af2b96b9b15ea67ccdd40ae17019f1c373faa227"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-win_amd64.whl", hash = "sha256:4b600e9a212ed59355813becbcf282cfda5c93678e15c25a0ef896b354423238"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b6cf796d9fcc9b37011d3f9936189b3c8074a02a4ed0c0fbbc126772c31a6d4"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:78fe11dbe37d92667c2c6e74379f75746dc947ee505555a0197cfba9a6d4f1a4"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc47dc6185a83c8100b37acda27658fe4dbd33b7d5e7324111f6521008ab4fe"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a41514c1a779e2aa9a19f67aaadeb5cbddf0b2b508843fcd7bafdf4c6864005"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:afb6dde6c11ea4525318e279cd93c8734b795ac8bb5dda0eedd9ebaca7fa23f1"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3f9faef422cfbb8fd53716cd14ba95e2ef655400235c3dfad1b5f467ba179c8c"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-win32.whl", hash = "sha256:fc6b14e8602f59c6ba893980bea96571dd0ed83d8ebb9c4479d9ed5425d562e9"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-win_amd64.whl", hash = "sha256:3cb8a66b167b033ec72c3812ffc8441d4e9f5f78f5e31e54dcd4c90a4ca5bebc"}, + {file = "SQLAlchemy-2.0.31-py3-none-any.whl", hash = "sha256:69f3e3c08867a8e4856e92d7afb618b95cdee18e0bc1647b77599722c9a28911"}, + {file = "SQLAlchemy-2.0.31.tar.gz", hash = "sha256:b607489dd4a54de56984a0c7656247504bd5523d9d0ba799aef59d4add009484"}, ] [package.dependencies] @@ -4025,13 +3949,13 @@ files = [ [[package]] name = "webcolors" -version = "24.8.0" +version = "24.6.0" description = "A library for working with the color formats defined by HTML and CSS." optional = false python-versions = ">=3.8" files = [ - {file = "webcolors-24.8.0-py3-none-any.whl", hash = "sha256:fc4c3b59358ada164552084a8ebee637c221e4059267d0f8325b3b560f6c7f0a"}, - {file = "webcolors-24.8.0.tar.gz", hash = "sha256:08b07af286a01bcd30d583a7acadf629583d1f79bfef27dd2c2c5c263817277d"}, + {file = "webcolors-24.6.0-py3-none-any.whl", hash = "sha256:8cf5bc7e28defd1d48b9e83d5fc30741328305a8195c29a8e668fa45586568a1"}, + {file = "webcolors-24.6.0.tar.gz", hash = "sha256:1d160d1de46b3e81e58d0a280d0c78b467dc80f47294b91b1ad8029d2cedb55b"}, ] [package.extras] @@ -4091,13 +4015,13 @@ viz = ["matplotlib", "nc-time-axis", "seaborn"] [[package]] name = "zipp" -version = "3.20.0" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.20.0-py3-none-any.whl", hash = "sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d"}, - {file = "zipp-3.20.0.tar.gz", hash = "sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] From 0c29a36512fc5d275a102f07b784398be61acb95 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 1 Oct 2024 18:41:17 +0100 Subject: [PATCH 197/241] Draft of community projected area plot --- docs/source/users/demography/canopy.md | 291 +++++++------------------ 1 file changed, 81 insertions(+), 210 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index 2f2da88a..3b08901f 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -37,6 +37,7 @@ import pandas as pd from pyrealm.demography.flora import PlantFunctionalType, Flora from pyrealm.demography.community import Community +from pyrealm.demography.crown import CrownProfile from pyrealm.demography.canopy import Canopy ``` @@ -92,7 +93,7 @@ The code below creates a simple community and then fits the canopy model: short_pft = PlantFunctionalType( name="short", h_max=15, m=1.5, n=1.5, f_g=0, ca_ratio=380 ) -tall_pft = PlantFunctionalType(name="tall", h_max=30, m=1.5, n=4, f_g=0.2, ca_ratio=500) +tall_pft = PlantFunctionalType(name="tall", h_max=30, m=1.5, n=2, f_g=0.2, ca_ratio=500) # Create the flora flora = Flora([short_pft, tall_pft]) @@ -166,219 +167,89 @@ towards the ground in the last cohort, because the `tall` PFT has a large gap fr canopy.stem_leaf_area ``` -We can now plot the canopy stems alongside the community $A_p(z)$ profile, and -superimpose the calculated $z^*_l$ values and the cumulative canopy area for each layer -to confirm that the calculated values coincide with the profile. Note here that the -total area at each closed layer height is omitting the community gap fraction. - -```{code-cell} -community_Ap_z = np.nansum(Ap_z, axis=1) - -fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(10, 5)) +### Visualizing layer closure heights and areas -zcol = "red" +We can use the {class}`~pyrealm.demography.crown.CrownProfile` class to calculate a +community crown and leaf area profile across a range of height values. For each height, +we calculate the sum of the product of stem projected area and the number of +individuals in each cohort. -# Plot the canopy parts -ax1.plot(stem_x + rz_below_zm, z, color="khaki") -ax1.plot(stem_x - rz_below_zm, z, color="khaki") -ax1.plot(stem_x + rz_above_zm, z, color="forestgreen") -ax1.plot(stem_x - rz_above_zm, z, color="forestgreen") +```{code-cell} +# Set of vertical height to calculate crown profiles +at_z = np.linspace(0, 26, num=261)[:, None] -# Add the maximum radius -ax1.plot(np.vstack((stem_x - rm, stem_x + rm)), np.vstack((zm, zm)), color="firebrick") +# Calculate the crown profile for the stem for each cohort +crown_profiles = CrownProfile( + stem_traits=community.stem_traits, stem_allometry=community.stem_allometry, z=at_z +) -# Plot the stem centre lines -ax1.vlines(stem_x, 0, pft.height, linestyles="-", color="grey") +# Calculate the total projected crown area across the community at each height +community_crown_area = np.nansum( + crown_profiles.projected_crown_area * community.cohort_data["n_individuals"], axis=1 +) +# Do the same for the projected leaf area +community_leaf_area = np.nansum( + crown_profiles.projected_leaf_area * community.cohort_data["n_individuals"], axis=1 +) +``` -ax1.set_ylabel("Height above ground ($z$, m)") -ax1.set_xlabel("Arbitrary stem position") -ax1.hlines(z_star, 0, (stem_x + rm).max(), color=zcol, linewidth=0.5) +We can now plot community-wide $A_p(z)$ and $\tilde{A}_{cp}(z)$ profiles, and +superimpose the calculated $z^*_l$ values and the cumulative canopy area for each layer +to confirm that the calculated values coincide with the profile. Note here that the +total area at each closed layer height is omitting the community gap fraction. -# Plot the projected community crown area by height along with the heights -# at which different canopy layers close -ax2.hlines(z_star, 0, community_Ap_z.max(), color=zcol, linewidth=0.5) -ax2.vlines( - canopy_area * np.arange(1, len(z_star)) * (1 - community_gap_fraction), - 0, - pft.height.max(), - color=zcol, - linewidth=0.5, +```{code-cell} +fig, ax = plt.subplots(ncols=1) + +# Calculate the crown area at which each canopy layer closes. +closure_areas = np.arange(1, canopy.n_layers + 1) * canopy.crown_area_per_layer + +# Add lines showing the canopy closure heights and closure areas. +for val in canopy.layer_heights: + ax.axhline(val, color="red", linewidth=0.5, zorder=0) + +for val in closure_areas: + ax.axvline(val, color="red", linewidth=0.5, zorder=0) + +# Show the community projected crown area profile +ax.plot(community_crown_area, at_z, zorder=1, label="Crown area") +ax.plot( + community_leaf_area, + at_z, + zorder=1, + linestyle="--", + color="black", + linewidth=1, + label="Leaf area", ) -ax2.plot(community_Ap_z, z) -ax2.set_xlabel("Projected crown area above height $z$ ($A_p(z)$, m2)") # Add z* values on the righthand axis -ax3 = ax2.twinx() - - -def z_star_labels(X): - return [f"$z^*_{l + 1}$ = {z:.2f}" for l, z in enumerate(X)] - - -ax3.set_ylim(ax2.get_ylim()) -ax3.set_yticks(z_star) -ax3.set_yticklabels(z_star_labels(z_star)) - -ax4 = ax2.twiny() - -# Add canopy layer closure areas on top axis -cum_area = np.arange(1, len(z_star)) * canopy_area * (1 - community_gap_fraction) - - -def cum_area_labels(X): - return [f"$A_{l + 1}$ = {z:.1f}" for l, z in enumerate(X)] - - -ax4.set_xlim(ax2.get_xlim()) -ax4.set_xticks(cum_area) -ax4.set_xticklabels(cum_area_labels(cum_area)) - -plt.tight_layout() +ax_rhs = ax.twinx() +ax_rhs.set_ylim(ax.get_ylim()) +z_star_labels = [ + f"$z^*_{l + 1} = {val:.2f}$" + for l, val in enumerate(np.nditer(canopy.layer_heights)) +] +ax_rhs.set_yticks(canopy.layer_heights.flatten()) +ax_rhs.set_yticklabels(z_star_labels) + +# Add cumulative canopy area at top +ax_top = ax.twiny() +ax_top.set_xlim(ax.get_xlim()) +area_labels = [f"$A_{l + 1}$ = {z:.1f}" for l, z in enumerate(np.nditer(closure_areas))] +ax_top.set_xticks(closure_areas) +ax_top.set_xticklabels(area_labels) + +ax.set_ylabel("Vertical height ($z$, m)") +ax.set_xlabel("Community-wide projected area (m2)") +ax.legend(frameon=False) ``` The projected area from individual stems to each canopy layer can then be calculated at $z^*_l$ and hence the projected area of canopy **within each layer**. -```{code-cell} -# Calculate the canopy area above z_star for each stem -Ap_z_star = calculate_projected_area(z=z_star[:, None], pft=pft, m=m, n=n, qm=qm, zm=zm) - -print(Ap_z_star) -``` - -```{code-cell} -:lines_to_next_cell: 2 - -# Calculate the contribution _within_ each layer per stem -Ap_within_layer = np.diff(Ap_z_star, axis=0, prepend=0) - -print(Ap_within_layer) -``` - -+++ {"lines_to_next_cell": 2} - -### Leaf area within canopy layers - -The projected area occupied by leaves at a given height $\tilde{A}_{cp}(z)$ is -needed to calculate light transmission through those layers. This differs from the -projected area $A_p(z)$ because, although a tree occupies an area in the canopy -following the PPA, a **crown gap fraction** ($f_g$) reduces the actual leaf area -at a given height $z$. - -The crown gap fraction does not affect the overall projected canopy area at ground -level or the community gap fraction: the amount of clear sky at ground level is -governed purely by $f_G$. Instead it models how leaf gaps in the upper canopy are -filled by leaf area at lower heights. It captures the vertical distribution of -leaf area within the canopy: a higher $f_g$ will give fewer leaves at the top of -the canopy and more leaves further down within the canopy. - -The calculation of $\tilde{A}_{cp}(z)$ is defined as: - -$$ -\tilde{A}_{cp}(z)= -\begin{cases} -0, & z \gt H \\ -A_c \left(\dfrac{q(z)}{q_m}\right)^2 \left(1 - f_g\right), & H \gt z \gt z_m \\ -Ac - A_c \left(\dfrac{q(z)}{q_m}\right)^2 f_g, & zm \gt z -\end{cases} -$$ - -The function below calculates $\tilde{A}_{cp}(z)$. - -```{code-cell} -def calculate_leaf_area( - z: float, - fg: float, - pft, - m: Stems, - n: Stems, - qm: Stems, - zm: Stems, -) -> np.ndarray: - """Calculate leaf area above a given height. - - This function takes PFT specific parameters (shape parameters) and stem specific - sizes and estimates the projected crown area above a given height $z$. The inputs - can either be scalars describing a single stem or arrays representing a community - of stems. If only a single PFT is being modelled then `m`, `n`, `qm` and `fg` can - be scalars with arrays `H`, `Ac` and `zm` giving the sizes of stems within that - PFT. - - Args: - z: Canopy height - fg: crown gap fraction - m, n, qm : PFT specific shape parameters - pft, qm, zm: stem data - """ - - # Calculate q(z) - qz = calculate_relative_canopy_radius_at_z(z, pft.height, m, n) - - # Calculate Ac term - Ac_term = pft.crown_area * (qz / qm) ** 2 - # Set Acp either side of zm - Acp = np.where(z <= zm, pft.crown_area - Ac_term * fg, Ac_term * (1 - fg)) - # Set Ap = 0 where z > H - Acp = np.where(z > pft.height, 0, Acp) - - return Acp -``` - -The plot below shows how the vertical leaf area profile for the community changes for -different values of $f_g$. When $f_g = 0$, then $A_cp(z) = A_p(z)$ (red line) because -there are no crown gaps and hence all of the leaf area is within the crown surface. As -$f_g \to 1$, more of the leaf area is displaced deeper into the canopy, leaves in the -lower crown intercepting light coming through holes in the upper canopy. - -```{code-cell} -fig, ax1 = plt.subplots(1, 1, figsize=(6, 5)) - -for fg in np.arange(0, 1.01, 0.05): - - if fg == 0: - color = "red" - label = "$f_g = 0$" - lwd = 0.5 - elif fg == 1: - color = "blue" - label = "$f_g = 1$" - lwd = 0.5 - else: - color = "black" - label = None - lwd = 0.25 - - Acp_z = calculate_leaf_area(z=z[:, None], fg=fg, pft=pft, m=m, n=n, qm=qm, zm=zm) - ax1.plot(np.nansum(Acp_z, axis=1), z, color=color, linewidth=lwd, label=label) - -ax1.set_xlabel(r"Projected leaf area above height $z$ ($\tilde{A}_{cp}(z)$, m2)") -ax1.legend(frameon=False) -``` - -We can now calculate the crown area occupied by leaves above the height of each closed -layer $z^*_l$: - -```{code-cell} -# Calculate the leaf area above z_star for each stem -crown_gap_fraction = 0.05 -Acp_z_star = calculate_leaf_area( - z=z_star[:, None], fg=crown_gap_fraction, pft=pft, m=m, n=n, qm=qm, zm=zm -) - -print(Acp_z_star) -``` - -And from that, the area occupied by leaves **within each layer**. These values are -similar to the projected crown area within layers (`Ap_within_layer`, above) but -leaf area is displaced into lower layers because $f_g > 0$. - -```{code-cell} -# Calculate the contribution _within_ each layer per stem -Acp_within_layer = np.diff(Acp_z_star, axis=0, prepend=0) - -print(Acp_within_layer) -``` ++++ ### Light transmission through the canopy @@ -391,30 +262,30 @@ where $k$ is the light extinction coefficient ($k$) and $L$ is the leaf area ind (LAI). The LAI can be calculated for each stem and layer: ```{code-cell} -LAI = Acp_within_layer / canopy_area -print(LAI) +# LAI = Acp_within_layer / canopy_area +# print(LAI) ``` This can be used to calculate the LAI of individual stems but also the LAI of each layer in the canopy: ```{code-cell} -LAI_stem = LAI.sum(axis=0) -LAI_layer = LAI.sum(axis=1) +# LAI_stem = LAI.sum(axis=0) +# LAI_layer = LAI.sum(axis=1) -print("LAI stem = ", LAI_stem) -print("LAI layer = ", LAI_layer) +# print("LAI stem = ", LAI_stem) +# print("LAI layer = ", LAI_layer) ``` The layer LAI values can now be used to calculate the light transmission of each layer and hence the cumulative light extinction profile through the canopy. ```{code-cell} -f_abs = 1 - np.exp(-pft.traits.par_ext * LAI_layer) -ext = np.cumprod(f_abs) +# f_abs = 1 - np.exp(-pft.traits.par_ext * LAI_layer) +# ext = np.cumprod(f_abs) -print("f_abs = ", f_abs) -print("extinction = ", ext) +# print("f_abs = ", f_abs) +# print("extinction = ", ext) ``` One issue that needs to be resolved is that the T Model implementation in `pyrealm` @@ -422,7 +293,7 @@ follows the original implementation of the T Model in having LAI as a fixed trai a given plant functional type, so is constant for all stems of that PFT. ```{code-cell} -print("f_abs = ", (1 - np.exp(-pft.traits.par_ext * pft.traits.lai))) +# print("f_abs = ", (1 - np.exp(-pft.traits.par_ext * pft.traits.lai))) ``` ## Things to worry about later From 7da129583797677129d6585a21ff04b8672c94c8 Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 1 Oct 2024 22:05:53 +0100 Subject: [PATCH 198/241] More doc updates --- docs/source/users/demography/canopy.md | 7 +--- docs/source/users/demography/community.md | 43 ++++++++++++++++++++++- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index 3b08901f..3913bfe8 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -83,7 +83,7 @@ The {class}`~pyrealm.demography.canopy.Canopy` class automatically finds the can closure heights, given a {class}`~pyrealm.demography.community.Community` instance and the required canopy gap fraction. -The code below creates a simple community and then fits the canopy model: +The code below creates a simple community: ```{code-cell} # Two PFTs @@ -246,11 +246,6 @@ ax.set_xlabel("Community-wide projected area (m2)") ax.legend(frameon=False) ``` -The projected area from individual stems to each canopy layer can then be calculated at -$z^*_l$ and hence the projected area of canopy **within each layer**. - -+++ - ### Light transmission through the canopy Now we can use the leaf area by layer and the Beer-Lambert equation to calculate light diff --git a/docs/source/users/demography/community.md b/docs/source/users/demography/community.md index d7caf0f8..0961b8e2 100644 --- a/docs/source/users/demography/community.md +++ b/docs/source/users/demography/community.md @@ -6,7 +6,7 @@ jupytext: format_name: myst format_version: 0.13 kernelspec: - display_name: python3 + display_name: Python 3 (ipykernel) language: python name: python3 --- @@ -18,3 +18,44 @@ kernelspec: This area of `pyrealm` is in active development. ::: + +```{code-cell} +from matplotlib import pyplot as plt +import numpy as np +import pandas as pd + +from pyrealm.demography.flora import PlantFunctionalType, Flora +from pyrealm.demography.community import Community +``` + +```{code-cell} +short_pft = PlantFunctionalType( + name="short", h_max=15, m=1.5, n=1.5, f_g=0, ca_ratio=380 +) +tall_pft = PlantFunctionalType(name="tall", h_max=30, m=1.5, n=2, f_g=0.2, ca_ratio=500) + +# Create the flora +flora = Flora([short_pft, tall_pft]) + +# Create a simply community with three cohorts +# - 15 saplings of the short PFT +# - 5 larger stems of the short PFT +# - 2 large stems of tall PFT + +community = Community( + flora=flora, + cell_area=32, + cell_id=1, + cohort_dbh_values=np.array([0.02, 0.20, 0.5]), + cohort_n_individuals=np.array([15, 5, 2]), + cohort_pft_names=np.array(["short", "short", "tall"]), +) +``` + +```{code-cell} +community +``` + +```{code-cell} + +``` From 35b6d6a9df8b033b08138285d4053e56981d9c2d Mon Sep 17 00:00:00 2001 From: David Orme Date: Tue, 1 Oct 2024 22:15:37 +0100 Subject: [PATCH 199/241] Doc build fixes --- docs/source/_toc.yml | 1 + docs/source/api/demography_api.md | 8 + docs/source/refs.bib | 299 +++++++++++++++++------------- 3 files changed, 179 insertions(+), 129 deletions(-) diff --git a/docs/source/_toc.yml b/docs/source/_toc.yml index 592b04fa..b91919bc 100644 --- a/docs/source/_toc.yml +++ b/docs/source/_toc.yml @@ -34,6 +34,7 @@ subtrees: - file: users/demography/flora.md - file: users/demography/t_model.md - file: users/demography/crown.md + - file: users/demography/community.md - file: users/demography/canopy.md - file: users/tmodel/tmodel.md - file: users/tmodel/canopy.md diff --git a/docs/source/api/demography_api.md b/docs/source/api/demography_api.md index 459345c4..9290a0b0 100644 --- a/docs/source/api/demography_api.md +++ b/docs/source/api/demography_api.md @@ -50,3 +50,11 @@ kernelspec: :autosummary: :members: ``` + +## The {mod}`~pyrealm.demography.canopy` module + +```{eval-rst} +.. automodule:: pyrealm.demography.canopy + :autosummary: + :members: +``` diff --git a/docs/source/refs.bib b/docs/source/refs.bib index 0dcb8e4a..7a4abd0d 100644 --- a/docs/source/refs.bib +++ b/docs/source/refs.bib @@ -82,22 +82,6 @@ @article{BerberanSantos:2009bk file = {/Users/dorme/Zotero/storage/EN33QA2H/J Math Chem 2009 Berberan-Santos.pdf} } -@article{berger:1993a, - title = {Insolation and {{Earth}}'s Orbital Periods}, - author = {Berger, Andr{\'e} and Loutre, Marie-France and Tricot, Christian}, - year = {1993}, - journal = {Journal of Geophysical Research: Atmospheres}, - volume = {98}, - number = {D6}, - pages = {10341--10362}, - issn = {2156-2202}, - doi = {10.1029/93JD00222}, - urldate = {2024-08-02}, - abstract = {Solar irradiance received on a horizontal surface depends on the solar output, the semimajor axis of the elliptical orbit of the Earth around the sun (a), the distance from the Earth to the sun (r), and the zenith distance (z). The spectrum of the distance, r, for a given value of the true longitude, {$\lambda$}, displays mainly the precessional periods and, with much less power, half precession periods, eccentricity periods, and some combination tones. The zenith distance or its equivalent, the elevation angle (E), is only a function of obliquity ({$\epsilon$}) for a given latitude, {$\phi$}, true longitude, and hour angle, H. Therefore the insolation at a given constant value of z is only a function of precession and eccentricity. On the other hand, the value of the hour angle, H, corresponding to this fixed value of z varies with {$\varepsilon$}, except for the equinoxes, where H corresponding to a constant z also remains constant through time. Three kinds of insolation have been computed both analytically and numerically: the instantaneous insolation (irradiance) at noon, the daily irradiation, and the irradiations received during particular time intervals of the day defined by two constant values of the zenith distance (diurnal irradiations). Mean irradiances (irradiations divided by the length of the time interval over which they are calculated) are also computed for different time intervals, like the interval between sunrise and sunset, in particular. Examples of these insolations are given in this paper for the equinoxes and the solstices. At the equinoxes, for each latitude, all insolations are only a function of precession (this invalidates the results obtained by Cerveny [1991]). At the solstices, both precession and obliquity are present, although precession dominates for most of the latitudes. Because the lengths of the astronomical seasons are secularly variable (in terms of precession only), a particular calendar day does not always correspond to the same position relative to the sun through geological time. Similarly, a given longitude of the Sun on its orbit does not correspond to the same calendar day. For example, 103 kyr ago, assuming arbitrarily that the spring equinox is always on March 21, autumn began on September 13, and 114 kyr ago, it began on September 27, the length of the summer season being 85 and 98 calendar days, respectively, at these remote times in the past.}, - langid = {english}, - file = {/Users/dorme/Zotero/storage/ALTXDVSM/Berger et al. - 1993 - Insolation and Earth's orbital periods.pdf;/Users/dorme/Zotero/storage/HWQ4XSZN/93JD00222.html} -} - @article{berger:1978a, title = {Long-{{Term Variations}} of {{Daily Insolation}} and {{Quaternary Climatic Changes}}}, author = {Berger, Andr{\'e}L}, @@ -117,25 +101,20 @@ @article{berger:1978a file = {/Users/dorme/Zotero/storage/DPM5WN32/Berger - 1978 - Long-Term Variations of Daily Insolation and Quate.pdf} } -@article{Bernacchi:2003dc, - title = {In Vivo Temperature Response Functions of Parameters Required to Model {{RuBP-limited}} Photosynthesis}, - author = {Bernacchi, C J and Pimentel, C and Long, S P}, - year = {2003}, - month = sep, - journal = {Plant, Cell \& Environment}, - volume = {26}, - number = {9}, - pages = {1419--1430}, - publisher = {John Wiley \& Sons, Ltd}, - doi = {10.1046/j.0016-8025.2003.01050.x}, - abstract = {The leaf model of C3 photosynthesis of Farquhar, von Caemmerer \& Berry (Planta 149, 78--90, 1980) provides the basis for scaling carbon exchange from leaf to canopy and Earth-System models, and is wid...}, - date-added = {2020-11-30T14:15:56GMT}, - date-modified = {2020-11-30T14:42:52GMT}, +@article{berger:1993a, + title = {Insolation and {{Earth}}'s Orbital Periods}, + author = {Berger, Andr{\'e} and Loutre, Marie-France and Tricot, Christian}, + year = {1993}, + journal = {Journal of Geophysical Research: Atmospheres}, + volume = {98}, + number = {D6}, + pages = {10341--10362}, + issn = {2156-2202}, + doi = {10.1029/93JD00222}, + urldate = {2024-08-02}, + abstract = {Solar irradiance received on a horizontal surface depends on the solar output, the semimajor axis of the elliptical orbit of the Earth around the sun (a), the distance from the Earth to the sun (r), and the zenith distance (z). The spectrum of the distance, r, for a given value of the true longitude, {$\lambda$}, displays mainly the precessional periods and, with much less power, half precession periods, eccentricity periods, and some combination tones. The zenith distance or its equivalent, the elevation angle (E), is only a function of obliquity ({$\epsilon$}) for a given latitude, {$\phi$}, true longitude, and hour angle, H. Therefore the insolation at a given constant value of z is only a function of precession and eccentricity. On the other hand, the value of the hour angle, H, corresponding to this fixed value of z varies with {$\varepsilon$}, except for the equinoxes, where H corresponding to a constant z also remains constant through time. Three kinds of insolation have been computed both analytically and numerically: the instantaneous insolation (irradiance) at noon, the daily irradiation, and the irradiations received during particular time intervals of the day defined by two constant values of the zenith distance (diurnal irradiations). Mean irradiances (irradiations divided by the length of the time interval over which they are calculated) are also computed for different time intervals, like the interval between sunrise and sunset, in particular. Examples of these insolations are given in this paper for the equinoxes and the solstices. At the equinoxes, for each latitude, all insolations are only a function of precession (this invalidates the results obtained by Cerveny [1991]). At the solstices, both precession and obliquity are present, although precession dominates for most of the latitudes. Because the lengths of the astronomical seasons are secularly variable (in terms of precession only), a particular calendar day does not always correspond to the same position relative to the sun through geological time. Similarly, a given longitude of the Sun on its orbit does not correspond to the same calendar day. For example, 103 kyr ago, assuming arbitrarily that the spring equinox is always on March 21, autumn began on September 13, and 114 kyr ago, it began on September 27, the length of the summer season being 85 and 98 calendar days, respectively, at these remote times in the past.}, langid = {english}, - local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2003/Bernacchi/Plant\%20Cell\%20\&\%20Environment\%202003\%20Bernacchi.pdf}, - rating = {0}, - uri = {papers3://publication/doi/10.1046/j.0016-8025.2003.01050.x}, - file = {/Users/dorme/Zotero/storage/7J2I98DM/Plant Cell & Environment 2003 Bernacchi.pdf} + file = {/Users/dorme/Zotero/storage/ALTXDVSM/Berger et al. - 1993 - Insolation and Earth's orbital periods.pdf;/Users/dorme/Zotero/storage/HWQ4XSZN/93JD00222.html} } @article{Bernacchi:2001kg, @@ -157,6 +136,27 @@ @article{Bernacchi:2001kg file = {/Users/dorme/Zotero/storage/FI9562Z3/Plant Cell & Environment 2001 Bernacchi.pdf} } +@article{Bernacchi:2003dc, + title = {In Vivo Temperature Response Functions of Parameters Required to Model {{RuBP-limited}} Photosynthesis}, + author = {Bernacchi, C J and Pimentel, C and Long, S P}, + year = {2003}, + month = sep, + journal = {Plant, Cell \& Environment}, + volume = {26}, + number = {9}, + pages = {1419--1430}, + publisher = {John Wiley \& Sons, Ltd}, + doi = {10.1046/j.0016-8025.2003.01050.x}, + abstract = {The leaf model of C3 photosynthesis of Farquhar, von Caemmerer \& Berry (Planta 149, 78--90, 1980) provides the basis for scaling carbon exchange from leaf to canopy and Earth-System models, and is wid...}, + date-added = {2020-11-30T14:15:56GMT}, + date-modified = {2020-11-30T14:42:52GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2003/Bernacchi/Plant\%20Cell\%20\&\%20Environment\%202003\%20Bernacchi.pdf}, + rating = {0}, + uri = {papers3://publication/doi/10.1046/j.0016-8025.2003.01050.x}, + file = {/Users/dorme/Zotero/storage/7J2I98DM/Plant Cell & Environment 2003 Bernacchi.pdf} +} + @article{boyd:2015a, title = {Temperature Response of {{C4}} Photosynthesis: {{Biochemical}} Analysis of {{Rubisco}}, {{Phosphoenolpyruvate Carboxylase}} and {{Carbonic Anhydrase}} in {{Setaria}} Viridis.}, shorttitle = {Temperature Response of {{C4}} Photosynthesis}, @@ -247,6 +247,16 @@ @article{DeKauwe:2015im file = {/Users/dorme/Zotero/storage/8WDYDVKQ/Geoscientific Model Development 2015 De Kauwe.pdf;/Users/dorme/Zotero/storage/WXI7ASHC/Geoscientific Model Development 2015 De Kauwe.pdf} } +@article{depury:1997a, + title = {Simple Scaling of Photosynthesis from Leaves to Canopies without the Errors of Big-Leaf Models}, + author = {{de Pury}, G. D. D. and Farquhar, G D}, + year = {1997}, + journal = {Plant Cell and Environment}, + number = {20}, + pages = {537--557}, + abstract = {In big-leaf models of canopy photosynthesis, the Rubisco activity per unit ground area is taken as the sum of activities per unit leaf area within the canopy, and electron transport capacity is similarly summed. Such models overestimate rates of photosynthesis and require empirical curvature factors in the response to irradiance. We show that, with any distribution of leaf nitrogen within the canopy (including optimal), the required curvature factors are not constant but vary with canopy leaf area index and leaf nitrogen content. We further show that the underlying reason is the difference between the time-averaged and instantaneous distributions of absorbed irradiance, caused by penetration of sunflecks and the range of leaf angles in canopies. These errors are avoided in models that treat the canopy in terms of a number of layers -- the multi-layer models. We present an alternative to the multi-layer model: by separately integrating the sunlit and shaded leaf fractions of the canopy, a single layered sun/shade model is obtained, which is as accurate and simpler. The model is a scaled version of a leaf model as distinct from an integrative approach.} +} + @article{Diaz:2016by, title = {The Global Spectrum of Plant Form and Function}, author = {D{\'i}az, Sandra and Kattge, Jens and Cornelissen, Johannes H C and Wright, Ian J. and Lavorel, Sandra and Dray, St{\'e}phane and Reu, Bj{\"o}rn and Kleyer, Michael and Wirth, Christian and Prentice, I. Colin and Garnier, Eric and B{\"o}nisch, Gerhard and Westoby, Mark and Poorter, Hendrik and Reich, Peter B and Moles, Angela T and Dickie, John and Gillison, Andrew N and Zanne, Amy E and Chave, J{\'e}r{\^o}me and Wright, S Joseph and Sheremet'ev, Serge N and Jactel, Herv{\'e} and Baraloto, Christopher and Cerabolini, Bruno and Pierce, Simon and Shipley, Bill and Kirkup, Donald and Casanoves, Fernando and Joswig, Julia S and G{\"u}nther, Angela and Falczuk, Valeria and R{\"u}ger, Nadja and Mahecha, Miguel D and Gorn{\'e}, Lucas D}, @@ -267,6 +277,19 @@ @article{Diaz:2016by file = {/Users/dorme/Zotero/storage/RGG46LIG/Nature 2016 Díaz.pdf} } +@book{duffie:2013a, + title = {Solar {{Engineering}} of {{Thermal Processes}}}, + author = {Duffie, John A. and Beckman, William A.}, + year = {2013}, + month = apr, + publisher = {John Wiley \& Sons}, + abstract = {The updated fourth edition of the "bible" of solar energy theory and applications Over several editions, Solar Engineering of Thermal Processes has become a classic solar engineering text and reference. This revised Fourth Edition offers current coverage of solar energy theory, systems design, and applications in different market sectors along with an emphasis on solar system design and analysis using simulations to help readers translate theory into practice. An important resource for students of solar engineering, solar energy, and alternative energy as well as professionals working in the power and energy industry or related fields, Solar Engineering of Thermal Processes, Fourth Edition features: Increased coverage of leading-edge topics such as photovoltaics and the design of solar cells and heaters A brand-new chapter on applying CombiSys (a readymade TRNSYS simulation program available for free download) to simulate a solar heated house with solar- heated domestic hot water Additional simulation problems available through a companion website An extensive array of homework problems and exercises}, + googlebooks = {5uDdUfMgXYQC}, + isbn = {978-1-118-41541-2}, + langid = {english}, + keywords = {Technology & Engineering / Electronics / General,Technology & Engineering / Mechanical,Technology & Engineering / Power Resources / General} +} + @article{Farquhar:1980ft, title = {A Biochemical Model of Photosynthetic {{CO2}} Assimilation in Leaves of {{C3}} Species.}, author = {Farquhar, G D and {von Caemmerer}, S and Berry, J A}, @@ -437,6 +460,26 @@ @article{Huber:2009fy file = {/Users/dorme/Zotero/storage/HREIVFC4/Journal of Physical and Chemical Reference Data 2009 Huber.pdf} } +@book{iqbal:1983a, + title = {An Introduction to Solar Radiation}, + author = {Iqbal, Mohammed}, + year = {1983}, + langid = {english} +} + +@techreport{joshi:2022a, + title = {Plant-{{FATE}}: {{Predicting}} the Adaptive Responses of Biodiverse Plant Communities Using Functional-Trait Evolution}, + author = {Joshi, Jaideep and Prentice, Iain Colin and Br{\"a}nnstr{\"o}m, {\AA}ke and Singh, Shipra and Hofhansl, Florian and Dieckmann, Ulf}, + year = {2022}, + month = mar, + number = {EGU22-9994}, + institution = {Copernicus Meetings}, + doi = {10.5194/egusphere-egu22-9994}, + urldate = {2024-09-05}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/47RVAZGK/EGU22-9994.html} +} + @article{Kattge:2007db, title = {Temperature Acclimation in a Biochemical Model of Photosynthesis: A Reanalysis of Data from 36 Species}, author = {Kattge, Jens and Knorr, Wolfgang}, @@ -489,14 +532,6 @@ @phdthesis{Lancelot:2020tm file = {/Users/dorme/Zotero/storage/86NBGKCA/2020 Lancelot.pdf} } -@article{lavergne:2022a, - title = {A Semi-Empirical Model for Primary Production, Isotopic Discrimination and Competition of {{C3}} and {{C4}} Plants}, - author = {Lavergne, Ali{\'e}nor and Harrison, Sandy P. and Atsawawaranunt, Kamolphat and Dong, Ning and Prentice, Iain Colin}, - year = {2022}, - journal = {Global Ecology and Biogeography (submitted)}, - file = {/Users/dorme/Zotero/storage/I797PRT2/Lavergneetal_GEB.docx} -} - @article{lavergne:2020a, title = {Impacts of Soil Water Stress on the Acclimated Stomatal Limitation of Photosynthesis: {{Insights}} from Stable Carbon Isotope Data}, shorttitle = {Impacts of Soil Water Stress on the Acclimated Stomatal Limitation of Photosynthesis}, @@ -515,6 +550,14 @@ @article{lavergne:2020a file = {/Users/dorme/Zotero/storage/ECFRUWX5/Lavergne et al. - 2020 - Impacts of soil water stress on the acclimated sto.pdf} } +@article{lavergne:2022a, + title = {A Semi-Empirical Model for Primary Production, Isotopic Discrimination and Competition of {{C3}} and {{C4}} Plants}, + author = {Lavergne, Ali{\'e}nor and Harrison, Sandy P. and Atsawawaranunt, Kamolphat and Dong, Ning and Prentice, Iain Colin}, + year = {2022}, + journal = {Global Ecology and Biogeography (submitted)}, + file = {/Users/dorme/Zotero/storage/I797PRT2/Lavergneetal_GEB.docx} +} + @article{Li:2014bc, title = {Simulation of Tree-Ring Widths with a Model for Primary Production, Carbon Allocation, and Growth}, author = {Li, G and Harrison, S P and Prentice, I. C. and Falster, D}, @@ -551,6 +594,22 @@ @article{Lin:2015wh file = {/Users/dorme/Zotero/storage/J7WANJNI/2015 Lin-2.pdf} } +@article{linacre:1968a, + title = {Estimating the Net-Radiation Flux}, + author = {Linacre, E. T.}, + year = {1968}, + month = jan, + journal = {Agricultural Meteorology}, + volume = {5}, + number = {1}, + pages = {49--63}, + issn = {0002-1571}, + doi = {10.1016/0002-1571(68)90022-8}, + urldate = {2024-08-02}, + abstract = {A major influence controlling the water loss from irrigated crops is the net-radiation intensity Qn, but measurements of this are not normally available, and so attempts are often made to deduce it from other climatic data, such as the solar-radiation. Here it is shown that the relationship between net and solar-radiation intensities depends on the degree of cloudiness and the ambient temperature. By making appropriate assumptions, a series of expressions for Qn is derived, with decreasing accuracy but increasing simplicity of estimation. It appears that clouds lower the net-radiation intensity when it exceeds a critical value in the region of 0.02 cal./cm2 min, but increase it when the intensity is lower.}, + file = {/Users/dorme/Zotero/storage/UY4NRV4W/0002157168900228.html} +} + @article{long:1993a, title = {Quantum Yields for Uptake of Carbon Dioxide in {{C3}} Vascular Plants of Contrasting Habitats and Taxonomic Groupings}, author = {Long, S. P. and Postl, W. F. and {Bolh{\'a}r-Nordenkampf}, H. R.}, @@ -676,6 +735,32 @@ @article{Prentice:2014bc file = {/Users/dorme/Zotero/storage/MDRBDVTF/Ecol Lett 2014 Prentice.pdf} } +@article{purves:2008a, + title = {Predicting and Understanding Forest Dynamics Using a Simple Tractable Model}, + author = {Purves, Drew W. and Lichstein, Jeremy W. and Strigul, Nikolay and Pacala, Stephen W.}, + year = {2008}, + month = nov, + journal = {Proceedings of the National Academy of Sciences}, + volume = {105}, + number = {44}, + pages = {17018--17022}, + issn = {0027-8424, 1091-6490}, + doi = {10.1073/pnas.0807754105}, + urldate = {2022-06-20}, + abstract = {The perfect-plasticity approximation (PPA) is an analytically tractable model of forest dynamics, defined in terms of parameters for individual trees, including allometry, growth, and mortality. We estimated these parameters for the eight most common species on each of four soil types in the US Lake states (Michigan, Wisconsin, and Minnesota) by using short-term ({$\leq$}15-year) inventory data from individual trees. We implemented 100-year PPA simulations given these parameters and compared these predictions to chronosequences of stand development. Predictions for the timing and magnitude of basal area dynamics and ecological succession on each soil were accurate, and predictions for the diameter distribution of 100-year-old stands were correct in form and slope. For a given species, the PPA provides analytical metrics for early-successional performance ( H 20 , height of a 20-year-old open-grown tree) and late-successional performance ( {\^Z} *, equilibrium canopy height in monoculture). These metrics predicted which species were early or late successional on each soil type. Decomposing {\^Z} * showed that ( i ) succession is driven both by superior understory performance and superior canopy performance of late-successional species, and ( ii ) performance differences primarily reflect differences in mortality rather than growth. The predicted late-successional dominants matched chronosequences on xeromesic ( Quercus rubra ) and mesic (codominance by Acer rubrum and Acer saccharum ) soil. On hydromesic and hydric soils, the literature reports that the current dominant species in old stands ( Thuja occidentalis ) is now failing to regenerate. Consistent with this, the PPA predicted that, on these soils, stands are now succeeding to dominance by other late-successional species (e.g., Fraxinus nigra , A. rubrum ).}, + langid = {english}, + file = {/Users/dorme/Zotero/storage/KI43FP4H/Purves et al. - 2008 - Predicting and understanding forest dynamics using.pdf} +} + +@article{sandoval:in_prep, + title = {Aridity and Growth Temperature Effects on Phio Manuscript}, + author = {Sandoval, David}, + year = {in\_prep}, + journal = {Placeholder}, + volume = {?}, + pages = {??-??} +} + @article{Smith:2019dv, title = {Global Photosynthetic Capacity Is Optimized to the Environment}, author = {Smith, Nicholas G and Keenan, Trevor F and Colin Prentice, I and Wang, Han and Wright, Ian J. and Niinemets, {\"U}lo and Crous, Kristine Y and Domingues, Tomas F and Guerrieri, Rossella and Yoko Ishida, F and Kattge, Jens and Kruger, Eric L and Maire, Vincent and Rogers, Alistair and Serbin, Shawn P and Tarvainen, Lasse and Togashi, Henrique F and Townsend, Philip A and Wang, Meng and Weerasinghe, Lasantha K and Zhou, Shuang Xi}, @@ -696,25 +781,6 @@ @article{Smith:2019dv file = {/Users/dorme/Zotero/storage/EIWDBL6T/Ecol Lett 2019 Smith.pdf} } -@article{Stocker:2020dh, - title = {P-Model v1.0: An Optimality-Based Light Use Efficiency Model for Simulating Ecosystem Gross Primary Production}, - author = {Stocker, Benjamin D and Wang, Han and Smith, Nicholas G and Harrison, Sandy P and Keenan, Trevor F and Sandoval, David and Davis, Tyler and Prentice, I. Colin}, - year = {2020}, - journal = {Geoscientific Model Development}, - volume = {13}, - number = {3}, - pages = {1545--1581}, - doi = {10.5194/gmd-13-1545-2020}, - date-added = {2020-11-30T12:24:06GMT}, - date-modified = {2021-01-28T11:55:51GMT}, - langid = {english}, - local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Stocker/Geoscientific\%20Model\%20Development\%202020\%20Stocker.pdf}, - rating = {0}, - read = {Yes}, - uri = {papers3://publication/doi/10.5194/gmd-13-1545-2020}, - file = {/Users/dorme/Zotero/storage/J4YM5X2R/Geoscientific Model Development 2020 Stocker.pdf} -} - @article{Stocker:2018be, title = {Quantifying Soil Moisture Impacts on Light Use Efficiency across Biomes}, author = {Stocker, Benjamin D and Zscheischler, Jakob and Keenan, Trevor F and Prentice, I. Colin and Penuelas, Josep and Seneviratne, Sonia I}, @@ -735,6 +801,25 @@ @article{Stocker:2018be file = {/Users/dorme/Zotero/storage/E6PPD38Z/New Phytol. 2018 Stocker.pdf} } +@article{Stocker:2020dh, + title = {P-Model v1.0: An Optimality-Based Light Use Efficiency Model for Simulating Ecosystem Gross Primary Production}, + author = {Stocker, Benjamin D and Wang, Han and Smith, Nicholas G and Harrison, Sandy P and Keenan, Trevor F and Sandoval, David and Davis, Tyler and Prentice, I. Colin}, + year = {2020}, + journal = {Geoscientific Model Development}, + volume = {13}, + number = {3}, + pages = {1545--1581}, + doi = {10.5194/gmd-13-1545-2020}, + date-added = {2020-11-30T12:24:06GMT}, + date-modified = {2021-01-28T11:55:51GMT}, + langid = {english}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2020/Stocker/Geoscientific\%20Model\%20Development\%202020\%20Stocker.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.5194/gmd-13-1545-2020}, + file = {/Users/dorme/Zotero/storage/J4YM5X2R/Geoscientific Model Development 2020 Stocker.pdf} +} + @article{Togashi:2018es, title = {Functional Trait Variation Related to Gap Dynamics in Tropical Moist forests{{{\textsubscript{A}}}} Vegetation Modelling Perspective}, author = {Togashi, Henrique F{\"u}rstenau and Atkin, Owen K and Bloomfield, Keith J and Bradford, Matt and Cao, Kunfang and Dong, Ning and Evans, Bradley J and Fan, Zexin and Harrison, Sandy P and Hua, Zhu and Liddell, Michael J and Lloyd, Jon and Ni, Jian and Wang, Han and Weerasinghe, Lasantha K and Prentice, Iain Colin}, @@ -809,6 +894,25 @@ @article{Walker:2014ce file = {/Users/dorme/Zotero/storage/N8LKZ4EP/Ecology and Evolution 2014 Walker.pdf} } +@article{Wang:2017go, + title = {Towards a Universal Model for Carbon Dioxide Uptake by Plants}, + author = {Wang, Han and Prentice, I. Colin and Keenan, Trevor F and Davis, Tyler W and Wright, Ian J. and Cornwell, William K and Evans, Bradley J and Peng, Changhui}, + year = {2017}, + month = sep, + journal = {Nature Plants}, + pages = {1--8}, + publisher = {Springer US}, + doi = {10.1038/s41477-017-0006-8}, + abstract = {Nature Plants, doi:10.1038/s41477-017-0006-8}, + date-added = {2020-11-30T12:27:00GMT}, + date-modified = {2021-01-28T09:14:19GMT}, + local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2017/Wang/Nature\%20Plants\%202017\%20Wang.pdf}, + rating = {0}, + read = {Yes}, + uri = {papers3://publication/doi/10.1038/s41477-017-0006-8}, + file = {/Users/dorme/Zotero/storage/D4RYI3NP/Nature Plants 2017 Wang.pdf} +} + @article{Wang:2020ik, title = {Acclimation of Leaf Respiration Consistent with Optimal Photosynthetic Capacity}, author = {Wang, Han and Atkin, Owen K and Keenan, Trevor F and Smith, Nicholas G and Wright, Ian J. and Bloomfield, Keith J and Kattge, Jens and Reich, Peter B and Prentice, I. Colin}, @@ -829,25 +933,6 @@ @article{Wang:2020ik file = {/Users/dorme/Zotero/storage/2XYW4BF4/gcb15314-sup-0004-Supinfo.pdf;/Users/dorme/Zotero/storage/RAGU56IZ/Global Change Biol 2020 Wang.pdf} } -@article{Wang:2017go, - title = {Towards a Universal Model for Carbon Dioxide Uptake by Plants}, - author = {Wang, Han and Prentice, I. Colin and Keenan, Trevor F and Davis, Tyler W and Wright, Ian J. and Cornwell, William K and Evans, Bradley J and Peng, Changhui}, - year = {2017}, - month = sep, - journal = {Nature Plants}, - pages = {1--8}, - publisher = {Springer US}, - doi = {10.1038/s41477-017-0006-8}, - abstract = {Nature Plants, doi:10.1038/s41477-017-0006-8}, - date-added = {2020-11-30T12:27:00GMT}, - date-modified = {2021-01-28T09:14:19GMT}, - local-url = {file://localhost/Users/dorme/References/Library.papers3/Articles/2017/Wang/Nature\%20Plants\%202017\%20Wang.pdf}, - rating = {0}, - read = {Yes}, - uri = {papers3://publication/doi/10.1038/s41477-017-0006-8}, - file = {/Users/dorme/Zotero/storage/D4RYI3NP/Nature Plants 2017 Wang.pdf} -} - @book{woolf:1968a, title = {On the {{Computation}} of {{Solar Elevation Angles}} and the {{Determination}} of {{Sunrise}} and {{Sunset Times}}}, author = {Woolf, Harold M.}, @@ -856,53 +941,9 @@ @book{woolf:1968a langid = {english} } -@book{duffie:2013a, - title = {Solar {{Engineering}} of {{Thermal Processes}}}, - author = {Duffie, John A. and Beckman, William A.}, - year = {2013}, - month = apr, - publisher = {John Wiley \& Sons}, - abstract = {The updated fourth edition of the "bible" of solar energy theory and applications Over several editions, Solar Engineering of Thermal Processes has become a classic solar engineering text and reference. This revised Fourth Edition offers current coverage of solar energy theory, systems design, and applications in different market sectors along with an emphasis on solar system design and analysis using simulations to help readers translate theory into practice. An important resource for students of solar engineering, solar energy, and alternative energy as well as professionals working in the power and energy industry or related fields, Solar Engineering of Thermal Processes, Fourth Edition features: Increased coverage of leading-edge topics such as photovoltaics and the design of solar cells and heaters A brand-new chapter on applying CombiSys (a readymade TRNSYS simulation program available for free download) to simulate a solar heated house with solar- heated domestic hot water Additional simulation problems available through a companion website An extensive array of homework problems and exercises}, - googlebooks = {5uDdUfMgXYQC}, - isbn = {978-1-118-41541-2}, - langid = {english}, - keywords = {Technology & Engineering / Electronics / General,Technology & Engineering / Mechanical,Technology & Engineering / Power Resources / General} -} - -@article{linacre:1968a, - title = {Estimating the Net-Radiation Flux}, - author = {Linacre, E. T.}, - year = {1968}, - month = jan, - journal = {Agricultural Meteorology}, - volume = {5}, - number = {1}, - pages = {49--63}, - issn = {0002-1571}, - doi = {10.1016/0002-1571(68)90022-8}, - urldate = {2024-08-02}, - abstract = {A major influence controlling the water loss from irrigated crops is the net-radiation intensity Qn, but measurements of this are not normally available, and so attempts are often made to deduce it from other climatic data, such as the solar-radiation. Here it is shown that the relationship between net and solar-radiation intensities depends on the degree of cloudiness and the ambient temperature. By making appropriate assumptions, a series of expressions for Qn is derived, with decreasing accuracy but increasing simplicity of estimation. It appears that clouds lower the net-radiation intensity when it exceeds a critical value in the region of 0.02 cal./cm2 min, but increase it when the intensity is lower.}, - file = {/Users/dorme/Zotero/storage/UY4NRV4W/0002157168900228.html} -} - -@article{sandoval:in_prep, - title = {Aridity and Growth Temperature Effects on Phio Manuscript}, - author = {Sandoval, David}, - year = {in\_prep}, - journal = {Placeholder}, - volume = {?}, - pages = {??-??} -} - -@techreport{joshi:2022a, - title = {Plant-{{FATE}}: {{Predicting}} the Adaptive Responses of Biodiverse Plant Communities Using Functional-Trait Evolution}, - author = {Joshi, Jaideep and Prentice, Iain Colin and Br{\"a}nnstr{\"o}m, {\AA}ke and Singh, Shipra and Hofhansl, Florian and Dieckmann, Ulf}, - year = {2022}, - month = mar, - number = {EGU22-9994}, - institution = {Copernicus Meetings}, - doi = {10.5194/egusphere-egu22-9994}, - urldate = {2024-09-05}, - langid = {english}, - file = {/Users/dorme/Zotero/storage/47RVAZGK/EGU22-9994.html} +@misc{zotero-2443a, + title = {Crown.Md\#cro{\dots} - {{JupyterLab}}}, + urldate = {2024-09-30}, + howpublished = {http://localhost:8888/lab/tree/source/users/demography/crown.md\#crown-radius-values}, + file = {/Users/dorme/Zotero/storage/LHHVRPS9/crown.html} } From 3f48d921379abc710ea3230cd964cbe0d5aefdd8 Mon Sep 17 00:00:00 2001 From: MarionBWeinzierl Date: Wed, 2 Oct 2024 12:44:12 +0100 Subject: [PATCH 200/241] correct memory_effect to use correct dimensional array assignments --- pyrealm/pmodel/subdaily.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 4bbde39a..dffedb2c 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -113,7 +113,7 @@ def memory_effect( if initial_values is None: memory_values[0] = values[0] else: - memory_values[0] = initial_values + memory_values[0] = initial_values[0] # Handle the data if there are no missing data, if not nan_present: @@ -408,20 +408,23 @@ def __init__( # 5) Calculate the realised daily values from the instantaneous optimal values self.xi_real: NDArray = memory_effect( self.pmodel_acclim.optchi.xi, - init_xi_real, + initial_values=init_xi_real, alpha=alpha, allow_holdover=allow_holdover, ) r"""Realised daily slow responses in :math:`\xi`""" self.vcmax25_real: NDArray = memory_effect( self.vcmax25_opt, - init_vcmax_real, + initial_values=init_vcmax_real, alpha=alpha, allow_holdover=allow_holdover, ) r"""Realised daily slow responses in :math:`V_{cmax25}`""" self.jmax25_real: NDArray = memory_effect( - self.jmax25_opt, init_jmax_real, alpha=alpha, allow_holdover=allow_holdover + self.jmax25_opt, + initial_values=init_jmax_real, + alpha=alpha, + allow_holdover=allow_holdover, ) r"""Realised daily slow responses in :math:`J_{max25}`""" From e3e5769308333a0bb90448b92e1adc760f812c40 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 2 Oct 2024 14:21:11 +0100 Subject: [PATCH 201/241] Initial functionality from light extinction doc draft --- pyrealm/demography/canopy.py | 84 ++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 05c35631..d27dd824 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -6,9 +6,7 @@ from pyrealm.demography.community import Community from pyrealm.demography.crown import ( - calculate_relative_crown_radius_at_z, - calculate_stem_projected_crown_area_at_z, - calculate_stem_projected_leaf_area_at_z, + CrownProfile, solve_community_projected_canopy_area, ) @@ -57,12 +55,8 @@ def __init__( """Total number of cohorts in the canopy.""" self.layer_heights: NDArray[np.float32] """Column vector of the heights of canopy layers.""" - self.stem_relative_radius: NDArray[np.float32] - """Relative radius values of stems at canopy layer heights.""" - self.stem_crown_area: NDArray[np.float32] - """Stem projected crown area at canopy layer heights.""" - self.stem_leaf_area: NDArray[np.float32] - """Stem projected leaf area at canopy layer heights.""" + self.crown_profile: CrownProfile + """The crown profiles of stems at layer heights.""" self._calculate_canopy(community=community) @@ -130,37 +124,53 @@ def _calculate_canopy(self, community: Community) -> None: self.layer_heights[layer] = starting_guess = solution.root - # Find relative canopy radius at the layer heights - # NOTE - here and in the calls below, validate=False is enforced because the - # Community class structures and code should guarantee valid inputs and so - # turning off the validation internally should simply speed up the code. - self.stem_relative_radius = calculate_relative_crown_radius_at_z( + # Calculate the crown profile at the layer heights + # TODO - reimpose validation + self.crown_profile = CrownProfile( + stem_traits=community.stem_traits, + stem_allometry=community.stem_allometry, z=self.layer_heights, - stem_height=community.stem_allometry.stem_height, - m=community.stem_traits.m, - n=community.stem_traits.n, - validate=False, ) - # Calculate projected crown area of a cohort stem at canopy closure heights. - self.stem_crown_area = calculate_stem_projected_crown_area_at_z( - z=self.layer_heights, - q_z=self.stem_relative_radius, - crown_area=community.stem_allometry.crown_area, - stem_height=community.stem_allometry.stem_height, - q_m=community.stem_traits.q_m, - z_max=community.stem_allometry.crown_z_max, - validate=False, + # self.canopy_projected_crown_area + # self.canopy_projected_leaf_area + + # Partition the projected leaf area into the leaf area in each layer for each + # stem and then scale up to the cohort leaf area in each layer. + self.layer_stem_leaf_area = np.diff( + self.crown_profile.projected_leaf_area, axis=0, prepend=0 + ) + self.layer_cohort_leaf_area = ( + self.layer_stem_leaf_area * community.cohort_data["n_individuals"] ) - # Find the projected leaf area of a cohort stem at canopy closure heights. - self.stem_leaf_area = calculate_stem_projected_leaf_area_at_z( - z=self.layer_heights, - q_z=self.stem_relative_radius, - crown_area=community.stem_allometry.crown_area, - stem_height=community.stem_allometry.stem_height, - f_g=community.stem_traits.f_g, - q_m=community.stem_traits.q_m, - z_max=community.stem_allometry.crown_z_max, - validate=False, + # Calculate the leaf area index per layer per cohort, using the stem + # specific leaf area index values. LAI is a value per m2, so scale back down by + # the community area. + self.layer_cohort_lai = ( + self.layer_cohort_leaf_area * community.stem_traits.lai + ) / community.cell_area + + # Calculate the Beer-Lambert light extinction per layer and cohort + self.layer_cohort_f_abs = 1 - np.exp( + -community.stem_traits.par_ext * self.layer_cohort_lai ) + + # Calculate the canopy wide light extinction per layer + self.layer_canopy_f_abs = self.layer_cohort_f_abs.sum(axis=1) + + # Calculate cumulative light extinction across the canopy + self.canopy_extinction_profile = np.cumprod(self.layer_canopy_f_abs) + + # Calculate the fraction of radiation absorbed by each layer + # # TODO - include append=0 here to include ground or just backcalculate + self.fapar_profile = -np.diff( + np.cumprod(1 - self.layer_canopy_f_abs), + prepend=1, # append=0 + ) + + # Partition the light back among the individual stems: simply weighting by per + # cohort contribution to f_abs and divide through by the number of individuals + self.stem_fapar = ( + self.layer_cohort_f_abs * self.fapar_profile[:, None] + ) / self.layer_cohort_f_abs.sum(axis=1)[:, None] From d260ebec6e69ba170645fbb83231fbaf60d2d669 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 2 Oct 2024 14:45:08 +0100 Subject: [PATCH 202/241] Moving canopy solver into canopy from crown, adding new canopy attributes and docstrings to __init__ --- pyrealm/demography/canopy.py | 91 +++++++++++++++++++++++++++++++++++- pyrealm/demography/crown.py | 69 --------------------------- 2 files changed, 89 insertions(+), 71 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index d27dd824..7f484f73 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -7,10 +7,81 @@ from pyrealm.demography.community import Community from pyrealm.demography.crown import ( CrownProfile, - solve_community_projected_canopy_area, + _validate_z_qz_args, + calculate_relative_crown_radius_at_z, + calculate_stem_projected_crown_area_at_z, ) +def solve_canopy_area_filling_height( + z: float, + stem_height: NDArray[np.float32], + crown_area: NDArray[np.float32], + m: NDArray[np.float32], + n: NDArray[np.float32], + q_m: NDArray[np.float32], + z_max: NDArray[np.float32], + n_individuals: NDArray[np.float32], + target_area: float = 0, + validate: bool = True, +) -> NDArray[np.float32]: + """Solver function for finding the height where a canopy occupies a given area. + + This function takes the number of individuals in each cohort along with the stem + height and crown area and a given vertical height (:math:`z`). It then uses the + crown shape parameters associated with each cohort to calculate the community wide + projected crown area above that height (:math:`A_p(z)`). This is simply the sum of + the products of the individual stem crown projected area at :math:`z` and the number + of individuals in each cohort. + + The return value is the difference between the calculated :math:`A_p(z)` and a + user-specified target area, This allows the function to be used with a root solver + to find :math:`z` values that result in a given :math:`A_p(z)`. The default target + area is zero, so the default return value will be the actual total :math:`A_p(z)` + for the community. + + A typical use case for the target area would be to specify the area at which a given + canopy layer closes under the perfect plasticity approximation in order to find the + closure height. + + Args: + z: Vertical height on the z axis. + n_individuals: Number of individuals in each cohort + crown_area: Crown area of each cohort + stem_height: Stem height of each cohort + m: Crown shape parameter ``m``` for each cohort + n: Crown shape parameter ``n``` for each cohort + q_m: Crown shape parameter ``q_m``` for each cohort + z_max: Crown shape parameter ``z_m``` for each cohort + target_area: A target projected crown area. + validate: Boolean flag to suppress argument validation. + """ + # Convert z to array for validation and typing + z_arr = np.array(z) + + if validate: + _validate_z_qz_args( + z=z_arr, + stem_properties=[n_individuals, crown_area, stem_height, m, n, q_m, z_max], + ) + + q_z = calculate_relative_crown_radius_at_z( + z=z_arr, stem_height=stem_height, m=m, n=n, validate=False + ) + # Calculate A(p) for the stems in each cohort + A_p = calculate_stem_projected_crown_area_at_z( + z=z_arr, + q_z=q_z, + stem_height=stem_height, + crown_area=crown_area, + q_m=q_m, + z_max=z_max, + validate=False, + ) + + return (A_p * n_individuals).sum() - target_area + + class Canopy: """Model of the canopy for a plant community. @@ -57,6 +128,22 @@ def __init__( """Column vector of the heights of canopy layers.""" self.crown_profile: CrownProfile """The crown profiles of stems at layer heights.""" + self.layer_stem_leaf_area: NDArray[np.float32] + """The leaf area of an individual stem per cohorts by layer.""" + self.layer_cohort_leaf_area: NDArray[np.float32] + """The total leaf areas within cohorts by layer.""" + self.layer_cohort_lai: NDArray[np.float32] + """The leaf area index for each cohort by layer.""" + self.layer_cohort_f_abs: NDArray[np.float32] + """The fraction of light absorbed by each cohort by layer.""" + self.layer_canopy_f_abs: NDArray[np.float32] + """The canopy-wide fraction of light absorbed by layer.""" + self.canopy_extinction_profile: NDArray[np.float32] + """The canopy-wide light extinction profile by layer.""" + self.fapar_profile: NDArray[np.float32] + """The canopy-wide fAPAR profile by layer.""" + self.stem_fapar: NDArray[np.float32] + """The fAPAR for individual stems by layer.""" self._calculate_canopy(community=community) @@ -101,7 +188,7 @@ def _calculate_canopy(self, community: Community) -> None: # TODO - the solution here is typically closer to the upper bracket, might # be a better algorithm to find the root (#293). solution = root_scalar( - solve_community_projected_canopy_area, + solve_canopy_area_filling_height, args=( community.stem_allometry.stem_height, community.stem_allometry.crown_area, diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index ed93fa32..bb3a01d8 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -217,75 +217,6 @@ def calculate_stem_projected_crown_area_at_z( return A_p -def solve_community_projected_canopy_area( - z: float, - stem_height: NDArray[np.float32], - crown_area: NDArray[np.float32], - m: NDArray[np.float32], - n: NDArray[np.float32], - q_m: NDArray[np.float32], - z_max: NDArray[np.float32], - n_individuals: NDArray[np.float32], - target_area: float = 0, - validate: bool = True, -) -> NDArray[np.float32]: - """Solver function for community wide projected canopy area. - - This function takes the number of individuals in each cohort along with the stem - height and crown area and a given vertical height (:math:`z`). It then uses the - crown shape parameters associated with each cohort to calculate the community wide - projected crown area above that height (:math:`A_p(z)`). This is simply the sum of - the products of the individual stem crown projected area at :math:`z` and the number - of individuals in each cohort. - - The return value is the difference between the calculated :math:`A_p(z)` and a - user-specified target area, This allows the function to be used with a root solver - to find :math:`z` values that result in a given :math:`A_p(z)`. The default target - area is zero, so the default return value will be the actual total :math:`A_p(z)` - for the community. - - A typical use case for the target area would be to specify the area at which a given - canopy layer closes under the perfect plasticity approximation in order to find the - closure height. - - Args: - z: Vertical height on the z axis. - n_individuals: Number of individuals in each cohort - crown_area: Crown area of each cohort - stem_height: Stem height of each cohort - m: Crown shape parameter ``m``` for each cohort - n: Crown shape parameter ``n``` for each cohort - q_m: Crown shape parameter ``q_m``` for each cohort - z_max: Crown shape parameter ``z_m``` for each cohort - target_area: A target projected crown area. - validate: Boolean flag to suppress argument validation. - """ - # Convert z to array for validation and typing - z_arr = np.array(z) - - if validate: - _validate_z_qz_args( - z=z_arr, - stem_properties=[n_individuals, crown_area, stem_height, m, n, q_m, z_max], - ) - - q_z = calculate_relative_crown_radius_at_z( - z=z_arr, stem_height=stem_height, m=m, n=n, validate=False - ) - # Calculate A(p) for the stems in each cohort - A_p = calculate_stem_projected_crown_area_at_z( - z=z_arr, - q_z=q_z, - stem_height=stem_height, - crown_area=crown_area, - q_m=q_m, - z_max=z_max, - validate=False, - ) - - return (A_p * n_individuals).sum() - target_area - - def calculate_stem_projected_leaf_area_at_z( z: NDArray[np.float32], q_z: NDArray[np.float32], From d0f2d72c49d4c483ea2653d9a53d6be649fd7de4 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 2 Oct 2024 15:35:28 +0100 Subject: [PATCH 203/241] Isolated the PPA model in its own function, made the canopy solver also accept an array of heights --- pyrealm/demography/canopy.py | 162 +++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 64 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 7f484f73..c4b5518a 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -82,6 +82,75 @@ def solve_canopy_area_filling_height( return (A_p * n_individuals).sum() - target_area +def fit_perfect_plasticity_approximation( + community: Community, + canopy_gap_fraction: float, + max_stem_height: float, + solver_tolerance: float, +) -> NDArray[np.float32]: + """Find canopy layer heights under the PPA model. + + Finds the closure heights of the canopy layers under the perfect plasticity + approximation by solving Ac(z) - L_n = 0 across the community where L is the + total cumulative crown area in layer n and above, discounted by the canopy gap + fraction. + + Args: + community: A community instance providing plant cohort data + canopy_gap_fraction: The canopy gap fraction + max_stem_height: The maximum stem height in the canopy, used as an upper bound + on finding the closure height of the topmost layer. + solver_tolerance: The absolute tolerance used with the root solver to find the + layer heights. + """ + + # Calculate the number of layers to contain the total community crown area + total_community_crown_area = ( + community.stem_allometry.crown_area * community.cohort_data["n_individuals"] + ).sum() + crown_area_per_layer = community.cell_area * (1 - canopy_gap_fraction) + n_layers = int(np.ceil(total_community_crown_area / crown_area_per_layer)) + + # Initialise the layer heights array and then loop over the layers indices, + # except for the final layer, which will be the partial remaining vegetation below + # the last closed layer. + layer_heights = np.zeros(n_layers, dtype=np.float32) + upper_bound = max_stem_height + + for layer in np.arange(n_layers - 1): + # Set the target area for this layer + target_area = (layer + 1) * crown_area_per_layer + + # TODO - the solution is typically closer to the upper bound of the bracket, + # there might be a better algorithm to find the root (#293). + solution = root_scalar( + solve_canopy_area_filling_height, + args=( + community.stem_allometry.stem_height, + community.stem_allometry.crown_area, + community.stem_traits.m, + community.stem_traits.n, + community.stem_traits.q_m, + community.stem_allometry.crown_z_max, + community.cohort_data["n_individuals"], + target_area, + False, # validate + ), + bracket=(0, upper_bound), + xtol=solver_tolerance, + ) + + if not solution.converged: + raise RuntimeError( + "Estimation of canopy layer closure heights failed to converge." + ) + + # Store the solution and update the upper bound for the next layer down. + layer_heights[layer] = upper_bound = solution.root + + return layer_heights + + class Canopy: """Model of the canopy for a plant community. @@ -106,20 +175,22 @@ class Canopy: def __init__( self, community: Community, + fit_ppa: bool = True, + layer_heights: NDArray[np.float32] | None = None, canopy_gap_fraction: float = 0.05, - layer_tolerance: float = 0.001, + solver_tolerance: float = 0.001, ) -> None: + # Store required init vars self.canopy_gap_fraction: float = canopy_gap_fraction """Canopy gap fraction.""" - self.layer_tolerance: float = layer_tolerance - """Numerical tolerance for solving canopy layer closure.""" + self.solver_tolerance: float = solver_tolerance + """Numerical tolerance for fitting the PPA model of canopy layer closure.""" + + # Define class attributes self.total_community_crown_area: float """Total crown area across individuals in the community (metres 2).""" self.max_stem_height: float """Maximum height of any individual in the community (metres).""" - self.crown_area_per_layer: float - """Total crown area permitted in a single canopy layer, given the available - cell area of the community and its canopy gap fraction.""" self.n_layers: int """Total number of canopy layers.""" self.n_cohorts: int @@ -145,72 +216,38 @@ def __init__( self.stem_fapar: NDArray[np.float32] """The fAPAR for individual stems by layer.""" + # Check operating mode + if fit_ppa ^ (layer_heights is None): + raise ValueError("Either set fit_ppa=True or provide layer heights.") + + # Set simple attributes + self.max_stem_height = community.stem_allometry.stem_height.max() + self.n_cohorts = community.number_of_cohorts + + # Populate layer heights + if layer_heights is not None: + self.layer_heights = layer_heights + else: + self.layer_heights = fit_perfect_plasticity_approximation( + community=community, + canopy_gap_fraction=canopy_gap_fraction, + max_stem_height=self.max_stem_height, + solver_tolerance=solver_tolerance, + ) + self._calculate_canopy(community=community) def _calculate_canopy(self, community: Community) -> None: """Calculate the canopy structure. This private method runs the calculations needed to populate the instance - attributes. + attributes, given the layer heights provided by the user or calculated using the + PPA model. Args: community: The Community object passed to the instance. """ - # Calculate community wide properties: total crown area, maximum height, crown - # area required to fill a layer and total number of canopy layers - self.total_community_crown_area = ( - community.stem_allometry.crown_area * community.cohort_data["n_individuals"] - ).sum() - - self.max_stem_height = community.stem_allometry.stem_height.max() - - self.crown_area_per_layer = community.cell_area * (1 - self.canopy_gap_fraction) - - self.n_layers = int( - np.ceil(self.total_community_crown_area / self.crown_area_per_layer) - ) - self.n_cohorts = community.number_of_cohorts - - # Find the closure heights of the canopy layers under the perfect plasticity - # approximation by solving Ac(z) - L_n = 0 across the community where L is the - # total cumulative crown area in layer n and above, discounted by the canopy gap - # fraction. - - self.layer_heights = np.zeros((self.n_layers, 1), dtype=np.float32) - - # Loop over the layers except for the final layer, which will be the partial - # remaining vegetation below the last closed layer. - starting_guess = self.max_stem_height - for layer in np.arange(self.n_layers - 1): - target_area = (layer + 1) * self.crown_area_per_layer - - # TODO - the solution here is typically closer to the upper bracket, might - # be a better algorithm to find the root (#293). - solution = root_scalar( - solve_canopy_area_filling_height, - args=( - community.stem_allometry.stem_height, - community.stem_allometry.crown_area, - community.stem_traits.m, - community.stem_traits.n, - community.stem_traits.q_m, - community.stem_allometry.crown_z_max, - community.cohort_data["n_individuals"], - target_area, - False, # validate - ), - bracket=(0, starting_guess), - xtol=self.layer_tolerance, - ) - - if not solution.converged: - raise RuntimeError( - "Estimation of canopy layer closure heights failed to converge." - ) - - self.layer_heights[layer] = starting_guess = solution.root - # Calculate the crown profile at the layer heights # TODO - reimpose validation self.crown_profile = CrownProfile( @@ -219,9 +256,6 @@ def _calculate_canopy(self, community: Community) -> None: z=self.layer_heights, ) - # self.canopy_projected_crown_area - # self.canopy_projected_leaf_area - # Partition the projected leaf area into the leaf area in each layer for each # stem and then scale up to the cohort leaf area in each layer. self.layer_stem_leaf_area = np.diff( From e3f74e2293a44510a2519e78dac2bd0a54371498 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 3 Oct 2024 08:37:17 +0100 Subject: [PATCH 204/241] Apply suggestions from code review Co-authored-by: Marion <56403724+MarionBWeinzierl@users.noreply.github.com> --- docs/source/users/demography/canopy.md | 2 +- docs/source/users/demography/t_model.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index 3913bfe8..f9c0688c 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -27,7 +27,7 @@ space $A$. When the area $A$ is filled, a new lower canopy layer is formed until of the individual crown area has been distributed across within the canopy. The key variables in calculating the canopy model are the crown projected area $A_p$ -and leaf projected projected area $\tilde{A}_{cp}(z)$, which are calculated for a stem +and leaf projected area $\tilde{A}_{cp}(z)$, which are calculated for a stem of a given size using the [crown model](./crown.md). ```{code-cell} diff --git a/docs/source/users/demography/t_model.md b/docs/source/users/demography/t_model.md index 72be1d0d..23510daa 100644 --- a/docs/source/users/demography/t_model.md +++ b/docs/source/users/demography/t_model.md @@ -131,7 +131,7 @@ pd.DataFrame( ) ``` -Using a column array of potential GPP values can be used predict multiple estimates of +Using a column array of potential GPP values can be used to predict multiple estimates of allocation per stem. In the first example, the code takes the allometric predictions from above and calculates the GPP allocation for stems of varying size with the same potential GPP: From 53a6c76be60d18fd84a446c0a50b24912bf857eb Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 3 Oct 2024 11:04:59 +0100 Subject: [PATCH 205/241] docstring updates --- pyrealm/demography/canopy.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index c4b5518a..6bc9fe1b 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -148,17 +148,17 @@ def fit_perfect_plasticity_approximation( # Store the solution and update the upper bound for the next layer down. layer_heights[layer] = upper_bound = solution.root - return layer_heights + return layer_heights[:, None] class Canopy: - """Model of the canopy for a plant community. + """Calculate canopy characteristics for a plant community. This class generates a canopy structure for a community of trees using the - perfect-plasticity approximation model :cite:`purves:2008a`. In this approach, each - individual is assumed to arrange its canopy crown area plastically to take up space - in canopy layers and that new layers form below the canopy top as the available - space is occupied. + perfect-plasticity approximation (PPA) model :cite:`purves:2008a`. In this approach, + each individual is assumed to arrange its canopy crown area plastically to take up + space in canopy layers and that new layers form below the canopy top as the + available space is occupied. Real canopies contain canopy gaps, through process such as crown shyness. This is included in the model through the canopy gap fraction, which sets the proportion @@ -166,6 +166,10 @@ class Canopy: Args: community: A Community object that will be used to generate the canopy model. + layer_heights: A column array of vertical heights at which to calculate canopy + variables. + fit_ppa: Calculate layer heights as the canopy layer closure heights under the + PPA model. canopy_gap_fraction: The proportion of the available space unfilled by canopy (default: 0.05). layer_tolerance: The minimum precision used by the solver to find canopy layer @@ -175,8 +179,8 @@ class Canopy: def __init__( self, community: Community, - fit_ppa: bool = True, layer_heights: NDArray[np.float32] | None = None, + fit_ppa: bool = False, canopy_gap_fraction: float = 0.05, solver_tolerance: float = 0.001, ) -> None: From 9c1e31e30c38c101dbb73298d5ce9e5a78f2b70a Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 3 Oct 2024 11:09:29 +0100 Subject: [PATCH 206/241] Crown doc changes --- docs/source/users/demography/crown.md | 437 ++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) create mode 100644 docs/source/users/demography/crown.md diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md new file mode 100644 index 00000000..eaa76c4c --- /dev/null +++ b/docs/source/users/demography/crown.md @@ -0,0 +1,437 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# The tree crown model + +:::{admonition} Warning + +This area of `pyrealm` is in active development and this notebook currently contains +notes and initial demonstration code. + +::: + +```{code-cell} +from matplotlib import pyplot as plt +import numpy as np +import pandas as pd + +from pyrealm.demography.flora import ( + calculate_crown_q_m, + calculate_crown_z_max_proportion, + PlantFunctionalType, + Flora, +) + +from pyrealm.demography.t_model_functions import ( + calculate_dbh_from_height, + StemAllometry, +) + +from pyrealm.demography.crown import ( + CrownProfile, +) +``` + +The {mod}`pyrealm.demography` module uses three-dimensional model of crown shape to +define the vertical distribution of leaf area, following the implementation of crown +shape in the Plant-FATE model {cite}`joshi:2022a`. + +## Crown traits + +The crown model for a plant functional type (PFT) is driven by four traits within +the {class}`~pyrealm.demography.flora.PlantFunctionalType` class: + +* The `m` and `n` ($m, n$) traits set the vertical shape of the crown profile. +* The `ca_ratio` trait sets the area of the crown ($A_c$) relative to the stem size. +* The `f_g` ($f_g$) trait sets the crown gap fraction and sets the vertical + distribution of leaves within the crown. + +### Canopy shape + +For a stem of height $H$, the $m$ and $n$ traits are used to calculate the *relative* +crown radius $q(z)$ at a height $z$ of as: + +$$ +q(z)= m n \left(\dfrac{z}{H}\right) ^ {n -1} + \left( 1 - \left(\dfrac{z}{H}\right) ^ n \right)^{m-1} +$$ + +In order to align the arbitrary relative radius values with the predictions of the +T Model for the stem, we then need to find the height at which the relative radius +is at its maximum and a scaling factor that will convert the relative area at this +height to the expected crown area under the T Model. These can be calculated using +the following two additional traits, which are invariant for a PFT. + +* `z_max_prop` ($p_{zm}$) sets the proportion of the height of the stem at which + the maximum relative crown radius is found. +* `q_m` ($q_m$) is used to scale the size of the crown radius at $z_{max}$ to match + the expected crown area. + +$$ +\begin{align} +p_{zm} &= \left(\dfrac{n-1}{m n -1}\right)^ {\tfrac{1}{n}}\\[8pt] +q_m &= m n \left(\dfrac{n-1}{m n -1}\right)^ {1 - \tfrac{1}{n}} + \left(\dfrac{\left(m-1\right) n}{m n -1}\right)^ {m-1} +\end{align} +$$ + +For individual stems, with expected height $H$ and crown area $A_c$, we can then +calculate: + +* the height $z_m$ at which the maximum crown radius $r_m$ is found, +* a height-specific scaling factor $r_0$ such that $\pi q(z_m)^2 = A_c$, +* the actual crown radius $r(z)$ at a given height $z$. + +$$ +\begin{align} +z_m &= H p_{zm}\\[8pt] +r_0 &= \frac{1}{q_m}\sqrt{\frac{A_c}{\pi}}\\[8pt] +r(z) &= r_0 \; q(z) +\end{align} +$$ + +### Projected crown and leaf area + +From the crown radius profile, the model can then be used to calculate how crown area +and leaf area accumulates from the top of the crown towards the ground, giving +functions given height $z$ for: + +* the projected crown area $A_p(z)$, and +* the projected leaf area $\tilde{A}_{cp}(z)$. + +The projected crown area is calculated for a stem of known height and crown area is: + +$$ +A_p(z)= +\begin{cases} +A_c, & z \le z_m \\ +A_c \left(\dfrac{q(z)}{q_m}\right)^2, & H > z > z_m \\ +0, & z > H +\end{cases} +$$ + +That is, the projected crown area is zero above the top of the stem, increases to the +expected crown area at $z_max$ and is then constant to ground level. + +The projected leaf area $\tilde{A}_{cp}(z)$ models how the vertical distribution of +leaf area within the crown is modified by the crown gap fraction $f_g$. This trait +models how leaf gaps higher in the crown are filled by leaf area at lower heights: +it does not change the profile of the crown but allows leaf area in the crown to be +displaced downwards. When $f_g = 0$, the projected crown and leaf areas are identical, +but as $f_g \to 1$ the projected leaf area is pushed downwards. +The calculation of $\tilde{A}_{cp}(z)$ is defined as: + +$$ +\tilde{A}_{cp}(z)= +\begin{cases} +0, & z \gt H \\ +A_c \left(\dfrac{q(z)}{q_m}\right)^2 \left(1 - f_g\right), & H \gt z \gt z_m \\ +Ac - A_c \left(\dfrac{q(z)}{q_m}\right)^2 f_g, & zm \gt z +\end{cases} +$$ + +## Calculating crown model traits in `pyrealm` + +The {class}`~pyrealm.demography.flora.PlantFunctionalType` class is typically +used to set specific PFTs, but the functions to calculate $q_m$ and $p_{zm}$ +are used directly below to provides a demonstration of the impacts of each trait. + +```{code-cell} +# Set a range of values for m and n traits +m = n = np.arange(1.0, 5, 0.1) + +# Calculate the invariant q_m and z_max_prop traits +q_m = calculate_crown_q_m(m=m, n=n[:, None]) +z_max_prop = calculate_crown_z_max_proportion(m=m, n=n[:, None]) +``` + +```{code-cell} +fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10.9, 4)) + +# Plot q_m as a function of m and n +cntr_set1 = ax1.contourf(m, n, q_m, levels=10) +fig.colorbar(cntr_set1, ax=ax1, label="q_m") +ax1.set_xlabel("m") +ax1.set_ylabel("n") +ax1.set_aspect("equal") + +# Plot z_max_prop as a function of m and n +cntr_set2 = ax2.contourf(m, n, z_max_prop, levels=10) +fig.colorbar(cntr_set2, ax=ax2, label="z_max_prop") +ax2.set_xlabel("m") +ax2.set_ylabel("n") +ax2.set_aspect("equal") +``` + +## Crown calculations in `pyrealm` + +The examples below show the calculation of crown variables in `pyrealm`. + +### Calculting crown profiles + +The {class}`~pyrealm.demography.crown.CrownProfile` class is used to calculate crown +profiles for PFTs. It requires: + +* a {class}`~pyrealm.demography.flora.Flora` instance providing a set of PFTs to be + compared, +* a {class}`~pyrealm.demography.t_model_functions.StemAllometry` instance setting the + specific stem sizes for the profile, and +* a set of heights at which to estimate the profile variables + +The code below creates a set of PFTS with differing crown trait values and then creates +a `Flora` object using the PFTs. + +```{code-cell} +# A PFT with a small crown area and equal m and n values +narrow_pft = PlantFunctionalType(name="narrow", h_max=20, m=1.5, n=1.5, ca_ratio=20) +# A PFT with an intermediate crown area and m < n +medium_pft = PlantFunctionalType(name="medium", h_max=20, m=1.5, n=4, ca_ratio=500) +# A PFT with a wide crown area and m > n +wide_pft = PlantFunctionalType(name="wide", h_max=20, m=4, n=1.5, ca_ratio=2000) + +# Generate a Flora instance using those PFTs +flora = Flora([narrow_pft, medium_pft, wide_pft]) +flora +``` + +The Flora object can also be used to show a table of canopy variables: + +```{code-cell} +# TODO - add a Flora.to_pandas() method +flora_data = pd.DataFrame({k: getattr(flora, k) for k in flora.trait_attrs}) +flora_data[["name", "ca_ratio", "m", "n", "f_g", "q_m", "z_max_prop"]] +``` + +The next section of code generates the `StemAllometry` to use for the profiles. +The T Model requires DBH to define stem size - here the +{meth}`~pyrealm.demography.t_model_functions.calculate_dbh_from_height` function +is used to back-calculate the required DBH values to give three stems with similar +heights that are near the maximum height for each PFT. + +```{code-cell} +# Generate the expected stem allometries at similar heights for each PFT +stem_height = np.array([19, 17, 15]) +stem_dbh = calculate_dbh_from_height( + a_hd=flora.a_hd, h_max=flora.h_max, stem_height=stem_height +) +stem_dbh +``` + +```{code-cell} +# Calculate the stem allometries +allometry = StemAllometry(stem_traits=flora, at_dbh=stem_dbh) +``` + +We can again use {mod}`pandas` to get a table of those allometric predictions: + +```{code-cell} +pd.DataFrame({k: getattr(allometry, k) for k in allometry.allometry_attrs}) +``` + +Finally, we can define a set of vertical heights. In order to calculate the +variables for each PFT at each height, this needs to be provided as a column array, +that is with a shape `(N, 1)`. + +We can then calculate the crown profiles. + +```{code-cell} +# Create a set of vertical heights as a column array. +z = np.linspace(-1, 20.0, num=211)[:, None] + +# Calculate the crown profile across those heights for each PFT +crown_profiles = CrownProfile(stem_traits=flora, stem_allometry=allometry, z=z) +``` + +The `crown_profiles` object then provides the four crown profile attributes describe +above calculated at each height $z$: + +* The relative crown radius $q(z)$ +* The crown radius $r(z)$ +* The projected crown area +* The projected leaf area + +```{code-cell} +crown_profiles +``` + +### Visualising crown profiles + +The code below generates a plot of the vertical shape profiles of the crowns for each +stem. For each stem: + +* the dashed line shows how the relative crown radius $q(z)$ varies with height $z$, +* the solid line shows the actual crown radius $r(z)$ varies with height, and +* the dotted horizontal line shows the height at which the maximum crown radius is + found ($z_{max}$). + +Note that the equation for the relative radius $q(z)$ that defines canopy shape can +make predictions with actual values outside of the range of the actual stem and not +only where $0 \leq z \leq H$. + +```{code-cell} +fig, ax = plt.subplots(ncols=1) + +# Find the maximum of the actual and relative maximum crown widths +max_relative_crown_radius = np.nanmax(crown_profiles.relative_crown_radius, axis=0) +max_crown_radius = np.nanmax(crown_profiles.crown_radius, axis=0) +stem_max_width = np.maximum(max_crown_radius, max_relative_crown_radius) + + +for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 12), ("r", "g", "b")): + + # Plot relative radius either side of offset + stem_qz = crown_profiles.relative_crown_radius[:, pft_idx] + ax.plot(stem_qz + offset, z, color=colour, linestyle="--", linewidth=1) + ax.plot(-stem_qz + offset, z, color=colour, linestyle="--", linewidth=1) + + # Plot actual crown radius either side of offset + stem_rz = crown_profiles.crown_radius[:, pft_idx] + ax.plot(stem_rz + offset, z, color=colour) + ax.plot(-stem_rz + offset, z, color=colour) + + # Add the height of maximum crown radius + stem_rz_max = stem_max_width[pft_idx] + + ax.plot( + [offset - stem_rz_max, offset + stem_rz_max], + [allometry.crown_z_max[pft_idx]] * 2, + color=colour, + linewidth=1, + linestyle=":", + ) + + ax.set_xlabel("Crown profile") + ax.set_ylabel("Height above ground (m)") + +ax.set_aspect(aspect=1) +``` + +We can also use the `CanopyProfile` class with a single row of heights to calculate +the crown profile at the expected $z_{max}$ and show that this matches the expected +crown area from the T Model allometry. + +```{code-cell} +# Calculate the crown profile across those heights for each PFT +z_max = flora.z_max_prop * stem_height +profile_at_zmax = CrownProfile(stem_traits=flora, stem_allometry=allometry, z=z_max) + +print(profile_at_zmax.crown_radius**2 * np.pi) +print(allometry.crown_area) +``` + +### Visualising crown and leaf projected areas + +We can also use the crown profile to generate projected area plots. This is hard to see +using the PFTs defined above because they have very different crown areas, so the code +below generates new profiles for a new set of PFTs that have similar crown area ratios +but different shapes and gap fractions. + +```{code-cell} +no_gaps_pft = PlantFunctionalType( + name="no_gaps", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=380 +) +few_gaps_pft = PlantFunctionalType( + name="few_gaps", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=400 +) +many_gaps_pft = PlantFunctionalType( + name="many_gaps", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=420 +) + +# Calculate allometries for each PFT at the same stem DBH +area_stem_dbh = np.array([0.4, 0.4, 0.4]) +area_flora = Flora([no_gaps_pft, few_gaps_pft, many_gaps_pft]) +area_allometry = StemAllometry(stem_traits=area_flora, at_dbh=area_stem_dbh) + +# Calculate the crown profiles across those heights for each PFT +area_z = np.linspace(0, area_allometry.stem_height.max(), 201)[:, None] +area_crown_profiles = CrownProfile( + stem_traits=area_flora, stem_allometry=area_allometry, z=area_z +) +``` + +The plot below then shows how projected crown area (solid lines) and leaf area (dashed +lines) change with height along the stem. + +* The projected crown area increases from zero at the top of the crown until it reaches + the maximum crown radius, at which point it remains constant down to ground level. The + total crown areas differs for each stem because of the slightly different values used + for the crown area ratio. + +* The projected leaf area is very similar but leaf area is displaced towards the ground + because of the crown gap fraction (`f_g`). Where `f_g = 0` (the red line), the two + lines are identical, but as `f_g` increases, more of the leaf area is displaced down + within the crown. + +```{code-cell} +fig, ax = plt.subplots(ncols=1) + +for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 10), ("r", "g", "b")): + + ax.plot(area_crown_profiles.projected_crown_area[:, pft_idx], area_z, color=colour) + ax.plot( + area_crown_profiles.projected_leaf_area[:, pft_idx], + area_z, + color=colour, + linestyle="--", + ) + ax.set_xlabel("Projected area (m2)") + ax.set_ylabel("Height above ground (m)") +``` + +We can also generate predictions for a single PFT with varying crown gap fraction. In +the plot below, note that all leaf area is above $z_{max}$ when $f_g=1$ and all leaf +area is *below* + +```{code-cell} +fig, ax = plt.subplots(ncols=1) + +# Loop over f_g values +for f_g in np.linspace(0, 1, num=11): + + label = None + colour = "gray" + + if f_g == 0: + label = "$f_g=0$" + colour = "red" + elif f_g == 1: + label = "$f_g=1$" + colour = "blue" + + # Create a flora with a single PFT with current f_g and then generate a + # stem allometry and crown profile + flora_f_g = Flora( + [PlantFunctionalType(name="example", h_max=20, m=2, n=2, f_g=f_g)] + ) + allometry_f_g = StemAllometry(stem_traits=flora_f_g, at_dbh=np.array([0.4])) + profile = CrownProfile( + stem_traits=flora_f_g, stem_allometry=allometry_f_g, z=area_z + ) + + # Plot the projected leaf area with height + ax.plot(profile.projected_leaf_area, area_z, color=colour, label=label, linewidth=1) + +# Add a horizontal line for z_max +ax.plot( + [-1, allometry_f_g.crown_area[0] + 1], + [allometry_f_g.crown_z_max, allometry_f_g.crown_z_max], + linestyle="--", + color="black", + label="$z_{max}$", + linewidth=1, +) + +ax.set_ylabel(r"Vertical height ($z$, m)") +ax.set_xlabel(r"Projected leaf area ($\tilde{A}_{cp}(z)$, m2)") +ax.legend(frameon=False) +``` From a71b38479c27b59d2924b9a4382b12b8bae812ad Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 3 Oct 2024 16:13:18 +0100 Subject: [PATCH 207/241] Updating plot helper function get_crown_xy --- pyrealm/demography/crown.py | 130 ++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 5 deletions(-) diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index f8833f57..9da04f51 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -3,6 +3,7 @@ """ # noqa: D205 from dataclasses import InitVar, dataclass, field +from typing import ClassVar import numpy as np from numpy.typing import NDArray @@ -306,11 +307,20 @@ class CrownProfile: z_max: A row array providing expected z_max height for each PFT. """ + var_attr_names: ClassVar[tuple[str, ...]] = ( + "relative_crown_radius", + "crown_radius", + "projected_crown_area", + "projected_leaf_area", + "projected_crown_radius", + "projected_leaf_radius", + ) + stem_traits: InitVar[StemTraits | Flora] """A Flora or StemTraits instance providing plant functional trait data.""" stem_allometry: InitVar[StemAllometry] """A StemAllometry instance setting the stem allometries for the crown profile.""" - z: InitVar[NDArray[np.float32]] + z: NDArray[np.float32] """An array of vertical height values at which to calculate crown profiles.""" relative_crown_radius: NDArray[np.float32] = field(init=False) @@ -332,12 +342,11 @@ def __post_init__( self, stem_traits: StemTraits | Flora, stem_allometry: StemAllometry, - z: NDArray[np.float32], ) -> None: """Populate crown profile attributes from the traits, allometry and height.""" # Calculate relative crown radius self.relative_crown_radius = calculate_relative_crown_radius_at_z( - z=z, + z=self.z, m=stem_traits.m, n=stem_traits.n, stem_height=stem_allometry.stem_height, @@ -350,7 +359,7 @@ def __post_init__( # Calculate projected crown area self.projected_crown_area = calculate_stem_projected_crown_area_at_z( - z=z, + z=self.z, q_z=self.relative_crown_radius, crown_area=stem_allometry.crown_area, q_m=stem_traits.q_m, @@ -360,7 +369,7 @@ def __post_init__( # Calculate projected leaf area self.projected_leaf_area = calculate_stem_projected_leaf_area_at_z( - z=z, + z=self.z, q_z=self.relative_crown_radius, f_g=stem_traits.f_g, q_m=stem_traits.q_m, @@ -383,3 +392,114 @@ def __repr__(self) -> str: f"CrownProfile: Prediction for {self._n_stems} stems " f"at {self._n_pred} observations." ) + + @property + def projected_crown_radius(self) -> NDArray[np.float32]: + """An array of the projected crown radius of stems at z heights.""" + return np.sqrt(self.projected_crown_area / np.pi) + + @property + def projected_leaf_radius(self) -> NDArray[np.float32]: + """An array of the projected leaf radius of stems at z heights.""" + return np.sqrt(self.projected_leaf_area / np.pi) + + +def get_crown_xy( + crown_profile: CrownProfile, + stem_allometry: StemAllometry, + attr: str, + stem_offsets: NDArray[np.float32] | None, + two_sided: bool = True, + as_xy: bool = False, +) -> list[tuple[NDArray, NDArray]] | list[NDArray]: + """Extract plotting data from crown profiles. + + A CrownProfile instance contains crown radius and projected area data for a set of + stems at given heights, but can contain predictions of these attributes above the + actual heights of some or all of the stems or indeed below ground. + + This function extracts plotting data for a given attribute for each crown that + includes only the predictions within the height range of the actual stem. It can + also mirror the values around the vertical midline to provide a two sided canopy + shape. + + The data are returned as a list with one entry per stem. The default value for each + entry a tuple of two arrays (height, attribute values) but the `as_xy=True` option + will return an `(N, 2)` dimensioned XY array suitable for use with + {class}`~matplotlib.patches.Polygon`. + + Args: + crown_profile: A crown profile instance + stem_allometry: The stem allometry instance used to create the crown profile + attr: The crown profile attribute to plot + stem_offsets: An optional array of offsets to add to the midline of stems. + two_sided: Should the plotting data show a two sided canopy. + as_xy: Should the plotting data be returned as a single XY array. + + """ + + # Input validation + if attr not in crown_profile.var_attr_names: + raise ValueError(f"Unknown crown profile attribute: {attr}") + + # TODO + # - more validation once the dimensioning has been thought through #317 + # - we're expecting a one d allometry and a 2D profile with multiple heights. + + # Get the attribute and flatten the heights from a column array to one dimensional + attr_values = getattr(crown_profile, attr) + z = crown_profile.z.flatten() + + # Orient the data so that lower heights always come first + if z[0] < z[-1]: + z = np.flip(z) + attr_values = np.flip(attr_values, axis=0) + + # Collect the per stem data + crown_plotting_data: list[tuple[NDArray, NDArray]] | list[NDArray] = [] + + for stem_index in np.arange(attr_values.shape[1]): + # Find the heights and values that fall within the individual stem + height_is_valid = np.logical_and( + z <= stem_allometry.stem_height[stem_index], z >= 0 + ) + valid_attr_values: NDArray = attr_values[height_is_valid, stem_index] + valid_heights: NDArray = z[height_is_valid] + + if two_sided: + # The values are extended to include the reverse profile as well as the zero + # value at the stem height + valid_heights = np.concatenate( + [ + np.flip(valid_heights), + stem_allometry.stem_height[[stem_index]], + valid_heights, + ] + ) + valid_attr_values = np.concatenate( + [-np.flip(valid_attr_values), [0], valid_attr_values] + ) + else: + # Only the zero value is added + valid_heights = np.concatenate( + [ + stem_allometry.stem_height[[stem_index]], + valid_heights, + ] + ) + valid_attr_values = np.concatenate([[0], valid_attr_values]) + + # Add offsets if provided + if stem_offsets is not None: + valid_attr_values += stem_offsets[stem_index] + + if as_xy: + # Combine the values into an XY array + crown_plotting_data.append( + np.hstack([valid_attr_values[:, None], valid_heights[:, None]]) + ) + else: + # Return the individual 1D arrays + crown_plotting_data.append((valid_heights, valid_attr_values)) + + return crown_plotting_data From 18a58da959e72af81063c5737f427c90bbbb33a8 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 3 Oct 2024 16:14:03 +0100 Subject: [PATCH 208/241] Updating crown.md --- docs/source/users/demography/crown.md | 50 +++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md index eaa76c4c..808b0b72 100644 --- a/docs/source/users/demography/crown.md +++ b/docs/source/users/demography/crown.md @@ -22,6 +22,7 @@ notes and initial demonstration code. ```{code-cell} from matplotlib import pyplot as plt +from matplotlib.patches import Polygon import numpy as np import pandas as pd @@ -39,6 +40,7 @@ from pyrealm.demography.t_model_functions import ( from pyrealm.demography.crown import ( CrownProfile, + get_crown_xy, ) ``` @@ -341,10 +343,10 @@ no_gaps_pft = PlantFunctionalType( name="no_gaps", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=380 ) few_gaps_pft = PlantFunctionalType( - name="few_gaps", h_max=20, m=1.5, n=4, f_g=0.05, ca_ratio=400 + name="few_gaps", h_max=20, m=1.5, n=4, f_g=0.1, ca_ratio=400 ) many_gaps_pft = PlantFunctionalType( - name="many_gaps", h_max=20, m=4, n=1.5, f_g=0.2, ca_ratio=420 + name="many_gaps", h_max=20, m=4, n=1.5, f_g=0.3, ca_ratio=420 ) # Calculate allometries for each PFT at the same stem DBH @@ -435,3 +437,47 @@ ax.set_ylabel(r"Vertical height ($z$, m)") ax.set_xlabel(r"Projected leaf area ($\tilde{A}_{cp}(z)$, m2)") ax.legend(frameon=False) ``` + +```{code-cell} +# Set stem offsets for plotting +stem_offsets = np.array([0, 6, 12]) + +crown_radius_as_xy = get_crown_xy( + crown_profile=area_crown_profiles, + stem_allometry=area_allometry, + attr="crown_radius", + stem_offsets=stem_offsets, + as_xy=True, +) + +projected_crown_radius_xy = get_crown_xy( + crown_profile=area_crown_profiles, + stem_allometry=area_allometry, + attr="projected_crown_radius", + stem_offsets=stem_offsets, +) + +projected_leaf_radius_xy = get_crown_xy( + crown_profile=area_crown_profiles, + stem_allometry=area_allometry, + attr="projected_leaf_radius", + stem_offsets=stem_offsets, +) +``` + +```{code-cell} +fig, ax = plt.subplots() + +for cr_xy, (ch, cpr), (lh, lpr) in zip( + crown_radius_as_xy, projected_crown_radius_xy, projected_leaf_radius_xy +): + ax.add_patch(Polygon(cr_xy, color="lightgrey")) + ax.plot(cpr, ch, color="black", linewidth=1) + ax.plot(lpr, lh, color="red", linewidth=1) + +ax.set_aspect(0.5) +``` + +```{code-cell} + +``` From 504ad7410f6bedb7d591289c712f7be650826663 Mon Sep 17 00:00:00 2001 From: MarionBWeinzierl Date: Thu, 3 Oct 2024 16:33:04 +0100 Subject: [PATCH 209/241] corrected assignment of init values --- pyrealm/pmodel/subdaily.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index dffedb2c..52fb13cd 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -113,7 +113,7 @@ def memory_effect( if initial_values is None: memory_values[0] = values[0] else: - memory_values[0] = initial_values[0] + memory_values[0] = initial_values # Handle the data if there are no missing data, if not nan_present: @@ -393,17 +393,15 @@ def __init__( """Instantaneous optimal :math:`x_{i}`, :math:`V_{cmax}` and :math:`J_{max}`""" if init_realised is not None: if not ( - (init_realised[0].shape() == self.xi_real.shape()) - and (init_realised[1].shape() == self.vcmax25_real.shape()) - and (init_realised[2].shape() == self.jmax25_real.shape()) + (init_realised[0].shape() == self.xi_real[0].shape()) + and (init_realised[1].shape() == self.vcmax25_real[0].shape()) + and (init_realised[2].shape() == self.jmax25_real[0].shape()) ): raise Exception("`init_realised` has wrong shape in Subdaily PModel") else: init_xi_real, init_vcmax_real, init_jmax_real = init_realised else: - init_xi_real = self.pmodel_acclim.optchi.xi - init_vcmax_real = self.vcmax25_opt - init_jmax_real = self.jmax25_opt + init_xi_real, init_vcmax_real, init_jmax_real = [None, None, None] # 5) Calculate the realised daily values from the instantaneous optimal values self.xi_real: NDArray = memory_effect( From 4683fbfbb9e5d838099f4bfaa686fdd7e71aa9c1 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 3 Oct 2024 18:50:11 +0100 Subject: [PATCH 210/241] Add get_crown_xy example to crown doc --- docs/source/users/demography/crown.md | 60 ++++++++++++++++++++++----- pyrealm/demography/crown.py | 6 +++ 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md index 808b0b72..2653a5c0 100644 --- a/docs/source/users/demography/crown.md +++ b/docs/source/users/demography/crown.md @@ -22,7 +22,8 @@ notes and initial demonstration code. ```{code-cell} from matplotlib import pyplot as plt -from matplotlib.patches import Polygon +from matplotlib.lines import Line2D +from matplotlib.patches import Polygon, Patch import numpy as np import pandas as pd @@ -276,9 +277,20 @@ stem. For each stem: * the dotted horizontal line shows the height at which the maximum crown radius is found ($z_{max}$). -Note that the equation for the relative radius $q(z)$ that defines canopy shape can -make predictions with actual values outside of the range of the actual stem and not -only where $0 \leq z \leq H$. +:::{admonition} Note + +The predictions of the equation for the relative radius $q(z)$ are not limited to +height values within the range of the actual height of a given stem +($0 \leq z \leq H$). This is critical for calculating behaviour with height across +multiple stems when calculating canopy profiles for a community. The plot below +includes predictions of $q(z)$ below ground level and above stem height. + +The {meth}`~pyrealm.demography.crown.get_crown_xy` helper function can be used to +extract plotting structures for each stem within a `CrownProfile` that *are* +restricted to actual valid heights for that stem and is demonstrated in the +[code below](#plotting-tools-for-crown-shapes). + +::: ```{code-cell} fig, ax = plt.subplots(ncols=1) @@ -438,10 +450,30 @@ ax.set_xlabel(r"Projected leaf area ($\tilde{A}_{cp}(z)$, m2)") ax.legend(frameon=False) ``` +## Plotting tools for crown shapes + +The {meth}`~pyrealm.demography.crown.get_crown_xy` function makes it easier to extract +neat crown profiles from `CrownProfile` objects, for use in plotting crown data. The +function takes a paired `CrownProfile` and `StemAllometry` and extracts a particular +crown profile variable, and removes predictions for each stem that are outside of +the stem range for that stem. It converts the data for each stem into coordinates that +will plot as a complete two-sided crown outline. The returned value is a list with an +entry for each stem in one of two formats. + +* A pair of coordinate arrays: height and variable value. +* An single XY array with height and variable values in the columns, as used for + example in `matplotlib` Patch objects. + +The code below uses this function to generate plotting data for the crown radius, +projected crown radius and projected leaf radius. These last two variables do not +have direct computational use - the cumulative projected area is what matters - but +allow the projected variables to be visualised at the same scale as the crown radius. + ```{code-cell} -# Set stem offsets for plotting +# Set stem offsets for separating stems along the x axis stem_offsets = np.array([0, 6, 12]) +# Get the crown radius in XY format to plot as a polygon crown_radius_as_xy = get_crown_xy( crown_profile=area_crown_profiles, stem_allometry=area_allometry, @@ -450,6 +482,7 @@ crown_radius_as_xy = get_crown_xy( as_xy=True, ) +# Get the projected crown and leaf radii to plot as lines projected_crown_radius_xy = get_crown_xy( crown_profile=area_crown_profiles, stem_allometry=area_allometry, @@ -468,16 +501,23 @@ projected_leaf_radius_xy = get_crown_xy( ```{code-cell} fig, ax = plt.subplots() +# Bundle the three plotting structures and loop over the three stems. for cr_xy, (ch, cpr), (lh, lpr) in zip( crown_radius_as_xy, projected_crown_radius_xy, projected_leaf_radius_xy ): ax.add_patch(Polygon(cr_xy, color="lightgrey")) - ax.plot(cpr, ch, color="black", linewidth=1) + ax.plot(cpr, ch, color="0.4", linewidth=2) ax.plot(lpr, lh, color="red", linewidth=1) ax.set_aspect(0.5) -``` - -```{code-cell} - +plt.legend( + handles=[ + Patch(color="lightgrey", label="Crown profile"), + Line2D([0], [0], label="Projected crown", color="0.4", linewidth=2), + Line2D([0], [0], label="Projected leaf", color="red", linewidth=1), + ], + ncols=3, + loc="upper center", + bbox_to_anchor=(0.5, 1.15), +) ``` diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index 9da04f51..39311141 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -295,6 +295,12 @@ class CrownProfile: allometric predictions of stem height, crown area and z_max for an actual stem of a given size for each PFT. + In addition to the variables above, the class can also has properties the calculate + the projected crown radius and projected leaf radius. These are simply the radii + that would result in the two projected areas: the values are not directly meaningful + for calculating canopy models, but can be useful for exploring the behavour of + projected area on the same linear scale as the crown radius. + Args: stem_traits: A Flora or StemTraits instance providing plant functional trait data. From b77e70a55fa695286874dd9df81ff864e83e07c7 Mon Sep 17 00:00:00 2001 From: MarionBWeinzierl Date: Fri, 4 Oct 2024 11:17:03 +0100 Subject: [PATCH 211/241] corrected docs --- pyrealm/pmodel/subdaily.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 52fb13cd..5a425d42 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -93,7 +93,7 @@ def memory_effect( Args: values: The values to apply the memory effect to. initial_values: Last available realised value used if model is fitted in - chunks and value at t=0 is not optimal. + chunks and value at t=0 is not optimal. alpha: The relative weight applied to the most recent observation. allow_holdover: Allow missing values to be filled by holding over earlier values. From e775f3f55dacfe6a42f0396024597de74992d7dd Mon Sep 17 00:00:00 2001 From: MarionBWeinzierl Date: Fri, 4 Oct 2024 17:46:23 +0100 Subject: [PATCH 212/241] implemented test for chunked memory effect -- all close fails --- tests/unit/pmodel/test_memory_effect.py | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/unit/pmodel/test_memory_effect.py b/tests/unit/pmodel/test_memory_effect.py index b4d49cc2..4f9fc042 100644 --- a/tests/unit/pmodel/test_memory_effect.py +++ b/tests/unit/pmodel/test_memory_effect.py @@ -54,6 +54,43 @@ def test_memory_effect(inputs, alpha): assert np.allclose(result, expected) +@pytest.mark.parametrize( + argnames="inputs_whole", + argvalues=[ + pytest.param(np.arange(0, 10), id="1D"), + pytest.param( + np.column_stack([np.arange(0, 10)] * 4) + np.arange(4), + id="2D", + ), + pytest.param( + np.dstack([np.column_stack([np.arange(0, 10)] * 4)] * 4) + + np.arange(16).reshape(4, 4), + id="3D", + ), + ], +) +@pytest.mark.parametrize(argnames="alpha", argvalues=(0.0, 0.5, 1.0)) +def test_memory_effect_chunked(inputs_whole, alpha): + """Test that the memory effect works when chunking the time series up. + + This compares the output of `test_memory_effect` with the output of + `memory_effect` which gets the two time chunks fed sequentially., + """ + from pyrealm.pmodel import memory_effect + + result_whole = memory_effect(inputs_whole, alpha=alpha) + + [inputs_chunk1, inputs_chunk2] = np.split(inputs_whole, [5], axis=0) + + result_chunk1 = memory_effect(inputs_chunk1, alpha=alpha) + + result_chunk2 = memory_effect( + inputs_chunk2, initial_values=result_chunk1[-1], alpha=alpha + ) + + assert np.allclose(result_whole[-1], result_chunk2[-1]) + + @pytest.mark.parametrize( argnames="inputs,allow_holdover,context_manager,expected", argvalues=[ From ffef774a9a5b8cdecccb2547bf4ae5c117d5eceb Mon Sep 17 00:00:00 2001 From: David Orme Date: Sat, 5 Oct 2024 11:37:00 +0100 Subject: [PATCH 213/241] Docstrings and comments --- pyrealm/demography/canopy.py | 20 ++++++++++++++++---- pyrealm/demography/crown.py | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 6bc9fe1b..1d57119d 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -88,12 +88,24 @@ def fit_perfect_plasticity_approximation( max_stem_height: float, solver_tolerance: float, ) -> NDArray[np.float32]: - """Find canopy layer heights under the PPA model. + r"""Find canopy layer heights under the PPA model. Finds the closure heights of the canopy layers under the perfect plasticity - approximation by solving Ac(z) - L_n = 0 across the community where L is the - total cumulative crown area in layer n and above, discounted by the canopy gap - fraction. + approximation by fidnding the set of heights that lead to complete closure of canopy + layers through the canopy. The function solves the following equation for integers + :math:`l \in (1,2,..., m)`: + + .. math:: + + \sum_{s=1}^{N_s}{ A_p(z^*_l)} = l A(1 - f_G) + + The right hand side sets out the total area needed to close a given layer :math:`l` + and all layers above it: :math:`l` times the total community area :math:`A` less + any canopy gap fraction (:math:`f_G`). The left hand side then calculates the + projected crown area for each stem :math:`s` :math:`A_p(z^*_l)_{[s]}` and sums those + areas across all stems in the community :math:`N_s`. The specific height + :math:`z^*_l` is then the height at which the two terms are equal and hence solves + the equation for layer :math:`l`. Args: community: A community instance providing plant cohort data diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index 39311141..9aaaee3f 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -500,7 +500,7 @@ def get_crown_xy( valid_attr_values += stem_offsets[stem_index] if as_xy: - # Combine the values into an XY array + # Combine the values into an (N,2) XY array crown_plotting_data.append( np.hstack([valid_attr_values[:, None], valid_heights[:, None]]) ) From 7602f6a12e8a2b6f96d486592e2509b3f36bf706 Mon Sep 17 00:00:00 2001 From: David Orme Date: Sat, 5 Oct 2024 11:46:18 +0100 Subject: [PATCH 214/241] Doc updates --- docs/source/users/demography/canopy.md | 72 +++++++++++++++++++++----- pyproject.toml | 16 +++--- 2 files changed, 68 insertions(+), 20 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index f9c0688c..5fa428b1 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -1,17 +1,14 @@ --- jupytext: - formats: md:myst text_representation: - extension: .md - format_name: myst - format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 --- -# Canopy model +# The canopy model :::{admonition} Warning @@ -20,16 +17,39 @@ notes and initial demonstration code. ::: +The canopy is the representation of the combined crowns across all individual stems +within each cohort in a [community](./community.md). The main use of the canopy is +to calculate the light environment within the canopy, which allows the the productivity +of stems to be estimated across the vertical dimension. + +The key variables in calculating the canopy model are the crown projected area $A_p(z)$ +and leaf projected area $\tilde{A}_{cp}(z)$, which are calculated for a stem +of a given size at a vertical height $z$ using the [crown model](./crown.md). For a +given stem, the difference in projected leaf area values between two heights provides +the actual leaf area between two heights. This then gives an expression for the leaf +area index (LAI, $L$) between two heights $z_i$ and $z_j$: + +$$ + L_{i,j} = \frac{L\left(\tilde{A}_{cp}(z_j) - \tilde{A}_{cp}(z_i)\right)}{A}, +$$ + +where $z_i > z_j$ and $A$ is the area occupied by the community. The value of $L_{i,j}$ +is then the leaf area index per square metre for the stem between the two heights. The +light extinction between $z_i$ and $z_j$ then follows the Beer Lambert law, +with the fraction of light absorbed $f_{abs}$ calculated as: + +$$ +f_{abs[i,j]} = 1 - e^{-kL_{i,j}} +$$ + +given the extinction coefficient $k$ from the plant functional type of the stem. + The canopy model uses the perfect plasticity approximation (PPA) {cite}`purves:2008a`, which assumes that plants are always able to plastically arrange their crown within the broader canopy of the community to maximise their crown size and fill the available space $A$. When the area $A$ is filled, a new lower canopy layer is formed until all of the individual crown area has been distributed across within the canopy. -The key variables in calculating the canopy model are the crown projected area $A_p$ -and leaf projected area $\tilde{A}_{cp}(z)$, which are calculated for a stem -of a given size using the [crown model](./crown.md). - ```{code-cell} from matplotlib import pyplot as plt import numpy as np @@ -93,7 +113,7 @@ The code below creates a simple community: short_pft = PlantFunctionalType( name="short", h_max=15, m=1.5, n=1.5, f_g=0, ca_ratio=380 ) -tall_pft = PlantFunctionalType(name="tall", h_max=30, m=1.5, n=2, f_g=0.2, ca_ratio=500) +tall_pft = PlantFunctionalType(name="tall", h_max=30, m=3, n=1.5, f_g=0.2, ca_ratio=500) # Create the flora flora = Flora([short_pft, tall_pft]) @@ -107,7 +127,7 @@ community = Community( flora=flora, cell_area=32, cell_id=1, - cohort_dbh_values=np.array([0.02, 0.20, 0.5]), + cohort_dbh_values=np.array([0.05, 0.20, 0.5]), cohort_n_individuals=np.array([15, 5, 2]), cohort_pft_names=np.array(["short", "short", "tall"]), ) @@ -123,7 +143,35 @@ print("Ac = ", community.stem_allometry.crown_area) We can now calculate the canopy model for the community: ```{code-cell} -canopy = Canopy(community=community, canopy_gap_fraction=2 / 32) +:lines_to_next_cell: 2 + +hghts = np.linspace(26, 0, num=251)[:, None] +canopy = Canopy( + community=community, canopy_gap_fraction=2 / 32, layer_heights=hghts, fit_ppa=False +) +``` + +```{code-cell} +fig, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(ncols=5, sharey=True, figsize=(12, 6)) + +ax1.plot(canopy.fapar_profile, hghts) + +ax2.plot(np.cumsum(canopy.fapar_profile), hghts) +ax3.plot(canopy.layer_stem_leaf_area, hghts) +ax4.plot(canopy.crown_profile.projected_leaf_radius, hghts) + +ax5.set_prop_cycle("color", ["r", "b", "g"]) +ax5.plot(canopy.crown_profile.crown_radius, hghts) +ax5.plot(canopy.crown_profile.projected_leaf_radius, hghts, linestyle="--") + +# ax1.plot(canopy.crown_profile.projected_leaf_radius, hghts) +# ax1.plot(canopy.crown_profile.projected_crown_radius, hghts) +# ax1.set_aspect(1) +# plt.xscale('log') +``` + +```{code-cell} +canopy.stem_fapar.sum() ``` We can then look at three key properties of the canopy model: the layer closure diff --git a/pyproject.toml b/pyproject.toml index 2823f7cc..45aac833 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,15 +31,15 @@ repository = "https://github.com/ImperialCollegeLondon/pyrealm" version = "1.0.0" [tool.poetry.dependencies] -dacite = "^1.6.0" -numpy = "^2.0.0" +dacite = "^1.6.0" +numpy = "^2.0.0" python = ">=3.10" -scipy = "^1.7.3" -tabulate = "^0.8.10" +scipy = "^1.7.3" +tabulate = "^0.8.10" marshmallow = "^3.22.0" -pandas = "^2.2.2" marshmallow-dataclass = "^8.7.0" +pandas = "^2.2.2" pandas-stubs = "^2.2.2.240909" [tool.poetry.group.types.dependencies] pandas-stubs = "^2.2.0.240218" @@ -132,7 +132,7 @@ select = [ "I", # isort "UP", # pyupgrade "RUF", # RUF specific checks - "NPY201" + "NPY201", ] # On top of the Google convention, disable: @@ -147,6 +147,6 @@ convention = "google" [tool.jupytext] # Stop jupytext from removing mystnb and other settings in MyST Notebook YAML headers -notebook_metadata_filter = "-jupytext.text_representation.jupytext_version,settings,mystnb" +notebook_metadata_filter = "jupytext.text_representation.jupytext_version,settings,mystnb,language_info" # Also stop it from stripping cell metadata. -cell_metadata_filter = "all" \ No newline at end of file +cell_metadata_filter = "all" From 7f18eb8f6c283ff6b891ce962f0b4be2955308bd Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 7 Oct 2024 09:54:09 +0100 Subject: [PATCH 215/241] Updating jupytext settings --- docs/source/users/demography/canopy.md | 7 +++++-- pyproject.toml | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index 5fa428b1..2dbc140a 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -1,6 +1,9 @@ --- jupytext: text_representation: + extension: .md + format_name: myst + format_version: 0.13 jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) @@ -103,6 +106,8 @@ The {class}`~pyrealm.demography.canopy.Canopy` class automatically finds the can closure heights, given a {class}`~pyrealm.demography.community.Community` instance and the required canopy gap fraction. +THIS IS A TEST CHANGE TO CHECK JUPYTEXT BEHAVIOUR. + The code below creates a simple community: ```{code-cell} @@ -143,8 +148,6 @@ print("Ac = ", community.stem_allometry.crown_area) We can now calculate the canopy model for the community: ```{code-cell} -:lines_to_next_cell: 2 - hghts = np.linspace(26, 0, num=251)[:, None] canopy = Canopy( community=community, canopy_gap_fraction=2 / 32, layer_heights=hghts, fit_ppa=False diff --git a/pyproject.toml b/pyproject.toml index 45aac833..b656af26 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -147,6 +147,6 @@ convention = "google" [tool.jupytext] # Stop jupytext from removing mystnb and other settings in MyST Notebook YAML headers -notebook_metadata_filter = "jupytext.text_representation.jupytext_version,settings,mystnb,language_info" +notebook_metadata_filter = "settings,mystnb,language_info" # Also stop it from stripping cell metadata. -cell_metadata_filter = "all" +cell_metadata_filter = "all,-trusted" From a1ad5f0c008964cc58856f9436d1182dfe6743dd Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 7 Oct 2024 09:54:45 +0100 Subject: [PATCH 216/241] Testing jupytext settings --- docs/source/users/demography/canopy.md | 44 +++++++++++++++----------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index 2dbc140a..9a9b9901 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -9,6 +9,16 @@ kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The canopy model @@ -53,7 +63,7 @@ broader canopy of the community to maximise their crown size and fill the availa space $A$. When the area $A$ is filled, a new lower canopy layer is formed until all of the individual crown area has been distributed across within the canopy. -```{code-cell} +```{code-cell} ipython3 from matplotlib import pyplot as plt import numpy as np import pandas as pd @@ -106,11 +116,9 @@ The {class}`~pyrealm.demography.canopy.Canopy` class automatically finds the can closure heights, given a {class}`~pyrealm.demography.community.Community` instance and the required canopy gap fraction. -THIS IS A TEST CHANGE TO CHECK JUPYTEXT BEHAVIOUR. - The code below creates a simple community: -```{code-cell} +```{code-cell} ipython3 # Two PFTs # - a shorter understory tree with a columnar canopy and no crown gaps # - a taller canopy tree with a top heavy canopy and more crown gaps @@ -140,21 +148,21 @@ community = Community( We can then look at the expected allometries for the stems in each cohort: -```{code-cell} +```{code-cell} ipython3 print("H = ", community.stem_allometry.stem_height) print("Ac = ", community.stem_allometry.crown_area) ``` We can now calculate the canopy model for the community: -```{code-cell} +```{code-cell} ipython3 hghts = np.linspace(26, 0, num=251)[:, None] canopy = Canopy( community=community, canopy_gap_fraction=2 / 32, layer_heights=hghts, fit_ppa=False ) ``` -```{code-cell} +```{code-cell} ipython3 fig, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(ncols=5, sharey=True, figsize=(12, 6)) ax1.plot(canopy.fapar_profile, hghts) @@ -173,7 +181,7 @@ ax5.plot(canopy.crown_profile.projected_leaf_radius, hghts, linestyle="--") # plt.xscale('log') ``` -```{code-cell} +```{code-cell} ipython3 canopy.stem_fapar.sum() ``` @@ -184,14 +192,14 @@ heights for each stem in the three cohorts. There are four canopy layers, with the top two very close together because of the large crown area in the two stems in the cohort of `tall` trees. -```{code-cell} +```{code-cell} ipython3 canopy.layer_heights ``` The `stem_crown_area` attribute then provides the crown area of each stem found in each layer. -```{code-cell} +```{code-cell} ipython3 canopy.stem_crown_area ``` @@ -200,7 +208,7 @@ the first two layers are taken up entirely by the two stems in the cohort of lar trees. We can confirm that the calculation is correct by calculating the total crown area across the cohorts at each height: -```{code-cell} +```{code-cell} ipython3 np.sum(canopy.stem_crown_area * community.cohort_data["n_individuals"], axis=1) ``` @@ -214,7 +222,7 @@ identical to the projected crown area for the first two cohorts because the crow fraction $f_g$ is zero for this PFT. The projected leaf area is however displaced towards the ground in the last cohort, because the `tall` PFT has a large gap fraction. -```{code-cell} +```{code-cell} ipython3 canopy.stem_leaf_area ``` @@ -225,7 +233,7 @@ community crown and leaf area profile across a range of height values. For each we calculate the sum of the product of stem projected area and the number of individuals in each cohort. -```{code-cell} +```{code-cell} ipython3 # Set of vertical height to calculate crown profiles at_z = np.linspace(0, 26, num=261)[:, None] @@ -249,7 +257,7 @@ superimpose the calculated $z^*_l$ values and the cumulative canopy area for eac to confirm that the calculated values coincide with the profile. Note here that the total area at each closed layer height is omitting the community gap fraction. -```{code-cell} +```{code-cell} ipython3 fig, ax = plt.subplots(ncols=1) # Calculate the crown area at which each canopy layer closes. @@ -307,7 +315,7 @@ $f_{abs} = 1 - e ^ {-kL}$, where $k$ is the light extinction coefficient ($k$) and $L$ is the leaf area index (LAI). The LAI can be calculated for each stem and layer: -```{code-cell} +```{code-cell} ipython3 # LAI = Acp_within_layer / canopy_area # print(LAI) ``` @@ -315,7 +323,7 @@ where $k$ is the light extinction coefficient ($k$) and $L$ is the leaf area ind This can be used to calculate the LAI of individual stems but also the LAI of each layer in the canopy: -```{code-cell} +```{code-cell} ipython3 # LAI_stem = LAI.sum(axis=0) # LAI_layer = LAI.sum(axis=1) @@ -326,7 +334,7 @@ in the canopy: The layer LAI values can now be used to calculate the light transmission of each layer and hence the cumulative light extinction profile through the canopy. -```{code-cell} +```{code-cell} ipython3 # f_abs = 1 - np.exp(-pft.traits.par_ext * LAI_layer) # ext = np.cumprod(f_abs) @@ -338,7 +346,7 @@ One issue that needs to be resolved is that the T Model implementation in `pyrea follows the original implementation of the T Model in having LAI as a fixed trait of a given plant functional type, so is constant for all stems of that PFT. -```{code-cell} +```{code-cell} ipython3 # print("f_abs = ", (1 - np.exp(-pft.traits.par_ext * pft.traits.lai))) ``` From 2ab3acc3fbd396709c33b4d80d509215c4799763 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:23:39 +0000 Subject: [PATCH 217/241] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.6.0 → v5.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.6.0...v5.0.0) - [github.com/astral-sh/ruff-pre-commit: v0.6.8 → v0.6.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.8...v0.6.9) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 969a879d..41cf7f95 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,12 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-merge-conflict - id: debug-statements - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.6.8 + rev: v0.6.9 hooks: # Run the linter. - id: ruff From bb8d3c9ca920f6503d32dfb3a772032ced8aeae0 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 9 Oct 2024 18:23:45 +0100 Subject: [PATCH 218/241] Working through implementation of canopy model with user docs --- docs/source/users/demography/canopy.md | 435 +++++++++++++++++-------- docs/source/users/demography/crown.md | 49 ++- pyrealm/demography/canopy.py | 31 +- pyrealm/demography/crown.py | 2 +- 4 files changed, 354 insertions(+), 163 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index 9a9b9901..7068b33d 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -30,167 +30,374 @@ notes and initial demonstration code. ::: -The canopy is the representation of the combined crowns across all individual stems -within each cohort in a [community](./community.md). The main use of the canopy is -to calculate the light environment within the canopy, which allows the the productivity -of stems to be estimated across the vertical dimension. - -The key variables in calculating the canopy model are the crown projected area $A_p(z)$ -and leaf projected area $\tilde{A}_{cp}(z)$, which are calculated for a stem -of a given size at a vertical height $z$ using the [crown model](./crown.md). For a -given stem, the difference in projected leaf area values between two heights provides -the actual leaf area between two heights. This then gives an expression for the leaf -area index (LAI, $L$) between two heights $z_i$ and $z_j$: +```{code-cell} ipython3 +from matplotlib import pyplot as plt +import matplotlib as mpl +import numpy as np +import pandas as pd + +from pyrealm.demography.flora import PlantFunctionalType, Flora +from pyrealm.demography.community import Community +from pyrealm.demography.crown import CrownProfile, get_crown_xy +from pyrealm.demography.canopy import Canopy +from pyrealm.demography.t_model_functions import StemAllometry +``` + +The `canopy` module in `pyrealm` is used to calculate a model of the light environment +across all of cohorts within a plant [community](./community.md). Each cohort consists +of a number of identically-sized individuals $n_{ch}$ from a given [plant functional +type (PFT)](./flora.md). Because the individuals are identically sized, they all share +the same [stem allometry](./t_model.md) and the same [crown model](./crown.md). + +## Light extinction for a single stem + +The key variables in determining the light environment for a given +stem are as follows: + +* The projected crown area ${A}_{p}(z)$ sets how crown area accumulates, given + the crown shape, from the top of the stem to the ground. +* The projected leaf area $\tilde{A}_{cp}(z)$ modifies the crown area to allow + for the vertical displacement of crown area by the crown gap fraction. +* The leaf area index $L$ for the PFT is a simple factor that sets the leaf density + of the crown, allowing stems with identical crown area to vary in the density of + actual leaf surface for light capture. Values of $L$ are always expressed as the area + of leaf surface per square meter. +* The extinction coefficient $k$ for a PFT sets how much light is absorbed when passing + through the leaf surface of that PFT. + +For a single stem, the fraction of light absorbed through the entire crown is described +by the Beer-Lambert law: + +$$ +f_{abs} = 1 - e^{-kL} +$$ + +However, to calculate a vertical profile of light extinction through a crown with total +area $A_c$ and maximum stem height $H$, that equation needs to be expanded to calculate +the fraction of $L$ that falls between pairs of vertical heights $z_a > z_b$. The actual +area amount of leaf area $A_l$ for an individual stem falling between those two heights +is simply the diffence in projected leaf area between the two heights: $$ - L_{i,j} = \frac{L\left(\tilde{A}_{cp}(z_j) - \tilde{A}_{cp}(z_i)\right)}{A}, +A_{l[a,b]} = \tilde{A}_{cp}(z_a) - \tilde{A}_{cp}(z_b) $$ -where $z_i > z_j$ and $A$ is the area occupied by the community. The value of $L_{i,j}$ -is then the leaf area index per square metre for the stem between the two heights. The -light extinction between $z_i$ and $z_j$ then follows the Beer Lambert law, -with the fraction of light absorbed $f_{abs}$ calculated as: +Given that information, the calculation of $f_{abs}$ becomes: $$ -f_{abs[i,j]} = 1 - e^{-kL_{i,j}} +f_{abs[a,b]} = 1 - e^{\left(-k\dfrac{L A_{l[a,b]}}{A_c}\right)} $$ -given the extinction coefficient $k$ from the plant functional type of the stem. +When $z_a = H$ and $z_b=0$, then $A_{l[a,b]} = A_c$ and hence simplifies to +the original equation. -The canopy model uses the perfect plasticity approximation (PPA) {cite}`purves:2008a`, -which assumes that plants are always able to plastically arrange their crown within the -broader canopy of the community to maximise their crown size and fill the available -space $A$. When the area $A$ is filled, a new lower canopy layer is formed until all -of the individual crown area has been distributed across within the canopy. +The code below creates a simple example community containing a single cohort containing +a single stem and then calculates the light extinction profile down through the canopy. ```{code-cell} ipython3 -from matplotlib import pyplot as plt -import numpy as np -import pandas as pd +# Create a simple community with a single stem +simple_pft = PlantFunctionalType(name="defaults", m=2, n=2) +simple_flora = Flora([simple_pft]) +stem_dbh = np.array([0.5]) +simple_stem = StemAllometry(stem_traits=simple_flora, at_dbh=stem_dbh) + +# The total area is exactly the crown area +total_area = simple_stem.crown_area[0] + +# Define a simple community +simple_community = Community( + flora=simple_flora, + cell_area=total_area, + cell_id=1, + cohort_dbh_values=stem_dbh, + cohort_n_individuals=np.array([1]), + cohort_pft_names=np.array(["defaults"]), +) -from pyrealm.demography.flora import PlantFunctionalType, Flora -from pyrealm.demography.community import Community -from pyrealm.demography.crown import CrownProfile -from pyrealm.demography.canopy import Canopy +# Get the canopy model for the simple case from the canopy top +# to the ground +hghts = np.linspace(simple_stem.stem_height[0], 0, num=101)[:, None] +simple_canopy = Canopy(community=simple_community, layer_heights=hghts) ``` -## Canopy closure and canopy gap fraction +As a simple check that the calculation across height layers is correct, the canopy +instance returns a vertical light extinction profile. The last value in this profile +should equal the whole canopy $f_{abs}$ calculated using the simple Beer-Lambert +equation and the PFT trait values. -A simple method for finding the first canopy closure height is to find a height $z^*_1$ -at which the sum of crown projected area across all stems $N_s$ in a community equals $A$: +```{code-cell} ipython3 +:scrolled: true -$$ -\sum_1^{N_s}{ A_p(z^*_1)} = A -$$ +print(simple_canopy.extinction_profile[-1]) +``` + +```{code-cell} ipython3 +:scrolled: true + +print(1 - np.exp(-simple_pft.par_ext * simple_pft.lai)) +``` + +The plot below shows: + +1. The shape of crown radius for the stem (solid line) along with the projected leaf + radius (dashed line). The leaf radius does not show the actual expected boundary of + leaf area - which follows the crown - but is useful to visualise the displacement of + leaf area on the same scale as the crown radius. +2. The vertical profile of the actual leaf area $A_{l[a,b]}$ between two height. +3. The resulting light absorption at each height. +4. The light extinction profile through the canopy. + +```{code-cell} ipython3 +fig, (ax1, ax2, ax3, ax4) = plt.subplots(ncols=4, sharey=True, figsize=(12, 6)) + +# Generate plot structures for stem profiles +ch, crown_radius = get_crown_xy( + crown_profile=simple_canopy.crown_profile, + stem_allometry=simple_community.stem_allometry, + attr="crown_radius", + two_sided=False, +)[0] + +ch, projected_leaf_radius = get_crown_xy( + crown_profile=simple_canopy.crown_profile, + stem_allometry=simple_community.stem_allometry, + attr="projected_leaf_radius", + two_sided=False, +)[0] + +ax1.plot(crown_radius, ch, color="red") +ax1.plot(projected_leaf_radius, ch, linestyle="--", color="red") +ax1.set_xlabel("Profile radius (m)") +ax1.set_ylabel("Vertical height (m)") + +# Plot the leaf area between heights for stems +ax2.plot(simple_canopy.layer_stem_leaf_area, hghts, color="red") +ax2.set_xlabel("Leaf area (m2)") + +# Plot the fraction of light absorbed at different heights +ax3.plot(simple_canopy.layer_f_abs, hghts, color="red") +ax3.set_xlabel("Light absorption fraction (-)") + +# Plot the light extinction profile through the canopy. +ax4.plot(simple_canopy.extinction_profile, hghts, color="red") +ax4.set_xlabel("Cumulative light\nabsorption fraction (-)") +``` + +## Light extinction within a community + +Within a community, the calculations above need to be modified to account for: + +* the number of cohorts $n$, +* the number of individuals $i_{h}$ within each cohort, +* differences in the LAI $L_{h}$ and light extinction coefficients $k_{h}$ between + cohorts, +* scaling LAI to the total area available to the community $A_T$ rather than the cohort + specific crown area $A_h$. -However, the canopy model is modified by a community-level -**canopy gap fraction** ($f_G$) that captures the overall proportion of the canopy area -that is left unfilled by canopy. This gap fraction, capturing processes such as crown -shyness, describes the proportion of open sky visible from the forest floor. This -gives the following definition of the height of canopy layer closure ($z^*_l$) for a -given canopy layer $l = 1, ..., l_m$: +Within the community, each cohort now requires a whole cohort LAI component $L_H$, +which consists of the total leaf area index across individuals divided by the total +community area to give an average leaf area index across the available space: $$ -\sum_1^{N_s}{ A_p(z^*_l)} = l A(1 - f_G) +L_H = \frac{i_h L_h A_h}{A_T} $$ -The set of heights $z^*$ can be found numerically by using a root solver to find -values of $z^*_l$ for $l = 1, ..., l_m$ that satisfy: +The Beer-Lambert equation across the cohorts is then: $$ -\sum_1^{N_s}{ A_p(z^*_l)} - l A(1 - f_G) = 0 +f_{abs} = 1 - e^{\left(\sum\limits_{m=1}^{n}-k_h{[m]} L_{H[m]}\right)} $$ -The total number of layers $l_m$ in a canopy, where the final layer may not be fully -closed, can be found given the total crown area across stems as: +or equivalently $$ -l_m = \left\lceil \frac{\sum_1^{N_s}{A_c}}{ A(1 - f_G)}\right\rceil +f_{abs} = 1 - \prod\limits_{m=1}^{n}e^{-k_{[m]} L_{H[m]}} $$ -+++ +This equation can be adjusted as before to partition light absorption within vertical +layers and the implementation is demonstrated below using a simple community containing +two plant functional types: -## Implementation in `pyrealm` +* a shorter understory tree with a columnar canopy and no crown gaps +* a taller canopy tree with a top heavy canopy and more crown gaps -The {class}`~pyrealm.demography.canopy.Canopy` class automatically finds the canopy -closure heights, given a {class}`~pyrealm.demography.community.Community` instance -and the required canopy gap fraction. +and then three cohorts: -The code below creates a simple community: +* 7 saplings of the short PFT +* 3 larger stems of the short PFT +* 1 large stems of tall PFT ```{code-cell} ipython3 -# Two PFTs -# - a shorter understory tree with a columnar canopy and no crown gaps -# - a taller canopy tree with a top heavy canopy and more crown gaps - +# Define PFTs short_pft = PlantFunctionalType( - name="short", h_max=15, m=1.5, n=1.5, f_g=0, ca_ratio=380 + name="short", + h_max=15, + m=1.5, + n=1.5, + f_g=0, + ca_ratio=380, + lai=4, ) tall_pft = PlantFunctionalType(name="tall", h_max=30, m=3, n=1.5, f_g=0.2, ca_ratio=500) # Create the flora flora = Flora([short_pft, tall_pft]) -# Create a simply community with three cohorts -# - 15 saplings of the short PFT -# - 5 larger stems of the short PFT -# - 2 large stems of tall PFT - +# Define a simply community with three cohorts community = Community( flora=flora, cell_area=32, cell_id=1, cohort_dbh_values=np.array([0.05, 0.20, 0.5]), - cohort_n_individuals=np.array([15, 5, 2]), + cohort_n_individuals=np.array([7, 3, 1]), cohort_pft_names=np.array(["short", "short", "tall"]), ) + +# Calculate the canopy profile across vertical heights +hghts = np.linspace(community.stem_allometry.stem_height.max(), 0, num=101)[:, None] +canopy = Canopy(community=community, canopy_gap_fraction=0, layer_heights=hghts) ``` -We can then look at the expected allometries for the stems in each cohort: +As before, we can verify that the cumulative light extinction at the bottom of the +vertical profile is equal to the expected value across the whole community. ```{code-cell} ipython3 -print("H = ", community.stem_allometry.stem_height) -print("Ac = ", community.stem_allometry.crown_area) +# Calculate L_h for each cohort +cohort_lai = ( + community.cohort_data["n_individuals"] + * community.stem_traits.lai + * community.stem_allometry.crown_area +) / community.cell_area + +# Calculate 1 - e ^ -k L +print(1 - np.exp(np.sum(-community.stem_traits.par_ext * cohort_lai))) ``` -We can now calculate the canopy model for the community: +```{code-cell} ipython3 +print(canopy.extinction_profile[-1]) +``` ```{code-cell} ipython3 -hghts = np.linspace(26, 0, num=251)[:, None] -canopy = Canopy( - community=community, canopy_gap_fraction=2 / 32, layer_heights=hghts, fit_ppa=False +cols = ["r", "b", "g"] + +mpl.rcParams["axes.prop_cycle"] = mpl.cycler(color=cols) + +fig, (ax1, ax2, ax3, ax4) = plt.subplots(ncols=4, sharey=True, figsize=(12, 6)) + +# Generate plot structures for stem profiles +crown_profile = get_crown_xy( + crown_profile=canopy.crown_profile, + stem_allometry=community.stem_allometry, + attr="crown_radius", + two_sided=False, +) + +leaf_profile = get_crown_xy( + crown_profile=canopy.crown_profile, + stem_allometry=community.stem_allometry, + attr="projected_leaf_radius", + two_sided=False, ) + +for (stem_rh, stem_cr), (stem_lh, stem_plr), col in zip( + crown_profile, leaf_profile, cols +): + ax1.plot(stem_cr, stem_rh, color=col) + ax1.plot(stem_plr, stem_lh, linestyle="--", color=col) + +ax1.set_xlabel("Profile radius (m)") +ax1.set_ylabel("Vertical height (m)") + +# Plot the leaf area between heights for stems +ax2.plot(canopy.layer_stem_leaf_area, hghts) +ax2.set_xlabel("Leaf area per stem (m2)") + +# Plot the fraction of light absorbed at different heights +ax3.plot(canopy.layer_f_abs, hghts, color="grey") +ax3.plot(1 - canopy.layer_cohort_f_trans, hghts) +ax3.set_xlabel("Light absorption fraction (-)") + +# Plot the light extinction profile through the canopy. +ax4.plot(canopy.extinction_profile, hghts, color="grey") +ax4.set_xlabel("Cumulative light\nabsorption fraction (-)") ``` +## Canopy closure and canopy gap fraction + +In addition to calculating profiles from a provided sequence of vertical heights, the +canopy model also implements the calculation of canopy layers, following the perfect +plasticity approximation (PPA) {cite}`purves:2008a`. This model divides the vertical +structure of the canopy into discrete closed layers. The model assumes that plants are +always able to plastically arrange their crown within the broader canopy of the +community to maximise their crown size and fill the available space $A$. When the area +$A$ is filled, a new lower canopy layer is formed until all of the individual crown area +has been distributed across within the canopy. + +A simple method for finding the first canopy closure height is to find a height $z^*_1$ +at which the sum of crown projected area across all stems $N_s$ in a community equals +$A$: + +$$ +\sum_1^{N_s}{ A_p(z^*_1)} = A +$$ + +However, the canopy model also allows for modification by a community-level **canopy gap +fraction** ($f_G$) that captures the overall proportion of the canopy area that is left +unfilled by canopy. This gap fraction, capturing processes such as crown shyness, +describes the proportion of open sky visible from the forest floor. This gives the +following definition of the height of canopy layer closure ($z^*_l$) for a given canopy +layer $l = 1, ..., l_m$: + +$$ +\sum_1^{N_s}{ A_p(z^*_l)} = l A(1 - f_G) +$$ + +The set of heights $z^*$ can be found numerically by using a root solver to find values +of $z^*_l$ for $l = 1, ..., l_m$ that satisfy: + +$$ +\sum_1^{N_s}{ A_p(z^*_l)} - l A(1 - f_G) = 0 +$$ + +The total number of layers $l_m$ in a canopy, where the final layer may not be fully +closed, can be found given the total crown area across stems as: + +$$ +l_m = \left\lceil \frac{\sum_1^{N_s}{A_c}}{ A(1 - f_G)}\right\rceil +$$ + ```{code-cell} ipython3 -fig, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(ncols=5, sharey=True, figsize=(12, 6)) +canopy = Canopy(community=community, canopy_gap_fraction=2 / 32, fit_ppa=True) +``` -ax1.plot(canopy.fapar_profile, hghts) +```{code-cell} ipython3 +canopy.layer_heights +``` -ax2.plot(np.cumsum(canopy.fapar_profile), hghts) -ax3.plot(canopy.layer_stem_leaf_area, hghts) -ax4.plot(canopy.crown_profile.projected_leaf_radius, hghts) +## Implementation in `pyrealm` -ax5.set_prop_cycle("color", ["r", "b", "g"]) -ax5.plot(canopy.crown_profile.crown_radius, hghts) -ax5.plot(canopy.crown_profile.projected_leaf_radius, hghts, linestyle="--") +The {class}`~pyrealm.demography.canopy.Canopy` class automatically finds the canopy +closure heights, given a {class}`~pyrealm.demography.community.Community` instance and +the required canopy gap fraction. -# ax1.plot(canopy.crown_profile.projected_leaf_radius, hghts) -# ax1.plot(canopy.crown_profile.projected_crown_radius, hghts) -# ax1.set_aspect(1) -# plt.xscale('log') +```{code-cell} ipython3 +canopy.crown_profile.projected_leaf_area[:, 1] ``` ```{code-cell} ipython3 -canopy.stem_fapar.sum() +canopy.layer_stem_leaf_area[:, 1] ``` -We can then look at three key properties of the canopy model: the layer closure -heights ($z^*_l$) and the projected crown areas and leaf areas at each of those -heights for each stem in the three cohorts. +```{code-cell} ipython3 +plt.plot(canopy.layer_stem_leaf_area[:, 1], "ro") +``` + +We can then look at three key properties of the canopy model: the layer closure heights +($z^*_l$) and the projected crown areas and leaf areas at each of those heights for each +stem in the three cohorts. -There are four canopy layers, with the top two very close together because of the -large crown area in the two stems in the cohort of `tall` trees. +There are four canopy layers, with the top two very close together because of the large +crown area in the two stems in the cohort of `tall` trees. ```{code-cell} ipython3 canopy.layer_heights @@ -261,7 +468,9 @@ total area at each closed layer height is omitting the community gap fraction. fig, ax = plt.subplots(ncols=1) # Calculate the crown area at which each canopy layer closes. -closure_areas = np.arange(1, canopy.n_layers + 1) * canopy.crown_area_per_layer +closure_areas = ( + np.arange(1, len(canopy.layer_heights) + 1) * community.cell_area * (30 / 32) +) # Add lines showing the canopy closure heights and closure areas. for val in canopy.layer_heights: @@ -305,49 +514,15 @@ ax.set_xlabel("Community-wide projected area (m2)") ax.legend(frameon=False) ``` -### Light transmission through the canopy - -Now we can use the leaf area by layer and the Beer-Lambert equation to calculate light -attenuation through the canopy layers. - -$f_{abs} = 1 - e ^ {-kL}$, - -where $k$ is the light extinction coefficient ($k$) and $L$ is the leaf area index -(LAI). The LAI can be calculated for each stem and layer: - -```{code-cell} ipython3 -# LAI = Acp_within_layer / canopy_area -# print(LAI) -``` - -This can be used to calculate the LAI of individual stems but also the LAI of each layer -in the canopy: - ```{code-cell} ipython3 -# LAI_stem = LAI.sum(axis=0) -# LAI_layer = LAI.sum(axis=1) +ppfd = 1000 -# print("LAI stem = ", LAI_stem) -# print("LAI layer = ", LAI_layer) +ppfd_layer = -np.diff(ppfd * np.cumprod(canopy.layer_f_trans), prepend=ppfd) +ppfd_layer ``` -The layer LAI values can now be used to calculate the light transmission of each layer and -hence the cumulative light extinction profile through the canopy. - -```{code-cell} ipython3 -# f_abs = 1 - np.exp(-pft.traits.par_ext * LAI_layer) -# ext = np.cumprod(f_abs) - -# print("f_abs = ", f_abs) -# print("extinction = ", ext) -``` - -One issue that needs to be resolved is that the T Model implementation in `pyrealm` -follows the original implementation of the T Model in having LAI as a fixed trait of -a given plant functional type, so is constant for all stems of that PFT. - ```{code-cell} ipython3 -# print("f_abs = ", (1 - np.exp(-pft.traits.par_ext * pft.traits.lai))) +(1 - canopy.layer_cohort_f_trans) * ppfd_layer[:, None] ``` ## Things to worry about later diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md index 2653a5c0..69e64018 100644 --- a/docs/source/users/demography/crown.md +++ b/docs/source/users/demography/crown.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The tree crown model @@ -20,7 +31,7 @@ notes and initial demonstration code. ::: -```{code-cell} +```{code-cell} ipython3 from matplotlib import pyplot as plt from matplotlib.lines import Line2D from matplotlib.patches import Polygon, Patch @@ -149,7 +160,7 @@ The {class}`~pyrealm.demography.flora.PlantFunctionalType` class is typically used to set specific PFTs, but the functions to calculate $q_m$ and $p_{zm}$ are used directly below to provides a demonstration of the impacts of each trait. -```{code-cell} +```{code-cell} ipython3 # Set a range of values for m and n traits m = n = np.arange(1.0, 5, 0.1) @@ -158,7 +169,7 @@ q_m = calculate_crown_q_m(m=m, n=n[:, None]) z_max_prop = calculate_crown_z_max_proportion(m=m, n=n[:, None]) ``` -```{code-cell} +```{code-cell} ipython3 fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10.9, 4)) # Plot q_m as a function of m and n @@ -194,7 +205,7 @@ profiles for PFTs. It requires: The code below creates a set of PFTS with differing crown trait values and then creates a `Flora` object using the PFTs. -```{code-cell} +```{code-cell} ipython3 # A PFT with a small crown area and equal m and n values narrow_pft = PlantFunctionalType(name="narrow", h_max=20, m=1.5, n=1.5, ca_ratio=20) # A PFT with an intermediate crown area and m < n @@ -209,7 +220,7 @@ flora The Flora object can also be used to show a table of canopy variables: -```{code-cell} +```{code-cell} ipython3 # TODO - add a Flora.to_pandas() method flora_data = pd.DataFrame({k: getattr(flora, k) for k in flora.trait_attrs}) flora_data[["name", "ca_ratio", "m", "n", "f_g", "q_m", "z_max_prop"]] @@ -221,7 +232,7 @@ The T Model requires DBH to define stem size - here the is used to back-calculate the required DBH values to give three stems with similar heights that are near the maximum height for each PFT. -```{code-cell} +```{code-cell} ipython3 # Generate the expected stem allometries at similar heights for each PFT stem_height = np.array([19, 17, 15]) stem_dbh = calculate_dbh_from_height( @@ -230,14 +241,14 @@ stem_dbh = calculate_dbh_from_height( stem_dbh ``` -```{code-cell} +```{code-cell} ipython3 # Calculate the stem allometries allometry = StemAllometry(stem_traits=flora, at_dbh=stem_dbh) ``` We can again use {mod}`pandas` to get a table of those allometric predictions: -```{code-cell} +```{code-cell} ipython3 pd.DataFrame({k: getattr(allometry, k) for k in allometry.allometry_attrs}) ``` @@ -247,7 +258,7 @@ that is with a shape `(N, 1)`. We can then calculate the crown profiles. -```{code-cell} +```{code-cell} ipython3 # Create a set of vertical heights as a column array. z = np.linspace(-1, 20.0, num=211)[:, None] @@ -263,7 +274,7 @@ above calculated at each height $z$: * The projected crown area * The projected leaf area -```{code-cell} +```{code-cell} ipython3 crown_profiles ``` @@ -292,7 +303,7 @@ restricted to actual valid heights for that stem and is demonstrated in the ::: -```{code-cell} +```{code-cell} ipython3 fig, ax = plt.subplots(ncols=1) # Find the maximum of the actual and relative maximum crown widths @@ -334,7 +345,7 @@ We can also use the `CanopyProfile` class with a single row of heights to calcul the crown profile at the expected $z_{max}$ and show that this matches the expected crown area from the T Model allometry. -```{code-cell} +```{code-cell} ipython3 # Calculate the crown profile across those heights for each PFT z_max = flora.z_max_prop * stem_height profile_at_zmax = CrownProfile(stem_traits=flora, stem_allometry=allometry, z=z_max) @@ -350,7 +361,7 @@ using the PFTs defined above because they have very different crown areas, so th below generates new profiles for a new set of PFTs that have similar crown area ratios but different shapes and gap fractions. -```{code-cell} +```{code-cell} ipython3 no_gaps_pft = PlantFunctionalType( name="no_gaps", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=380 ) @@ -386,7 +397,7 @@ lines) change with height along the stem. lines are identical, but as `f_g` increases, more of the leaf area is displaced down within the crown. -```{code-cell} +```{code-cell} ipython3 fig, ax = plt.subplots(ncols=1) for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 10), ("r", "g", "b")): @@ -406,7 +417,7 @@ We can also generate predictions for a single PFT with varying crown gap fractio the plot below, note that all leaf area is above $z_{max}$ when $f_g=1$ and all leaf area is *below* -```{code-cell} +```{code-cell} ipython3 fig, ax = plt.subplots(ncols=1) # Loop over f_g values @@ -469,7 +480,7 @@ projected crown radius and projected leaf radius. These last two variables do no have direct computational use - the cumulative projected area is what matters - but allow the projected variables to be visualised at the same scale as the crown radius. -```{code-cell} +```{code-cell} ipython3 # Set stem offsets for separating stems along the x axis stem_offsets = np.array([0, 6, 12]) @@ -498,7 +509,7 @@ projected_leaf_radius_xy = get_crown_xy( ) ``` -```{code-cell} +```{code-cell} ipython3 fig, ax = plt.subplots() # Bundle the three plotting structures and loop over the three stems. @@ -521,3 +532,7 @@ plt.legend( bbox_to_anchor=(0.5, 1.15), ) ``` + +```{code-cell} ipython3 + +``` diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 1d57119d..7271fb93 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -277,37 +277,38 @@ def _calculate_canopy(self, community: Community) -> None: self.layer_stem_leaf_area = np.diff( self.crown_profile.projected_leaf_area, axis=0, prepend=0 ) - self.layer_cohort_leaf_area = ( - self.layer_stem_leaf_area * community.cohort_data["n_individuals"] - ) - # Calculate the leaf area index per layer per cohort, using the stem + # Calculate the leaf area index per layer per stem, using the stem # specific leaf area index values. LAI is a value per m2, so scale back down by # the community area. self.layer_cohort_lai = ( - self.layer_cohort_leaf_area * community.stem_traits.lai + self.layer_stem_leaf_area + * community.cohort_data["n_individuals"] + * community.stem_traits.lai ) / community.cell_area - # Calculate the Beer-Lambert light extinction per layer and cohort - self.layer_cohort_f_abs = 1 - np.exp( + # Calculate the Beer-Lambert light transmission component per layer and cohort + self.layer_cohort_f_trans = np.exp( -community.stem_traits.par_ext * self.layer_cohort_lai ) + # Aggregate across cohorts into a layer wide transimissivity + self.layer_f_trans = self.layer_cohort_f_trans.prod(axis=1) # Calculate the canopy wide light extinction per layer - self.layer_canopy_f_abs = self.layer_cohort_f_abs.sum(axis=1) + self.layer_f_abs = 1 - self.layer_f_trans # Calculate cumulative light extinction across the canopy - self.canopy_extinction_profile = np.cumprod(self.layer_canopy_f_abs) + self.extinction_profile = 1 - np.cumprod(self.layer_f_trans) # Calculate the fraction of radiation absorbed by each layer # # TODO - include append=0 here to include ground or just backcalculate self.fapar_profile = -np.diff( - np.cumprod(1 - self.layer_canopy_f_abs), + np.cumprod(1 - self.layer_cohort_f_trans), prepend=1, # append=0 ) - # Partition the light back among the individual stems: simply weighting by per - # cohort contribution to f_abs and divide through by the number of individuals - self.stem_fapar = ( - self.layer_cohort_f_abs * self.fapar_profile[:, None] - ) / self.layer_cohort_f_abs.sum(axis=1)[:, None] + # # Partition the light back among the individual stems: simply weighting by per + # # cohort contribution to f_abs and divide through by the number of individuals + # self.stem_fapar = ( + # self.layer_cohort_f_trans * self.fapar_profile[:, None] + # ) / self.layer_cohort_f_trans.sum(axis=1)[:, None] diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index 9aaaee3f..7d5f7665 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -414,7 +414,7 @@ def get_crown_xy( crown_profile: CrownProfile, stem_allometry: StemAllometry, attr: str, - stem_offsets: NDArray[np.float32] | None, + stem_offsets: NDArray[np.float32] | None = None, two_sided: bool = True, as_xy: bool = False, ) -> list[tuple[NDArray, NDArray]] | list[NDArray]: From 5a56a2264ef7cfa7328da9bac23166175b0219a8 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 10 Oct 2024 11:08:29 +0100 Subject: [PATCH 219/241] Docs update and some bug catches --- docs/source/users/demography/canopy.md | 157 ++++++++----------------- pyrealm/demography/canopy.py | 16 ++- pyrealm/demography/crown.py | 6 +- 3 files changed, 61 insertions(+), 118 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index 7068b33d..2a1fa595 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -45,23 +45,28 @@ from pyrealm.demography.t_model_functions import StemAllometry The `canopy` module in `pyrealm` is used to calculate a model of the light environment across all of cohorts within a plant [community](./community.md). Each cohort consists -of a number of identically-sized individuals $n_{ch}$ from a given [plant functional -type (PFT)](./flora.md). Because the individuals are identically sized, they all share -the same [stem allometry](./t_model.md) and the same [crown model](./crown.md). +of: + +* a number of identically-sized individuals, +* of the same [plant functional type (PFT)](./flora.md), +* that share the same [stem allometry](./t_model.md) and [crown model](./crown.md). + +The purpose of the `canopy` module is to estimate how light is absorbed down through the +canopy and allow the absorption of incoming light at different heights in the canopy to +be partitioned across stems within each cohort. ## Light extinction for a single stem -The key variables in determining the light environment for a given -stem are as follows: - -* The projected crown area ${A}_{p}(z)$ sets how crown area accumulates, given - the crown shape, from the top of the stem to the ground. -* The projected leaf area $\tilde{A}_{cp}(z)$ modifies the crown area to allow - for the vertical displacement of crown area by the crown gap fraction. -* The leaf area index $L$ for the PFT is a simple factor that sets the leaf density - of the crown, allowing stems with identical crown area to vary in the density of - actual leaf surface for light capture. Values of $L$ are always expressed as the area - of leaf surface per square meter. +The key variables in determining the light environment for a given stem are as follows: + +* The projected crown area ${A}_{p}(z)$ sets how crown area accumulates, given the crown + shape, from the top of the stem to the ground. +* The projected leaf area $\tilde{A}_{cp}(z)$ modifies the crown area to allow for the + vertical displacement of crown area by the crown gap fraction. +* The leaf area index $L$ for the PFT is a simple factor that sets the leaf density of + the crown, allowing stems with identical crown area to vary in the density of actual + leaf surface for light capture. Values of $L$ are always expressed as the area of leaf + surface per square meter. * The extinction coefficient $k$ for a PFT sets how much light is absorbed when passing through the leaf surface of that PFT. @@ -88,8 +93,8 @@ $$ f_{abs[a,b]} = 1 - e^{\left(-k\dfrac{L A_{l[a,b]}}{A_c}\right)} $$ -When $z_a = H$ and $z_b=0$, then $A_{l[a,b]} = A_c$ and hence simplifies to -the original equation. +When $z_a = H$ and $z_b=0$, then $A_{l[a,b]} = A_c$ and hence simplifies to the original +equation. The code below creates a simple example community containing a single cohort containing a single stem and then calculates the light extinction profile down through the canopy. @@ -117,7 +122,10 @@ simple_community = Community( # Get the canopy model for the simple case from the canopy top # to the ground hghts = np.linspace(simple_stem.stem_height[0], 0, num=101)[:, None] -simple_canopy = Canopy(community=simple_community, layer_heights=hghts) +simple_canopy = Canopy( + community=simple_community, + layer_heights=hghts, +) ``` As a simple check that the calculation across height layers is correct, the canopy @@ -126,14 +134,10 @@ should equal the whole canopy $f_{abs}$ calculated using the simple Beer-Lambert equation and the PFT trait values. ```{code-cell} ipython3 -:scrolled: true - print(simple_canopy.extinction_profile[-1]) ``` ```{code-cell} ipython3 -:scrolled: true - print(1 - np.exp(-simple_pft.par_ext * simple_pft.lai)) ``` @@ -205,13 +209,8 @@ $$ The Beer-Lambert equation across the cohorts is then: $$ -f_{abs} = 1 - e^{\left(\sum\limits_{m=1}^{n}-k_h{[m]} L_{H[m]}\right)} -$$ - -or equivalently - -$$ -f_{abs} = 1 - \prod\limits_{m=1}^{n}e^{-k_{[m]} L_{H[m]}} +f_{abs} = 1 - e^{\left(\sum\limits_{m=1}^{n}-k_{[m]} L_{H[m]}\right)} + = 1 - \prod\limits_{m=1}^{n}e^{-k_{[m]} L_{H[m]}} $$ This equation can be adjusted as before to partition light absorption within vertical @@ -255,7 +254,7 @@ community = Community( # Calculate the canopy profile across vertical heights hghts = np.linspace(community.stem_allometry.stem_height.max(), 0, num=101)[:, None] -canopy = Canopy(community=community, canopy_gap_fraction=0, layer_heights=hghts) +canopy = Canopy(community=community, layer_heights=hghts) ``` As before, we can verify that the cumulative light extinction at the bottom of the @@ -367,95 +366,31 @@ l_m = \left\lceil \frac{\sum_1^{N_s}{A_c}}{ A(1 - f_G)}\right\rceil $$ ```{code-cell} ipython3 -canopy = Canopy(community=community, canopy_gap_fraction=2 / 32, fit_ppa=True) -``` - -```{code-cell} ipython3 -canopy.layer_heights -``` - -## Implementation in `pyrealm` - -The {class}`~pyrealm.demography.canopy.Canopy` class automatically finds the canopy -closure heights, given a {class}`~pyrealm.demography.community.Community` instance and -the required canopy gap fraction. - -```{code-cell} ipython3 -canopy.crown_profile.projected_leaf_area[:, 1] -``` - -```{code-cell} ipython3 -canopy.layer_stem_leaf_area[:, 1] -``` - -```{code-cell} ipython3 -plt.plot(canopy.layer_stem_leaf_area[:, 1], "ro") -``` - -We can then look at three key properties of the canopy model: the layer closure heights -($z^*_l$) and the projected crown areas and leaf areas at each of those heights for each -stem in the three cohorts. - -There are four canopy layers, with the top two very close together because of the large -crown area in the two stems in the cohort of `tall` trees. - -```{code-cell} ipython3 -canopy.layer_heights -``` - -The `stem_crown_area` attribute then provides the crown area of each stem found in each -layer. - -```{code-cell} ipython3 -canopy.stem_crown_area +canopy_ppa = Canopy(community=community, canopy_gap_fraction=0, fit_ppa=True) ``` -Given the canopy gap fraction, the available crown area per layer is 30 m2, so -the first two layers are taken up entirely by the two stems in the cohort of large -trees. We can confirm that the calculation is correct by calculating the total crown area -across the cohorts at each height: - -```{code-cell} ipython3 -np.sum(canopy.stem_crown_area * community.cohort_data["n_individuals"], axis=1) -``` - -Those are equal to the layer closure areas of 30, 60 and 90 m2 and the last layer does -not quite close. The slight numerical differences result from the precision of the root -solver for finding $z^*_l$ and this can be adjusted by using the `layer_tolerance` -argument to the `Canopy` class - -The projected leaf area per stem is reported in the `stem_leaf_area` attribute. This is -identical to the projected crown area for the first two cohorts because the crown gap -fraction $f_g$ is zero for this PFT. The projected leaf area is however displaced -towards the ground in the last cohort, because the `tall` PFT has a large gap fraction. - ```{code-cell} ipython3 -canopy.stem_leaf_area +canopy_ppa.layer_heights ``` ### Visualizing layer closure heights and areas -We can use the {class}`~pyrealm.demography.crown.CrownProfile` class to calculate a -community crown and leaf area profile across a range of height values. For each height, +We can use the crown profile calculated for the previous canopy model to calculate a +whole community crown and leaf area profile for the community. For each height, we calculate the sum of the product of stem projected area and the number of individuals in each cohort. ```{code-cell} ipython3 -# Set of vertical height to calculate crown profiles -at_z = np.linspace(0, 26, num=261)[:, None] - -# Calculate the crown profile for the stem for each cohort -crown_profiles = CrownProfile( - stem_traits=community.stem_traits, stem_allometry=community.stem_allometry, z=at_z -) - # Calculate the total projected crown area across the community at each height community_crown_area = np.nansum( - crown_profiles.projected_crown_area * community.cohort_data["n_individuals"], axis=1 + canopy.crown_profile.projected_crown_area * community.cohort_data["n_individuals"], + axis=1, ) + # Do the same for the projected leaf area community_leaf_area = np.nansum( - crown_profiles.projected_leaf_area * community.cohort_data["n_individuals"], axis=1 + canopy.crown_profile.projected_leaf_area * community.cohort_data["n_individuals"], + axis=1, ) ``` @@ -469,21 +404,21 @@ fig, ax = plt.subplots(ncols=1) # Calculate the crown area at which each canopy layer closes. closure_areas = ( - np.arange(1, len(canopy.layer_heights) + 1) * community.cell_area * (30 / 32) + np.arange(1, len(canopy_ppa.layer_heights) + 1) * canopy.filled_community_area ) # Add lines showing the canopy closure heights and closure areas. -for val in canopy.layer_heights: +for val in canopy_ppa.layer_heights: ax.axhline(val, color="red", linewidth=0.5, zorder=0) for val in closure_areas: ax.axvline(val, color="red", linewidth=0.5, zorder=0) # Show the community projected crown area profile -ax.plot(community_crown_area, at_z, zorder=1, label="Crown area") +ax.plot(community_crown_area, canopy.layer_heights, zorder=1, label="Crown area") ax.plot( community_leaf_area, - at_z, + canopy.layer_heights, zorder=1, linestyle="--", color="black", @@ -497,9 +432,9 @@ ax_rhs = ax.twinx() ax_rhs.set_ylim(ax.get_ylim()) z_star_labels = [ f"$z^*_{l + 1} = {val:.2f}$" - for l, val in enumerate(np.nditer(canopy.layer_heights)) + for l, val in enumerate(np.nditer(canopy_ppa.layer_heights)) ] -ax_rhs.set_yticks(canopy.layer_heights.flatten()) +ax_rhs.set_yticks(canopy_ppa.layer_heights.flatten()) ax_rhs.set_yticklabels(z_star_labels) # Add cumulative canopy area at top @@ -514,15 +449,17 @@ ax.set_xlabel("Community-wide projected area (m2)") ax.legend(frameon=False) ``` +## Light allocation + ```{code-cell} ipython3 ppfd = 1000 -ppfd_layer = -np.diff(ppfd * np.cumprod(canopy.layer_f_trans), prepend=ppfd) +ppfd_layer = -np.diff(ppfd * np.cumprod(canopy_ppa.layer_f_trans), prepend=ppfd) ppfd_layer ``` ```{code-cell} ipython3 -(1 - canopy.layer_cohort_f_trans) * ppfd_layer[:, None] +(1 - canopy_ppa.layer_cohort_f_trans) * ppfd_layer[:, None] ``` ## Things to worry about later diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 7271fb93..dd38854c 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -193,7 +193,7 @@ def __init__( community: Community, layer_heights: NDArray[np.float32] | None = None, fit_ppa: bool = False, - canopy_gap_fraction: float = 0.05, + canopy_gap_fraction: float = 0, solver_tolerance: float = 0.001, ) -> None: # Store required init vars @@ -204,9 +204,9 @@ def __init__( # Define class attributes self.total_community_crown_area: float - """Total crown area across individuals in the community (metres 2).""" + """Total crown area across all individuals in the community (m2).""" self.max_stem_height: float - """Maximum height of any individual in the community (metres).""" + """Maximum height of any individual in the community (m).""" self.n_layers: int """Total number of canopy layers.""" self.n_cohorts: int @@ -231,7 +231,8 @@ def __init__( """The canopy-wide fAPAR profile by layer.""" self.stem_fapar: NDArray[np.float32] """The fAPAR for individual stems by layer.""" - + self.filled_community_area: float + """The area filled by crown.""" # Check operating mode if fit_ppa ^ (layer_heights is None): raise ValueError("Either set fit_ppa=True or provide layer heights.") @@ -239,6 +240,9 @@ def __init__( # Set simple attributes self.max_stem_height = community.stem_allometry.stem_height.max() self.n_cohorts = community.number_of_cohorts + self.filled_community_area = community.cell_area * ( + 1 - self.canopy_gap_fraction + ) # Populate layer heights if layer_heights is not None: @@ -280,12 +284,12 @@ def _calculate_canopy(self, community: Community) -> None: # Calculate the leaf area index per layer per stem, using the stem # specific leaf area index values. LAI is a value per m2, so scale back down by - # the community area. + # the available community area. self.layer_cohort_lai = ( self.layer_stem_leaf_area * community.cohort_data["n_individuals"] * community.stem_traits.lai - ) / community.cell_area + ) / community.cell_area # self.filled_community_area # Calculate the Beer-Lambert light transmission component per layer and cohort self.layer_cohort_f_trans = np.exp( diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index 7d5f7665..ac9dac50 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -77,7 +77,9 @@ def _validate_z_qz_args( # Now test q_z congruence with z if provided if q_z is not None: - if ((z.size == 1) or (z.ndim == 1)) and (q_z.shape != stem_shape): + if q_z.shape == z.shape: + pass + elif ((z.size == 1) or (z.ndim == 1)) and (q_z.shape != stem_shape): raise ValueError( f"The q_z argument (shape: {q_z.shape}) is not a row array " f"matching stem properties (shape: {stem_shape})" @@ -198,7 +200,7 @@ def calculate_stem_projected_crown_area_at_z( crown_area: Crown area of each stem stem_height: Stem height of each stem q_m: Canopy shape parameter ``q_m``` for each stem - z_max: Height of maximum crown radous for each stem + z_max: Height of maximum crown radi `us for each stem validate: Boolean flag to suppress argument validation. """ From 42d8106dfc66ca14abbe1f6cad6251854abccfc4 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 10 Oct 2024 15:58:57 +0100 Subject: [PATCH 220/241] Doc build fixes --- pyrealm/demography/crown.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index ac9dac50..00f0019b 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -200,7 +200,7 @@ def calculate_stem_projected_crown_area_at_z( crown_area: Crown area of each stem stem_height: Stem height of each stem q_m: Canopy shape parameter ``q_m``` for each stem - z_max: Height of maximum crown radi `us for each stem + z_max: Height of maximum crown radius for each stem validate: Boolean flag to suppress argument validation. """ From a57287ce41c8938079a82e9ed917d7c4df49f612 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 11 Oct 2024 13:40:03 +0100 Subject: [PATCH 221/241] Updating canopy docs --- docs/source/users/demography/canopy.md | 176 +++++++++++++++++++++---- 1 file changed, 151 insertions(+), 25 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index 2a1fa595..6894f11c 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -19,6 +19,8 @@ language_info: nbconvert_exporter: python pygments_lexer: ipython3 version: 3.11.9 +settings: + output_matplotlib_strings: remove --- # The canopy model @@ -152,6 +154,8 @@ The plot below shows: 4. The light extinction profile through the canopy. ```{code-cell} ipython3 +:tags: [hide-input] + fig, (ax1, ax2, ax3, ax4) = plt.subplots(ncols=4, sharey=True, figsize=(12, 6)) # Generate plot structures for stem profiles @@ -233,11 +237,14 @@ short_pft = PlantFunctionalType( h_max=15, m=1.5, n=1.5, + par_ext=0.4, f_g=0, ca_ratio=380, lai=4, ) -tall_pft = PlantFunctionalType(name="tall", h_max=30, m=3, n=1.5, f_g=0.2, ca_ratio=500) +tall_pft = PlantFunctionalType( + name="tall", h_max=30, m=3, n=1.5, par_ext=0.6, f_g=0.2, ca_ratio=500 +) # Create the flora flora = Flora([short_pft, tall_pft]) @@ -318,11 +325,20 @@ ax3.set_xlabel("Light absorption fraction (-)") # Plot the light extinction profile through the canopy. ax4.plot(canopy.extinction_profile, hghts, color="grey") -ax4.set_xlabel("Cumulative light\nabsorption fraction (-)") +_ = ax4.set_xlabel("Cumulative light\nabsorption fraction (-)") ``` ## Canopy closure and canopy gap fraction +:::{admonition} TODO + +Need to work out how to include the gap fraction in the calculation of light extinction +because at the moment, the gap fraction in the PPA calculates the layer closure heights +accounting for that, but the LAI is not accounting for it so there is no shift in the +light extinction profile. + +::: + In addition to calculating profiles from a provided sequence of vertical heights, the canopy model also implements the calculation of canopy layers, following the perfect plasticity approximation (PPA) {cite}`purves:2008a`. This model divides the vertical @@ -369,10 +385,20 @@ $$ canopy_ppa = Canopy(community=community, canopy_gap_fraction=0, fit_ppa=True) ``` +The `canopy_ppa.layer_heights` attribute now contains the heights at which the PPA +layers close: + ```{code-cell} ipython3 canopy_ppa.layer_heights ``` +And the final value in the canopy extinction profile still matches the expectation from +above: + +```{code-cell} ipython3 +print(canopy_ppa.extinction_profile[-1]) +``` + ### Visualizing layer closure heights and areas We can use the crown profile calculated for the previous canopy model to calculate a @@ -400,23 +426,25 @@ to confirm that the calculated values coincide with the profile. Note here that total area at each closed layer height is omitting the community gap fraction. ```{code-cell} ipython3 -fig, ax = plt.subplots(ncols=1) +fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True, figsize=(12, 6)) # Calculate the crown area at which each canopy layer closes. closure_areas = ( np.arange(1, len(canopy_ppa.layer_heights) + 1) * canopy.filled_community_area ) +# LH plot - projected leaf area with height. + # Add lines showing the canopy closure heights and closure areas. for val in canopy_ppa.layer_heights: - ax.axhline(val, color="red", linewidth=0.5, zorder=0) + ax1.axhline(val, color="red", linewidth=0.5, zorder=0) for val in closure_areas: - ax.axvline(val, color="red", linewidth=0.5, zorder=0) + ax1.axvline(val, color="red", linewidth=0.5, zorder=0) # Show the community projected crown area profile -ax.plot(community_crown_area, canopy.layer_heights, zorder=1, label="Crown area") -ax.plot( +ax1.plot(community_crown_area, canopy.layer_heights, zorder=1, label="Crown area") +ax1.plot( community_leaf_area, canopy.layer_heights, zorder=1, @@ -426,42 +454,140 @@ ax.plot( label="Leaf area", ) +# Add cumulative canopy area at top +ax1_top = ax1.twiny() +ax1_top.set_xlim(ax1.get_xlim()) +area_labels = [f"$A_{l + 1}$ = {z:.1f}" for l, z in enumerate(np.nditer(closure_areas))] +ax1_top.set_xticks(closure_areas) +ax1_top.set_xticklabels(area_labels, rotation=90) + +ax1.set_ylabel("Vertical height ($z$, m)") +ax1.set_xlabel("Community-wide projected area (m2)") +ax1.legend(frameon=False) + +# RH plot - light extinction +for val in canopy_ppa.layer_heights: + ax2.axhline(val, color="red", linewidth=0.5, zorder=0) + +for val in canopy_ppa.extinction_profile: + ax2.axvline(val, color="red", linewidth=0.5, zorder=0) + +ax2.plot(canopy.extinction_profile, hghts) + +ax2_top = ax2.twiny() +ax2_top.set_xlim(ax2.get_xlim()) +extinction_labels = [ + f"$f_{{abs{l + 1}}}$ = {z:.3f}" + for l, z in enumerate(np.nditer(canopy_ppa.extinction_profile)) +] +ax2_top.set_xticks(canopy_ppa.extinction_profile) +ax2_top.set_xticklabels(extinction_labels, rotation=90) + +ax2.set_xlabel("Light extinction (-)") # Add z* values on the righthand axis -ax_rhs = ax.twinx() -ax_rhs.set_ylim(ax.get_ylim()) +ax2_rhs = ax2.twinx() +ax2_rhs.set_ylim(ax2.get_ylim()) z_star_labels = [ f"$z^*_{l + 1} = {val:.2f}$" for l, val in enumerate(np.nditer(canopy_ppa.layer_heights)) ] -ax_rhs.set_yticks(canopy_ppa.layer_heights.flatten()) -ax_rhs.set_yticklabels(z_star_labels) +ax2_rhs.set_yticks(canopy_ppa.layer_heights.flatten()) +_ = ax2_rhs.set_yticklabels(z_star_labels) +``` -# Add cumulative canopy area at top -ax_top = ax.twiny() -ax_top.set_xlim(ax.get_xlim()) -area_labels = [f"$A_{l + 1}$ = {z:.1f}" for l, z in enumerate(np.nditer(closure_areas))] -ax_top.set_xticks(closure_areas) -ax_top.set_xticklabels(area_labels) +## Light allocation + +In order to use the light extinction with the P Model, we need to calculate the +photosynthetic photon flux density (PPFD) captured within each layer and each cohort. +The steps below show this partitioning process for the PPA layers calculated above. + +1. Calculate the fraction of light transmitted $f_{tr}$ through each layer for each + cohort. The two arrays below show the extinction coefficients for the PFT of each + cohort and then the cohort LAI ($L_H$, columns) components within each layer (rows). + The transmission through each component is then $f_{tr}=e^{-kL_H}$. -ax.set_ylabel("Vertical height ($z$, m)") -ax.set_xlabel("Community-wide projected area (m2)") -ax.legend(frameon=False) +```{code-cell} ipython3 +print("k = \n", community.stem_traits.par_ext, "\n") +print("L_H = \n", canopy_ppa.layer_cohort_lai) ``` -## Light allocation +```{code-cell} ipython3 +layer_cohort_f_tr = np.exp(-community.stem_traits.par_ext * canopy_ppa.layer_cohort_lai) +print(layer_cohort_f_tr) +``` + +The fraction absorbed $f_{abs} = 1 - f_{tr}$. ```{code-cell} ipython3 -ppfd = 1000 +layer_cohort_f_abs = 1 - layer_cohort_f_tr +print(layer_cohort_f_abs) +``` + +These matrices show that there is complete transmission ($f_{abs} = 0, f_{tr} = 1$) +where a given stem has no leaf area within the layer but otherwise the leaves of each +stem absorb some light. + +If we want to calculate the total transmission within each layer, we need to sum the +individual cohort contributions within the exponent: + +```{code-cell} ipython3 +np.exp(np.sum(-community.stem_traits.par_ext * canopy_ppa.layer_cohort_lai, axis=1)) +``` + +Or alternatively, take the product within layers of the cohort components: + +```{code-cell} ipython3 +layer_f_tr = np.prod(layer_cohort_f_tr, axis=1) +print(layer_f_tr) +``` + +From that we can calculate $f_{abs} for each layer. + +```{code-cell} ipython3 +layer_f_abs = 1 - layer_f_tr +print(layer_f_abs) +``` -ppfd_layer = -np.diff(ppfd * np.cumprod(canopy_ppa.layer_f_trans), prepend=ppfd) -ppfd_layer +We can also calculate the cumulative fraction of light transmitted through the layers: + +```{code-cell} ipython3 +transmission_profile = np.cumprod(layer_f_tr) +print(transmission_profile) +``` + +And then the extinction profile: + +```{code-cell} ipython3 +extinction_profile = 1 - transmission_profile +print(extinction_profile) +``` + +The last thing to do is then calculate how much light is absorbed within each cohort. +The light can be partitioned into the light absorbed within each layer and reaching the +ground as follows: + +```{code-cell} ipython3 +ppfd = 1000 +ppfd_layer = -np.diff(ppfd * transmission_profile, prepend=ppfd, append=0) +print(ppfd_layer) ``` +The cumulative sum across those quantities accounts for all of the incoming light and +matches the scaling of the extinction profile: + ```{code-cell} ipython3 -(1 - canopy_ppa.layer_cohort_f_trans) * ppfd_layer[:, None] +print(np.cumsum(ppfd_layer)) ``` +:::{admonition} TODO + +Now need to work out what the correct partition is of this within cohorts. It might +simply be weighted by relative $f_{abs}$ by cohort (i.e. `layer_cohort_f_abs`) but I'm +not 100% convinced! + +::: + ## Things to worry about later Herbivory - leaf fall (transmission increases, truncate at 0, replace from NSCs) vs leaf From 9d920b1e9002177fe21f7999270484d1a28da90d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:59:32 +0000 Subject: [PATCH 222/241] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/source/api/constants_api.md | 1 + docs/source/api/core_api.md | 1 + docs/source/api/demography_api.md | 1 + docs/source/api/pmodel_api.md | 1 + docs/source/api/splash_api.md | 1 + docs/source/api/tmodel_api.md | 1 + docs/source/development/code_qa_and_typing.md | 1 + docs/source/development/code_testing.md | 1 + docs/source/development/documentation.md | 1 + docs/source/development/github_actions.md | 1 + docs/source/development/overview.md | 1 + .../development/profiling_and_benchmarking.md | 1 + docs/source/development/pyrealm_build_data.md | 1 + docs/source/development/release_process.md | 1 + docs/source/index.md | 1 + docs/source/users/constants.md | 1 + docs/source/users/demography/community.md | 1 + docs/source/users/demography/flora.md | 1 + .../users/demography/module_overview.md | 1 + docs/source/users/demography/t_model.md | 1 + docs/source/users/hygro.md | 1 + docs/source/users/pmodel/c3c4model.md | 1 + .../users/pmodel/isotopic_discrimination.md | 1 + docs/source/users/pmodel/module_overview.md | 1 + .../pmodel_details/envt_variation_outputs.md | 1 + .../pmodel/pmodel_details/extreme_values.md | 6 +---- .../pmodel/pmodel_details/jmax_limitation.md | 1 + .../pmodel/pmodel_details/optimal_chi.md | 1 + .../photosynthetic_environment.md | 1 + .../pmodel/pmodel_details/pmodel_overview.md | 1 + .../pmodel/pmodel_details/quantum_yield.md | 1 + .../users/pmodel/pmodel_details/rpmodel.md | 1 + .../pmodel/pmodel_details/soil_moisture.md | 1 + .../pmodel/pmodel_details/worked_examples.md | 25 +------------------ .../pmodel/subdaily_details/acclimation.md | 1 + .../subdaily_details/subdaily_calculations.md | 24 +----------------- .../subdaily_model_and_missing_data.md | 1 + .../subdaily_details/subdaily_overview.md | 1 + .../pmodel/subdaily_details/worked_example.md | 21 +--------------- docs/source/users/splash.md | 1 + docs/source/users/tmodel/canopy.md | 1 + docs/source/users/tmodel/tmodel.md | 1 + 42 files changed, 42 insertions(+), 72 deletions(-) diff --git a/docs/source/api/constants_api.md b/docs/source/api/constants_api.md index 1b992418..80bd4ba2 100644 --- a/docs/source/api/constants_api.md +++ b/docs/source/api/constants_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/core_api.md b/docs/source/api/core_api.md index 1324720e..89843589 100644 --- a/docs/source/api/core_api.md +++ b/docs/source/api/core_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/demography_api.md b/docs/source/api/demography_api.md index 9290a0b0..6700bad9 100644 --- a/docs/source/api/demography_api.md +++ b/docs/source/api/demography_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/pmodel_api.md b/docs/source/api/pmodel_api.md index 9bb4f669..0d385f1f 100644 --- a/docs/source/api/pmodel_api.md +++ b/docs/source/api/pmodel_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/splash_api.md b/docs/source/api/splash_api.md index fe55c923..e8177ab3 100644 --- a/docs/source/api/splash_api.md +++ b/docs/source/api/splash_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/tmodel_api.md b/docs/source/api/tmodel_api.md index b7fa9312..d74b7989 100644 --- a/docs/source/api/tmodel_api.md +++ b/docs/source/api/tmodel_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/code_qa_and_typing.md b/docs/source/development/code_qa_and_typing.md index 848f7a5c..b951cd8a 100644 --- a/docs/source/development/code_qa_and_typing.md +++ b/docs/source/development/code_qa_and_typing.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/code_testing.md b/docs/source/development/code_testing.md index 43829394..9d126f5a 100644 --- a/docs/source/development/code_testing.md +++ b/docs/source/development/code_testing.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/documentation.md b/docs/source/development/documentation.md index 0ce6b2f8..cbe8cc3f 100644 --- a/docs/source/development/documentation.md +++ b/docs/source/development/documentation.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/github_actions.md b/docs/source/development/github_actions.md index d26a7452..fda8ad3d 100644 --- a/docs/source/development/github_actions.md +++ b/docs/source/development/github_actions.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/overview.md b/docs/source/development/overview.md index 837b1efe..72207d53 100644 --- a/docs/source/development/overview.md +++ b/docs/source/development/overview.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/profiling_and_benchmarking.md b/docs/source/development/profiling_and_benchmarking.md index d705d43f..ccafd4f3 100644 --- a/docs/source/development/profiling_and_benchmarking.md +++ b/docs/source/development/profiling_and_benchmarking.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/pyrealm_build_data.md b/docs/source/development/pyrealm_build_data.md index b59ec2b2..0f9dd7c1 100644 --- a/docs/source/development/pyrealm_build_data.md +++ b/docs/source/development/pyrealm_build_data.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/release_process.md b/docs/source/development/release_process.md index e9ff6b00..9396484c 100644 --- a/docs/source/development/release_process.md +++ b/docs/source/development/release_process.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/index.md b/docs/source/index.md index 43aef59b..10234635 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/constants.md b/docs/source/users/constants.md index 899076b3..7997e3a9 100644 --- a/docs/source/users/constants.md +++ b/docs/source/users/constants.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/demography/community.md b/docs/source/users/demography/community.md index 0961b8e2..15dd5954 100644 --- a/docs/source/users/demography/community.md +++ b/docs/source/users/demography/community.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index 4b9bf3f7..541ad5e2 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/demography/module_overview.md b/docs/source/users/demography/module_overview.md index e2aaceab..f4d2e47c 100644 --- a/docs/source/users/demography/module_overview.md +++ b/docs/source/users/demography/module_overview.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/demography/t_model.md b/docs/source/users/demography/t_model.md index 23510daa..f23fcbc7 100644 --- a/docs/source/users/demography/t_model.md +++ b/docs/source/users/demography/t_model.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/hygro.md b/docs/source/users/hygro.md index a235875e..39322beb 100644 --- a/docs/source/users/hygro.md +++ b/docs/source/users/hygro.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/c3c4model.md b/docs/source/users/pmodel/c3c4model.md index ac4ba204..4a400e50 100644 --- a/docs/source/users/pmodel/c3c4model.md +++ b/docs/source/users/pmodel/c3c4model.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/isotopic_discrimination.md b/docs/source/users/pmodel/isotopic_discrimination.md index 574b2f67..5020de17 100644 --- a/docs/source/users/pmodel/isotopic_discrimination.md +++ b/docs/source/users/pmodel/isotopic_discrimination.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/module_overview.md b/docs/source/users/pmodel/module_overview.md index 04c29687..26d69734 100644 --- a/docs/source/users/pmodel/module_overview.md +++ b/docs/source/users/pmodel/module_overview.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md b/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md index e7364837..eae62e95 100644 --- a/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md +++ b/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/extreme_values.md b/docs/source/users/pmodel/pmodel_details/extreme_values.md index 7119ac7f..b9d28fcc 100644 --- a/docs/source/users/pmodel/pmodel_details/extreme_values.md +++ b/docs/source/users/pmodel/pmodel_details/extreme_values.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -53,7 +54,6 @@ Note that the default values for C3 photosynthesis give **non-zero values below ```{code-cell} :tags: [hide-input] -:trusted: true from matplotlib import pyplot import numpy as np @@ -93,7 +93,6 @@ that again, $\Gamma^_$ has non-zero values for sub-zero temperatures. ```{code-cell} :tags: [hide-input] -:trusted: true # Calculate gammastar at different pressures tc_1d = np.linspace(-80, 100, n_pts) @@ -119,7 +118,6 @@ temperature and atmospheric pressure and again behaves smoothly with extreme val ```{code-cell} :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) @@ -144,7 +142,6 @@ issue with low temperatures arising from the equations for the density of water. ```{code-cell} :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) @@ -169,7 +166,6 @@ predictions below about -30 °C. ```{code-cell} :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) diff --git a/docs/source/users/pmodel/pmodel_details/jmax_limitation.md b/docs/source/users/pmodel/pmodel_details/jmax_limitation.md index 5e07802f..84b22e97 100644 --- a/docs/source/users/pmodel/pmodel_details/jmax_limitation.md +++ b/docs/source/users/pmodel/pmodel_details/jmax_limitation.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/pmodel/pmodel_details/optimal_chi.md b/docs/source/users/pmodel/pmodel_details/optimal_chi.md index fb22b49e..4c794fe0 100644 --- a/docs/source/users/pmodel/pmodel_details/optimal_chi.md +++ b/docs/source/users/pmodel/pmodel_details/optimal_chi.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md b/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md index cedd27fe..adbbca1a 100644 --- a/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md +++ b/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md index 9626ee98..1343a4b5 100644 --- a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md +++ b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/pmodel/pmodel_details/quantum_yield.md b/docs/source/users/pmodel/pmodel_details/quantum_yield.md index 92a3ae8c..dd6e3600 100644 --- a/docs/source/users/pmodel/pmodel_details/quantum_yield.md +++ b/docs/source/users/pmodel/pmodel_details/quantum_yield.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/pmodel/pmodel_details/rpmodel.md b/docs/source/users/pmodel/pmodel_details/rpmodel.md index 7e691cc2..f2b4eb93 100644 --- a/docs/source/users/pmodel/pmodel_details/rpmodel.md +++ b/docs/source/users/pmodel/pmodel_details/rpmodel.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/soil_moisture.md b/docs/source/users/pmodel/pmodel_details/soil_moisture.md index 2b4b8a53..afe55613 100644 --- a/docs/source/users/pmodel/pmodel_details/soil_moisture.md +++ b/docs/source/users/pmodel/pmodel_details/soil_moisture.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/worked_examples.md b/docs/source/users/pmodel/pmodel_details/worked_examples.md index f3db6947..ccd1d0c8 100644 --- a/docs/source/users/pmodel/pmodel_details/worked_examples.md +++ b/docs/source/users/pmodel/pmodel_details/worked_examples.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -39,8 +40,6 @@ The example shows the steps required using a single site with: ### Estimate photosynthetic environment ```{code-cell} -:trusted: true - from importlib import resources from matplotlib import pyplot as plt @@ -61,14 +60,10 @@ terse - just the shape of the data - but the more detailed summary of the attributes. ```{code-cell} -:trusted: true - env ``` ```{code-cell} -:trusted: true - env.summarize() ``` @@ -78,8 +73,6 @@ Next, the P Model can be fitted to the photosynthetic environment using the ({class}`~pyrealm.pmodel.pmodel.PModel`) class: ```{code-cell} -:trusted: true - model = PModel(env) ``` @@ -87,8 +80,6 @@ The returned model object holds a lot of information. The representation of the model object shows a terse display of the settings used to run the model: ```{code-cell} -:trusted: true - model ``` @@ -99,8 +90,6 @@ photosynthetic efficiency: the intrinsic water use efficiency (``iwue``) and the use efficiency (``lue``). ```{code-cell} -:trusted: true - model.summarize() ``` @@ -113,8 +102,6 @@ This object also has a {meth}`~pyrealm.pmodel.optimal_chi.OptimalChiABC.summariz method: ```{code-cell} -:trusted: true - model.optchi.summarize() ``` @@ -131,8 +118,6 @@ Here we are using: * a PPFD of 834 µmol m-2 s-1. ```{code-cell} -:trusted: true - model.estimate_productivity(fapar=0.91, ppfd=834) model.summarize() ``` @@ -165,8 +150,6 @@ to be the same size so some of the variables have repeated data across dimension * Elevation is constant across months, so the data for each month is repeated. ```{code-cell} -:trusted: true - # Load an example dataset containing the forcing variables. data_path = resources.files("pyrealm_build_data.rpmodel") / "pmodel_global.nc" ds = xarray.load_dataset(data_path) @@ -186,8 +169,6 @@ data to atmospheric pressure, and then this is used to set the photosynthetic environment for the model: ```{code-cell} -:trusted: true - # Convert elevation to atmospheric pressure patm = calc_patm(elev) @@ -206,8 +187,6 @@ That environment can then be run to calculate the P model predictions for light efficiency: ```{code-cell} -:trusted: true - # Run the P model model = PModel(env) @@ -221,8 +200,6 @@ Finally, the light use efficiency can be used to calculate GPP given the photosynthetic photon flux density and fAPAR. ```{code-cell} -:trusted: true - # Scale the outputs from values per unit iabs to realised values model.estimate_productivity(fapar, ppfd) diff --git a/docs/source/users/pmodel/subdaily_details/acclimation.md b/docs/source/users/pmodel/subdaily_details/acclimation.md index 193b38f9..09512e49 100644 --- a/docs/source/users/pmodel/subdaily_details/acclimation.md +++ b/docs/source/users/pmodel/subdaily_details/acclimation.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md index 1a134c84..f16c6831 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -21,7 +22,6 @@ are handled internally by the model fitting in `pyrealm`. ```{code-cell} :tags: [hide-input] -:trusted: true from importlib import resources @@ -48,8 +48,6 @@ site](https://fluxnet.org/doi/FLUXNET2015/BE-Vie), which was also used as a demonstration in {cite:t}`mengoli:2022a`. ```{code-cell} -:trusted: true - data_path = resources.files("pyrealm_build_data.subdaily") / "subdaily_BE_Vie_2014.csv" data = pandas.read_csv(str(data_path)) @@ -71,8 +69,6 @@ subdaily timescale. The code below also estimates GPP under the standard P Model slow responses for comparison. ```{code-cell} -:trusted: true - # Calculate the photosynthetic environment subdaily_env = PModelEnvironment( tc=temp_subdaily, @@ -99,8 +95,6 @@ conditions at the observation closest to noon, or the mean environmental conditi window around noon. ```{code-cell} -:trusted: true - # Create the fast slow scaler fsscaler = SubdailyScaler(datetime_subdaily) @@ -122,7 +116,6 @@ pmodel_subdaily = SubdailyPModel( ```{code-cell} :tags: [hide-input] -:trusted: true idx = np.arange(48 * 120, 48 * 130) plt.figure(figsize=(10, 4)) @@ -146,8 +139,6 @@ inputs to the standard P Model to calculate the optimal behaviour of plants unde conditions. ```{code-cell} -:trusted: true - # Get the daily acclimation conditions for the forcing variables temp_acclim = fsscaler.get_daily_means(temp_subdaily) co2_acclim = fsscaler.get_daily_means(co2_subdaily) @@ -179,8 +170,6 @@ at 25°C. This is acheived by multiplying by the reciprocal of the exponential p the Arrhenius equation ($h^{-1}$ in {cite}`mengoli:2022a`). ```{code-cell} -:trusted: true - # Are these any of the existing values in the constants? ha_vcmax25 = 65330 ha_jmax25 = 43900 @@ -196,8 +185,6 @@ The memory effect can now be applied to the three parameters with slow responses to calculate realised values, here using the default 15 day window. ```{code-cell} -:trusted: true - # Calculation of memory effect in xi, vcmax25 and jmax25 xi_real = memory_effect(pmodel_acclim.optchi.xi, alpha=1 / 15) vcmax25_real = memory_effect(vcmax25_acclim, alpha=1 / 15, allow_holdover=True) @@ -210,7 +197,6 @@ application of the memory effect. ```{code-cell} :tags: [hide-input] -:trusted: true fig, axes = plt.subplots(1, 3, figsize=(16, 5)) @@ -244,8 +230,6 @@ temperature at fast scales: responses of $J_{max}$ and $V_{cmax}$. ```{code-cell} -:trusted: true - tk_subdaily = subdaily_env.tc + pmodel_subdaily.env.core_const.k_CtoK # Fill the realised jmax and vcmax from subdaily to daily @@ -266,8 +250,6 @@ optimal $\chi$, rather than calculating the instantaneously optimal values of $\ as is the case in the standard P Model. ```{code-cell} -:trusted: true - # Interpolate xi to subdaily scale xi_subdaily = fsscaler.fill_daily_to_subdaily(xi_real) @@ -287,8 +269,6 @@ include the slow responses of $V_{cmax25}$ and $J_{max25}$ and fast responses to temperature. ```{code-cell} -:trusted: true - # Calculate Ac Ac_subdaily = ( vcmax_subdaily @@ -319,7 +299,5 @@ print(np.nanmin(diff), np.nanmax(diff)) ``` ```{code-cell} -:trusted: true - ``` diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md b/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md index 881f71b8..5f1e995b 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_overview.md b/docs/source/users/pmodel/subdaily_details/subdaily_overview.md index 3278b056..31234000 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_overview.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_overview.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/worked_example.md b/docs/source/users/pmodel/subdaily_details/worked_example.md index fac12b6a..4d60302d 100644 --- a/docs/source/users/pmodel/subdaily_details/worked_example.md +++ b/docs/source/users/pmodel/subdaily_details/worked_example.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -14,8 +15,6 @@ kernelspec: # Worked example of the Subdaily P Model ```{code-cell} -:trusted: true - from importlib import resources import xarray @@ -61,8 +60,6 @@ The test data use some UK WFDE data for three sites in order to compare predicti over a time series. ```{code-cell} -:trusted: true - # Loading the example dataset: dpath = ( resources.files("pyrealm_build_data.uk_data") / "UK_WFDE5_FAPAR_2018_JuneJuly.nc" @@ -84,8 +81,6 @@ The WFDE data need some conversion for use in the PModel, along with the definit the atmospheric CO2 concentration. ```{code-cell} -:trusted: true - # Variable set up # Air temperature in °C from Tair in Kelvin tc = (ds["Tair"] - 273.15).to_numpy() @@ -105,8 +100,6 @@ co2 = np.ones_like(tc) * 400 The code below then calculates the photosynthetic environment. ```{code-cell} -:trusted: true - # Generate and check the PModelEnvironment pm_env = PModelEnvironment(tc=tc, patm=patm, vpd=vpd, co2=co2) pm_env.summarize() @@ -118,8 +111,6 @@ The standard implementation of the P Model used below assumes that plants can instantaneously adopt optimal behaviour. ```{code-cell} -:trusted: true - # Standard PModels pmodC3 = PModel( env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="prentice14" @@ -129,8 +120,6 @@ pmodC3.summarize() ``` ```{code-cell} -:trusted: true - pmodC4 = PModel( env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="c4_no_gamma" ) @@ -147,8 +136,6 @@ calculations: essentially the plant does not acclimate until the optimal values calculated again to update those realised estimates. ```{code-cell} -:trusted: true - # Set the acclimation window to an hour either side of noon fsscaler = SubdailyScaler(datetimes) fsscaler.set_window( @@ -188,8 +175,6 @@ shown above and plots the instantaneous predictions against predictions includin photosynthetic responses. ```{code-cell} -:trusted: true - # Store the predictions in the xarray Dataset to use indexing ds["GPP_pmodC3"] = (ds["Tair"].dims, pmodC3.gpp) ds["GPP_subdailyC3"] = (ds["Tair"].dims, subdailyC3.gpp) @@ -247,8 +232,6 @@ The subdaily models can also be obtained directly from the standard models, usin `convert_pmodel_to_subdaily` method: ```{code-cell} -:trusted: true - # Convert standard C3 model converted_C3 = convert_pmodel_to_subdaily( pmodel=pmodC3, @@ -270,8 +253,6 @@ This produces the same outputs as the `SubdailyPModel` class, but is convenient compact when the two models are going to be compared. ```{code-cell} -:trusted: true - # Models have identical GPP - maximum absolute difference is zero. print(np.nanmax(abs(subdailyC3.gpp.flatten() - converted_C3.gpp.flatten()))) print(np.nanmax(abs(subdailyC4.gpp.flatten() - converted_C4.gpp.flatten()))) diff --git a/docs/source/users/splash.md b/docs/source/users/splash.md index e5c4d283..e852f49c 100644 --- a/docs/source/users/splash.md +++ b/docs/source/users/splash.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/tmodel/canopy.md b/docs/source/users/tmodel/canopy.md index 3fab2df8..b5e49112 100644 --- a/docs/source/users/tmodel/canopy.md +++ b/docs/source/users/tmodel/canopy.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/tmodel/tmodel.md b/docs/source/users/tmodel/tmodel.md index fda39de0..ca6c5eec 100644 --- a/docs/source/users/tmodel/tmodel.md +++ b/docs/source/users/tmodel/tmodel.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python From 0339465c5976943a4bb7cbfee784c44043c53a22 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 11 Oct 2024 15:16:13 +0100 Subject: [PATCH 223/241] Fix mypy issue --- docs/source/api/constants_api.md | 1 + docs/source/api/core_api.md | 1 + docs/source/api/demography_api.md | 1 + docs/source/api/pmodel_api.md | 1 + docs/source/api/splash_api.md | 1 + docs/source/api/tmodel_api.md | 1 + docs/source/development/code_qa_and_typing.md | 1 + docs/source/development/code_testing.md | 1 + docs/source/development/documentation.md | 1 + docs/source/development/github_actions.md | 1 + docs/source/development/overview.md | 1 + .../development/profiling_and_benchmarking.md | 1 + docs/source/development/pyrealm_build_data.md | 1 + docs/source/development/release_process.md | 1 + docs/source/index.md | 1 + docs/source/users/constants.md | 1 + docs/source/users/demography/community.md | 1 + docs/source/users/demography/flora.md | 1 + .../users/demography/module_overview.md | 1 + docs/source/users/demography/t_model.md | 1 + docs/source/users/hygro.md | 1 + docs/source/users/pmodel/c3c4model.md | 1 + .../users/pmodel/isotopic_discrimination.md | 1 + docs/source/users/pmodel/module_overview.md | 1 + .../pmodel_details/envt_variation_outputs.md | 1 + .../pmodel/pmodel_details/extreme_values.md | 6 +---- .../pmodel/pmodel_details/jmax_limitation.md | 1 + .../pmodel/pmodel_details/optimal_chi.md | 1 + .../photosynthetic_environment.md | 1 + .../pmodel/pmodel_details/pmodel_overview.md | 1 + .../pmodel/pmodel_details/quantum_yield.md | 1 + .../users/pmodel/pmodel_details/rpmodel.md | 1 + .../pmodel/pmodel_details/soil_moisture.md | 1 + .../pmodel/pmodel_details/worked_examples.md | 25 +------------------ .../pmodel/subdaily_details/acclimation.md | 1 + .../subdaily_details/subdaily_calculations.md | 24 +----------------- .../subdaily_model_and_missing_data.md | 1 + .../subdaily_details/subdaily_overview.md | 1 + .../pmodel/subdaily_details/worked_example.md | 21 +--------------- docs/source/users/splash.md | 1 + docs/source/users/tmodel/canopy.md | 1 + docs/source/users/tmodel/tmodel.md | 1 + pyrealm/demography/crown.py | 2 +- 43 files changed, 43 insertions(+), 73 deletions(-) diff --git a/docs/source/api/constants_api.md b/docs/source/api/constants_api.md index 1b992418..80bd4ba2 100644 --- a/docs/source/api/constants_api.md +++ b/docs/source/api/constants_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/core_api.md b/docs/source/api/core_api.md index 1324720e..89843589 100644 --- a/docs/source/api/core_api.md +++ b/docs/source/api/core_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/demography_api.md b/docs/source/api/demography_api.md index 9290a0b0..6700bad9 100644 --- a/docs/source/api/demography_api.md +++ b/docs/source/api/demography_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/pmodel_api.md b/docs/source/api/pmodel_api.md index 9bb4f669..0d385f1f 100644 --- a/docs/source/api/pmodel_api.md +++ b/docs/source/api/pmodel_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/splash_api.md b/docs/source/api/splash_api.md index fe55c923..e8177ab3 100644 --- a/docs/source/api/splash_api.md +++ b/docs/source/api/splash_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/api/tmodel_api.md b/docs/source/api/tmodel_api.md index b7fa9312..d74b7989 100644 --- a/docs/source/api/tmodel_api.md +++ b/docs/source/api/tmodel_api.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/code_qa_and_typing.md b/docs/source/development/code_qa_and_typing.md index 848f7a5c..b951cd8a 100644 --- a/docs/source/development/code_qa_and_typing.md +++ b/docs/source/development/code_qa_and_typing.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/code_testing.md b/docs/source/development/code_testing.md index 43829394..9d126f5a 100644 --- a/docs/source/development/code_testing.md +++ b/docs/source/development/code_testing.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/documentation.md b/docs/source/development/documentation.md index 0ce6b2f8..cbe8cc3f 100644 --- a/docs/source/development/documentation.md +++ b/docs/source/development/documentation.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/github_actions.md b/docs/source/development/github_actions.md index d26a7452..fda8ad3d 100644 --- a/docs/source/development/github_actions.md +++ b/docs/source/development/github_actions.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/overview.md b/docs/source/development/overview.md index 837b1efe..72207d53 100644 --- a/docs/source/development/overview.md +++ b/docs/source/development/overview.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/profiling_and_benchmarking.md b/docs/source/development/profiling_and_benchmarking.md index d705d43f..ccafd4f3 100644 --- a/docs/source/development/profiling_and_benchmarking.md +++ b/docs/source/development/profiling_and_benchmarking.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/pyrealm_build_data.md b/docs/source/development/pyrealm_build_data.md index b59ec2b2..0f9dd7c1 100644 --- a/docs/source/development/pyrealm_build_data.md +++ b/docs/source/development/pyrealm_build_data.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/development/release_process.md b/docs/source/development/release_process.md index e9ff6b00..9396484c 100644 --- a/docs/source/development/release_process.md +++ b/docs/source/development/release_process.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/index.md b/docs/source/index.md index 43aef59b..10234635 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/constants.md b/docs/source/users/constants.md index 899076b3..7997e3a9 100644 --- a/docs/source/users/constants.md +++ b/docs/source/users/constants.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/demography/community.md b/docs/source/users/demography/community.md index 0961b8e2..15dd5954 100644 --- a/docs/source/users/demography/community.md +++ b/docs/source/users/demography/community.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index 4b9bf3f7..541ad5e2 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/demography/module_overview.md b/docs/source/users/demography/module_overview.md index e2aaceab..f4d2e47c 100644 --- a/docs/source/users/demography/module_overview.md +++ b/docs/source/users/demography/module_overview.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/demography/t_model.md b/docs/source/users/demography/t_model.md index 23510daa..f23fcbc7 100644 --- a/docs/source/users/demography/t_model.md +++ b/docs/source/users/demography/t_model.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/hygro.md b/docs/source/users/hygro.md index a235875e..39322beb 100644 --- a/docs/source/users/hygro.md +++ b/docs/source/users/hygro.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/c3c4model.md b/docs/source/users/pmodel/c3c4model.md index ac4ba204..4a400e50 100644 --- a/docs/source/users/pmodel/c3c4model.md +++ b/docs/source/users/pmodel/c3c4model.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/isotopic_discrimination.md b/docs/source/users/pmodel/isotopic_discrimination.md index 574b2f67..5020de17 100644 --- a/docs/source/users/pmodel/isotopic_discrimination.md +++ b/docs/source/users/pmodel/isotopic_discrimination.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/module_overview.md b/docs/source/users/pmodel/module_overview.md index 04c29687..26d69734 100644 --- a/docs/source/users/pmodel/module_overview.md +++ b/docs/source/users/pmodel/module_overview.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md b/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md index e7364837..eae62e95 100644 --- a/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md +++ b/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/extreme_values.md b/docs/source/users/pmodel/pmodel_details/extreme_values.md index 7119ac7f..b9d28fcc 100644 --- a/docs/source/users/pmodel/pmodel_details/extreme_values.md +++ b/docs/source/users/pmodel/pmodel_details/extreme_values.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -53,7 +54,6 @@ Note that the default values for C3 photosynthesis give **non-zero values below ```{code-cell} :tags: [hide-input] -:trusted: true from matplotlib import pyplot import numpy as np @@ -93,7 +93,6 @@ that again, $\Gamma^_$ has non-zero values for sub-zero temperatures. ```{code-cell} :tags: [hide-input] -:trusted: true # Calculate gammastar at different pressures tc_1d = np.linspace(-80, 100, n_pts) @@ -119,7 +118,6 @@ temperature and atmospheric pressure and again behaves smoothly with extreme val ```{code-cell} :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) @@ -144,7 +142,6 @@ issue with low temperatures arising from the equations for the density of water. ```{code-cell} :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) @@ -169,7 +166,6 @@ predictions below about -30 °C. ```{code-cell} :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) diff --git a/docs/source/users/pmodel/pmodel_details/jmax_limitation.md b/docs/source/users/pmodel/pmodel_details/jmax_limitation.md index 5e07802f..84b22e97 100644 --- a/docs/source/users/pmodel/pmodel_details/jmax_limitation.md +++ b/docs/source/users/pmodel/pmodel_details/jmax_limitation.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/pmodel/pmodel_details/optimal_chi.md b/docs/source/users/pmodel/pmodel_details/optimal_chi.md index fb22b49e..4c794fe0 100644 --- a/docs/source/users/pmodel/pmodel_details/optimal_chi.md +++ b/docs/source/users/pmodel/pmodel_details/optimal_chi.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md b/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md index cedd27fe..adbbca1a 100644 --- a/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md +++ b/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md index 9626ee98..1343a4b5 100644 --- a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md +++ b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/pmodel/pmodel_details/quantum_yield.md b/docs/source/users/pmodel/pmodel_details/quantum_yield.md index 92a3ae8c..dd6e3600 100644 --- a/docs/source/users/pmodel/pmodel_details/quantum_yield.md +++ b/docs/source/users/pmodel/pmodel_details/quantum_yield.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/pmodel/pmodel_details/rpmodel.md b/docs/source/users/pmodel/pmodel_details/rpmodel.md index 7e691cc2..f2b4eb93 100644 --- a/docs/source/users/pmodel/pmodel_details/rpmodel.md +++ b/docs/source/users/pmodel/pmodel_details/rpmodel.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/soil_moisture.md b/docs/source/users/pmodel/pmodel_details/soil_moisture.md index 2b4b8a53..afe55613 100644 --- a/docs/source/users/pmodel/pmodel_details/soil_moisture.md +++ b/docs/source/users/pmodel/pmodel_details/soil_moisture.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/pmodel_details/worked_examples.md b/docs/source/users/pmodel/pmodel_details/worked_examples.md index f3db6947..ccd1d0c8 100644 --- a/docs/source/users/pmodel/pmodel_details/worked_examples.md +++ b/docs/source/users/pmodel/pmodel_details/worked_examples.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -39,8 +40,6 @@ The example shows the steps required using a single site with: ### Estimate photosynthetic environment ```{code-cell} -:trusted: true - from importlib import resources from matplotlib import pyplot as plt @@ -61,14 +60,10 @@ terse - just the shape of the data - but the more detailed summary of the attributes. ```{code-cell} -:trusted: true - env ``` ```{code-cell} -:trusted: true - env.summarize() ``` @@ -78,8 +73,6 @@ Next, the P Model can be fitted to the photosynthetic environment using the ({class}`~pyrealm.pmodel.pmodel.PModel`) class: ```{code-cell} -:trusted: true - model = PModel(env) ``` @@ -87,8 +80,6 @@ The returned model object holds a lot of information. The representation of the model object shows a terse display of the settings used to run the model: ```{code-cell} -:trusted: true - model ``` @@ -99,8 +90,6 @@ photosynthetic efficiency: the intrinsic water use efficiency (``iwue``) and the use efficiency (``lue``). ```{code-cell} -:trusted: true - model.summarize() ``` @@ -113,8 +102,6 @@ This object also has a {meth}`~pyrealm.pmodel.optimal_chi.OptimalChiABC.summariz method: ```{code-cell} -:trusted: true - model.optchi.summarize() ``` @@ -131,8 +118,6 @@ Here we are using: * a PPFD of 834 µmol m-2 s-1. ```{code-cell} -:trusted: true - model.estimate_productivity(fapar=0.91, ppfd=834) model.summarize() ``` @@ -165,8 +150,6 @@ to be the same size so some of the variables have repeated data across dimension * Elevation is constant across months, so the data for each month is repeated. ```{code-cell} -:trusted: true - # Load an example dataset containing the forcing variables. data_path = resources.files("pyrealm_build_data.rpmodel") / "pmodel_global.nc" ds = xarray.load_dataset(data_path) @@ -186,8 +169,6 @@ data to atmospheric pressure, and then this is used to set the photosynthetic environment for the model: ```{code-cell} -:trusted: true - # Convert elevation to atmospheric pressure patm = calc_patm(elev) @@ -206,8 +187,6 @@ That environment can then be run to calculate the P model predictions for light efficiency: ```{code-cell} -:trusted: true - # Run the P model model = PModel(env) @@ -221,8 +200,6 @@ Finally, the light use efficiency can be used to calculate GPP given the photosynthetic photon flux density and fAPAR. ```{code-cell} -:trusted: true - # Scale the outputs from values per unit iabs to realised values model.estimate_productivity(fapar, ppfd) diff --git a/docs/source/users/pmodel/subdaily_details/acclimation.md b/docs/source/users/pmodel/subdaily_details/acclimation.md index 193b38f9..09512e49 100644 --- a/docs/source/users/pmodel/subdaily_details/acclimation.md +++ b/docs/source/users/pmodel/subdaily_details/acclimation.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md index 1a134c84..f16c6831 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -21,7 +22,6 @@ are handled internally by the model fitting in `pyrealm`. ```{code-cell} :tags: [hide-input] -:trusted: true from importlib import resources @@ -48,8 +48,6 @@ site](https://fluxnet.org/doi/FLUXNET2015/BE-Vie), which was also used as a demonstration in {cite:t}`mengoli:2022a`. ```{code-cell} -:trusted: true - data_path = resources.files("pyrealm_build_data.subdaily") / "subdaily_BE_Vie_2014.csv" data = pandas.read_csv(str(data_path)) @@ -71,8 +69,6 @@ subdaily timescale. The code below also estimates GPP under the standard P Model slow responses for comparison. ```{code-cell} -:trusted: true - # Calculate the photosynthetic environment subdaily_env = PModelEnvironment( tc=temp_subdaily, @@ -99,8 +95,6 @@ conditions at the observation closest to noon, or the mean environmental conditi window around noon. ```{code-cell} -:trusted: true - # Create the fast slow scaler fsscaler = SubdailyScaler(datetime_subdaily) @@ -122,7 +116,6 @@ pmodel_subdaily = SubdailyPModel( ```{code-cell} :tags: [hide-input] -:trusted: true idx = np.arange(48 * 120, 48 * 130) plt.figure(figsize=(10, 4)) @@ -146,8 +139,6 @@ inputs to the standard P Model to calculate the optimal behaviour of plants unde conditions. ```{code-cell} -:trusted: true - # Get the daily acclimation conditions for the forcing variables temp_acclim = fsscaler.get_daily_means(temp_subdaily) co2_acclim = fsscaler.get_daily_means(co2_subdaily) @@ -179,8 +170,6 @@ at 25°C. This is acheived by multiplying by the reciprocal of the exponential p the Arrhenius equation ($h^{-1}$ in {cite}`mengoli:2022a`). ```{code-cell} -:trusted: true - # Are these any of the existing values in the constants? ha_vcmax25 = 65330 ha_jmax25 = 43900 @@ -196,8 +185,6 @@ The memory effect can now be applied to the three parameters with slow responses to calculate realised values, here using the default 15 day window. ```{code-cell} -:trusted: true - # Calculation of memory effect in xi, vcmax25 and jmax25 xi_real = memory_effect(pmodel_acclim.optchi.xi, alpha=1 / 15) vcmax25_real = memory_effect(vcmax25_acclim, alpha=1 / 15, allow_holdover=True) @@ -210,7 +197,6 @@ application of the memory effect. ```{code-cell} :tags: [hide-input] -:trusted: true fig, axes = plt.subplots(1, 3, figsize=(16, 5)) @@ -244,8 +230,6 @@ temperature at fast scales: responses of $J_{max}$ and $V_{cmax}$. ```{code-cell} -:trusted: true - tk_subdaily = subdaily_env.tc + pmodel_subdaily.env.core_const.k_CtoK # Fill the realised jmax and vcmax from subdaily to daily @@ -266,8 +250,6 @@ optimal $\chi$, rather than calculating the instantaneously optimal values of $\ as is the case in the standard P Model. ```{code-cell} -:trusted: true - # Interpolate xi to subdaily scale xi_subdaily = fsscaler.fill_daily_to_subdaily(xi_real) @@ -287,8 +269,6 @@ include the slow responses of $V_{cmax25}$ and $J_{max25}$ and fast responses to temperature. ```{code-cell} -:trusted: true - # Calculate Ac Ac_subdaily = ( vcmax_subdaily @@ -319,7 +299,5 @@ print(np.nanmin(diff), np.nanmax(diff)) ``` ```{code-cell} -:trusted: true - ``` diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md b/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md index 881f71b8..5f1e995b 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_overview.md b/docs/source/users/pmodel/subdaily_details/subdaily_overview.md index 3278b056..31234000 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_overview.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_overview.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/pmodel/subdaily_details/worked_example.md b/docs/source/users/pmodel/subdaily_details/worked_example.md index fac12b6a..4d60302d 100644 --- a/docs/source/users/pmodel/subdaily_details/worked_example.md +++ b/docs/source/users/pmodel/subdaily_details/worked_example.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python @@ -14,8 +15,6 @@ kernelspec: # Worked example of the Subdaily P Model ```{code-cell} -:trusted: true - from importlib import resources import xarray @@ -61,8 +60,6 @@ The test data use some UK WFDE data for three sites in order to compare predicti over a time series. ```{code-cell} -:trusted: true - # Loading the example dataset: dpath = ( resources.files("pyrealm_build_data.uk_data") / "UK_WFDE5_FAPAR_2018_JuneJuly.nc" @@ -84,8 +81,6 @@ The WFDE data need some conversion for use in the PModel, along with the definit the atmospheric CO2 concentration. ```{code-cell} -:trusted: true - # Variable set up # Air temperature in °C from Tair in Kelvin tc = (ds["Tair"] - 273.15).to_numpy() @@ -105,8 +100,6 @@ co2 = np.ones_like(tc) * 400 The code below then calculates the photosynthetic environment. ```{code-cell} -:trusted: true - # Generate and check the PModelEnvironment pm_env = PModelEnvironment(tc=tc, patm=patm, vpd=vpd, co2=co2) pm_env.summarize() @@ -118,8 +111,6 @@ The standard implementation of the P Model used below assumes that plants can instantaneously adopt optimal behaviour. ```{code-cell} -:trusted: true - # Standard PModels pmodC3 = PModel( env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="prentice14" @@ -129,8 +120,6 @@ pmodC3.summarize() ``` ```{code-cell} -:trusted: true - pmodC4 = PModel( env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="c4_no_gamma" ) @@ -147,8 +136,6 @@ calculations: essentially the plant does not acclimate until the optimal values calculated again to update those realised estimates. ```{code-cell} -:trusted: true - # Set the acclimation window to an hour either side of noon fsscaler = SubdailyScaler(datetimes) fsscaler.set_window( @@ -188,8 +175,6 @@ shown above and plots the instantaneous predictions against predictions includin photosynthetic responses. ```{code-cell} -:trusted: true - # Store the predictions in the xarray Dataset to use indexing ds["GPP_pmodC3"] = (ds["Tair"].dims, pmodC3.gpp) ds["GPP_subdailyC3"] = (ds["Tair"].dims, subdailyC3.gpp) @@ -247,8 +232,6 @@ The subdaily models can also be obtained directly from the standard models, usin `convert_pmodel_to_subdaily` method: ```{code-cell} -:trusted: true - # Convert standard C3 model converted_C3 = convert_pmodel_to_subdaily( pmodel=pmodC3, @@ -270,8 +253,6 @@ This produces the same outputs as the `SubdailyPModel` class, but is convenient compact when the two models are going to be compared. ```{code-cell} -:trusted: true - # Models have identical GPP - maximum absolute difference is zero. print(np.nanmax(abs(subdailyC3.gpp.flatten() - converted_C3.gpp.flatten()))) print(np.nanmax(abs(subdailyC4.gpp.flatten() - converted_C4.gpp.flatten()))) diff --git a/docs/source/users/splash.md b/docs/source/users/splash.md index e5c4d283..e852f49c 100644 --- a/docs/source/users/splash.md +++ b/docs/source/users/splash.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/docs/source/users/tmodel/canopy.md b/docs/source/users/tmodel/canopy.md index 3fab2df8..b5e49112 100644 --- a/docs/source/users/tmodel/canopy.md +++ b/docs/source/users/tmodel/canopy.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python diff --git a/docs/source/users/tmodel/tmodel.md b/docs/source/users/tmodel/tmodel.md index fda39de0..ca6c5eec 100644 --- a/docs/source/users/tmodel/tmodel.md +++ b/docs/source/users/tmodel/tmodel.md @@ -5,6 +5,7 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index 00f0019b..0f1d43ed 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -464,7 +464,7 @@ def get_crown_xy( attr_values = np.flip(attr_values, axis=0) # Collect the per stem data - crown_plotting_data: list[tuple[NDArray, NDArray]] | list[NDArray] = [] + crown_plotting_data: list = [] for stem_index in np.arange(attr_values.shape[1]): # Find the heights and values that fall within the individual stem From 848a96ef5ce97d90e2dcc7ed7c79fee167280022 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 11 Oct 2024 15:37:28 +0100 Subject: [PATCH 224/241] Fixing tests --- tests/unit/demography/conftest.py | 19 +++++++++ tests/unit/demography/test_canopy.py | 44 ++++++++++++++++++++- tests/unit/demography/test_crown.py | 58 +--------------------------- 3 files changed, 62 insertions(+), 59 deletions(-) diff --git a/tests/unit/demography/conftest.py b/tests/unit/demography/conftest.py index 5605db74..735cb4c1 100644 --- a/tests/unit/demography/conftest.py +++ b/tests/unit/demography/conftest.py @@ -63,6 +63,25 @@ def rtmodel_flora(): ) +@pytest.fixture +def fixture_community(): + """A fixture providing a simple community.""" + from pyrealm.demography.community import Community + from pyrealm.demography.flora import Flora, PlantFunctionalType + + # A simple community containing one sample stem, with an initial crown gap fraction + # of zero. + flora = Flora([PlantFunctionalType(name="test", f_g=0.0)]) + return Community( + cell_id=1, + cell_area=100, + flora=flora, + cohort_n_individuals=np.repeat([1], 4), + cohort_pft_names=np.repeat(["test"], 4), + cohort_dbh_values=np.array([0.2, 0.4, 0.6, 0.8]), + ) + + @pytest.fixture def rtmodel_data(): """Loads some simple predictions from the R implementation for testing.""" diff --git a/tests/unit/demography/test_canopy.py b/tests/unit/demography/test_canopy.py index 615f963a..33d457a5 100644 --- a/tests/unit/demography/test_canopy.py +++ b/tests/unit/demography/test_canopy.py @@ -1,6 +1,7 @@ """Testing the Canopy object.""" import numpy as np +import pytest def test_Canopy__init__(): @@ -31,7 +32,7 @@ def test_Canopy__init__(): ) canopy_gap_fraction = 0.05 - canopy = Canopy(community, canopy_gap_fraction=canopy_gap_fraction) + canopy = Canopy(community, canopy_gap_fraction=canopy_gap_fraction, fit_ppa=True) # Simply check that the shape of the stem leaf area matrix is the right shape n_layers_from_crown_area = int( @@ -46,4 +47,43 @@ def test_Canopy__init__(): / community.cell_area ) ) - assert canopy.stem_leaf_area.shape == (n_layers_from_crown_area, canopy.n_cohorts) + assert canopy.layer_stem_leaf_area.shape == ( + n_layers_from_crown_area, + canopy.n_cohorts, + ) + + +def test_solve_canopy_area_filling_height(fixture_community): + """Test solve_community_projected_canopy_area. + + The logic of this test is that given the cumulative sum of the crown areas in the + fixture from tallest to shortest as the target, providing the z_max of each stem as + the height _should_ always return zero, as this is exactly the height at which that + cumulative area would close: crown 1 closes at z_max 1, crown 1 + 2 closes at z_max + 2 and so on. + """ + + from pyrealm.demography.canopy import ( + solve_canopy_area_filling_height, + ) + + for ( + this_height, + this_target, + ) in zip( + np.flip(fixture_community.stem_allometry.crown_z_max), + np.cumsum(np.flip(fixture_community.stem_allometry.crown_area)), + ): + solved = solve_canopy_area_filling_height( + z=this_height, + stem_height=fixture_community.stem_allometry.stem_height, + crown_area=fixture_community.stem_allometry.crown_area, + n_individuals=fixture_community.cohort_data["n_individuals"], + m=fixture_community.stem_traits.m, + n=fixture_community.stem_traits.n, + q_m=fixture_community.stem_traits.q_m, + z_max=fixture_community.stem_allometry.crown_z_max, + target_area=this_target, + ) + + assert solved == pytest.approx(0) diff --git a/tests/unit/demography/test_crown.py b/tests/unit/demography/test_crown.py index 221eac2c..a7cd10ec 100644 --- a/tests/unit/demography/test_crown.py +++ b/tests/unit/demography/test_crown.py @@ -1,4 +1,4 @@ -"""test the functions in canopy_functions.py.""" +"""Test the functions in crown.py.""" from collections import namedtuple from contextlib import nullcontext as does_not_raise @@ -6,26 +6,6 @@ import numpy as np import pytest - -@pytest.fixture -def fixture_community(): - """A fixture providing a simple community.""" - from pyrealm.demography.community import Community - from pyrealm.demography.flora import Flora, PlantFunctionalType - - # A simple community containing one sample stem, with an initial crown gap fraction - # of zero. - flora = Flora([PlantFunctionalType(name="test", f_g=0.0)]) - return Community( - cell_id=1, - cell_area=100, - flora=flora, - cohort_n_individuals=np.repeat([1], 4), - cohort_pft_names=np.repeat(["test"], 4), - cohort_dbh_values=np.array([0.2, 0.4, 0.6, 0.8]), - ) - - ZQZInput = namedtuple( "ZQZInput", ["z", "stem", "more_stem", "q_z", "outcome", "excep_msg", "output_shape"], @@ -466,42 +446,6 @@ def test_calculate_stem_projected_crown_area_at_z_values( ) -def test_solve_community_projected_canopy_area(fixture_community): - """Test solve_community_projected_canopy_area. - - The logic of this test is that given the cumulative sum of the crown areas in the - fixture from tallest to shortest as the target, providing the z_max of each stem as - the height _should_ always return zero, as this is exactly the height at which that - cumulative area would close: crown 1 closes at z_max 1, crown 1 + 2 closes at z_max - 2 and so on. - """ - - from pyrealm.demography.crown import ( - solve_community_projected_canopy_area, - ) - - for ( - this_height, - this_target, - ) in zip( - np.flip(fixture_community.stem_allometry.crown_z_max), - np.cumsum(np.flip(fixture_community.stem_allometry.crown_area)), - ): - solved = solve_community_projected_canopy_area( - z=this_height, - stem_height=fixture_community.stem_allometry.stem_height, - crown_area=fixture_community.stem_allometry.crown_area, - n_individuals=fixture_community.cohort_data["n_individuals"], - m=fixture_community.stem_traits.m, - n=fixture_community.stem_traits.n, - q_m=fixture_community.stem_traits.q_m, - z_max=fixture_community.stem_allometry.crown_z_max, - target_area=this_target, - ) - - assert solved == pytest.approx(0) - - @pytest.mark.parametrize( argnames="fixture_z_qz_stem_properties", argvalues=[ From 69819e637e2a1133b260ac80d8b328078e826ae3 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 11 Oct 2024 16:01:43 +0100 Subject: [PATCH 225/241] Force matplotlib to build font cache early in conf.py --- docs/source/conf.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index 9c3a2970..2de60f86 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -12,6 +12,9 @@ from dataclasses import dataclass, field from datetime import datetime +# Import Matplotlib to avoid this message in notebooks: +# "Matplotlib is building the font cache; this may take a moment." +import matplotlib.pyplot # noqa: F401 import sphinxcontrib.bibtex.plugin from sphinxcontrib.bibtex.style.referencing import BracketStyle from sphinxcontrib.bibtex.style.referencing.author_year import AuthorYearReferenceStyle From 81fabc059f285c2abddeb4f2a2536110e5522901 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 14 Oct 2024 14:24:36 +0100 Subject: [PATCH 226/241] Revising calculations and docs for canopy --- docs/source/users/demography/canopy.md | 121 +++++++++++-------------- docs/source/users/demography/flora.md | 22 +++-- pyrealm/demography/canopy.py | 102 +++++++++++---------- 3 files changed, 125 insertions(+), 120 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index 6894f11c..f875cfa7 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -179,11 +179,11 @@ ax1.set_xlabel("Profile radius (m)") ax1.set_ylabel("Vertical height (m)") # Plot the leaf area between heights for stems -ax2.plot(simple_canopy.layer_stem_leaf_area, hghts, color="red") +ax2.plot(simple_canopy.stem_leaf_area, hghts, color="red") ax2.set_xlabel("Leaf area (m2)") # Plot the fraction of light absorbed at different heights -ax3.plot(simple_canopy.layer_f_abs, hghts, color="red") +ax3.plot(simple_canopy.f_abs, hghts, color="red") ax3.set_xlabel("Light absorption fraction (-)") # Plot the light extinction profile through the canopy. @@ -254,8 +254,8 @@ community = Community( flora=flora, cell_area=32, cell_id=1, - cohort_dbh_values=np.array([0.05, 0.20, 0.5]), - cohort_n_individuals=np.array([7, 3, 1]), + cohort_dbh_values=np.array([0.1, 0.20, 0.5]), + cohort_n_individuals=np.array([7, 3, 2]), cohort_pft_names=np.array(["short", "short", "tall"]), ) @@ -284,6 +284,8 @@ print(canopy.extinction_profile[-1]) ``` ```{code-cell} ipython3 +:tags: [hide-input] + cols = ["r", "b", "g"] mpl.rcParams["axes.prop_cycle"] = mpl.cycler(color=cols) @@ -315,12 +317,12 @@ ax1.set_xlabel("Profile radius (m)") ax1.set_ylabel("Vertical height (m)") # Plot the leaf area between heights for stems -ax2.plot(canopy.layer_stem_leaf_area, hghts) +ax2.plot(canopy.stem_leaf_area, hghts) ax2.set_xlabel("Leaf area per stem (m2)") # Plot the fraction of light absorbed at different heights -ax3.plot(canopy.layer_f_abs, hghts, color="grey") -ax3.plot(1 - canopy.layer_cohort_f_trans, hghts) +ax3.plot(canopy.f_abs, hghts, color="grey") +ax3.plot(1 - canopy.cohort_f_trans, hghts) ax3.set_xlabel("Light absorption fraction (-)") # Plot the light extinction profile through the canopy. @@ -385,11 +387,11 @@ $$ canopy_ppa = Canopy(community=community, canopy_gap_fraction=0, fit_ppa=True) ``` -The `canopy_ppa.layer_heights` attribute now contains the heights at which the PPA +The `canopy_ppa.heights` attribute now contains the heights at which the PPA layers close: ```{code-cell} ipython3 -canopy_ppa.layer_heights +canopy_ppa.heights ``` And the final value in the canopy extinction profile still matches the expectation from @@ -426,27 +428,27 @@ to confirm that the calculated values coincide with the profile. Note here that total area at each closed layer height is omitting the community gap fraction. ```{code-cell} ipython3 +:tags: [hide-input] + fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True, figsize=(12, 6)) # Calculate the crown area at which each canopy layer closes. -closure_areas = ( - np.arange(1, len(canopy_ppa.layer_heights) + 1) * canopy.filled_community_area -) +closure_areas = np.arange(1, len(canopy_ppa.heights) + 1) * canopy.filled_community_area # LH plot - projected leaf area with height. # Add lines showing the canopy closure heights and closure areas. -for val in canopy_ppa.layer_heights: +for val in canopy_ppa.heights: ax1.axhline(val, color="red", linewidth=0.5, zorder=0) for val in closure_areas: ax1.axvline(val, color="red", linewidth=0.5, zorder=0) # Show the community projected crown area profile -ax1.plot(community_crown_area, canopy.layer_heights, zorder=1, label="Crown area") +ax1.plot(community_crown_area, canopy.heights, zorder=1, label="Crown area") ax1.plot( community_leaf_area, - canopy.layer_heights, + canopy.heights, zorder=1, linestyle="--", color="black", @@ -466,7 +468,7 @@ ax1.set_xlabel("Community-wide projected area (m2)") ax1.legend(frameon=False) # RH plot - light extinction -for val in canopy_ppa.layer_heights: +for val in canopy_ppa.heights: ax2.axhline(val, color="red", linewidth=0.5, zorder=0) for val in canopy_ppa.extinction_profile: @@ -489,111 +491,96 @@ ax2.set_xlabel("Light extinction (-)") ax2_rhs = ax2.twinx() ax2_rhs.set_ylim(ax2.get_ylim()) z_star_labels = [ - f"$z^*_{l + 1} = {val:.2f}$" - for l, val in enumerate(np.nditer(canopy_ppa.layer_heights)) + f"$z^*_{l + 1} = {val:.2f}$" for l, val in enumerate(np.nditer(canopy_ppa.heights)) ] -ax2_rhs.set_yticks(canopy_ppa.layer_heights.flatten()) +ax2_rhs.set_yticks(canopy_ppa.heights.flatten()) _ = ax2_rhs.set_yticklabels(z_star_labels) ``` ## Light allocation -In order to use the light extinction with the P Model, we need to calculate the -photosynthetic photon flux density (PPFD) captured within each layer and each cohort. + + +In order to use the light extinction with the P Model, we need to calculate the fraction +of absorbed photosynthetically active radiation $f_{APAR}$ within each layer for each +cohort. These values can be multiplied by the canopy-top photosynthetic photon flux +density (PPFD) to give the actual light absorbed for photosynthesis. + The steps below show this partitioning process for the PPA layers calculated above. 1. Calculate the fraction of light transmitted $f_{tr}$ through each layer for each cohort. The two arrays below show the extinction coefficients for the PFT of each cohort and then the cohort LAI ($L_H$, columns) components within each layer (rows). - The transmission through each component is then $f_{tr}=e^{-kL_H}$. + The transmission through each component is then $f_{tr}=e^{-kL_H}$ and + $f_{abs} = 1 - f_{tr}$ . ```{code-cell} ipython3 print("k = \n", community.stem_traits.par_ext, "\n") -print("L_H = \n", canopy_ppa.layer_cohort_lai) +print("L_H = \n", canopy_ppa.cohort_lai) ``` ```{code-cell} ipython3 -layer_cohort_f_tr = np.exp(-community.stem_traits.par_ext * canopy_ppa.layer_cohort_lai) +layer_cohort_f_tr = np.exp(-community.stem_traits.par_ext * canopy_ppa.cohort_lai) print(layer_cohort_f_tr) ``` -The fraction absorbed $f_{abs} = 1 - f_{tr}$. - ```{code-cell} ipython3 layer_cohort_f_abs = 1 - layer_cohort_f_tr print(layer_cohort_f_abs) ``` -These matrices show that there is complete transmission ($f_{abs} = 0, f_{tr} = 1$) -where a given stem has no leaf area within the layer but otherwise the leaves of each -stem absorb some light. - -If we want to calculate the total transmission within each layer, we need to sum the -individual cohort contributions within the exponent: - -```{code-cell} ipython3 -np.exp(np.sum(-community.stem_traits.par_ext * canopy_ppa.layer_cohort_lai, axis=1)) -``` + These matrices show that there is complete transmission ($f_{abs} = 0, f_{tr} = 1$) + where a given stem has no leaf area within the layer but otherwise the leaves of each + stem absorb some light. -Or alternatively, take the product within layers of the cohort components: +2. Calculate the total transmission across cohorts within each layer, as the product of + the individual cohort transmission within the layers, and then the absorption within + each layer ```{code-cell} ipython3 layer_f_tr = np.prod(layer_cohort_f_tr, axis=1) print(layer_f_tr) ``` -From that we can calculate $f_{abs} for each layer. - ```{code-cell} ipython3 layer_f_abs = 1 - layer_f_tr print(layer_f_abs) ``` -We can also calculate the cumulative fraction of light transmitted through the layers: +3. Calculate the transmission and extinction profiles through the layers as the + cumulative product of light transmitted. ```{code-cell} ipython3 transmission_profile = np.cumprod(layer_f_tr) print(transmission_profile) ``` -And then the extinction profile: - ```{code-cell} ipython3 extinction_profile = 1 - transmission_profile print(extinction_profile) ``` -The last thing to do is then calculate how much light is absorbed within each cohort. -The light can be partitioned into the light absorbed within each layer and reaching the -ground as follows: +4. Calculate the fraction of light transmitted through each each layer: ```{code-cell} ipython3 -ppfd = 1000 -ppfd_layer = -np.diff(ppfd * transmission_profile, prepend=ppfd, append=0) -print(ppfd_layer) +layer_fapar = -np.diff(transmission_profile, prepend=1) +print(layer_fapar) ``` -The cumulative sum across those quantities accounts for all of the incoming light and -matches the scaling of the extinction profile: +5. Calculate the relative absorbance across cohort within each layer and then use this + to partition the light absorbed in that layer across the cohorts: ```{code-cell} ipython3 -print(np.cumsum(ppfd_layer)) +cohort_fapar = ( + layer_cohort_f_abs / layer_cohort_f_abs.sum(axis=1)[:, None] +) * layer_fapar[:, None] +print(cohort_fapar) ``` -:::{admonition} TODO - -Now need to work out what the correct partition is of this within cohorts. It might -simply be weighted by relative $f_{abs}$ by cohort (i.e. `layer_cohort_f_abs`) but I'm -not 100% convinced! - -::: +6. Last, divide the cohort $f_{APAR}$ through by the number of individuals in each + cohort to given the $f_{APAR}$ for each stem at each height. -## Things to worry about later - -Herbivory - leaf fall (transmission increases, truncate at 0, replace from NSCs) vs leaf -turnover (transmission constant, increased GPP penalty) - -Leaf area dynamics in PlantFATE - acclimation to herbivory and transitory decreases in -transimission, need non-structural carbohydrates to recover from total defoliation. - -Leaf economics. +```{code-cell} ipython3 +stem_fapar = cohort_fapar / community.cohort_data["n_individuals"] +print(stem_fapar) +``` diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index 541ad5e2..8db0615d 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -10,6 +10,16 @@ kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Plant Functional Types and Traits @@ -24,7 +34,7 @@ notes and initial demonstration code. This page introduces the main components of the {mod}`~pyrealm.demography` module that describe plant functional types (PFTs) and their traits. -```{code-cell} +```{code-cell} ipython3 from matplotlib import pyplot as plt import numpy as np import pandas as pd @@ -101,7 +111,7 @@ their maximum height. Note that the `q_m` and `z_max_prop` traits are calculated from the `m` and `n` traits and cannot be set directly. -```{code-cell} +```{code-cell} ipython3 short_pft = PlantFunctionalType(name="short", h_max=10) medium_pft = PlantFunctionalType(name="medium", h_max=20) tall_pft = PlantFunctionalType(name="tall", h_max=30) @@ -109,7 +119,7 @@ tall_pft = PlantFunctionalType(name="tall", h_max=30) The traits values set for a PFT instance can then be shown: -```{code-cell} +```{code-cell} ipython3 short_pft ``` @@ -130,13 +140,13 @@ that will be used in a demographic simulation. It can be created directly by pro the list of {class}`~pyrealm.demography.flora.PlantFunctionalType` instances. The only requirement is that each PFT instance uses a different name. -```{code-cell} +```{code-cell} ipython3 flora = Flora([short_pft, medium_pft, tall_pft]) flora ``` -```{code-cell} +```{code-cell} ipython3 pd.DataFrame({k: getattr(flora, k) for k in flora.trait_attrs}) ``` @@ -154,7 +164,7 @@ within {class}`~pyrealm.demography.community.Community` objects. A `StemTraits` instance can be created directly by providing arrays for each trait, but is more easily created from a `Flora` object by providing a list of PFT names: -```{code-cell} +```{code-cell} ipython3 # Get stem traits for a range of stems stem_pfts = ["short", "short", "short", "medium", "medium", "tall"] stem_traits = flora.get_stem_traits(pft_names=stem_pfts) diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index dd38854c..49f47176 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -203,36 +203,42 @@ def __init__( """Numerical tolerance for fitting the PPA model of canopy layer closure.""" # Define class attributes - self.total_community_crown_area: float - """Total crown area across all individuals in the community (m2).""" self.max_stem_height: float """Maximum height of any individual in the community (m).""" self.n_layers: int """Total number of canopy layers.""" self.n_cohorts: int """Total number of cohorts in the canopy.""" - self.layer_heights: NDArray[np.float32] - """Column vector of the heights of canopy layers.""" + self.heights: NDArray[np.float32] + """The vertical heights at which the canopy structure is calculated.""" + self.crown_profile: CrownProfile - """The crown profiles of stems at layer heights.""" - self.layer_stem_leaf_area: NDArray[np.float32] - """The leaf area of an individual stem per cohorts by layer.""" - self.layer_cohort_leaf_area: NDArray[np.float32] - """The total leaf areas within cohorts by layer.""" - self.layer_cohort_lai: NDArray[np.float32] + """The crown profiles of the community stems at the provided layer heights.""" + self.stem_leaf_area: NDArray[np.float32] + """The leaf area of the crown model for each cohort by layer.""" + self.cohort_lai: NDArray[np.float32] """The leaf area index for each cohort by layer.""" - self.layer_cohort_f_abs: NDArray[np.float32] + self.cohort_f_trans: NDArray[np.float32] + """The fraction of light transmitted by each cohort by layer.""" + self.cohort_f_abs: NDArray[np.float32] """The fraction of light absorbed by each cohort by layer.""" - self.layer_canopy_f_abs: NDArray[np.float32] - """The canopy-wide fraction of light absorbed by layer.""" - self.canopy_extinction_profile: NDArray[np.float32] - """The canopy-wide light extinction profile by layer.""" - self.fapar_profile: NDArray[np.float32] - """The canopy-wide fAPAR profile by layer.""" + self.f_trans: NDArray[np.float32] + """The fraction of light transmitted by the whole community by layer.""" + self.f_abs: NDArray[np.float32] + """The fraction of light absorbed by the whole community by layer.""" + self.transmission_profile: NDArray[np.float32] + """The light transmission profile for the whole community by layer.""" + self.extinction_profile: NDArray[np.float32] + """The light extinction profile for the whole community by layer.""" + self.fapar: NDArray[np.float32] + """The fraction of absorbed radiation for the whole community by layer.""" + self.cohort_fapar: NDArray[np.float32] + """The fraction of absorbed radiation for each cohort by layer.""" self.stem_fapar: NDArray[np.float32] - """The fAPAR for individual stems by layer.""" + """The fraction of absorbed radiation for each stem by layer.""" self.filled_community_area: float - """The area filled by crown.""" + """The area filled by crown after accounting for the crown gap fraction.""" + # Check operating mode if fit_ppa ^ (layer_heights is None): raise ValueError("Either set fit_ppa=True or provide layer heights.") @@ -246,9 +252,9 @@ def __init__( # Populate layer heights if layer_heights is not None: - self.layer_heights = layer_heights + self.heights = layer_heights else: - self.layer_heights = fit_perfect_plasticity_approximation( + self.heights = fit_perfect_plasticity_approximation( community=community, canopy_gap_fraction=canopy_gap_fraction, max_stem_height=self.max_stem_height, @@ -273,46 +279,48 @@ def _calculate_canopy(self, community: Community) -> None: self.crown_profile = CrownProfile( stem_traits=community.stem_traits, stem_allometry=community.stem_allometry, - z=self.layer_heights, + z=self.heights, ) # Partition the projected leaf area into the leaf area in each layer for each # stem and then scale up to the cohort leaf area in each layer. - self.layer_stem_leaf_area = np.diff( + self.stem_leaf_area = np.diff( self.crown_profile.projected_leaf_area, axis=0, prepend=0 ) # Calculate the leaf area index per layer per stem, using the stem # specific leaf area index values. LAI is a value per m2, so scale back down by # the available community area. - self.layer_cohort_lai = ( - self.layer_stem_leaf_area + self.cohort_lai = ( + self.stem_leaf_area * community.cohort_data["n_individuals"] * community.stem_traits.lai ) / community.cell_area # self.filled_community_area - # Calculate the Beer-Lambert light transmission component per layer and cohort - self.layer_cohort_f_trans = np.exp( - -community.stem_traits.par_ext * self.layer_cohort_lai - ) + # Calculate the Beer-Lambert light transmission and absorption components per + # layer and cohort + self.cohort_f_trans = np.exp(-community.stem_traits.par_ext * self.cohort_lai) + self.cohort_f_abs = 1 - self.cohort_f_trans + # Aggregate across cohorts into a layer wide transimissivity - self.layer_f_trans = self.layer_cohort_f_trans.prod(axis=1) + self.f_trans = self.cohort_f_trans.prod(axis=1) # Calculate the canopy wide light extinction per layer - self.layer_f_abs = 1 - self.layer_f_trans - - # Calculate cumulative light extinction across the canopy - self.extinction_profile = 1 - np.cumprod(self.layer_f_trans) - - # Calculate the fraction of radiation absorbed by each layer - # # TODO - include append=0 here to include ground or just backcalculate - self.fapar_profile = -np.diff( - np.cumprod(1 - self.layer_cohort_f_trans), - prepend=1, # append=0 - ) - - # # Partition the light back among the individual stems: simply weighting by per - # # cohort contribution to f_abs and divide through by the number of individuals - # self.stem_fapar = ( - # self.layer_cohort_f_trans * self.fapar_profile[:, None] - # ) / self.layer_cohort_f_trans.sum(axis=1)[:, None] + self.f_abs = 1 - self.f_trans + + # Calculate cumulative light transmission and extinction profiles + self.transmission_profile = np.cumprod(self.f_trans) + self.extinction_profile = 1 - self.transmission_profile + + # Calculate the fapar profile across cohorts and layers + # * The first part of the equation is calculating the relative absorption of + # each cohort within each layer + # * Each layer is then multiplied by fraction of the total light absorbed in the + # layer + # * The resulting matrix can be multiplied by a canopy top PPFD to generate the + # flux absorbed within each layer for each cohort. + self.fapar = -np.diff(self.transmission_profile, prepend=1) + self.cohort_fapar = ( + self.cohort_f_abs / self.cohort_f_abs.sum(axis=1)[:, None] + ) * self.fapar[:, None] + self.stem_fapar = self.cohort_fapar / community.cohort_data["n_individuals"] From 802dc05fb775925e23c1f5ed03537a342a429c42 Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 14 Oct 2024 14:37:14 +0100 Subject: [PATCH 227/241] Fix test --- tests/unit/demography/test_canopy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/demography/test_canopy.py b/tests/unit/demography/test_canopy.py index 33d457a5..a078fbfe 100644 --- a/tests/unit/demography/test_canopy.py +++ b/tests/unit/demography/test_canopy.py @@ -47,7 +47,7 @@ def test_Canopy__init__(): / community.cell_area ) ) - assert canopy.layer_stem_leaf_area.shape == ( + assert canopy.stem_leaf_area.shape == ( n_layers_from_crown_area, canopy.n_cohorts, ) From 4504b3bd8ff61f985337c7d9c8699966d57ee2ed Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 16 Oct 2024 11:27:15 +0100 Subject: [PATCH 228/241] Simple community drawing --- docs/source/users/demography/canopy.md | 37 ++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index f875cfa7..234abb56 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -35,6 +35,7 @@ notes and initial demonstration code. ```{code-cell} ipython3 from matplotlib import pyplot as plt import matplotlib as mpl +from matplotlib.patches import Polygon import numpy as np import pandas as pd @@ -228,7 +229,7 @@ and then three cohorts: * 7 saplings of the short PFT * 3 larger stems of the short PFT -* 1 large stems of tall PFT +* 2 large stems of tall PFT ```{code-cell} ipython3 # Define PFTs @@ -264,6 +265,33 @@ hghts = np.linspace(community.stem_allometry.stem_height.max(), 0, num=101)[:, N canopy = Canopy(community=community, layer_heights=hghts) ``` +The plot below then shows a simplistic 2D representation of the community. + +```{code-cell} ipython3 +fig, ax = plt.subplots(ncols=1) + +# Extract the crown profiles as XY arrays for plotting +profiles = get_crown_xy( + crown_profile=canopy.crown_profile, + stem_allometry=community.stem_allometry, + attr="crown_radius", + as_xy=True, +) + +for idx, crown in enumerate(profiles): + + # Get spaced but slightly randomized stem locations + n_stems = community.cohort_data["n_individuals"][idx] + stem_locations = np.linspace(0, 10, num=n_stems) + np.random.normal(size=n_stems) + + # Plot the crown model for each stem + for stem_loc in stem_locations: + ax.add_patch(Polygon(crown + np.array([stem_loc, 0]), color="#00550055")) + +ax.autoscale_view() +ax.set_aspect(1) +``` + As before, we can verify that the cumulative light extinction at the bottom of the vertical profile is equal to the expected value across the whole community. @@ -384,7 +412,7 @@ l_m = \left\lceil \frac{\sum_1^{N_s}{A_c}}{ A(1 - f_G)}\right\rceil $$ ```{code-cell} ipython3 -canopy_ppa = Canopy(community=community, canopy_gap_fraction=0, fit_ppa=True) +canopy_ppa = Canopy(community=community, canopy_gap_fraction=2 / 32, fit_ppa=True) ``` The `canopy_ppa.heights` attribute now contains the heights at which the PPA @@ -497,6 +525,11 @@ ax2_rhs.set_yticks(canopy_ppa.heights.flatten()) _ = ax2_rhs.set_yticklabels(z_star_labels) ``` +```{code-cell} ipython3 +t = 0.6 +(1 - 0.2) - t +``` + ## Light allocation From bcd9ba283ad298038243453051233c5a4bcd5e96 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 16 Oct 2024 13:54:15 +0100 Subject: [PATCH 229/241] Update jupytext filters --- pyproject.toml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2823f7cc..e436ab8a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,15 +31,15 @@ repository = "https://github.com/ImperialCollegeLondon/pyrealm" version = "1.0.0" [tool.poetry.dependencies] -dacite = "^1.6.0" -numpy = "^2.0.0" +dacite = "^1.6.0" +numpy = "^2.0.0" python = ">=3.10" -scipy = "^1.7.3" -tabulate = "^0.8.10" +scipy = "^1.7.3" +tabulate = "^0.8.10" marshmallow = "^3.22.0" -pandas = "^2.2.2" marshmallow-dataclass = "^8.7.0" +pandas = "^2.2.2" pandas-stubs = "^2.2.2.240909" [tool.poetry.group.types.dependencies] pandas-stubs = "^2.2.0.240218" @@ -132,7 +132,7 @@ select = [ "I", # isort "UP", # pyupgrade "RUF", # RUF specific checks - "NPY201" + "NPY201", ] # On top of the Google convention, disable: @@ -147,6 +147,6 @@ convention = "google" [tool.jupytext] # Stop jupytext from removing mystnb and other settings in MyST Notebook YAML headers -notebook_metadata_filter = "-jupytext.text_representation.jupytext_version,settings,mystnb" -# Also stop it from stripping cell metadata. -cell_metadata_filter = "all" \ No newline at end of file +notebook_metadata_filter = "settings,mystnb,language_info" +# Also stop it from stripping cell metadata, except for specific ones to lose. +cell_metadata_filter = "all,-trusted" From 6accc054e2cef51b085842490c68177744f18eb6 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 16 Oct 2024 13:55:30 +0100 Subject: [PATCH 230/241] Add language_info metadata to markdown files --- docs/source/api/constants_api.md | 11 ++++ docs/source/api/core_api.md | 11 ++++ docs/source/api/demography_api.md | 11 ++++ docs/source/api/pmodel_api.md | 11 ++++ docs/source/api/splash_api.md | 11 ++++ docs/source/api/tmodel_api.md | 11 ++++ docs/source/development/code_qa_and_typing.md | 11 ++++ docs/source/development/code_testing.md | 11 ++++ docs/source/development/documentation.md | 21 +++++++ docs/source/development/github_actions.md | 11 ++++ docs/source/development/overview.md | 11 ++++ .../development/profiling_and_benchmarking.md | 11 ++++ docs/source/development/pyrealm_build_data.md | 11 ++++ docs/source/development/release_process.md | 11 ++++ docs/source/index.md | 11 ++++ docs/source/users/constants.md | 21 +++++-- docs/source/users/demography/canopy.md | 39 +++++++----- docs/source/users/demography/community.md | 19 ++++-- docs/source/users/demography/crown.md | 43 ++++++++----- docs/source/users/demography/flora.md | 23 +++++-- .../users/demography/module_overview.md | 11 ++++ docs/source/users/demography/t_model.md | 37 ++++++++---- docs/source/users/hygro.md | 21 +++++-- docs/source/users/pmodel/c3c4model.md | 19 ++++-- .../users/pmodel/isotopic_discrimination.md | 19 ++++-- docs/source/users/pmodel/module_overview.md | 11 ++++ .../pmodel_details/envt_variation_outputs.md | 33 ++++++---- .../pmodel/pmodel_details/extreme_values.md | 26 ++++---- .../pmodel/pmodel_details/jmax_limitation.md | 15 ++++- .../pmodel/pmodel_details/optimal_chi.md | 29 ++++++--- .../photosynthetic_environment.md | 21 +++++-- .../pmodel/pmodel_details/pmodel_overview.md | 11 ++++ .../pmodel/pmodel_details/quantum_yield.md | 21 +++++-- .../users/pmodel/pmodel_details/rpmodel.md | 11 ++++ .../pmodel/pmodel_details/soil_moisture.md | 25 +++++--- .../pmodel/pmodel_details/worked_examples.md | 59 +++++++----------- .../pmodel/subdaily_details/acclimation.md | 25 +++++--- .../subdaily_details/subdaily_calculations.md | 60 ++++++++----------- .../subdaily_model_and_missing_data.md | 25 +++++--- .../subdaily_details/subdaily_overview.md | 11 ++++ .../pmodel/subdaily_details/worked_example.md | 51 +++++++--------- docs/source/users/splash.md | 27 ++++++--- docs/source/users/tmodel/canopy.md | 59 ++++++++++-------- docs/source/users/tmodel/tmodel.md | 25 +++++--- 44 files changed, 697 insertions(+), 275 deletions(-) diff --git a/docs/source/api/constants_api.md b/docs/source/api/constants_api.md index 1b992418..0565da39 100644 --- a/docs/source/api/constants_api.md +++ b/docs/source/api/constants_api.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The {mod}`~pyrealm.constants` module diff --git a/docs/source/api/core_api.md b/docs/source/api/core_api.md index 1324720e..528f10d3 100644 --- a/docs/source/api/core_api.md +++ b/docs/source/api/core_api.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The {mod}`~pyrealm.core` module diff --git a/docs/source/api/demography_api.md b/docs/source/api/demography_api.md index 9290a0b0..db9dd62e 100644 --- a/docs/source/api/demography_api.md +++ b/docs/source/api/demography_api.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The {mod}`~pyrealm.demography` module diff --git a/docs/source/api/pmodel_api.md b/docs/source/api/pmodel_api.md index 9bb4f669..b81a90d0 100644 --- a/docs/source/api/pmodel_api.md +++ b/docs/source/api/pmodel_api.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The {mod}`~pyrealm.pmodel` module diff --git a/docs/source/api/splash_api.md b/docs/source/api/splash_api.md index fe55c923..3cb0f3ac 100644 --- a/docs/source/api/splash_api.md +++ b/docs/source/api/splash_api.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The {mod}`~pyrealm.splash` module diff --git a/docs/source/api/tmodel_api.md b/docs/source/api/tmodel_api.md index b7fa9312..de3c0158 100644 --- a/docs/source/api/tmodel_api.md +++ b/docs/source/api/tmodel_api.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The {mod}`~pyrealm.tmodel` module diff --git a/docs/source/development/code_qa_and_typing.md b/docs/source/development/code_qa_and_typing.md index 848f7a5c..ed2c797d 100644 --- a/docs/source/development/code_qa_and_typing.md +++ b/docs/source/development/code_qa_and_typing.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Code quality and static typing diff --git a/docs/source/development/code_testing.md b/docs/source/development/code_testing.md index 43829394..3d76d292 100644 --- a/docs/source/development/code_testing.md +++ b/docs/source/development/code_testing.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Package testing and profiling diff --git a/docs/source/development/documentation.md b/docs/source/development/documentation.md index 0ce6b2f8..5552f055 100644 --- a/docs/source/development/documentation.md +++ b/docs/source/development/documentation.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Documentation @@ -60,6 +71,16 @@ kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- ``` diff --git a/docs/source/development/github_actions.md b/docs/source/development/github_actions.md index d26a7452..a0815478 100644 --- a/docs/source/development/github_actions.md +++ b/docs/source/development/github_actions.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # GitHub Actions diff --git a/docs/source/development/overview.md b/docs/source/development/overview.md index 837b1efe..8138127f 100644 --- a/docs/source/development/overview.md +++ b/docs/source/development/overview.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Developing `pyrealm` diff --git a/docs/source/development/profiling_and_benchmarking.md b/docs/source/development/profiling_and_benchmarking.md index d705d43f..4570cf26 100644 --- a/docs/source/development/profiling_and_benchmarking.md +++ b/docs/source/development/profiling_and_benchmarking.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Profiling and benchmarking diff --git a/docs/source/development/pyrealm_build_data.md b/docs/source/development/pyrealm_build_data.md index b59ec2b2..b94a4d87 100644 --- a/docs/source/development/pyrealm_build_data.md +++ b/docs/source/development/pyrealm_build_data.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The `pyrealm_build_data` package diff --git a/docs/source/development/release_process.md b/docs/source/development/release_process.md index e9ff6b00..27dd9021 100644 --- a/docs/source/development/release_process.md +++ b/docs/source/development/release_process.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Package release process diff --git a/docs/source/index.md b/docs/source/index.md index 43aef59b..32ec1e69 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The `pyrealm` package diff --git a/docs/source/users/constants.md b/docs/source/users/constants.md index 899076b3..91600360 100644 --- a/docs/source/users/constants.md +++ b/docs/source/users/constants.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Package constants @@ -35,7 +46,7 @@ of default model constants. The core API and details for each class can be seen These can be used to generate the default set of model parameters: -```{code-cell} +```{code-cell} ipython3 from pyrealm.constants import CoreConst, TModelTraits core_const = CoreConst() @@ -47,7 +58,7 @@ print(tmodel_const) And individual values can be altered using the parameter arguments: -```{code-cell} +```{code-cell} ipython3 # Estimate processes under the moon's gravity... core_const_moon = CoreConst(k_G=1.62) # ... allowing a much greater maximum height @@ -61,7 +72,7 @@ In order to ensure that a set of parameters cannot change while models are being instances of these parameter classes are **frozen**. You cannot edit an existing instance and will need to create a new instance to use different parameters. -```{code-cell} +```{code-cell} ipython3 :tags: [raises-exception] core_const_moon.k_G = 9.80665 @@ -75,7 +86,7 @@ export of parameter settings to dictionaries and to JSON formatted files. The co shows these methods working. First, a trait definition in a JSON file is read into a dictionary: -```{code-cell} +```{code-cell} ipython3 import json import pprint @@ -88,7 +99,7 @@ the {meth}`~pyrealm.constants.base.ConstantsClass.from_dict` method. The {meth}`~pyrealm.constants.base.ConstantsClass.from_json` method allows this to be done more directly and the resulting instances are identical. -```{code-cell} +```{code-cell} ipython3 traits1 = TModelTraits.from_dict(trt_dict) traits2 = TModelTraits.from_json("../files/traits.json") diff --git a/docs/source/users/demography/canopy.md b/docs/source/users/demography/canopy.md index f9c0688c..2ec8508d 100644 --- a/docs/source/users/demography/canopy.md +++ b/docs/source/users/demography/canopy.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Canopy model @@ -30,7 +41,7 @@ The key variables in calculating the canopy model are the crown projected area $ and leaf projected area $\tilde{A}_{cp}(z)$, which are calculated for a stem of a given size using the [crown model](./crown.md). -```{code-cell} +```{code-cell} ipython3 from matplotlib import pyplot as plt import numpy as np import pandas as pd @@ -85,7 +96,7 @@ and the required canopy gap fraction. The code below creates a simple community: -```{code-cell} +```{code-cell} ipython3 # Two PFTs # - a shorter understory tree with a columnar canopy and no crown gaps # - a taller canopy tree with a top heavy canopy and more crown gaps @@ -115,14 +126,14 @@ community = Community( We can then look at the expected allometries for the stems in each cohort: -```{code-cell} +```{code-cell} ipython3 print("H = ", community.stem_allometry.stem_height) print("Ac = ", community.stem_allometry.crown_area) ``` We can now calculate the canopy model for the community: -```{code-cell} +```{code-cell} ipython3 canopy = Canopy(community=community, canopy_gap_fraction=2 / 32) ``` @@ -133,14 +144,14 @@ heights for each stem in the three cohorts. There are four canopy layers, with the top two very close together because of the large crown area in the two stems in the cohort of `tall` trees. -```{code-cell} +```{code-cell} ipython3 canopy.layer_heights ``` The `stem_crown_area` attribute then provides the crown area of each stem found in each layer. -```{code-cell} +```{code-cell} ipython3 canopy.stem_crown_area ``` @@ -149,7 +160,7 @@ the first two layers are taken up entirely by the two stems in the cohort of lar trees. We can confirm that the calculation is correct by calculating the total crown area across the cohorts at each height: -```{code-cell} +```{code-cell} ipython3 np.sum(canopy.stem_crown_area * community.cohort_data["n_individuals"], axis=1) ``` @@ -163,7 +174,7 @@ identical to the projected crown area for the first two cohorts because the crow fraction $f_g$ is zero for this PFT. The projected leaf area is however displaced towards the ground in the last cohort, because the `tall` PFT has a large gap fraction. -```{code-cell} +```{code-cell} ipython3 canopy.stem_leaf_area ``` @@ -174,7 +185,7 @@ community crown and leaf area profile across a range of height values. For each we calculate the sum of the product of stem projected area and the number of individuals in each cohort. -```{code-cell} +```{code-cell} ipython3 # Set of vertical height to calculate crown profiles at_z = np.linspace(0, 26, num=261)[:, None] @@ -198,7 +209,7 @@ superimpose the calculated $z^*_l$ values and the cumulative canopy area for eac to confirm that the calculated values coincide with the profile. Note here that the total area at each closed layer height is omitting the community gap fraction. -```{code-cell} +```{code-cell} ipython3 fig, ax = plt.subplots(ncols=1) # Calculate the crown area at which each canopy layer closes. @@ -256,7 +267,7 @@ $f_{abs} = 1 - e ^ {-kL}$, where $k$ is the light extinction coefficient ($k$) and $L$ is the leaf area index (LAI). The LAI can be calculated for each stem and layer: -```{code-cell} +```{code-cell} ipython3 # LAI = Acp_within_layer / canopy_area # print(LAI) ``` @@ -264,7 +275,7 @@ where $k$ is the light extinction coefficient ($k$) and $L$ is the leaf area ind This can be used to calculate the LAI of individual stems but also the LAI of each layer in the canopy: -```{code-cell} +```{code-cell} ipython3 # LAI_stem = LAI.sum(axis=0) # LAI_layer = LAI.sum(axis=1) @@ -275,7 +286,7 @@ in the canopy: The layer LAI values can now be used to calculate the light transmission of each layer and hence the cumulative light extinction profile through the canopy. -```{code-cell} +```{code-cell} ipython3 # f_abs = 1 - np.exp(-pft.traits.par_ext * LAI_layer) # ext = np.cumprod(f_abs) @@ -287,7 +298,7 @@ One issue that needs to be resolved is that the T Model implementation in `pyrea follows the original implementation of the T Model in having LAI as a fixed trait of a given plant functional type, so is constant for all stems of that PFT. -```{code-cell} +```{code-cell} ipython3 # print("f_abs = ", (1 - np.exp(-pft.traits.par_ext * pft.traits.lai))) ``` diff --git a/docs/source/users/demography/community.md b/docs/source/users/demography/community.md index 0961b8e2..8bee4431 100644 --- a/docs/source/users/demography/community.md +++ b/docs/source/users/demography/community.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Plant Communities @@ -19,7 +30,7 @@ This area of `pyrealm` is in active development. ::: -```{code-cell} +```{code-cell} ipython3 from matplotlib import pyplot as plt import numpy as np import pandas as pd @@ -28,7 +39,7 @@ from pyrealm.demography.flora import PlantFunctionalType, Flora from pyrealm.demography.community import Community ``` -```{code-cell} +```{code-cell} ipython3 short_pft = PlantFunctionalType( name="short", h_max=15, m=1.5, n=1.5, f_g=0, ca_ratio=380 ) @@ -52,10 +63,10 @@ community = Community( ) ``` -```{code-cell} +```{code-cell} ipython3 community ``` -```{code-cell} +```{code-cell} ipython3 ``` diff --git a/docs/source/users/demography/crown.md b/docs/source/users/demography/crown.md index dcf41bc7..6f542632 100644 --- a/docs/source/users/demography/crown.md +++ b/docs/source/users/demography/crown.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The tree crown model @@ -20,7 +31,7 @@ notes and initial demonstration code. ::: -```{code-cell} +```{code-cell} ipython3 from matplotlib import pyplot as plt import numpy as np import pandas as pd @@ -146,7 +157,7 @@ The {class}`~pyrealm.demography.flora.PlantFunctionalType` class is typically used to set specific PFTs, but the functions to calculate $q_m$ and $p_{zm}$ are used directly below to provides a demonstration of the impacts of each trait. -```{code-cell} +```{code-cell} ipython3 # Set a range of values for m and n traits m = n = np.arange(1.0, 5, 0.1) @@ -155,7 +166,7 @@ q_m = calculate_crown_q_m(m=m, n=n[:, None]) z_max_prop = calculate_crown_z_max_proportion(m=m, n=n[:, None]) ``` -```{code-cell} +```{code-cell} ipython3 fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10.9, 4)) # Plot q_m as a function of m and n @@ -191,7 +202,7 @@ profiles for PFTs. It requires: The code below creates a set of PFTS with differing crown trait values and then creates a `Flora` object using the PFTs. -```{code-cell} +```{code-cell} ipython3 # A PFT with a small crown area and equal m and n values narrow_pft = PlantFunctionalType(name="narrow", h_max=20, m=1.5, n=1.5, ca_ratio=20) # A PFT with an intermediate crown area and m < n @@ -206,7 +217,7 @@ flora The Flora object can also be used to show a table of canopy variables: -```{code-cell} +```{code-cell} ipython3 # TODO - add a Flora.to_pandas() method flora_data = pd.DataFrame({k: getattr(flora, k) for k in flora.trait_attrs}) flora_data[["name", "ca_ratio", "m", "n", "f_g", "q_m", "z_max_prop"]] @@ -217,7 +228,7 @@ The T Model uses DBH to define stem size - here the the code is being used to back-calculate the required DBH values to give three stems with similar heights near the maximum height for each PFT. -```{code-cell} +```{code-cell} ipython3 # Generate the expected stem allometries at similar heights for each PFT stem_height = np.array([19, 17, 15]) stem_dbh = calculate_dbh_from_height( @@ -226,14 +237,14 @@ stem_dbh = calculate_dbh_from_height( stem_dbh ``` -```{code-cell} +```{code-cell} ipython3 # Calculate the stem allometries allometry = StemAllometry(stem_traits=flora, at_dbh=stem_dbh) ``` We can again use {mod}`pandas` to get a table of those allometric predictions: -```{code-cell} +```{code-cell} ipython3 pd.DataFrame({k: getattr(allometry, k) for k in allometry.allometry_attrs}) ``` @@ -243,7 +254,7 @@ that is with a shape `(N, 1)`. We can then calculate the crown profiles. -```{code-cell} +```{code-cell} ipython3 # Create a set of vertical heights as a column array. z = np.linspace(-1, 20.0, num=211)[:, None] @@ -259,7 +270,7 @@ above calculated at each height $z$: * The projected crown area * The projected leaf area -```{code-cell} +```{code-cell} ipython3 crown_profiles ``` @@ -276,7 +287,7 @@ stem. For each stem: Note that the equation for the relative radius $q(z)$ does define values where $z <0$ or $z > H$. -```{code-cell} +```{code-cell} ipython3 fig, ax = plt.subplots(ncols=1) # Find the maximum of the actual and relative maximum crown widths @@ -318,7 +329,7 @@ We can also use the `CanopyProfile` class with a single row of heights to calcul the crown profile at the expected $z_max$ and show that this matches the expected crown area from the T Model allometry. -```{code-cell} +```{code-cell} ipython3 # Calculate the crown profile across those heights for each PFT z_max = flora.z_max_prop * stem_height profile_at_zmax = CrownProfile(stem_traits=flora, stem_allometry=allometry, z=z_max) @@ -334,7 +345,7 @@ using the PFTs defined above because they have very different crown areas, so th below generates new profiles for a new set of PFTs that have similar crown area ratios but different shapes and gap fractions. -```{code-cell} +```{code-cell} ipython3 no_gaps_pft = PlantFunctionalType( name="no_gaps", h_max=20, m=1.5, n=1.5, f_g=0, ca_ratio=380 ) @@ -370,7 +381,7 @@ lines) change with height along the stem. lines are identical, but as `f_g` increases, more of the leaf area is displaced down within the crown. -```{code-cell} +```{code-cell} ipython3 fig, ax = plt.subplots(ncols=1) for pft_idx, offset, colour in zip((0, 1, 2), (0, 5, 10), ("r", "g", "b")): @@ -390,7 +401,7 @@ We can also generate predictions for a single PFT with varying crown gap fractio the plot below, note that all leaf area is above $z_{max}$ when $f_g=1$ and all leaf area is *below* -```{code-cell} +```{code-cell} ipython3 fig, ax = plt.subplots(ncols=1) # Loop over f_g values @@ -434,6 +445,6 @@ ax.set_xlabel(r"Projected leaf area ($\tilde{A}_{cp}(z)$, m2)") ax.legend(frameon=False) ``` -```{code-cell} +```{code-cell} ipython3 ``` diff --git a/docs/source/users/demography/flora.md b/docs/source/users/demography/flora.md index 4b9bf3f7..8db0615d 100644 --- a/docs/source/users/demography/flora.md +++ b/docs/source/users/demography/flora.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Plant Functional Types and Traits @@ -23,7 +34,7 @@ notes and initial demonstration code. This page introduces the main components of the {mod}`~pyrealm.demography` module that describe plant functional types (PFTs) and their traits. -```{code-cell} +```{code-cell} ipython3 from matplotlib import pyplot as plt import numpy as np import pandas as pd @@ -100,7 +111,7 @@ their maximum height. Note that the `q_m` and `z_max_prop` traits are calculated from the `m` and `n` traits and cannot be set directly. -```{code-cell} +```{code-cell} ipython3 short_pft = PlantFunctionalType(name="short", h_max=10) medium_pft = PlantFunctionalType(name="medium", h_max=20) tall_pft = PlantFunctionalType(name="tall", h_max=30) @@ -108,7 +119,7 @@ tall_pft = PlantFunctionalType(name="tall", h_max=30) The traits values set for a PFT instance can then be shown: -```{code-cell} +```{code-cell} ipython3 short_pft ``` @@ -129,13 +140,13 @@ that will be used in a demographic simulation. It can be created directly by pro the list of {class}`~pyrealm.demography.flora.PlantFunctionalType` instances. The only requirement is that each PFT instance uses a different name. -```{code-cell} +```{code-cell} ipython3 flora = Flora([short_pft, medium_pft, tall_pft]) flora ``` -```{code-cell} +```{code-cell} ipython3 pd.DataFrame({k: getattr(flora, k) for k in flora.trait_attrs}) ``` @@ -153,7 +164,7 @@ within {class}`~pyrealm.demography.community.Community` objects. A `StemTraits` instance can be created directly by providing arrays for each trait, but is more easily created from a `Flora` object by providing a list of PFT names: -```{code-cell} +```{code-cell} ipython3 # Get stem traits for a range of stems stem_pfts = ["short", "short", "short", "medium", "medium", "tall"] stem_traits = flora.get_stem_traits(pft_names=stem_pfts) diff --git a/docs/source/users/demography/module_overview.md b/docs/source/users/demography/module_overview.md index e2aaceab..45d7f248 100644 --- a/docs/source/users/demography/module_overview.md +++ b/docs/source/users/demography/module_overview.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The demography module diff --git a/docs/source/users/demography/t_model.md b/docs/source/users/demography/t_model.md index 23510daa..cd38532c 100644 --- a/docs/source/users/demography/t_model.md +++ b/docs/source/users/demography/t_model.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The T Model module @@ -19,7 +30,7 @@ The T Model {cite}`Li:2014bc` provides a model of both: (PFT), and * a carbon allocation model, given stem allometry and potential GPP. -```{code-cell} +```{code-cell} ipython3 from matplotlib import pyplot as plt import numpy as np import pandas as pd @@ -31,7 +42,7 @@ from pyrealm.demography.t_model_functions import StemAllocation, StemAllometry To generate predictions under the T Model, we need a Flora object providing the [trait values](./flora.md) for each of the PFTsto be modelled: -```{code-cell} +```{code-cell} ipython3 # Three PFTS short_pft = PlantFunctionalType(name="short", h_max=10) medium_pft = PlantFunctionalType(name="medium", h_max=20) @@ -61,14 +72,14 @@ the predictions of the T Model for: The DBH input can be a scalar array or a one dimensional array providing a single value for each PFT. This then calculates a single estimate at the given size for each stem. -```{code-cell} +```{code-cell} ipython3 # Calculate a single prediction single_allometry = StemAllometry(stem_traits=flora, at_dbh=np.array([0.1, 0.1, 0.1])) ``` We can display those predictions as a `pandas.DataFrame`: -```{code-cell} +```{code-cell} ipython3 pd.DataFrame( {k: getattr(single_allometry, k) for k in single_allometry.allometry_attrs} ) @@ -79,7 +90,7 @@ predictions are made at each DBH value for each PFT and the allometry attributes predictions arranged with each PFT as a column and each DBH prediction as a row. This makes them convenient to plot using `matplotlib`. -```{code-cell} +```{code-cell} ipython3 # Column array of DBH values from 0 to 1.6 metres dbh_col = np.arange(0, 1.6, 0.01)[:, None] # Get the predictions @@ -89,7 +100,7 @@ allometries = StemAllometry(stem_traits=flora, at_dbh=dbh_col) The code below shows how to use the returned allometries to generate a plot of the scaling relationships across all of the PFTs in a `Flora` instance. -```{code-cell} +```{code-cell} ipython3 fig, axes = plt.subplots(ncols=2, nrows=4, sharex=True, figsize=(10, 10)) plot_details = [ @@ -118,14 +129,14 @@ The T Model also predicts how potential GPP will be allocated to respiration, tu and growth for stems with a given PFT and allometry. Again, a single value can be provided to get a single estimate of the allocation model for each stem: -```{code-cell} +```{code-cell} ipython3 single_allocation = StemAllocation( stem_traits=flora, stem_allometry=single_allometry, at_potential_gpp=np.array([55]) ) single_allocation ``` -```{code-cell} +```{code-cell} ipython3 pd.DataFrame( {k: getattr(single_allocation, k) for k in single_allocation.allocation_attrs} ) @@ -136,14 +147,14 @@ allocation per stem. In the first example, the code takes the allometric predict from above and calculates the GPP allocation for stems of varying size with the same potential GPP: -```{code-cell} +```{code-cell} ipython3 potential_gpp = np.repeat(5, dbh_col.size)[:, None] allocation = StemAllocation( stem_traits=flora, stem_allometry=allometries, at_potential_gpp=potential_gpp ) ``` -```{code-cell} +```{code-cell} ipython3 fig, axes = plt.subplots(ncols=2, nrows=5, sharex=True, figsize=(10, 12)) plot_details = [ @@ -175,7 +186,7 @@ fig.delaxes(axes[-1]) An alternative calculation is to make allocation predictions for varying potential GPP for constant allometries: -```{code-cell} +```{code-cell} ipython3 # Column array of DBH values from 0 to 1.6 metres dbh_constant = np.repeat(0.2, 50)[:, None] # Get the allometric predictions @@ -189,7 +200,7 @@ allocation_2 = StemAllocation( ) ``` -```{code-cell} +```{code-cell} ipython3 fig, axes = plt.subplots(ncols=2, nrows=5, sharex=True, figsize=(10, 12)) axes = axes.flatten() @@ -206,6 +217,6 @@ for ax, (var, ylab) in zip(axes, plot_details): fig.delaxes(axes[-1]) ``` -```{code-cell} +```{code-cell} ipython3 ``` diff --git a/docs/source/users/hygro.md b/docs/source/users/hygro.md index a235875e..bfd2f7fd 100644 --- a/docs/source/users/hygro.md +++ b/docs/source/users/hygro.md @@ -5,15 +5,26 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Hygrometric functions -```{code-cell} +```{code-cell} ipython3 # This code loads required packages and then creates a representative range of # values of the core variables to use in function plots. # @@ -72,7 +83,7 @@ and returns kPa, so if you are using VP to prepare input data for ## Saturated vapour pressure -```{code-cell} +```{code-cell} ipython3 # Create a sequence of air temperatures and calculate the saturated vapour pressure vp_sat = hygro.calc_vp_sat(ta_1d) @@ -85,7 +96,7 @@ pyplot.show() ## Vapour pressure to VPD -```{code-cell} +```{code-cell} ipython3 vpd = hygro.convert_vp_to_vpd(vp_2d, ta_2d.transpose()) # Plot vpd @@ -100,7 +111,7 @@ pyplot.show() ## Relative humidity to VPD -```{code-cell} +```{code-cell} ipython3 vpd = hygro.convert_rh_to_vpd(rh_2d, ta_2d.transpose()) # Plot vpd @@ -117,7 +128,7 @@ pyplot.show() ## Specific humidity to VPD -```{code-cell} +```{code-cell} ipython3 # Create a sequence of air temperatures and calculate the saturated vapour pressure vpd1 = hygro.convert_sh_to_vpd(sh_1d, ta=20, patm=101.325) vpd2 = hygro.convert_sh_to_vpd(sh_1d, ta=30, patm=101.325) diff --git a/docs/source/users/pmodel/c3c4model.md b/docs/source/users/pmodel/c3c4model.md index ac4ba204..9630134f 100644 --- a/docs/source/users/pmodel/c3c4model.md +++ b/docs/source/users/pmodel/c3c4model.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # C3 / C4 Competition @@ -41,7 +52,7 @@ expected C4 fraction ($F_4$) in a community (see correction term for the estimated percentage tree cover and the plot below shows how $F_4$ changes with $A_4$, given differing estimates of tree cover. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] import numpy as np @@ -87,7 +98,7 @@ The plot below shows how $h$ varies with the expected GPP from C3 plants alone. dashed line shows the C3 GPP estimate above which canopy closure leads to complete shading of C4 plants. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Just use the competition model to predict h across a GPP gradient @@ -123,7 +134,7 @@ cover of 0.5. ### Code -```{code-cell} +```{code-cell} ipython3 # Use a simple temperature sequence to generate a range of optimal chi values n_pts = 51 tc_1d = np.linspace(-10, 45, n_pts) @@ -201,7 +212,7 @@ Panel F : The contributions of plants using the C3 and C4 pathways to predicted $\delta\ce{^{13}C}$ . -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Generate the plots diff --git a/docs/source/users/pmodel/isotopic_discrimination.md b/docs/source/users/pmodel/isotopic_discrimination.md index 574b2f67..99bf30b8 100644 --- a/docs/source/users/pmodel/isotopic_discrimination.md +++ b/docs/source/users/pmodel/isotopic_discrimination.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Isotopic discrimination @@ -31,7 +42,7 @@ values of $\chi$. The sequence of $\chi$ values used is created by using the P M estimate $\chi$ across a temperature gradient, giving the range of $\chi$ values shown below for C3 and C4 plants. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] import numpy as np @@ -81,12 +92,12 @@ The calculations differ between C3 and C4 plants, and this is set by the selecti the `method_optchi` argument used for the {class}`~pyrealm.pmodel.pmodel.PModel` instance. -```{code-cell} +```{code-cell} ipython3 carb_c3 = CalcCarbonIsotopes(mod_c3, d13CO2=-8.4, D14CO2=19.2) carb_c3.summarize() ``` -```{code-cell} +```{code-cell} ipython3 carb_c4 = CalcCarbonIsotopes(mod_c4, d13CO2=-8.4, D14CO2=19.2) carb_c4.summarize() ``` @@ -95,7 +106,7 @@ The plots below show how the calculated values alter with $\chi$. The difference direction of these relationships between C3 and C4 pathways creates a predictable isotopic signature of relative contributions of the two pathways. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Create side by side subplots diff --git a/docs/source/users/pmodel/module_overview.md b/docs/source/users/pmodel/module_overview.md index 04c29687..951a560c 100644 --- a/docs/source/users/pmodel/module_overview.md +++ b/docs/source/users/pmodel/module_overview.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The P Model module diff --git a/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md b/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md index e7364837..fc69263a 100644 --- a/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md +++ b/docs/source/users/pmodel/pmodel_details/envt_variation_outputs.md @@ -5,15 +5,26 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # P Model predictions -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] from itertools import product @@ -115,7 +126,7 @@ environmental variables: All of the pairwise plots share the same legend: -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] fig, ax = pyplot.subplots(1, 1, figsize=(6, 1.2)) @@ -180,7 +191,7 @@ absorbed irradiance. Light use efficiency measures conversion efficiency of moles of absorbed irradiance into grams of Carbon ($\mathrm{g\,C}\; \mathrm{mol}^{-1}$ photons). -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] plot_fun("lue", r"LUE ($\mathrm{g\,C}\; \mathrm{mol}^{-1}$ photons).") @@ -192,7 +203,7 @@ The intrinsic water-use efficiency is ratio of net photosynthetic CO2 assimilation to stomatal conductance, and captures the cost of assimilation per unit of water, in units of $\mu\mathrm{mol}\;\mathrm{mol}^{-1}$. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] plot_fun("iwue", r"IWUE ($\mu\mathrm{mol}\;\mathrm{mol}^{-1}$)") @@ -249,7 +260,7 @@ calculated using ``fapar=1, ppfd=1``, which are the default values to ### Gross primary productivity (``gpp``, GPP) -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] plot_fun("gpp", r"GPP ($\mu\mathrm{g\,C}\,\mathrm{m}^{-2}\,\mathrm{s}^{-1}$)") @@ -257,7 +268,7 @@ plot_fun("gpp", r"GPP ($\mu\mathrm{g\,C}\,\mathrm{m}^{-2}\,\mathrm{s}^{-1}$)") ### Dark respiration (``rd``) -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] plot_fun("rd", r"$r_d$ ($\mu\mathrm{mol}\,\mathrm{m}^{-2}\,\mathrm{s}^{-1}$)") @@ -265,7 +276,7 @@ plot_fun("rd", r"$r_d$ ($\mu\mathrm{mol}\,\mathrm{m}^{-2}\,\mathrm{s}^{-1}$)") ### Maximum rate of carboxylation (``vcmax``) -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] plot_fun("vcmax", r"$v_{cmax}$ ($\mu\mathrm{mol}\,\mathrm{m}^{-2}\,\mathrm{s}^{-1}$)") @@ -273,7 +284,7 @@ plot_fun("vcmax", r"$v_{cmax}$ ($\mu\mathrm{mol}\,\mathrm{m}^{-2}\,\mathrm{s}^ ### Maximum rate of carboxylation at standard temperature (``vcmax25``) -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] plot_fun( @@ -283,7 +294,7 @@ plot_fun( ### Maximum rate of electron transport. (``jmax``) -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] plot_fun("jmax", r"$J_{max}$ ($\mu\mathrm{mol}\,\mathrm{m}^{-2}\,\mathrm{s}^{-1}$)") @@ -298,7 +309,7 @@ instability in estimates of $g_s$. The {meth}`~pyrealm.pmodel.pmodel.PModel.estimate_productivity` method will set $g_s$ to be undefined (`np.nan`) when VPD is zero or when $c_a - c_i = 0$. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] plot_fun("gs", r"$g_s$ ($\mu\mathrm{mol}\,\mathrm{m}^{-2}\,\mathrm{s}^{-1}$)") @@ -311,7 +322,7 @@ below show how each variable changes, for a constant environment with `tc` of 20 `patm` of 101325 Pa, `vpd` of 1000 Pa and $\ce{CO2}$ of 400 ppm, when absorbed irradiance changes from 0 to 2000 $\mu\text{mol}\,\mathrm{m}^{-2}\,\text{s}^{-1}$. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Calculate the photosynthetic environment diff --git a/docs/source/users/pmodel/pmodel_details/extreme_values.md b/docs/source/users/pmodel/pmodel_details/extreme_values.md index 7119ac7f..b4de861e 100644 --- a/docs/source/users/pmodel/pmodel_details/extreme_values.md +++ b/docs/source/users/pmodel/pmodel_details/extreme_values.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Extreme forcing values @@ -51,9 +62,8 @@ settings, the roots of these quadratics are: Note that the default values for C3 photosynthesis give **non-zero values below 0°C**. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] -:trusted: true from matplotlib import pyplot import numpy as np @@ -91,9 +101,8 @@ The photorespiratory compensation point ($\Gamma^*$) varies with as a function o temperature and atmospheric pressure, and behaves smoothly with extreme inputs. Note that again, $\Gamma^_$ has non-zero values for sub-zero temperatures. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] -:trusted: true # Calculate gammastar at different pressures tc_1d = np.linspace(-80, 100, n_pts) @@ -117,9 +126,8 @@ pyplot.show() The Michaelis-Menten coefficient for photosynthesis ($K_{mm}$) also varies with temperature and atmospheric pressure and again behaves smoothly with extreme values. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) @@ -142,9 +150,8 @@ The density ($\rho$) and viscosity ($\mu$) of water both vary with temperature a atmospheric pressure. Looking at the density of water, there is a serious numerical issue with low temperatures arising from the equations for the density of water. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) @@ -167,9 +174,8 @@ Zooming in, the behaviour of this function is not reliable at extreme low temper leading to unstable estimates of $\eta^*$ and the P Model should not be used to make predictions below about -30 °C. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] -:trusted: true fig, ax = pyplot.subplots(1, 1) diff --git a/docs/source/users/pmodel/pmodel_details/jmax_limitation.md b/docs/source/users/pmodel/pmodel_details/jmax_limitation.md index 5e07802f..b32d481e 100644 --- a/docs/source/users/pmodel/pmodel_details/jmax_limitation.md +++ b/docs/source/users/pmodel/pmodel_details/jmax_limitation.md @@ -5,15 +5,26 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # $J_{max}$ limitation -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] from matplotlib import pyplot @@ -50,7 +61,7 @@ The plot below shows the effects of each method on the light use efficienct acro temperature gradient. The other forcing variables are fixed ($P=101325.0 , \ce{CO2}= 400 \text{ppm}, \text{VPD}=820$) and $\phi_0$ is also fixed ($\phi_0=0.08$). -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Calculate variation in m_jlim with temperature diff --git a/docs/source/users/pmodel/pmodel_details/optimal_chi.md b/docs/source/users/pmodel/pmodel_details/optimal_chi.md index fb22b49e..3fdac455 100644 --- a/docs/source/users/pmodel/pmodel_details/optimal_chi.md +++ b/docs/source/users/pmodel/pmodel_details/optimal_chi.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Optimal $\chi$ and leaf $\ce{CO2}$ @@ -63,7 +74,7 @@ for use within a P Model. - {class}`~pyrealm.pmodel.optimal_chi.OptimalChiC4NoGammaRootzoneStress` ``` -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] from itertools import product @@ -196,7 +207,7 @@ def plot_opt_chi(mod): This **C3 method** follows the approach detailed in {cite:t}`Prentice:2014bc`, see {class}`~pyrealm.pmodel.optimal_chi.OptimalChiPrentice14` for details. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Run the P Model and plot predictions @@ -210,7 +221,7 @@ This **C4 method** follows the approach detailed in {cite:t}`Prentice:2014bc`, b a C4 specific version of the unit cost ratio ($\beta$). It also sets $m_j = m_c = 1$. See {class}`~pyrealm.pmodel.optimal_chi.OptimalChiC4` for details. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Run the P Model and plot predictions @@ -228,7 +239,7 @@ and also also sets $m_j = 1$, but $m_c$ is calculated as in {class}`~pyrealm.pmodel.optimal_chi.OptimalChiPrentice14`. See {meth}`~pyrealm.pmodel.optimal_chi.OptimalChiC4NoGamma` for details. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Run the P Model and plot predictions @@ -263,7 +274,7 @@ The calculation details are provided in the description of the {class}`~pyrealm.pmodel.optimal_chi.OptimalChiLavergne20C3` method, but the variation in $\beta$ with $\theta$ is shown below. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Theta is required for the calculation of beta @@ -291,7 +302,7 @@ The plots below show the impacts on optimal $\chi$ across a temperature gradient values of VPD and soil moisture, with constant atmospheric pressure (101325 Pa) and CO2 (280 ppm). -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Environments with high and low soil moisture @@ -356,7 +367,7 @@ pyplot.tight_layout() The plots below illustrate the impact of temperature and $\theta$ on $m_j$ and $m_c$, again with constant atmospheric pressure (101325 Pa) and CO2 (280 ppm). -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] fig, ((ax1, ax3), (ax2, ax4)) = pyplot.subplots(2, 2, figsize=(10, 10), sharey=True) @@ -454,7 +465,7 @@ but the variation in $\beta$ with rootzone stress is shown below. * {class}`~pyrealm.pmodel.optimal_chi.OptimalChiC4RootzoneStress` * {class}`~pyrealm.pmodel.optimal_chi.OptimalChiC4NoGammaRootzoneStress` -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] from pyrealm.pmodel.optimal_chi import ( @@ -500,7 +511,7 @@ The plots below show the impacts on optimal $\chi$ across a temperature gradient values of VPD and rootzone stress, with constant atmospheric pressure (101325 Pa) and CO2 (280 ppm). -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Environments with high and low rootzone stress diff --git a/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md b/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md index cedd27fe..9e2c902e 100644 --- a/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md +++ b/docs/source/users/pmodel/pmodel_details/photosynthetic_environment.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Photosynthetic environment @@ -26,7 +37,7 @@ The descriptions below show the typical ranges of these values under common environmental inputs along with links to the more detailed documentation of the key functions. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # This code loads required packages and then creates a representative range of @@ -68,7 +79,7 @@ Details: {func}`pyrealm.pmodel.functions.calc_gammastar` The photorespiratory compensation point ($\Gamma^*$) varies with as a function of temperature and atmospheric pressure: -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Calculate gammastar @@ -91,7 +102,7 @@ Details: {func}`pyrealm.pmodel.functions.calc_kmm` The Michaelis-Menten coefficient for photosynthesis ($K_{mm}$) also varies with temperature and atmospheric pressure: -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Calculate K_mm @@ -118,7 +129,7 @@ pressure ($\eta^*$). The figure shows how $\eta^*$ varies with temperature and pressure. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Calculate the viscosity under the range of values and the standard @@ -146,7 +157,7 @@ Details: {func}`pyrealm.pmodel.functions.calc_co2_to_ca` The partial pressure of $\ce{CO2}$ is a function of the atmospheric concentration of $\ce{CO2}$ in parts per million and the atmospheric pressure: -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Variation in partial pressure diff --git a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md index 9626ee98..475f9d6a 100644 --- a/docs/source/users/pmodel/pmodel_details/pmodel_overview.md +++ b/docs/source/users/pmodel/pmodel_details/pmodel_overview.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- diff --git a/docs/source/users/pmodel/pmodel_details/quantum_yield.md b/docs/source/users/pmodel/pmodel_details/quantum_yield.md index 92a3ae8c..d5162a1f 100644 --- a/docs/source/users/pmodel/pmodel_details/quantum_yield.md +++ b/docs/source/users/pmodel/pmodel_details/quantum_yield.md @@ -5,15 +5,26 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Quantum yield efficiency of photosynthesis -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # This code loads required packages and then creates a representative range of @@ -79,7 +90,7 @@ estimate of $\phi_0$, following {cite:t}`Bernacchi:2003dc` for C3 plants and $\phi_0 = 0.081785$, following the BRC parameterisation in Table 1. of {cite:t}`Stocker:2020dh`. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Calculate temperature dependence of quantum yield efficiency @@ -117,7 +128,7 @@ $\phi_0$ values to an otherwise constant environment. As you would expect given $\text{LUE} = \phi_0 \cdot M_C \cdot m_j$, light use efficiency changes linearly along this gradient of $\phi_0$ values. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # A constant environment to show a range of kphio values @@ -157,7 +168,7 @@ $\phi_{0A} = \dfrac{\phi_{0R}}{(1 + \textrm{AI}^m) ^ n}$ This captures a decrease in maximum $\phi_0$ in arid conditions, as shown below. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] n_vals = 51 @@ -188,7 +199,7 @@ approach also alters the temperature at which $\phi_0$ is maximised as a functio mean growth temperature ($T_g$) in a location. The plot below shows how aridity and mean growth temperature interact to change the location and height of the peak $\phi_0$. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] n_vals = 51 diff --git a/docs/source/users/pmodel/pmodel_details/rpmodel.md b/docs/source/users/pmodel/pmodel_details/rpmodel.md index 7e691cc2..c46c12ba 100644 --- a/docs/source/users/pmodel/pmodel_details/rpmodel.md +++ b/docs/source/users/pmodel/pmodel_details/rpmodel.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The `rpmodel` implementation diff --git a/docs/source/users/pmodel/pmodel_details/soil_moisture.md b/docs/source/users/pmodel/pmodel_details/soil_moisture.md index 2b4b8a53..8d94a557 100644 --- a/docs/source/users/pmodel/pmodel_details/soil_moisture.md +++ b/docs/source/users/pmodel/pmodel_details/soil_moisture.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Soil moisture effects @@ -85,7 +96,7 @@ varies with changing soil moisture for some different values of mean aridity. In the examples below, the default $\theta_0 = 0$ has been changed to $\theta_0 = 0.1$ to make the lower bound more obvious. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] from matplotlib import pyplot as plt @@ -151,7 +162,7 @@ by the resulting factor. The example below shows how the predicted light use efficiency from the P Model changes across an aridity gradient both with and without the soil moisture factor. -```{code-cell} +```{code-cell} ipython3 # Calculate the P Model in a constant environment tc = np.array([20] * 101) sm_gradient = np.linspace(0, 1.0, 101) @@ -174,7 +185,7 @@ for mean_alpha in [0.9, 0.5, 0.3, 0.1, 0.0]: gpp_stressed[mean_alpha] = model.gpp * sm_stress ``` -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] plt.plot(sm_gradient, model.gpp, label="No soil moisture penalty") @@ -234,7 +245,7 @@ y &= \min( a \textrm{AI} ^ {b}, 1)\\ \end{align*} $$ -```{code-cell} +```{code-cell} ipython3 from pyrealm.constants import PModelConst const = PModelConst() @@ -269,7 +280,7 @@ $$ \end{cases} $$ -```{code-cell} +```{code-cell} ipython3 # Calculate the soil moisture stress factor across a soil moisture # gradient for different aridity index values beta = {} @@ -298,7 +309,7 @@ calculated and then applied to the GPP calculated for a model ({attr}`~pyrealm.pmodel.pmodel.PModel.gpp`). In the example below, the result is obviously just $\beta(\theta)$ from above scaled to the constant GPP. -```{code-cell} +```{code-cell} ipython3 for ai in ai_vals: plt.plot(sm_gradient, model.gpp * beta[ai], label=f"AI = {ai}") @@ -309,6 +320,6 @@ plt.legend() plt.show() ``` -```{code-cell} +```{code-cell} ipython3 ``` diff --git a/docs/source/users/pmodel/pmodel_details/worked_examples.md b/docs/source/users/pmodel/pmodel_details/worked_examples.md index f3db6947..f69cc924 100644 --- a/docs/source/users/pmodel/pmodel_details/worked_examples.md +++ b/docs/source/users/pmodel/pmodel_details/worked_examples.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Worked examples @@ -38,9 +49,7 @@ The example shows the steps required using a single site with: ### Estimate photosynthetic environment -```{code-cell} -:trusted: true - +```{code-cell} ipython3 from importlib import resources from matplotlib import pyplot as plt @@ -60,15 +69,11 @@ terse - just the shape of the data - but the {meth}`~pyrealm.pmodel.pmodel_environment.PModelEnvironment.summarize` method provides a more detailed summary of the attributes. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 env ``` -```{code-cell} -:trusted: true - +```{code-cell} ipython3 env.summarize() ``` @@ -77,18 +82,14 @@ env.summarize() Next, the P Model can be fitted to the photosynthetic environment using the ({class}`~pyrealm.pmodel.pmodel.PModel`) class: -```{code-cell} -:trusted: true - +```{code-cell} ipython3 model = PModel(env) ``` The returned model object holds a lot of information. The representation of the model object shows a terse display of the settings used to run the model: -```{code-cell} -:trusted: true - +```{code-cell} ipython3 model ``` @@ -98,9 +99,7 @@ displays a summary of calculated predictions. Initially, this shows two measures photosynthetic efficiency: the intrinsic water use efficiency (``iwue``) and the light use efficiency (``lue``). -```{code-cell} -:trusted: true - +```{code-cell} ipython3 model.summarize() ``` @@ -112,9 +111,7 @@ recording key parameters from the [calculation of $\chi$](./optimal_chi). This object also has a {meth}`~pyrealm.pmodel.optimal_chi.OptimalChiABC.summarize` method: -```{code-cell} -:trusted: true - +```{code-cell} ipython3 model.optchi.summarize() ``` @@ -130,9 +127,7 @@ Here we are using: * An absorption fraction of 0.91 (-), and * a PPFD of 834 µmol m-2 s-1. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 model.estimate_productivity(fapar=0.91, ppfd=834) model.summarize() ``` @@ -164,9 +159,7 @@ to be the same size so some of the variables have repeated data across dimension cell. * Elevation is constant across months, so the data for each month is repeated. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Load an example dataset containing the forcing variables. data_path = resources.files("pyrealm_build_data.rpmodel") / "pmodel_global.nc" ds = xarray.load_dataset(data_path) @@ -185,9 +178,7 @@ The model can now be run using that data. The first step is to convert the eleva data to atmospheric pressure, and then this is used to set the photosynthetic environment for the model: -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Convert elevation to atmospheric pressure patm = calc_patm(elev) @@ -205,9 +196,7 @@ env.summarize() That environment can then be run to calculate the P model predictions for light use efficiency: -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Run the P model model = PModel(env) @@ -220,9 +209,7 @@ plt.title("Light use efficiency") Finally, the light use efficiency can be used to calculate GPP given the photosynthetic photon flux density and fAPAR. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Scale the outputs from values per unit iabs to realised values model.estimate_productivity(fapar, ppfd) diff --git a/docs/source/users/pmodel/subdaily_details/acclimation.md b/docs/source/users/pmodel/subdaily_details/acclimation.md index 193b38f9..31805af1 100644 --- a/docs/source/users/pmodel/subdaily_details/acclimation.md +++ b/docs/source/users/pmodel/subdaily_details/acclimation.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Estimating acclimation @@ -28,7 +39,7 @@ modelling approach to representing slow responses within the P Model, following * The interpolation of realised daily values back onto the subdaily timescale. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] from copy import copy @@ -58,7 +69,7 @@ interpolating data back to subdaily timescales. In practice {cite:t}`mengoli:202 present results using one hour windows around noon or even the single value closest to noon. -```{code-cell} +```{code-cell} ipython3 # Define a set of observations at a subdaily timescale fast_datetimes = np.arange( np.datetime64("1970-01-01"), np.datetime64("1970-01-08"), np.timedelta64(30, "m") @@ -78,7 +89,7 @@ demo_scaler.set_window(window_center=np.timedelta64(12, "h"), half_width=half_wi The plot below shows the rapidly changing variable and the defined daily acclimation windows. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] fig, ax = plt.subplots() @@ -129,7 +140,7 @@ applies the memory effect with three different values of $\alpha$. When $\alpha the realised values are identical to the daily optimum value within the acclimation window. -```{code-cell} +```{code-cell} ipython3 # Extract the optimal values within the daily acclimation windows daily_mean = demo_scaler.get_daily_means(fast_data) @@ -139,7 +150,7 @@ real_3 = memory_effect(daily_mean, alpha=1 / 3) real_1 = memory_effect(daily_mean, alpha=1) ``` -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] fig, ax = plt.subplots() @@ -194,7 +205,7 @@ The code below shows how the used to interpolate realised values back to the subdaily scale, using different settings for the update point and interpolation method. -```{code-cell} +```{code-cell} ipython3 # Fill to the subdaily scale using the default settings: # - update at the end of the acclimation window # - hold the value constant between update points @@ -248,7 +259,7 @@ Plot D : The daily optimal realised value is again able to instantaneously adopt the daily optimal value, but the one day offset for linear interpolation is applied. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] # Create the figure diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md index 1a134c84..f32823a8 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_calculations.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Subdaily P Model calculations @@ -19,9 +30,8 @@ steps used in the estimation process in order to show intermediates results but practice, as shown in the [worked example](worked_example), most of these calculations are handled internally by the model fitting in `pyrealm`. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] -:trusted: true from importlib import resources @@ -47,9 +57,7 @@ The code below uses half hourly data from 2014 for the [BE-Vie FluxNET site](https://fluxnet.org/doi/FLUXNET2015/BE-Vie), which was also used as a demonstration in {cite:t}`mengoli:2022a`. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 data_path = resources.files("pyrealm_build_data.subdaily") / "subdaily_BE_Vie_2014.csv" data = pandas.read_csv(str(data_path)) @@ -70,9 +78,7 @@ This dataset can then be used to calculate the photosynthetic environment at the subdaily timescale. The code below also estimates GPP under the standard P Model with no slow responses for comparison. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Calculate the photosynthetic environment subdaily_env = PModelEnvironment( tc=temp_subdaily, @@ -98,9 +104,7 @@ best to sample those conditions. Typically those might be the observed environme conditions at the observation closest to noon, or the mean environmental conditions in a window around noon. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Create the fast slow scaler fsscaler = SubdailyScaler(datetime_subdaily) @@ -120,9 +124,8 @@ pmodel_subdaily = SubdailyPModel( ) ``` -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] -:trusted: true idx = np.arange(48 * 120, 48 * 130) plt.figure(figsize=(10, 4)) @@ -145,9 +148,7 @@ The daily average conditions during the acclimation window can be sampled and us inputs to the standard P Model to calculate the optimal behaviour of plants under those conditions. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Get the daily acclimation conditions for the forcing variables temp_acclim = fsscaler.get_daily_means(temp_subdaily) co2_acclim = fsscaler.get_daily_means(co2_subdaily) @@ -178,9 +179,7 @@ temperatures so $J_{max}$ and $V_{cmax}$ must first be standardised to expected at 25°C. This is acheived by multiplying by the reciprocal of the exponential part of the Arrhenius equation ($h^{-1}$ in {cite}`mengoli:2022a`). -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Are these any of the existing values in the constants? ha_vcmax25 = 65330 ha_jmax25 = 43900 @@ -195,9 +194,7 @@ jmax25_acclim = pmodel_acclim.jmax * (1 / calc_ftemp_arrh(tk_acclim, ha_jmax25)) The memory effect can now be applied to the three parameters with slow responses to calculate realised values, here using the default 15 day window. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Calculation of memory effect in xi, vcmax25 and jmax25 xi_real = memory_effect(pmodel_acclim.optchi.xi, alpha=1 / 15) vcmax25_real = memory_effect(vcmax25_acclim, alpha=1 / 15, allow_holdover=True) @@ -208,9 +205,8 @@ The plots below show the instantaneously acclimated values for $J_{max25}$, $V_{cmax25}$ and $\xi$ in grey along with the realised slow reponses, after application of the memory effect. -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] -:trusted: true fig, axes = plt.subplots(1, 3, figsize=(16, 5)) @@ -243,9 +239,7 @@ temperature at fast scales: * These values are adjusted to the actual half hourly temperatures to give the fast responses of $J_{max}$ and $V_{cmax}$. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 tk_subdaily = subdaily_env.tc + pmodel_subdaily.env.core_const.k_CtoK # Fill the realised jmax and vcmax from subdaily to daily @@ -265,9 +259,7 @@ passing the realised values of $\xi$ as a fixed constraint to the calculation of optimal $\chi$, rather than calculating the instantaneously optimal values of $\xi$ as is the case in the standard P Model. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Interpolate xi to subdaily scale xi_subdaily = fsscaler.fill_daily_to_subdaily(xi_real) @@ -286,9 +278,7 @@ Model, where $c_i$ includes the slow responses of $\xi$ and $V_{cmax}$ and $J_{m include the slow responses of $V_{cmax25}$ and $J_{max25}$ and fast responses to temperature. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Calculate Ac Ac_subdaily = ( vcmax_subdaily @@ -318,8 +308,6 @@ diff = GPP_subdaily - pmodel_subdaily.gpp print(np.nanmin(diff), np.nanmax(diff)) ``` -```{code-cell} -:trusted: true - +```{code-cell} ipython3 ``` diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md b/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md index 881f71b8..61d730d8 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_model_and_missing_data.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Missing data in the subdaily model @@ -46,7 +57,7 @@ The code below gives a concrete example - a time series that starts and ends dur the middle of a one hour acclimation window around noon. Only two of the three observations are provided for the first and last day -```{code-cell} +```{code-cell} ipython3 import numpy as np from pyrealm.pmodel.scaler import SubdailyScaler @@ -88,7 +99,7 @@ problem of the missing data clearly: * One day has a single missing 12:00 data point within the acclimation window. * One day has no data within the acclimation window. -```{code-cell} +```{code-cell} ipython3 fsscaler.get_window_values(data) ``` @@ -97,7 +108,7 @@ The daily average conditions are calculated using the partial data are not allowed - which is the default - the daily average conditions for all days with missing data is also missing (`np.nan`). -```{code-cell} +```{code-cell} ipython3 partial_not_allowed = fsscaler.get_daily_means(data) partial_not_allowed ``` @@ -106,7 +117,7 @@ Setting `allow_partial_data = True` allows the daily average conditions to be ca from the partial available information. This does not solve the problem for the day with no data in the acclimation window, which still results in a missing value. -```{code-cell} +```{code-cell} ipython3 partial_allowed = fsscaler.get_daily_means(data, allow_partial_data=True) partial_allowed ``` @@ -115,7 +126,7 @@ The :func:`~pyrealm.pmodel.subdaily.memory_effect` function is used to calculate realised values of a variable from the optimal values. By default, this function *will raise an error* when missing data are present: -```{code-cell} +```{code-cell} ipython3 :tags: [raises-exception] memory_effect(partial_not_allowed) @@ -125,14 +136,14 @@ The `allow_holdover` option allows the function to be run - the value for the fi is still `np.nan` but the missing observations on day 3, 5 and 7 are filled by holding over the valid observations from the previous day. -```{code-cell} +```{code-cell} ipython3 memory_effect(partial_not_allowed, allow_holdover=True) ``` When the partial data is allowed, the `allow_holdover` is still required to fill the gap on day 5 by holding over the data from day 4. -```{code-cell} +```{code-cell} ipython3 memory_effect(partial_allowed, allow_holdover=True) ``` diff --git a/docs/source/users/pmodel/subdaily_details/subdaily_overview.md b/docs/source/users/pmodel/subdaily_details/subdaily_overview.md index 3278b056..e96a57c9 100644 --- a/docs/source/users/pmodel/subdaily_details/subdaily_overview.md +++ b/docs/source/users/pmodel/subdaily_details/subdaily_overview.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The P Model with acclimation diff --git a/docs/source/users/pmodel/subdaily_details/worked_example.md b/docs/source/users/pmodel/subdaily_details/worked_example.md index fac12b6a..f30d4155 100644 --- a/docs/source/users/pmodel/subdaily_details/worked_example.md +++ b/docs/source/users/pmodel/subdaily_details/worked_example.md @@ -5,17 +5,26 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Worked example of the Subdaily P Model -```{code-cell} -:trusted: true - +```{code-cell} ipython3 from importlib import resources import xarray @@ -60,9 +69,7 @@ fitting basically takes all of the same arguments as the standard The test data use some UK WFDE data for three sites in order to compare predictions over a time series. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Loading the example dataset: dpath = ( resources.files("pyrealm_build_data.uk_data") / "UK_WFDE5_FAPAR_2018_JuneJuly.nc" @@ -83,9 +90,7 @@ sites = xarray.Dataset( The WFDE data need some conversion for use in the PModel, along with the definition of the atmospheric CO2 concentration. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Variable set up # Air temperature in °C from Tair in Kelvin tc = (ds["Tair"] - 273.15).to_numpy() @@ -104,9 +109,7 @@ co2 = np.ones_like(tc) * 400 The code below then calculates the photosynthetic environment. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Generate and check the PModelEnvironment pm_env = PModelEnvironment(tc=tc, patm=patm, vpd=vpd, co2=co2) pm_env.summarize() @@ -117,9 +120,7 @@ pm_env.summarize() The standard implementation of the P Model used below assumes that plants can instantaneously adopt optimal behaviour. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Standard PModels pmodC3 = PModel( env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="prentice14" @@ -128,9 +129,7 @@ pmodC3.estimate_productivity(fapar=fapar, ppfd=ppfd) pmodC3.summarize() ``` -```{code-cell} -:trusted: true - +```{code-cell} ipython3 pmodC4 = PModel( env=pm_env, method_kphio="fixed", reference_kphio=1 / 8, method_optchi="c4_no_gamma" ) @@ -146,9 +145,7 @@ values to holdover previous realised values to cover missing data within the calculations: essentially the plant does not acclimate until the optimal values can be calculated again to update those realised estimates. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Set the acclimation window to an hour either side of noon fsscaler = SubdailyScaler(datetimes) fsscaler.set_window( @@ -187,9 +184,7 @@ The code below then extracts the time series for the two months from the three s shown above and plots the instantaneous predictions against predictions including slow photosynthetic responses. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Store the predictions in the xarray Dataset to use indexing ds["GPP_pmodC3"] = (ds["Tair"].dims, pmodC3.gpp) ds["GPP_subdailyC3"] = (ds["Tair"].dims, subdailyC3.gpp) @@ -246,9 +241,7 @@ plt.tight_layout() The subdaily models can also be obtained directly from the standard models, using the `convert_pmodel_to_subdaily` method: -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Convert standard C3 model converted_C3 = convert_pmodel_to_subdaily( pmodel=pmodC3, @@ -269,9 +262,7 @@ converted_C4 = convert_pmodel_to_subdaily( This produces the same outputs as the `SubdailyPModel` class, but is convenient and more compact when the two models are going to be compared. -```{code-cell} -:trusted: true - +```{code-cell} ipython3 # Models have identical GPP - maximum absolute difference is zero. print(np.nanmax(abs(subdailyC3.gpp.flatten() - converted_C3.gpp.flatten()))) print(np.nanmax(abs(subdailyC4.gpp.flatten() - converted_C4.gpp.flatten()))) diff --git a/docs/source/users/splash.md b/docs/source/users/splash.md index e5c4d283..20236db4 100644 --- a/docs/source/users/splash.md +++ b/docs/source/users/splash.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The `splash` submodule @@ -46,7 +57,7 @@ The data below provides a 2 year daily time series of precipitation, temperature solar fraction (1 - cloud cover) for 0.5° resolution grid cells in a 10° by 10° block of the North Western USA. It also provides the mean elevation of those cells. -```{code-cell} +```{code-cell} ipython3 from importlib import resources import numpy as np import xarray @@ -74,7 +85,7 @@ data The plot below shows the elevation for the example data area, along with the locations of three sites that will be used to compare SPLASH outputs. -```{code-cell} +```{code-cell} ipython3 # Get the latitude and longitude extents extent = ( data["lon"].min(), @@ -95,7 +106,7 @@ The three sites capture wetter coastal conditions with milder temperatures (San Francisco), intermediate rainfall with colder temperatures (Yosemite) and arid conditions with extreme temperatures (Death Valley). -```{code-cell} +```{code-cell} ipython3 # Get three sites to show time series for locations site_data = data.sel(sites, method="nearest") @@ -149,7 +160,7 @@ may well be constant across the longitude dimension for gridded data - but, at t moment, you need to broadcast these variables to match. ``` -```{code-cell} +```{code-cell} ipython3 splash = SplashModel( lat=np.broadcast_to(data.lat.data[None, :, None], data.sf.data.shape), elv=np.broadcast_to(data.elev.data[None, :, :], data.sf.data.shape), @@ -176,7 +187,7 @@ give the expected soil moisture at the end of the year. If this is sufficiently to the start values, the estimate is returned, otherwise the end of year expectations are used as a starting point to recalculate the annual water balances. -```{code-cell} +```{code-cell} ipython3 init_soil_moisture = splash.estimate_initial_soil_moisture(verbose=False) ``` @@ -200,7 +211,7 @@ The plots show the soil moisture for the first day, along with the changes in so moisture from the initial estimates (the 'previous day'). Note the saturated soil moisture of 150mm near the coast and in the mountains. -```{code-cell} +```{code-cell} ipython3 # Calculate the water balance equation for the first day from the initial soil # moisture estimates. aet, wn, ro = splash.estimate_daily_water_balance(init_soil_moisture, day_idx=0) @@ -223,13 +234,13 @@ the daily estimation across all of the dates in the input data from initial soil moisture estimates. It returns a set of time series of soil moisture, runoff and AET for all sites. -```{code-cell} +```{code-cell} ipython3 aet_out, wn_out, ro_out = splash.calculate_soil_moisture(init_soil_moisture) ``` The plots below show the resulting soil moisture and a time series for the three -```{code-cell} +```{code-cell} ipython3 # Add the outputs to the xarray to select the three sites easily. data["aet"] = xarray.DataArray(aet_out, dims=("time", "lat", "lon")) data["wn"] = xarray.DataArray(wn_out, dims=("time", "lat", "lon")) diff --git a/docs/source/users/tmodel/canopy.md b/docs/source/users/tmodel/canopy.md index 3fab2df8..d760ca77 100644 --- a/docs/source/users/tmodel/canopy.md +++ b/docs/source/users/tmodel/canopy.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 (ipykernel) language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # Canopy model @@ -36,7 +47,7 @@ This sketch: object. ``` -```{code-cell} +```{code-cell} ipython3 import numpy as np import matplotlib.pyplot as plt from scipy.optimize import root_scalar @@ -54,11 +65,11 @@ The scaling of a set of trees is automatically calculated using the initial diam the `TTree` instance. This automatically calculates the other dimensions, such as height, using the underlying scaling equations of the T Model. -```{code-cell} +```{code-cell} ipython3 pft.height ``` -```{code-cell} +```{code-cell} ipython3 :lines_to_next_cell: 2 pft.crown_area @@ -97,7 +108,7 @@ r_0 &= \frac{1}{q_m}\sqrt{\frac{A_c}{\pi}} \end{align} $$ -```{code-cell} +```{code-cell} ipython3 :lines_to_next_cell: 2 def calculate_qm(m, n): @@ -146,7 +157,7 @@ r(z) &= r_0 \; q(z) \end{align} $$ -```{code-cell} +```{code-cell} ipython3 def calculate_relative_canopy_radius_at_z(z, H, m, n): """Calculate q(z)""" @@ -155,20 +166,20 @@ def calculate_relative_canopy_radius_at_z(z, H, m, n): return m * n * z_over_H ** (n - 1) * (1 - z_over_H**n) ** (m - 1) ``` -```{code-cell} +```{code-cell} ipython3 # Validate that zm and r0 generate the predicted maximum crown area q_zm = calculate_relative_canopy_radius_at_z(zm, pft.height, m, n) rm = r0 * q_zm print("rm = ", rm) ``` -```{code-cell} +```{code-cell} ipython3 np.allclose(rm**2 * np.pi, pft.crown_area) ``` Vertical crown radius profiles can now be calculated for each stem: -```{code-cell} +```{code-cell} ipython3 # Create an interpolation from ground to maximum stem height, with 5 cm resolution. # Also append a set of values _fractionally_ less than the exact height of stems # so that the height at the top of each stem is included but to avoid floating @@ -190,7 +201,7 @@ np.cumsum(np.convolve(rm, np.ones(2), "valid") + 0.1) Those can be plotted out to show the vertical crown radius profiles -```{code-cell} +```{code-cell} ipython3 # Separate the stems along the x axis for plotting stem_x = np.concatenate( [np.array([0]), np.cumsum(np.convolve(rm, np.ones(2), "valid") + 0.4)] @@ -237,7 +248,7 @@ A_c \left(\dfrac{q(z)}{q_m}\right)^2, & H > z > z_m \\ \end{cases} $$ -```{code-cell} +```{code-cell} ipython3 Stems = float | np.ndarray @@ -281,7 +292,7 @@ def calculate_projected_area( The code below calculates the projected crown area for each stem and then plots the vertical profile for individual stems and across the community. -```{code-cell} +```{code-cell} ipython3 :lines_to_next_cell: 2 # Calculate the projected area for each stem @@ -331,7 +342,7 @@ $$ l_m = \left\lceil \frac{\sum_1^{N_s}{ A_c}}{ A(1 - f_G)}\right\rceil $$ -```{code-cell} +```{code-cell} ipython3 def solve_canopy_closure_height( z: float, l: int, @@ -395,7 +406,7 @@ def calculate_canopy_heights( The example below calculates the projected crown area above ground level for the example stems. These should be identical to the crown area of the stems. -```{code-cell} +```{code-cell} ipython3 # Set the total available canopy space and community gap fraction canopy_area = 32 community_gap_fraction = 2 / 32 @@ -412,7 +423,7 @@ superimpose the calculated $z^*_l$ values and the cumulative canopy area for eac to confirm that the calculated values coincide with the profile. Note here that the total area at each closed layer height is omitting the community gap fraction. -```{code-cell} +```{code-cell} ipython3 community_Ap_z = np.nansum(Ap_z, axis=1) fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(10, 5)) @@ -481,14 +492,14 @@ plt.tight_layout() The projected area from individual stems to each canopy layer can then be calculated at $z^*_l$ and hence the projected area of canopy **within each layer**. -```{code-cell} +```{code-cell} ipython3 # Calculate the canopy area above z_star for each stem Ap_z_star = calculate_projected_area(z=z_star[:, None], pft=pft, m=m, n=n, qm=qm, zm=zm) print(Ap_z_star) ``` -```{code-cell} +```{code-cell} ipython3 :lines_to_next_cell: 2 # Calculate the contribution _within_ each layer per stem @@ -527,7 +538,7 @@ $$ The function below calculates $\tilde{A}_{cp}(z)$. -```{code-cell} +```{code-cell} ipython3 def calculate_leaf_area( z: float, fg: float, @@ -572,7 +583,7 @@ there are no crown gaps and hence all of the leaf area is within the crown surfa $f_g \to 1$, more of the leaf area is displaced deeper into the canopy, leaves in the lower crown intercepting light coming through holes in the upper canopy. -```{code-cell} +```{code-cell} ipython3 fig, ax1 = plt.subplots(1, 1, figsize=(6, 5)) for fg in np.arange(0, 1.01, 0.05): @@ -600,7 +611,7 @@ ax1.legend(frameon=False) We can now calculate the crown area occupied by leaves above the height of each closed layer $z^*_l$: -```{code-cell} +```{code-cell} ipython3 # Calculate the leaf area above z_star for each stem crown_gap_fraction = 0.05 Acp_z_star = calculate_leaf_area( @@ -614,7 +625,7 @@ And from that, the area occupied by leaves **within each layer**. These values a similar to the projected crown area within layers (`Ap_within_layer`, above) but leaf area is displaced into lower layers because $f_g > 0$. -```{code-cell} +```{code-cell} ipython3 # Calculate the contribution _within_ each layer per stem Acp_within_layer = np.diff(Acp_z_star, axis=0, prepend=0) @@ -631,7 +642,7 @@ $f_{abs} = 1 - e ^ {-kL}$, where $k$ is the light extinction coefficient ($k$) and $L$ is the leaf area index (LAI). The LAI can be calculated for each stem and layer: -```{code-cell} +```{code-cell} ipython3 LAI = Acp_within_layer / canopy_area print(LAI) ``` @@ -639,7 +650,7 @@ print(LAI) This can be used to calculate the LAI of individual stems but also the LAI of each layer in the canopy: -```{code-cell} +```{code-cell} ipython3 LAI_stem = LAI.sum(axis=0) LAI_layer = LAI.sum(axis=1) @@ -650,7 +661,7 @@ print("LAI layer = ", LAI_layer) The layer LAI values can now be used to calculate the light transmission of each layer and hence the cumulative light extinction profile through the canopy. -```{code-cell} +```{code-cell} ipython3 f_abs = 1 - np.exp(-pft.traits.par_ext * LAI_layer) ext = np.cumprod(f_abs) @@ -662,7 +673,7 @@ One issue that needs to be resolved is that the T Model implementation in `pyrea follows the original implementation of the T Model in having LAI as a fixed trait of a given plant functional type, so is constant for all stems of that PFT. -```{code-cell} +```{code-cell} ipython3 print("f_abs = ", (1 - np.exp(-pft.traits.par_ext * pft.traits.lai))) ``` diff --git a/docs/source/users/tmodel/tmodel.md b/docs/source/users/tmodel/tmodel.md index fda39de0..d7e75b31 100644 --- a/docs/source/users/tmodel/tmodel.md +++ b/docs/source/users/tmodel/tmodel.md @@ -5,10 +5,21 @@ jupytext: extension: .md format_name: myst format_version: 0.13 + jupytext_version: 1.16.4 kernelspec: display_name: Python 3 language: python name: python3 +language_info: + codemirror_mode: + name: ipython + version: 3 + file_extension: .py + mimetype: text/x-python + name: python + nbconvert_exporter: python + pygments_lexer: ipython3 + version: 3.11.9 --- # The T Model @@ -31,7 +42,7 @@ class description. The class can be used to create a default T Model trait set: -```{code-cell} +```{code-cell} ipython3 import numpy as np from pyrealm import tmodel @@ -42,7 +53,7 @@ print(traits1) It can also be edited to generate different growth patterns: -```{code-cell} +```{code-cell} ipython3 # A slower growing tree with a higher maximum height traits2 = tmodel.TModelTraits(a_hd=50, h_max=40) print(traits2) @@ -71,7 +82,7 @@ diameters and an optional set of traits as a {class}`~pyrealm.constants.tmodel_const.TModelTraits` object. If no traits are provided, the default {class}`~pyrealm.constants.tmodel_const.TModelTraits` settings are used. -```{code-cell} +```{code-cell} ipython3 # Use a sequence of diameters from sapling to large tree diameters = np.linspace(0.02, 2, 100) tree1 = tmodel.TTree(diameters=diameters) # Using default traits @@ -92,7 +103,7 @@ These inputs are then immediately used to calculate the following properties of Using an array of diameter values provides an immediate way to visualise the geometric scaling resulting from a particular set of plant traits: -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] from matplotlib import pyplot @@ -144,12 +155,12 @@ provide estimates of the following growth parameters: The code below calculates growth estimates at each diameter under a constant GPP of 7 TODO - UNITS!. -```{code-cell} +```{code-cell} ipython3 tree1.calculate_growth(np.array([7])) tree2.calculate_growth(np.array([7])) ``` -```{code-cell} +```{code-cell} ipython3 :tags: [hide-input] fig, (ax1, ax2, ax3) = pyplot.subplots(1, 3, figsize=(12, 4)) @@ -183,7 +194,7 @@ The {meth}`~pyrealm.tmodel.TTree.reset_diameters` can be used to update an exist {meth}`~pyrealm.tmodel.TTree.reset_diameters` automatically resets any calculated growth parameters: they will need to be recalculated for the new diameters. -```{code-cell} +```{code-cell} ipython3 tree1.reset_diameters(np.array([0.0001])) print(tree1.height) ``` From 15586d92061a8db93fa878e6d5e64c160c563d1d Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 16 Oct 2024 17:43:04 +0100 Subject: [PATCH 231/241] Updates to pyrealm_build_data docstrings --- pyrealm_build_data/__init__.py | 22 +++- pyrealm_build_data/bigleaf/__init__.py | 17 ++- pyrealm_build_data/rpmodel/__init__.py | 59 +++++++++- pyrealm_build_data/sandoval_kphio/__init__.py | 14 +++ pyrealm_build_data/splash/README.md | 91 ---------------- pyrealm_build_data/splash/__init__.py | 98 ++++++++++++++++- pyrealm_build_data/subdaily/__init__.py | 12 ++- pyrealm_build_data/t_model/__init__.py | 23 +++- pyrealm_build_data/t_model/rtmodel_output.csv | 101 ------------------ pyrealm_build_data/two_leaf/__init__.py | 7 ++ pyrealm_build_data/uk_data/__init__.py | 11 +- 11 files changed, 253 insertions(+), 202 deletions(-) create mode 100644 pyrealm_build_data/sandoval_kphio/__init__.py delete mode 100644 pyrealm_build_data/splash/README.md delete mode 100644 pyrealm_build_data/t_model/rtmodel_output.csv create mode 100644 pyrealm_build_data/two_leaf/__init__.py diff --git a/pyrealm_build_data/__init__.py b/pyrealm_build_data/__init__.py index 2735eb94..13c9caca 100644 --- a/pyrealm_build_data/__init__.py +++ b/pyrealm_build_data/__init__.py @@ -1,4 +1,18 @@ -"""The pyrealm_build_data package is an sdist only package used to store build data -shared between the docs and testing. Making it a package allows it to be accessed using -importlib.resources(). -""" # noqa: D205 +"""The ``pyrealm`` repository includes both the ``pyrealm`` package and the +``pyrealm_build_data`` package. The ``pyrealm_build_data`` package contains datasets +that are used in the ``pyrealm`` build and testing process. This includes: + +* Example datasets that are used in the package documentation, such as simple spatial + datasets for showing the use of the P Model. +* "Golden" datasets for regression testing ``pyrealm`` implementations against the + outputs of other implementations. These datasets will include a set of input data and + then output predictions from other implementations. +* Datasets for providing profiling of ``pyrealm`` code and for benchmarking new versions + of the package code against earlier implementations to check for performance issues. + +Note that ``pyrealm_build_data`` is a source distribution only (``sdist``) component of +``pyrealm``, so is not included in binary distributions (``wheel``) that are typically +installed by end users. This means that files in ``pyrealm_build_data`` are not +available if a user has simply used ``pip install pyrealm``: please *do not* use +``pyrealm_build_data`` within the main ``pyrealm`` code. +""" # noqa: D205, D415 diff --git a/pyrealm_build_data/bigleaf/__init__.py b/pyrealm_build_data/bigleaf/__init__.py index 9e3edcee..e0568665 100644 --- a/pyrealm_build_data/bigleaf/__init__.py +++ b/pyrealm_build_data/bigleaf/__init__.py @@ -1 +1,16 @@ -"""Validation data from the bigleaf package in R.""" +"""This submodule contains benchmark outputs from the ``bigleaf`` package in ``R``, +which has been used as the basis for core hygrometry functions. The +``bigleaf_conversions.R`` R script runs a set of test values through `bigleaf`. The +first part of the file prints out some simple test values that have been used in package +doctests and then the second part of the file generates more complex benchmarking inputs +that are saved, along with `bigleaf` outputs as `bigleaf_test_values.json`. + +Running ``bigleaf_conversions.R`` requires an installation of ``R`` along with the +``jsonlite`` and ``bigleaf`` packages, and the script can then be run from within the +submodule folder as: + +.. code:: sh + + Rscript bigleaf_conversions.R + +""" # noqa: D205 diff --git a/pyrealm_build_data/rpmodel/__init__.py b/pyrealm_build_data/rpmodel/__init__.py index 0500ea06..7ca00769 100644 --- a/pyrealm_build_data/rpmodel/__init__.py +++ b/pyrealm_build_data/rpmodel/__init__.py @@ -1 +1,58 @@ -"""Validation data from the rpmodel package in R.""" +"""This submodule contains benchmark outputs from the ``rpmodel`` package in ``R``, +which has been used as the basis for initial development of the standard P Model. + +Test inputs +=========== + +The ``generate_test_inputs.py`` file defines a set of constants for running P Model +calculations and then defines a set of scalar and array inputs for the forcing variables +required to run the P Model. The array inputs are set of 100 values sampled randomly +across the ranges of plausible forcing value inputs in order to benchmark the +calculations of the P Model implementation. All of these values are stored in the +``test_inputs.json`` file. + +It requires ``python`` and the ``numpy`` package and can be run as: + +.. code:: sh + + python generate_test_inputs.py + +Simple `rpmodel` benchmarking +============================= + +The ``test_outputs_rpmodel.R`` contains R code to run the test input data set, and store +the expected predictions from the ``rpmodel`` package as ``test_outputs_rpmodel.json``. +It requires an installation of ``R`` and the ``rpmodel`` package and can be run as: + +.. code:: sh + + Rscript test_outputs_rpmodel.R + +Global array test +================= + +The remaining files in the submodule are intended to provide a global test dataset for +benchmarking the use of ``rpmodel`` on a global time-series, so using 3 dimensional +arrays with latitude, longitude and time coordinates. It is currently not used in +testing because of issues with the ``rpmodel`` package in version 1.2.0. It may also be +replaced in testing with the ``uk_data`` submodule, which is used as an example dataset +in the documentation. + +The files are: + +* ``pmodel_global.nc``: An input global NetCDF file containing forcing variables at 0.5° + spatial resolution and for two time steps. +* ``test_global_array.R``: An R script to run ``rpmodel`` using the dataset. +* ``rpmodel_global_gpp_do_ftkphio.nc``: A NetCDF file containing ``rpmodel`` predictions + using corrections for temperature effects on the `kphio` parameter. +* ``rpmodel_global_gpp_no_ftkphio.nc``: A NetCDF file containing ``rpmodel`` predictions + with fixed ``kphio``. + +To generate the predicted outputs again requires an R installation with the ``rpmodel`` +package: + +.. code:: sh + + Rscript test_global_array.R + +""" # noqa: D205 diff --git a/pyrealm_build_data/sandoval_kphio/__init__.py b/pyrealm_build_data/sandoval_kphio/__init__.py new file mode 100644 index 00000000..e5a8cf09 --- /dev/null +++ b/pyrealm_build_data/sandoval_kphio/__init__.py @@ -0,0 +1,14 @@ +r"""This submodule contains benchmark outputs from the ``calc_phi0.R`` script, which is +an experimental approach to calculating the :math:`\phi_0` parameter for the P Model +with modulation from climatic aridity and growing degree days and the current +temperature. The calculation is implemented in ``pyrealm`` as +:class:`~pyrealm.pmodel.quantum_yield.QuantumYieldSandoval`. + +The files are: + +* ``calc_phi0.R``: The original implementation and parameterisation. +* ``create_test_inputs.R``: A script to run the original implementation with a range of + inputs and save a file of test values. +* ``sandoval_kphio.csv``: The resulting test values. + +""" # noqa: D205 diff --git a/pyrealm_build_data/splash/README.md b/pyrealm_build_data/splash/README.md deleted file mode 100644 index a1bebba8..00000000 --- a/pyrealm_build_data/splash/README.md +++ /dev/null @@ -1,91 +0,0 @@ -# SPLASH benchmark data - -This directory contains the code and inputs used to generate the SPLASH benchmark -datasets used in unit testing `pyrealm.splash` and in regression tests against the -original SPLASH v1 implementation. - -## Benchmark test data - -The `splash_make_flux_benchmark_inputs.py` script is used to generate 100 random -locations around the globe with random dates, initial soil moisture, preciptation, -cloud fraction and temperature (within reasonable bounds). This provides a robust test -of the calculations of various fluxes across a wide range of plausible value -combinations. The input data is created using: - -```sh -python splash_make_flux_benchmark_inputs.py -o data/daily_flux_benchmark_inputs.csv -``` - -The `splash_run_calc_daily_fluxes.py` script can then be used to run the inputs through -the original SPLASH implementation provided in the `splash_py_version` module. - -```sh -python splash_run_calc_daily_fluxes.py \ - -i data/daily_flux_benchmark_inputs.csv \ - -o data/daily_flux_benchmark_outputs.csv -``` - -## Original time series - -The SPLASH v1.0 implementation provided a time series of inputs for a single location -around San Francisco in 2000, with precipitation and temperature taken from WFDEI and -sunshine fraction interpolated from CRU TS. The original source data is included as -`data/splash_sf_example_data.csv`. - -The original SPLASH `main.py` provides a simple example to run this code and output -water balance, which can be used as a direct benchmark without any wrapper scripts. With -the alterations to make the SPLASH code importable, the command below can be used to run -the code and capture the output: - -```sh -python -m splash_py_version.main > data/splash_sf_example_data_main_output.csv -``` - -Note that this command also generates `main.log`, which contains over 54K lines of -logging and takes up over 6 Mb. This is not included in the `pyrealm` repo. - -Because the `splash_sf_example_data_main_output.csv` file only contains predicted water -balance, the same input data is also run through a wrapper script to allow daily -calculations to be benchmarked in more detail. The first step is to use the -`splash_sf_example_to_netcdf.py` script to convert the CSV data into a properly -dimensioned NetCDF file: - -```sh -python splash_sf_example_to_netcdf.py -``` - -This creates the file `data/splash_sf_example_data.nc`, which can be run using the -original SPLASH components using script `splash_run_time_series_parallel.py`. - -```sh -python splash_run_time_series_parallel.py \ - -i "data/splash_sf_example_data.nc" \ - -o "data/splash_sf_example_data_details.nc" -``` - -## Gridded time series - -This is a 20 x 20 cell spatial grid covering 2 years of daily data that is used to -validate the spin up of the initial moisture and the calculation of SPLASH water balance -over a time series across a larger spatial extent. The dataset is generated using the -`splash_make_spatial_grid_data.py` script, which requires paths to local copies of the -`WFDE5_v2` dataset and a version of the `CRU TS` dataset. Note that the file paths below -are examples and these data **are not included in the `pyrealm` repo**. - -```sh -python splash_make_spatial_grid_data.py \ - -w "/rds/general/project/lemontree/live/source/wfde5/wfde5_v2/" \ - -c "/rds/general/project/lemontree/live/source/cru_ts/cru_ts_4.0.4/" \ - -o "data/splash_nw_us_grid_data.nc" -``` - -The resulting `splash_nw_us_grid_data.nc` dataset can then be analysed using the -original SPLASH implementation using the script `splash_run_time_series_parallel.py`. -This uses parallel processing to run multiple cells simultaneously and will output the -progress of the calculations. - -```sh -python splash_run_time_series_parallel.py \ - -i "data/splash_nw_us_grid_data.nc" \ - -o "data/splash_nw_us_grid_data_outputs.nc" -``` diff --git a/pyrealm_build_data/splash/__init__.py b/pyrealm_build_data/splash/__init__.py index f48e4a55..2ce2c510 100644 --- a/pyrealm_build_data/splash/__init__.py +++ b/pyrealm_build_data/splash/__init__.py @@ -1 +1,97 @@ -"""Validation data from the SPLASH V1 package in python.""" +r"""This module contains the code and inputs used to generate the SPLASH benchmark +datasets used in unit testing :mod:`~pyrealm.splash` and in regression tests against the +original SPLASH v1 implementation. + +Benchmark test data +=================== + +The ``splash_make_flux_benchmark_inputs.py`` script is used to generate 100 random +locations around the globe with random dates, initial soil moisture, preciptation, +cloud fraction and temperature (within reasonable bounds). This provides a robust test +of the calculations of various fluxes across a wide range of plausible value +combinations. The input data is created using: + +.. code:: sh + + python splash_make_flux_benchmark_inputs.py -o data/daily_flux_benchmark_inputs.csv + +The ``splash_run_calc_daily_fluxes.py`` script can then be used to run the inputs +through the original SPLASH implementation provided in the ``splash_py_version`` +directory. + +.. code:: sh + + python splash_run_calc_daily_fluxes.py \ + -i data/daily_flux_benchmark_inputs.csv \ + -o data/daily_flux_benchmark_outputs.csv + +Original time series +==================== + +The SPLASH v1.0 implementation provided a time series of inputs for a single location +around San Francisco in 2000, with precipitation and temperature taken from WFDEI and +sunshine fraction interpolated from CRU TS. The original source data is included as +``data/splash_sf_example_data.csv``. + +The original SPLASH ``main.py`` provides a simple example to run this code and output +water balance, which can be used as a direct benchmark without any wrapper scripts. With +the alterations to make the SPLASH code importable, the command below can be used to run +the code and capture the output: + +.. code:: sh + + python -m splash_py_version.main > data/splash_sf_example_data_main_output.csv + +Note that this command also generates ``main.log``, which contains over 54K lines of +logging and takes up over 6 Mb. This is not included in the ``pyrealm_build_data`` +package. + +Because the ``splash_sf_example_data_main_output.csv`` file only contains predicted +water balance, the same input data is also run through a wrapper script to allow daily +calculations to be benchmarked in more detail. The first step is to use the +``splash_sf_example_to_netcdf.py`` script to convert the CSV data into a properly +dimensioned NetCDF file: + +.. code:: sh + + python splash_sf_example_to_netcdf.py + + +This creates the file `data/splash_sf_example_data.nc`, which can be run using the +original SPLASH components using script `splash_run_time_series_parallel.py`. + +.. code:: sh + + python splash_run_time_series_parallel.py \ + -i "data/splash_sf_example_data.nc" \ + -o "data/splash_sf_example_data_details.nc" + +Gridded time series +=================== + +This is a 20 x 20 cell spatial grid covering 2 years of daily data that is used to +validate the spin up of the initial moisture and the calculation of SPLASH water balance +over a time series across a larger spatial extent. The dataset is generated using the +``splash_make_spatial_grid_data.py`` script, which requires paths to local copies of the +``WFDE5_v2`` dataset and a version of the ``CRU TS`` dataset. Note that the file paths +below are examples and these data are **not included** in the ``pyrealm_build_data`` +package. + +.. code:: sh + + python splash_make_spatial_grid_data.py \ + -w "/rds/general/project/lemontree/live/source/wfde5/wfde5_v2/" \ + -c "/rds/general/project/lemontree/live/source/cru_ts/cru_ts_4.0.4/" \ + -o "data/splash_nw_us_grid_data.nc" + +The resulting ``splash_nw_us_grid_data.nc`` dataset can then be analysed using the +original SPLASH implementation using the script ``splash_run_time_series_parallel.py``. +This uses parallel processing to run multiple cells simultaneously and will output the +progress of the calculations. + +.. code:: sh + + python splash_run_time_series_parallel.py \ + -i "data/splash_nw_us_grid_data.nc" \ + -o "data/splash_nw_us_grid_data_outputs.nc" +""" # noqa: D205 diff --git a/pyrealm_build_data/subdaily/__init__.py b/pyrealm_build_data/subdaily/__init__.py index 1a922b13..6e4a2e8b 100644 --- a/pyrealm_build_data/subdaily/__init__.py +++ b/pyrealm_build_data/subdaily/__init__.py @@ -1 +1,11 @@ -"""Validation data from the original R implementation of the subdaily model.""" +"""At present, this submodule only contains a single file containing the predictions for +the ``BE_Vie`` fluxnet site from the original implementation of the ``subdaily`` module, +published in :cite:`mengoli:2022a`. Generating these predictions requires an +installation of R and then code from the following repository: + +`https://github.com/GiuliaMengoli/P-model_subDaily `_ + +TODO - This submodule should be updated to include the required code along with the +settings files and a runner script to reproduce this code. Or possibly to checkout the +required code as part of a shell script. +""" # noqa: D205, D415 diff --git a/pyrealm_build_data/t_model/__init__.py b/pyrealm_build_data/t_model/__init__.py index 78415131..af9ae09a 100644 --- a/pyrealm_build_data/t_model/__init__.py +++ b/pyrealm_build_data/t_model/__init__.py @@ -1 +1,22 @@ -"""Validation data from the original implementation of the T model in R.""" +"""The `t_model` submodule provides reference data for testing the implementation of the +T model :cite:p:`Li:2014bc`. The file ``t_model.r`` contains the original implementation +in R. The ``rtmodel_test_outputs.r`` contains a slightly modified version of the +function that makes it easier to output test values and then runs the function for the +following scenarios: + +* A 100 year sequence of plant growth for each of three plant functional type (PFT) + definitions (``default``, ``alt_one`` and ``alt_two``). The parameterisations for the + three PFTs are in the file ``pft_definitions.csv`` and the resulting time series for + each PFT is written to ``rtmodel_output_xxx.csv``. + +* Single year predictions across a range of initial diameter at breast height values for + each of the three PFTs. These are saved as ``rtmodel_unit_testing.csv`` and are used + for simple validation of the main scaling functions. + +To generate the predicted outputs again requires an R installation + +.. code:: sh + + Rscript rtmodel_test_outputs.r + +""" # noqa: D205, D415 diff --git a/pyrealm_build_data/t_model/rtmodel_output.csv b/pyrealm_build_data/t_model/rtmodel_output.csv deleted file mode 100644 index 192908b5..00000000 --- a/pyrealm_build_data/t_model/rtmodel_output.csv +++ /dev/null @@ -1,101 +0,0 @@ -"dD","D","H","Ac","Wf","Ws","Wss","GPP","Rm1","Rm2","dWs","dWfr" -9.23535494468514,0.1,9.30685130731739,2.46024211324268,0.316316843131202,7.30958392378022,7.02392939699003,9.1978885806073,0.309052893467561,0.687337521113514,3.76476031902394,0.353180440335674 -9.41347975186052,0.11847070988937,10.6064694519639,3.3216732508429,0.427072275108373,11.6918358255143,11.0829530843886,12.418444631113,0.4876499357131,0.928002429473987,5.11540450334165,0.402164311708017 -9.56242271047402,0.137297669393091,11.8227317389103,4.29097588211766,0.551696899129414,17.5038687119995,16.341714741243,16.0422902499508,0.719035448614692,1.19880425999427,6.62787138562828,0.446337579848307 -9.69154513020616,0.156422514814039,12.9554153338523,5.35704971954974,0.68876353537068,24.8965832383358,22.8600457539045,20.0279257785112,1.0058420131718,1.49664183654837,8.28100480236048,0.485860611280906 -9.8067299345139,0.175805605074452,14.0065146815861,6.50935370650332,0.836916905121855,34.0005072801248,30.6655594427653,24.3359423049901,1.34928461548167,1.81857021981548,10.0553709356637,0.52100017161193 -9.9118179887506,0.19541906494348,14.9792591514052,7.73806437175455,0.994893990654156,44.9276887698395,39.7582456018626,28.9296136904005,1.74936280648195,2.16184494805204,11.9334707249518,0.552072706446046 -10.0093918091071,0.215242700920981,15.8775424513254,9.03413941905036,1.16153221102076,57.7736797915528,50.1151867893735,33.7751343052069,2.20506821873244,2.52393980261545,13.8997585704866,0.579412356468393 -10.1012253105873,0.235261484539195,16.7055797227729,10.389327995,1.33577074221428,72.619474012326,61.6950922673494,38.841657416978,2.71458405976337,2.90254967658711,15.9405589482595,0.603352606803862 -10.1885538666546,0.25546393516037,17.4676966162467,11.7961506682707,1.51664794306338,89.5333258349725,74.4424750457644,44.1012203403852,3.27546890201363,3.29558498140014,18.0439316139172,0.624215789412495 -10.2722432037438,0.275841042893679,18.1681979492976,13.2478625042661,1.70329660769136,108.572417149682,88.2913823468227,49.5286063877833,3.8848208232602,3.70116133071686,20.1995143511014,0.642307261965835 -10.3528989805214,0.296385529301166,18.8112859111281,14.7384072607093,1.89493807637692,129.784359269137,103.168645349644,55.1011736243075,4.53942039538435,4.11758674368246,22.3983600310141,0.65791243548126 -10.4309402999148,0.317091327262209,19.4010098996293,16.2623676083615,2.09087583536076,153.208530237407,118.996649730928,60.7986687624964,5.23585258816084,4.54334773768881,24.6327776139951,0.671295558231005 -10.5066505553506,0.337953207862039,19.9412369382857,17.8149143933709,2.2904889934334,178.877254866472,135.695650514095,66.6030374739461,5.97060862262016,4.97709515339117,26.8961824217297,0.682699582930953 -10.5802135953775,0.35896650897274,20.4356356570896,19.3917567830863,2.4932258721111,206.816838688539,153.185667373722,72.4982380038911,6.74016936444376,5.41763022654509,29.1829583714671,0.692346693223028 -10.6517401049225,0.380126936163495,20.8876692783712,20.9890943915628,2.69859785034379,237.048468789206,171.388002835312,78.4700621870874,7.54107212475373,5.86389121292604,31.4883332404618,0.70043921831005 -10.7212872876908,0.40143041637334,21.300594588579,22.6035720021614,2.90617354313504,269.588994995487,190.226427898919,84.5059661732193,8.36996282755243,6.31494073881986,33.8082670397389,0.707160761026536 -10.788873837953,0.422872990948721,21.6774648674801,24.2322371960362,3.11557335377609,304.451604634413,209.628079003584,90.5949120162889,9.22363547615769,6.76995396335422,36.1393529904729,0.712677426777046 -10.8544915107154,0.444450738624627,22.0211353971244,25.8725009974224,3.32646441395431,341.646403373464,229.524107986928,96.7272205426512,10.0990607514249,7.22820758365789,38.4787302691996,0.717139081457436 -10.9181141692032,0.466159721646058,22.3342706083702,27.5221015217334,3.53855590993715,381.180913710614,249.850123500867,102.894435445385,10.9934054340381,7.68906967893882,40.8240075270072,0.720680593366289 -10.9797049112577,0.487995949984465,22.6193522183127,29.1790705359805,3.75159478319749,423.060501631756,270.546458704653,109.089198266706,11.9040441830047,8.15199036820116,43.1731961323058,0.723423031954346 -11.0392216947139,0.50995535980698,22.8786879147386,30.8417027966632,3.96536178814241,467.28874088081,291.558296287291,115.30513376426,12.8285650366408,8.61649324392616,45.5246520968697,0.725474808061432 -11.0966217616171,0.532033803196408,23.1144202839139,32.508528007077,4.17966788662418,513.867723244362,312.835678172426,121.536745070403,13.7647698395867,9.08216753756115,47.8770256941991,0.726932748015837 -11.1518650808786,0.554227046719642,23.3285357753348,34.1782852265282,4.39435095769649,562.798322268441,334.333423749197,127.779318018207,14.7106706449647,9.548660970017,50.2292178503936,0.727883098927698 -11.2049169750738,0.576530776881399,23.5228735647065,35.8498995631448,4.60927280097576,614.080416916261,356.010977216961,134.028834004941,15.6644829975463,10.0156732401523,52.5803424692092,0.72840246558233 -11.2557500607435,0.598940610831546,23.699134223315,37.5224609864079,4.82431641253815,667.713080849277,377.832201659479,140.281890780365,16.6246168730171,10.4829501054607,54.929693937393,0.728558681142435 -11.3043456069087,0.621452110953033,23.8588881343156,39.1952051028777,5.03938351322714,723.694742271028,399.765134781884,146.535630574648,17.5896659304029,10.9502780112318,57.2767191390989,0.728411614824685 -11.3506943996244,0.644060802166851,24.0035836186046,40.867495747327,5.25439231037061,782.023318611418,421.781718844873,152.787675013381,18.5583956291744,11.4174792268967,59.6209933863983,0.728013920123719 -11.3947971885715,0.6667621909661,24.1345547479324,42.5388092506586,5.46927547508467,842.696329743805,443.857515200855,159.036066301443,19.5297306688376,11.8844074508305,61.9621997450884,0.72741172722304 -11.4366647830844,0.689551785343243,24.2530288329452,44.2087202549852,5.6839783184981,905.710992912826,465.971411958392,165.279214191096,20.5027421261692,12.3509438473973,64.3001113004591,0.726645283101856 -11.4763178583598,0.712425114909411,24.3601335804589,45.8768889547655,5.89845715132699,971.064302101036,488.105331654886,171.515848281556,21.476634592815,12.8169934824045,66.6345759662775,0.72574954261762 -11.5137865270621,0.735377750626131,24.4569039185977,47.5430496507862,6.11267781224394,1038.75309417099,510.243944383874,177.744975226784,22.4507335528904,13.2824821253373,68.965503492165,0.72475471358056 -11.5491097265677,0.758405323680255,24.5442884912449,49.2070005110274,6.3266143514178,1108.77410378004,532.374390583779,183.965840455342,23.4244731856863,13.7473533887698,71.2928543701998,0.72368675857888 -11.5823344673607,0.781503543133391,24.623155825123,50.8685944390853,6.54024785645383,1181.12400877234,554.486016631851,190.177894030974,24.3973847318015,14.2115661772028,73.6166303814841,0.722567856084471 -11.6135149834225,0.804668212068112,24.6943001741004,52.5277309569395,6.75356540874936,1255.79946750029,576.570125483616,196.380760305435,25.3690855212791,14.6750924192878,75.936866558147,0.721416823179015 -11.6427118207842,0.827895242034957,24.7584470462852,54.1843490145248,6.96655915901033,1332.797149312,598.619743838572,202.574211036269,26.3392687288971,15.1379150589799,78.253624366379,0.72024950209124 -11.6699908957385,0.851180665676526,24.8162584202463,55.8384206438972,7.1792255113582,1412.11375925615,620.62940668237,208.758141662209,27.3076938940243,15.6000262826507,80.5669859421713,0.719079112624556 -11.695422549592,0.874520647468003,24.8683376574133,57.4899453808399,7.39156440610798,1493.74605789843,642.594959540046,214.932550447731,28.274178219762,16.0614259606083,82.8770492339763,0.71791657247362 -11.719080622341,0.897911492567187,24.9152341183743,59.1389453816113,7.60357869192145,1577.69087700956,664.513378360821,221.097520226468,29.2385886478761,16.5221202828238,85.1839239259814,0.716770787371128 -11.7410415633662,0.921349653811869,24.9574474914475,60.7854611672287,7.81527357864369,1663.94513177103,686.382606629988,227.253202490747,30.2008346917195,16.982120569978,87.4877280325238,0.715648912964093 -11.7613835932232,0.944831736938601,24.995431842535,62.4295479322454,8.02665616271726,1752.50583004824,708.201409055604,233.39980359154,31.1608619984466,17.4414422422149,89.7885850687288,0.714556590285057 -11.7801859269303,0.968354504125048,25.0295993958697,64.071272359425,8.23773501764035,1843.37007919871,729.969240996173,239.53757282977,32.1186466038316,17.9001039292314,92.0866217150543,0.713498156651918 -11.7975280658584,0.991914875978908,25.0603240558164,65.7107098860491,8.44851984249203,1936.53509081381,751.68613267014,245.666792236099,33.0741898374862,18.3581267065446,94.38196590435,0.712476833795632 -11.8134891624399,1.01550993211063,25.0879446803725,67.3479423718062,8.65902116208937,2031.99818373354,773.352587109393,251.78776785207,34.0275138328133,18.8155334439505,96.6747452695209,0.711494894974698 -11.8281474594478,1.0391369104355,25.1127681174163,68.9830561222896,8.8692500728658,2129.7567856242,794.969490778912,257.900822340737,34.9786575942721,19.272348253333,98.9650858981251,0.710553812787041 -11.8415798035397,1.0627932053544,25.1350720150602,70.6161402260632,9.07921802906526,2229.80843336607,816.538035775549,264.006288769597,35.9276735741242,19.7285960240771,101.253111347416,0.7096543893328 -11.8538612311044,1.08647636496148,25.1551074176751,72.2472851670227,9.28893666433149,2332.15077246263,838.05965253416,270.104505422751,36.8746247115031,20.1843020353925,103.538941879587,0.708796870315698 -11.8650646231567,1.11018408742369,25.173101159261,73.8765816773654,9.4984176442327,2436.78155565152,859.535952003227,276.195811512602,37.819581888142,20.639491635859,105.822693882435,0.707981044596844 -11.8752604250679,1.13391421667,25.1892580658455,75.5041197998774,9.70767254569852,2543.6986408717,880.968676299715,282.280543674115,38.7626217571875,21.0941899814501,108.104479445418,0.707206330634246 -11.8845164262532,1.15766473752014,25.2037629785039,77.1299881314368,9.91671275975616,2652.89998871831,902.359656910159,288.359033136565,39.703824904047,21.5484218241846,110.384406065233,0.706471851155574 -11.8928975945279,1.18143377037264,25.2167826084184,78.754273222612,10.1255494143358,2764.38365949757,923.710779568305,294.431603478872,40.6432743010054,22.0022113443869,112.662576458682,0.705776497322344 -11.9004659596413,1.2052195655617,25.2284672351395,80.3770591109958,10.3341933142709,2878.14780997727,945.023955006398,300.498568884916,41.5810540202815,22.4555820203118,114.939088463738,0.705118983552523 -11.9072805404736,1.22902049748098,25.2389522588894,81.9984269684694,10.5426548959461,2994.19068991414,966.301094845036,306.560232824797,42.5172481731816,22.9085565295971,117.214035012502,0.704497894076989 -11.9133973104918,1.25283505856193,25.2483596173681,83.6184548449223,10.7509441943472,3112.51063842675,987.544091953677,312.616887096702,43.4519400459618,23.3611566776647,119.487504162134,0.703911722214845 -11.9188691962787,1.27666185318291,25.2567990770969,85.2372174930867,10.9590708205397,3233.106080272,1008.75480467921,318.668811172028,44.3852114058853,23.8134033487836,121.759579171935,0.703358903264433 -11.9237461042401,1.30049959157547,25.2643694088729,86.8547862610741,11.1670439478524,3355.97552207376,1029.93504440227,324.71627179362,45.3171419536999,24.2653164760464,124.030338616569,0.702837841822017 -11.9280749709458,1.32434708378395,25.271159456425,88.4712290409399,11.3748723052637,3481.11754854429,1051.08656593975,330.759522783474,46.2478089013491,24.7169150269997,126.299856526992,0.702346934259345 -11.9318998329353,1.34820323372584,25.2772491068575,90.0866102631639,11.5825641766925,3608.53081873188,1072.21106036679,336.798805022098,47.1772866561388,25.1682170021022,128.568202552003,0.701884587015119 -11.9352619122133,1.37206703339171,25.2827101709614,91.7009909283261,11.7901274050705,3738.21406232222,1093.31014988192,342.834346566941,48.1056465948044,25.6192394435739,130.835442134521,0.701449231284342 -11.9381997140573,1.39593755721614,25.287607180965,93.3144286684936,11.9975694002349,3870.16607601566,1114.38538438539,348.866362881891,49.0329569129571,26.0699984525464,133.10163669769,0.701039334623581 -11.9407491341446,1.41981395664425,25.2919981127896,94.9269778319297,12.2048971498195,4004.38571999813,1135.43823948266,354.895057153972,49.959282537237,26.5205092127289,135.366843836778,0.700653409929674 -11.9429435723781,1.44369545491254,25.2959350393887,96.5386895856977,12.4121172324468,4140.87191451933,1156.47011566282,360.920620676935,50.8846850891641,26.9707860190731,137.631117513583,0.700290022194102 -11.9448140511425,1.4675813420573,25.2994647212688,98.1496120315762,12.6192358326312,4279.6236365888,1177.48233843573,366.943233284627,51.8092228911721,27.4208423101577,139.894508250683,0.699947793385115 -11.9463893360423,1.49147097015958,25.302629139833,99.7597903314401,12.8262587568994,4420.63991679732,1198.47615924184,372.963063819736,52.7329510066408,27.8706907032171,142.157063323418,0.699625405764469 -11.9476960574774,1.51536374883167,25.3054659787496,101.369266838901,13.0331914507158,4563.91983626886,1219.45275697546,378.980270625947,53.6559213069204,28.3203430309185,144.418826947912,0.699321603905093 -11.9487588316758,1.53925914094662,25.3080090581336,102.978081234555,13.2400390158714,4709.46252374619,1240.41323998599,384.995002053579,54.5781825593838,28.7698103791476,146.679840463869,0.699035195639795 -11.9496003800507,1.56315665860998,25.3102887259348,104.586270662666,13.446806228057,4857.26715281142,1261.35864844211,391.007396970588,55.499780531453,29.2191031251943,148.940142511157,0.698765052139036 -11.9502416459605,1.58705585937008,25.3123322105577,106.193869867514,13.6534975543946,5007.33293924156,1282.28995696246,397.017585272329,56.4207581063483,29.6682309758462,151.199769199484,0.698510107287346 -11.9507019081418,1.610956342662,25.3141639383961,107.800911328006,13.8601171707436,5159.65913849779,1303.20807743181,403.025688384807,57.3411554069997,30.1172030049955,153.458754270681,0.698269356503016 -11.9509988902507,1.63485774647828,25.3158058196382,109.407425389423,14.06666897864,5314.24504334618,1324.11386193558,409.031819757225,58.2610099251653,30.5660276904461,155.717129253297,0.698041855123787 -11.9511488660899,1.65875974425878,25.317277505408,111.013440391445,14.2731566217573,5471.08998160699,1345.00810575727,415.036085340631,59.18035665332,31.0147129496812,157.974923609348,0.697826716462099 -11.9511667602222,1.68266204199096,25.3185966190244,112.618982791806,14.4795835018036,5630.19331402889,1365.89155039375,421.038584050197,60.0992282173251,31.4632661744092,160.23216487319,0.697623109616918 -11.9510662437754,1.70656437551141,25.3197789639113,114.224077285093,14.6859527937977,5791.55443228403,1386.76488655164,427.039408209385,61.0176550082721,31.9116942637547,162.488878782583,0.697430257114672 -11.95085982533,1.73046650799896,25.3208387104553,115.828746916384,14.892267460678,5955.17275707956,1407.6287570959,433.038643974783,61.9356653122196,32.3600036560057,164.745089402082,0.697247432439474 -11.9505589368557,1.75436822764962,25.3217885638921,117.433013189507,15.0985302672223,6121.04773638097,1428.48375992771,439.036371740836,62.8532854368194,32.8082003588581,167.000819238952,0.697073957502065 -11.9501740147204,1.77826934552333,25.3226399151073,119.036896169816,15.3047437932621,6289.17884374234,1449.33045077411,445.032666524105,63.770539834061,33.2562899781309,169.256089351856,0.696909200087836 -11.9497145758456,1.80216969355277,25.323402976057,120.64041458148,15.5109104461903,6459.56557673866,1470.16934587636,451.027598326976,64.68745121856,33.7042777449449,171.510919452591,0.696752571316395 -11.9491892891207,1.82606912270446,25.3240869013502,122.243585899309,15.7170324727683,6632.20745549527,1491.00092456774,457.021232480963,65.6040406809804,34.1521685413771,173.765328001152,0.696603523138593 -11.9486060422159,1.8499675012827,25.3246998973831,123.846426435221,15.9231119702428,6807.10402130943,1511.82563173442,463.013629969995,66.5203277963146,34.5999669246193,176.019332294468,0.696461545891287 -11.9479720039624,1.87386471336713,25.3252493202842,125.448951419498,16.1291508967926,6984.25483535922,1532.64388015593,469.004847734164,67.4363307268608,35.0476771496765,178.2729485491,0.696326165925379 -11.947293682477,1.89776065737506,25.3257417638004,127.05117507697,16.3351510813247,7163.65947749504,1553.45605272328,474.994938954582,68.3520663198244,35.4953031906537,180.526191978243,0.696196943318756 -11.9465769792282,1.92165524474001,25.3261831381463,128.653110698346,16.5411142326445,7345.31754510896,1574.26250453518,480.983953320044,69.2675501995478,35.9428487606825,182.779076863339,0.69607346968243 -11.9458272392406,1.94554839869847,25.3265787407367,130.25477070688,16.7470419480275,7529.22865207757,1595.06356487342,486.971937276264,70.1827968544307,36.3903173305468,185.031616620636,0.69595536606546 -11.9450492976437,1.96944005317695,25.3269333196293,131.85616672059,16.9529357212187,7715.39242777381,1615.85953906019,492.95893425849,71.0978197186482,36.837712146065,187.28382386298,0.695842280962021 -11.9442475227673,1.99333015177224,25.3272511304224,133.457309610253,17.1587969498897,7903.80851614384,1636.65071020033,498.944984908336,72.0126312488145,37.2850362442934,189.535710457149,0.695733888422098 -11.9434258559878,2.01721864681777,25.327535987279,135.058209553405,17.3646269425807,8094.47657484475,1657.43734081274,504.930127275648,72.9272429957607,37.7322924686113,191.787287577026,0.695629886265887 -11.9425878485214,2.04110549852975,25.3277913086781,136.658876084556,17.5704269251573,8287.39627443939,1678.21967435503,510.914397006251,73.8416656716215,38.1794834827512,194.038565752866,0.69552999440074 -11.9417366953606,2.06499067422679,25.3280201584364,138.259318141853,17.7761980468097,8482.56729764473,1698.99793664625,516.897827516402,74.755909212435,38.6266117838347,196.289554916939,0.695433953238604 -11.9408752665385,2.08887414761751,25.3282252824847,139.859544110396,17.9819413856223,8679.98933863027,1719.77233719249,522.880450154729,75.6699828364695,39.0736797144742,198.540264445788,0.695341522211167 -11.9400061359016,2.11275589815059,25.3284091418387,141.459561862421,18.1876579537398,8879.66210236323,1740.54307042038,528.862294352461,76.5838950984967,39.5206894739994,200.790703199337,0.695252478379422 -11.9391316075632,2.13663591042239,25.3285739421546,143.059378794547,18.393348702156,9081.58530399742,1761.3103168234,534.843387762681,77.4976539402297,39.9676431288628,203.040879557085,0.695166615133919 -11.9382537402013,2.16051417363752,25.3287216602227,144.659001862283,18.5990145251506,9285.75866830297,1782.07424402603,540.823756389335,78.4112667371455,40.4145426222808,205.290801451581,0.695083740981745 -11.9373743693555,2.18439068111792,25.3288540677147,146.258437611976,18.8046562643969,9492.18192913409,1802.83500777056,546.803424706665,79.3247403419046,40.8613897831587,207.540476399384,0.695003678416091 -11.9364951278701,2.20826542985663,25.3289727524698,147.857692210376,19.0102747127626,9700.85482893232,1823.59275283131,552.782415769751,80.2380811245776,41.3081863343504,209.789911529694,0.694926262864179 -11.9356174646233,2.23213842011237,25.3290791375723,149.456771471983,19.2158706178263,9911.77711826289,1844.34761386094,558.760751316748,81.1512950098814,41.7549339002996,212.039113610826,0.694851341709288 -11.9347426616697,2.25600965504162,25.329174498451,151.055680884333,19.4214446851286,10124.9485553818,1865.09971617314,564.738451863424,82.0643875116182,42.2016340141033,214.288089074682,0.69477877338268 -11.9338718499205,2.27987914036496,25.3292599782041,152.654425631377,19.6269975811771,10340.3689058318,1885.84917646605,570.71553679055,82.9773637645061,42.648288124043,216.536844039384,0.694708426521255 -11.9330060234746,2.3037468840648,25.3293366013341,154.253010615075,19.8325299362239,10558.0379420646,1906.59610349039,576.692024424647,83.890228553577,43.0948975996184,218.785384330193,0.694640179186923 -11.9321460527067,2.32761289611175,25.3294052860573,155.851440475352,20.038042346831,10777.9554430886,1927.34059866618,582.667932112599,84.8029863413119,43.541463737123,221.03371549886,0.694573918143752 -11.9312926962124,2.35147718821716,25.329466855335,157.449719608536,20.2435353782403,11000.1211941389,1948.08275665167,588.643276290556,85.7156412926734,43.9879877647935,223.281842841516,0.694509538189161 -11.9304466117017,2.37533977360959,25.3295220467605,159.047852184374,20.4490095665623,11224.5349863698,1968.82266586788,594.618072547588,86.6281972981868,44.4344708475659,225.529771415216,0.694446941535517 diff --git a/pyrealm_build_data/two_leaf/__init__.py b/pyrealm_build_data/two_leaf/__init__.py new file mode 100644 index 00000000..2c2da074 --- /dev/null +++ b/pyrealm_build_data/two_leaf/__init__.py @@ -0,0 +1,7 @@ +r"""This submodule contains benchmark outputs from an R implementation of the two leaf, +two stream model. + +TODO - this module is currently in development and the files here need to be cleaned up +and documented once the implementation has been completed. + +""" # noqa: D205 diff --git a/pyrealm_build_data/uk_data/__init__.py b/pyrealm_build_data/uk_data/__init__.py index 0489a3c0..ff85bef2 100644 --- a/pyrealm_build_data/uk_data/__init__.py +++ b/pyrealm_build_data/uk_data/__init__.py @@ -1 +1,10 @@ -"""Exemplar UK 3D XYT dataset containing P Model forcings.""" +"""This submodule provides P Model forcings for the United Kingdom at 0.5° spatial +resolution and hourly temporal resolution over 2 months (1464 temporal observations). It +is used for demonstrating the use of the subdaily P Model. + +The Python script ``create_2D_uk_inputs.py`` is used to generate the NetCDF output file +``UK_WFDE5_FAPAR_2018_JuneJuly.nc``. The script is currently written with a hard-coded +set of paths to key source data - the WFDE5 v2 climate data and a separate source of +interpolated hourly fAPAR. This should probably be rewritten to generate reproducible +content from publically available sources of these datasets. +""" # noqa: D205 From 941f5af31180efa7758fdbe47d2ceec7fa388f01 Mon Sep 17 00:00:00 2001 From: David Orme Date: Wed, 16 Oct 2024 17:51:30 +0100 Subject: [PATCH 232/241] More doc string tweaks --- docs/source/development/pyrealm_build_data.md | 178 +++++++----------- pyrealm_build_data/__init__.py | 3 + pyrealm_build_data/community/__init__.py | 5 + 3 files changed, 74 insertions(+), 112 deletions(-) create mode 100644 pyrealm_build_data/community/__init__.py diff --git a/docs/source/development/pyrealm_build_data.md b/docs/source/development/pyrealm_build_data.md index b59ec2b2..41035bb8 100644 --- a/docs/source/development/pyrealm_build_data.md +++ b/docs/source/development/pyrealm_build_data.md @@ -11,138 +11,92 @@ kernelspec: name: python3 --- -# The `pyrealm_build_data` package - -The `pyrealm` repository includes both the `pyrealm` package and the -`pyrealm_build_data` package. The `pyrealm_build_data` package contains datasets that -are used in the `pyrealm` build and testing process. This includes: - -* Example datasets that are used in the package documentation, such as simple spatial - datasets for showing the use of the P Model. -* "Golden" datasets for regression testing `pyrealm` implementations against the outputs - of other implementations. These datasets will include a set of input data and then - output predictions from other implementations. -* Datasets for providing profiling of `pyrealm` code and for benchmarking new versions - of the package code against earlier implementations to check for performance issues. - -Note that `pyrealm_build_data` is a source distribution only (`sdist`) component of -`pyrealm`, so is not included in binary distributions (`wheel`) that are typically -installed by end users. This means that files in `pyrealm_build_data` are not available -if a user has simply used `pip install pyrealm`: please *do not* use -`pyrealm_build_data` within the main `pyrealm` code. - -## Package contents - -The package is organised into submodules that reflect the data use or previous -implementation. - -### The `bigleaf` submodule - -This submodule contains benchmark outputs from the `bigleaf` package in `R`, which has -been used as the basis for core hygrometry functions. The `bigleaf_conversions.R` R -script runs a set of test values through `bigleaf`. The first part of the file prints -out some simple test values that have been used in package doctests and then the second -part of the file generates more complex benchmarking inputs that are saved, along with -`bigleaf` outputs as `bigleaf_test_values.json`. - -Running `bigleaf_conversions.R` requires an installation of R along with the `jsonlite` -and `bigleaf` packages, and the script can then be run from within the submodule folder -as: - -```sh -Rscript bigleaf_conversions.R -``` - -### The `rpmodel` submodule - -This submodule contains benchmark outputs from the `rpmodel` package in `R`, which has -been used as the basis for initial development of the standard P Model. - -#### Test inputs +# The {mod}`~pyrealm_build_data` module -The `generate_test_inputs.py` file defines a set of constants for running P Model -calculations and then defines a set of scalar and array inputs for the forcing variables -required to run the P Model. The array inputs are set of 100 values sampled randomly -across the ranges of plausible forcing value inputs in order to benchmark the -calculations of the P Model implementation. All of these values are stored in the -`test_inputs.json` file. - -It requires `python` and the `numpy` package and can be run as: - -```sh -python generate_test_inputs.py +```{eval-rst} +.. automodule:: pyrealm_build_data + :autosummary: + :members: + :special-members: __init__ ``` -#### Simple `rpmodel` benchmarking - -The `test_outputs_rpmodel.R` contains R code to run the test input data set, and store -the expected predictions from the `rpmodel` package as `test_outputs_rpmodel.json`. It -requires an installation of `R` and the `rpmodel` package and can be run as: +## The `bigleaf` submodule -```sh -Rscript test_outputs_rpmodel.R +```{eval-rst} +.. automodule:: pyrealm_build_data.bigleaf + :autosummary: + :members: + :special-members: __init__ ``` -#### Global array test +## The `community` submodule -The remaining files in the submodule are intended to provide a global test dataset for -benchmarking the use of `rpmodel` on a global time-series, so using 3 dimensional arrays -with latitude, longitude and time coordinates. It is currently not used in testing -because of issues with the `rpmodel` package in version 1.2.0. It may also be replaced -in testing with the `uk_data` submodule, which is used as an example dataset in the -documentation. +```{eval-rst} +.. automodule:: pyrealm_build_data.community + :autosummary: + :members: + :special-members: __init__ +``` -The files are: +## The `rpmodel` submodule -* pmodel_global.nc: An input global NetCDF file containing forcing variables at 0.5° - spatial resolution and for two time steps. -* test_global_array.R: An R script to run `rpmodel` using the dataset. -* rpmodel_global_gpp_do_ftkphio.nc: A NetCDF file containing `rpmodel` predictions using - corrections for temperature effects on the `kphio` parameter. -* rpmodel_global_gpp_no_ftkphio.nc: A NetCDF file containing `rpmodel` predictions with - fixed `kphio`. +```{eval-rst} +.. automodule:: pyrealm_build_data.rpmodel + :autosummary: + :members: + :special-members: __init__ +``` -To generate the predicted outputs again requires an R installation with the `rpmodel` -package: +## The `sandoval_kphio` submodule -```sh -Rscript test_global_array.R +```{eval-rst} +.. automodule:: pyrealm_build_data.sandoval_kphio + :autosummary: + :members: + :special-members: __init__ ``` -### The `subdaily` submodule +## The `splash` submodule -At present, this submodule only contains a single file containing the predictions for -the `BE_Vie` fluxnet site from the original implementation of the `subdaily` module, -published in {cite}`mengoli:2022a`. Generating these predictions requires an -installation of R and then code from the following repository: +```{eval-rst} +.. automodule:: pyrealm_build_data.splash + :autosummary: + :members: + :special-members: __init__ +``` -[https://github.com/GiuliaMengoli/P-model_subDaily](https://github.com/GiuliaMengoli/P-model_subDaily) +## The `subdaily` submodule -TODO - This submodule should be updated to include the required code along with the -settings files and a runner script to reproduce this code. Or possibly to checkout the -required code as part of a shell script. +```{eval-rst} +.. automodule:: pyrealm_build_data.subdaily + :autosummary: + :members: + :special-members: __init__ +``` -### The `t_model` submodule +## The `t_model` submodule -The `t_model.r` contains the original implementation of the T Model calculations in R -{cite:p}`Li:2014bc`. The `rtmodel_test_outputs.r` script sources this file and then -generates some simple bencmarking predictions, which are saved as `rtmodel_output.csv`. +```{eval-rst} +.. automodule:: pyrealm_build_data.t_model + :autosummary: + :members: + :special-members: __init__ +``` -To generate the predicted outputs again requires an R installation +## The `two_leaf` submodule -```sh -Rscript rtmodel_test_outputs.r +```{eval-rst} +.. automodule:: pyrealm_build_data.two_leaf + :autosummary: + :members: + :special-members: __init__ ``` -### The `uk_data` submodule - -This submodule contains the Python script `create_2D_uk_inputs.py`, which is used to -generate the NetCDF output file `UK_WFDE5_FAPAR_2018_JuneJuly.nc`. This contains P Model -forcings for the United Kingdom at 0.5° spatial resolution and hourly temporal -resolution over 2 months (1464 temporal observations). It is used for demonstrating the -use of the subdaily P Model. +## The `uk_data` submodule -The script is currently written with a hard-coded set of paths to key source data - the -WFDE5 v2 climate data and a separate source of interpolated hourly fAPAR. This should -probably be rewritten to generate reproducible content from publically available sources -of these datasets. +```{eval-rst} +.. automodule:: pyrealm_build_data.uk_data + :autosummary: + :members: + :special-members: __init__ +``` diff --git a/pyrealm_build_data/__init__.py b/pyrealm_build_data/__init__.py index 13c9caca..1b5e9bc0 100644 --- a/pyrealm_build_data/__init__.py +++ b/pyrealm_build_data/__init__.py @@ -10,6 +10,9 @@ * Datasets for providing profiling of ``pyrealm`` code and for benchmarking new versions of the package code against earlier implementations to check for performance issues. +The package is organised into submodules that reflect the data use or previous +implementation. + Note that ``pyrealm_build_data`` is a source distribution only (``sdist``) component of ``pyrealm``, so is not included in binary distributions (``wheel``) that are typically installed by end users. This means that files in ``pyrealm_build_data`` are not diff --git a/pyrealm_build_data/community/__init__.py b/pyrealm_build_data/community/__init__.py new file mode 100644 index 00000000..fc2675a9 --- /dev/null +++ b/pyrealm_build_data/community/__init__.py @@ -0,0 +1,5 @@ +"""The :mod:`pyrealm_build_data.community` submodule provides a set of input files for +the :mod:`pyrealm.demography` module that are used both in unit testing for the module +and as inputs for generating documentation of the module. The files provide definitions +of plant functional types and plant communities in a range of formats. +""" # noqa: D205 From ebfa29fe5276a574ee87e812ae0195bae19ed86a Mon Sep 17 00:00:00 2001 From: MarionBWeinzierl Date: Thu, 17 Oct 2024 09:43:28 +0100 Subject: [PATCH 233/241] corrected memory effect and renamed variable --- pyrealm/pmodel/subdaily.py | 14 +++++++------- tests/unit/pmodel/test_memory_effect.py | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 5a425d42..43d5d73a 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -42,7 +42,7 @@ def memory_effect( values: NDArray, - initial_values: NDArray | None = None, + previous_values: NDArray | None = None, alpha: float = 0.067, allow_holdover: bool = False, ) -> NDArray: @@ -92,7 +92,7 @@ def memory_effect( Args: values: The values to apply the memory effect to. - initial_values: Last available realised value used if model is fitted in + previous_values: Last available realised value used if model is fitted in chunks and value at t=0 is not optimal. alpha: The relative weight applied to the most recent observation. allow_holdover: Allow missing values to be filled by holding over earlier @@ -110,10 +110,10 @@ def memory_effect( # Initialise the output storage and set the first values to be a slice along the # first axis of the input values memory_values = np.empty_like(values, dtype=np.float32) - if initial_values is None: + if previous_values is None: memory_values[0] = values[0] else: - memory_values[0] = initial_values + memory_values[0] = previous_values * (1 - alpha) + values[0] * alpha # Handle the data if there are no missing data, if not nan_present: @@ -406,21 +406,21 @@ def __init__( # 5) Calculate the realised daily values from the instantaneous optimal values self.xi_real: NDArray = memory_effect( self.pmodel_acclim.optchi.xi, - initial_values=init_xi_real, + previous_values=init_xi_real, alpha=alpha, allow_holdover=allow_holdover, ) r"""Realised daily slow responses in :math:`\xi`""" self.vcmax25_real: NDArray = memory_effect( self.vcmax25_opt, - initial_values=init_vcmax_real, + previous_values=init_vcmax_real, alpha=alpha, allow_holdover=allow_holdover, ) r"""Realised daily slow responses in :math:`V_{cmax25}`""" self.jmax25_real: NDArray = memory_effect( self.jmax25_opt, - initial_values=init_jmax_real, + previous_values=init_jmax_real, alpha=alpha, allow_holdover=allow_holdover, ) diff --git a/tests/unit/pmodel/test_memory_effect.py b/tests/unit/pmodel/test_memory_effect.py index 4f9fc042..d5ab4402 100644 --- a/tests/unit/pmodel/test_memory_effect.py +++ b/tests/unit/pmodel/test_memory_effect.py @@ -85,7 +85,7 @@ def test_memory_effect_chunked(inputs_whole, alpha): result_chunk1 = memory_effect(inputs_chunk1, alpha=alpha) result_chunk2 = memory_effect( - inputs_chunk2, initial_values=result_chunk1[-1], alpha=alpha + inputs_chunk2, previous_values=result_chunk1[-1], alpha=alpha ) assert np.allclose(result_whole[-1], result_chunk2[-1]) From f8348fead3537b85e0d52b62e53f64038670d193 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 17 Oct 2024 14:42:59 +0100 Subject: [PATCH 234/241] Adding a higher level unit test and updating the checking --- pyrealm/pmodel/subdaily.py | 33 ++++++++---- tests/unit/pmodel/test_subdaily.py | 83 ++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 11 deletions(-) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 5a425d42..4556beaf 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -185,6 +185,10 @@ class SubdailyPModel: more rapid acclimation: :math:`\alpha=1` results in immediate acclimation and :math:`\alpha=0` results in no acclimation at all, with values pinned to the initial estimates. + * By default, the initial realised value :math:`R_1` for each of the three slowly + acclimating variables is assumed to be the first optimal value :math:`O_1`, but + the `previous_realised` argument can be used to provide values of :math:`R_0` from + which to calculate :math:`R_{1} = R_{0}(1 - \alpha) + O_{1} \alpha`. * The realised values are then filled back onto the original subdaily timescale, with :math:`V_{cmax}` and :math:`J_{max}` then being calculated from the slowly responding :math:`V_{cmax25}` and :math:`J_{max25}` and the actual subdaily @@ -229,12 +233,12 @@ class SubdailyPModel: allow_partial_data: Should estimates of daily optimal conditions be calculated with missing values in the acclimation window. reference_kphio: An optional alternative reference value for the quantum yield - efficiency of photosynthesis (:math:`\phi_0`, -) to be passed to the kphio - calculation method. + efficiency of photosynthesis (:math:`\phi_0`, -) to be passed to the kphio + calculation method. fill_kind: The approach used to fill daily realised values to the subdaily timescale, currently one of 'previous' or 'linear'. - init_realised: A tuple of initial realised values of three NumPy arrays - (xi_real, vcmax25_real, jmax25_real). + previous_realised: A tuple of previous realised values of three NumPy arrays + (xi_real, vcmax25_real, jmax25_real). """ def __init__( @@ -251,7 +255,7 @@ def __init__( allow_holdover: bool = False, allow_partial_data: bool = False, fill_kind: str = "previous", - init_realised: tuple[NDArray, NDArray, NDArray] | None = None, + previous_realised: tuple[NDArray, NDArray, NDArray] | None = None, ) -> None: # Warn about the API warn( @@ -391,15 +395,22 @@ def __init__( ) """Instantaneous optimal :math:`x_{i}`, :math:`V_{cmax}` and :math:`J_{max}`""" - if init_realised is not None: + # Check the shape of previous realised values are congruent with a slice across + # the time axis + if previous_realised is not None: + # All variables should share the shape of a slice along the first axis of + # the environmental forcings + expected_shape = self.env.tc[0].shape if not ( - (init_realised[0].shape() == self.xi_real[0].shape()) - and (init_realised[1].shape() == self.vcmax25_real[0].shape()) - and (init_realised[2].shape() == self.jmax25_real[0].shape()) + (previous_realised[0].shape == expected_shape) + and (previous_realised[1].shape == expected_shape) + and (previous_realised[2].shape == expected_shape) ): - raise Exception("`init_realised` has wrong shape in Subdaily PModel") + raise Exception( + "`previous_realised` entries have wrong shape in Subdaily PModel" + ) else: - init_xi_real, init_vcmax_real, init_jmax_real = init_realised + init_xi_real, init_vcmax_real, init_jmax_real = previous_realised else: init_xi_real, init_vcmax_real, init_jmax_real = [None, None, None] diff --git a/tests/unit/pmodel/test_subdaily.py b/tests/unit/pmodel/test_subdaily.py index 0796086d..4d56d5a8 100644 --- a/tests/unit/pmodel/test_subdaily.py +++ b/tests/unit/pmodel/test_subdaily.py @@ -114,6 +114,89 @@ def test_FSPModel_corr(be_vie_data_components, data_args): assert np.all(r_vals > 0.995) +def test_SubdailyPModel_previous_realised(be_vie_data_components): + """Test the functionality that allows the subdaily model to restart in blocks.""" + + from pyrealm.pmodel import SubdailyScaler + from pyrealm.pmodel.subdaily import SubdailyPModel + + # Run all in one model + env, ppfd, fapar, datetime, _ = be_vie_data_components.get( + mode="crop", start=0, end=17520 + ) + + # Get the fast slow scaler and set window + fsscaler = SubdailyScaler(datetime) + fsscaler.set_window( + window_center=np.timedelta64(12, "h"), + half_width=np.timedelta64(30, "m"), + ) + + # Run as a subdaily model using the kphio used in the reference implementation. + all_in_one_subdaily_pmodel = SubdailyPModel( + env=env, + ppfd=ppfd, + fapar=fapar, + reference_kphio=1 / 8, + fs_scaler=fsscaler, + allow_holdover=True, + ) + + # Run first half of year + env1, ppfd1, fapar1, datetime1, _ = be_vie_data_components.get( + mode="crop", start=0, end=182 * 48 + ) + + # Get the fast slow scaler and set window + fsscaler1 = SubdailyScaler(datetime1) + fsscaler1.set_window( + window_center=np.timedelta64(12, "h"), + half_width=np.timedelta64(30, "m"), + ) + + # Run as a subdaily model using the kphio used in the reference implementation. + part_1_subdaily_pmodel = SubdailyPModel( + env=env1, + ppfd=ppfd1, + fapar=fapar1, + reference_kphio=1 / 8, + fs_scaler=fsscaler1, + allow_holdover=True, + ) + + # Run second year + env2, ppfd2, fapar2, datetime2, _ = be_vie_data_components.get( + mode="crop", start=182 * 48, end=365 * 48 + ) + + # Get the fast slow scaler and set window + fsscaler2 = SubdailyScaler(datetime2) + fsscaler2.set_window( + window_center=np.timedelta64(12, "h"), + half_width=np.timedelta64(30, "m"), + ) + + # Run as a subdaily model using the kphio used in the reference implementation. + part_2_subdaily_pmodel = SubdailyPModel( + env=env2, + ppfd=ppfd2, + fapar=fapar2, + reference_kphio=1 / 8, + fs_scaler=fsscaler2, + allow_holdover=True, + init_realised=( + part_1_subdaily_pmodel.optimal_chi.xi[-1], + part_1_subdaily_pmodel.vcmax25_real[-1], + part_1_subdaily_pmodel.jmax25_real[-1], + ), + ) + + assert np.allclose( + all_in_one_subdaily_pmodel.gpp, + np.concat([part_1_subdaily_pmodel.gpp, part_2_subdaily_pmodel.gpp]), + ) + + @pytest.mark.parametrize("ndims", [2, 3, 4]) def test_FSPModel_dimensionality(be_vie_data, ndims): """Tests that the SubdailyPModel handles dimensions correctly. From 1b19f8d7b471035e0d4c3f8b14d004655a633e58 Mon Sep 17 00:00:00 2001 From: David Orme Date: Thu, 17 Oct 2024 16:07:04 +0100 Subject: [PATCH 235/241] Partial fix of test of previous values --- tests/unit/pmodel/test_subdaily.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/unit/pmodel/test_subdaily.py b/tests/unit/pmodel/test_subdaily.py index 4d56d5a8..d49a7787 100644 --- a/tests/unit/pmodel/test_subdaily.py +++ b/tests/unit/pmodel/test_subdaily.py @@ -184,18 +184,24 @@ def test_SubdailyPModel_previous_realised(be_vie_data_components): reference_kphio=1 / 8, fs_scaler=fsscaler2, allow_holdover=True, - init_realised=( + previous_realised=( part_1_subdaily_pmodel.optimal_chi.xi[-1], part_1_subdaily_pmodel.vcmax25_real[-1], part_1_subdaily_pmodel.jmax25_real[-1], ), ) - assert np.allclose( - all_in_one_subdaily_pmodel.gpp, - np.concat([part_1_subdaily_pmodel.gpp, part_2_subdaily_pmodel.gpp]), + # assert np.allclose( + # all_in_one_subdaily_pmodel.gpp, + # np.concat([part_1_subdaily_pmodel.gpp, part_2_subdaily_pmodel.gpp]), + # ) + + diff = all_in_one_subdaily_pmodel.gpp - np.concat( + [part_1_subdaily_pmodel.gpp, part_2_subdaily_pmodel.gpp] ) + assert np.nanmax(np.abs(diff)) == 0 + @pytest.mark.parametrize("ndims", [2, 3, 4]) def test_FSPModel_dimensionality(be_vie_data, ndims): From 46b419242bcdc26b858c7ecfafafd138a201986b Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 18 Oct 2024 10:01:42 +0100 Subject: [PATCH 236/241] Updated naming in and of test_fast_slow_scaler.py --- ..._slow_scaler.py => test_subdailyscaler.py} | 88 ++++++++++--------- 1 file changed, 48 insertions(+), 40 deletions(-) rename tests/unit/pmodel/{test_fast_slow_scaler.py => test_subdailyscaler.py} (90%) diff --git a/tests/unit/pmodel/test_fast_slow_scaler.py b/tests/unit/pmodel/test_subdailyscaler.py similarity index 90% rename from tests/unit/pmodel/test_fast_slow_scaler.py rename to tests/unit/pmodel/test_subdailyscaler.py index 1dfc1758..88e36de8 100644 --- a/tests/unit/pmodel/test_fast_slow_scaler.py +++ b/tests/unit/pmodel/test_subdailyscaler.py @@ -11,7 +11,7 @@ @pytest.fixture -def fixture_FSS(): +def fixture_SubdailyScaler(): """A fixture providing a SubdailyScaler object.""" from pyrealm.pmodel import SubdailyScaler @@ -114,7 +114,7 @@ def fixture_FSS(): ), ], ) -def test_FSS_init(ctext_mngr, msg, datetimes): +def test_SubdailyScaler_init(ctext_mngr, msg, datetimes): """Test the SubdailyScaler init handling of date ranges.""" from pyrealm.pmodel import SubdailyScaler @@ -162,11 +162,13 @@ def test_FSS_init(ctext_mngr, msg, datetimes): ), ], ) -def test_FSS_set_window(fixture_FSS, ctext_mngr, msg, kwargs, samp_mean, samp_max): +def test_SubdailyScaler_set_window( + fixture_SubdailyScaler, ctext_mngr, msg, kwargs, samp_mean, samp_max +): """Test the SubdailyScaler set_window method.""" with ctext_mngr as cman: - fixture_FSS.set_window(**kwargs) + fixture_SubdailyScaler.set_window(**kwargs) if msg is not None: assert str(cman.value) == msg @@ -174,8 +176,8 @@ def test_FSS_set_window(fixture_FSS, ctext_mngr, msg, kwargs, samp_mean, samp_ma # Check that _set_times has run correctly. Can't use allclose directly on # datetimes and since these are integers under the hood, don't need float # testing - assert np.all(fixture_FSS.sample_datetimes_mean == samp_mean) - assert np.all(fixture_FSS.sample_datetimes_max == samp_max) + assert np.all(fixture_SubdailyScaler.sample_datetimes_mean == samp_mean) + assert np.all(fixture_SubdailyScaler.sample_datetimes_max == samp_max) @pytest.mark.parametrize( @@ -227,10 +229,12 @@ def test_FSS_set_window(fixture_FSS, ctext_mngr, msg, kwargs, samp_mean, samp_ma ), ], ) -def test_FSS_set_include(fixture_FSS, ctext_mngr, msg, include, samp_mean, samp_max): +def test_SubdailyScaler_set_include( + fixture_SubdailyScaler, ctext_mngr, msg, include, samp_mean, samp_max +): """Test the SubdailyScaler set_include method.""" with ctext_mngr as cman: - fixture_FSS.set_include(include) + fixture_SubdailyScaler.set_include(include) if msg is not None: assert str(cman.value) == msg @@ -239,8 +243,8 @@ def test_FSS_set_include(fixture_FSS, ctext_mngr, msg, include, samp_mean, samp_ # Check that _set_times has run correctly. Can't use allclose directly on # datetimes and since these are integers under the hood, don't need float # testing - assert np.all(fixture_FSS.sample_datetimes_mean == samp_mean) - assert np.all(fixture_FSS.sample_datetimes_max == samp_max) + assert np.all(fixture_SubdailyScaler.sample_datetimes_mean == samp_mean) + assert np.all(fixture_SubdailyScaler.sample_datetimes_max == samp_max) @pytest.mark.parametrize( @@ -290,10 +294,12 @@ def test_FSS_set_include(fixture_FSS, ctext_mngr, msg, include, samp_mean, samp_ ), ], ) -def test_FSS_set_nearest(fixture_FSS, ctext_mngr, msg, time, samp_mean, samp_max): +def test_SubdailyScaler_set_nearest( + fixture_SubdailyScaler, ctext_mngr, msg, time, samp_mean, samp_max +): """Test the SubdailyScaler set_nearest method.""" with ctext_mngr as cman: - fixture_FSS.set_nearest(time) + fixture_SubdailyScaler.set_nearest(time) if msg is not None: assert str(cman.value) == msg @@ -302,8 +308,8 @@ def test_FSS_set_nearest(fixture_FSS, ctext_mngr, msg, time, samp_mean, samp_max # Check that _set_times has run correctly. Can't use allclose directly on # datetimes and since these are integers under the hood, don't need float # testing - assert np.all(fixture_FSS.sample_datetimes_mean == samp_mean) - assert np.all(fixture_FSS.sample_datetimes_max == samp_max) + assert np.all(fixture_SubdailyScaler.sample_datetimes_mean == samp_mean) + assert np.all(fixture_SubdailyScaler.sample_datetimes_max == samp_max) @pytest.mark.parametrize( @@ -317,15 +323,15 @@ def test_FSS_set_nearest(fixture_FSS, ctext_mngr, msg, time, samp_mean, samp_max ), ], ) -def test_FSS_get_wv_errors(fixture_FSS, ctext_mngr, msg, values): +def test_SubdailyScaler_get_wv_errors(fixture_SubdailyScaler, ctext_mngr, msg, values): """Test errors arising in the SubdailyScaler get_window_value method.""" - fixture_FSS.set_window( + fixture_SubdailyScaler.set_window( window_center=np.timedelta64(12, "h"), half_width=np.timedelta64(2, "h"), ) with ctext_mngr as cman: - _ = fixture_FSS.get_window_values(values) + _ = fixture_SubdailyScaler.get_window_values(values) assert str(cman.value) == msg @@ -488,8 +494,8 @@ def test_FSS_get_wv_errors(fixture_FSS, ctext_mngr, msg, values): ), ], ) -class Test_FSS_get_vals_window_and_include: - """Test FSS get methods for set_window and set_include. +class Test_SubdailyScaler_get_vals_window_and_include: + """Test SubdailyScaler get methods for set_window and set_include. The daily values extracted using the set_window and set_include methods can be the same, by setting the window and the include to cover the same observations, so these @@ -509,30 +515,30 @@ class Test_FSS_get_vals_window_and_include: are np.nan - this should revert to setting np.nan in the first day. """ - def test_FSS_get_vals_window( - self, fixture_FSS, values, expected_means, allow_partial_data + def test_SubdailyScaler_get_vals_window( + self, fixture_SubdailyScaler, values, expected_means, allow_partial_data ): """Test a window.""" - fixture_FSS.set_window( + fixture_SubdailyScaler.set_window( window_center=np.timedelta64(12, "h"), half_width=np.timedelta64(2, "h"), ) - calculated_means = fixture_FSS.get_daily_means( + calculated_means = fixture_SubdailyScaler.get_daily_means( values, allow_partial_data=allow_partial_data ) assert np.allclose(calculated_means, expected_means, equal_nan=True) - def test_FSS_get_vals_include( - self, fixture_FSS, values, expected_means, allow_partial_data + def test_SubdailyScaler_get_vals_include( + self, fixture_SubdailyScaler, values, expected_means, allow_partial_data ): """Test include.""" # This duplicates the selection of the window test but using direct include inc = np.zeros(48, dtype=np.bool_) inc[20:29] = True - fixture_FSS.set_include(inc) - calculated_means = fixture_FSS.get_daily_means( + fixture_SubdailyScaler.set_include(inc) + calculated_means = fixture_SubdailyScaler.get_daily_means( values, allow_partial_data=allow_partial_data ) @@ -607,7 +613,9 @@ def test_FSS_get_vals_include( ), ], ) -def test_FSS_get_vals_nearest(fixture_FSS, values, expected_means): +def test_SubdailyScaler_get_vals_nearest( + fixture_SubdailyScaler, values, expected_means +): """Test get_daily_values. This tests the specific behaviour when set_nearest is used and a single observation @@ -616,8 +624,8 @@ def test_FSS_get_vals_nearest(fixture_FSS, values, expected_means): """ # Select the 11:30 observation, which is missing in PARTIAL_ONES and PARTIAL_VARYING - fixture_FSS.set_nearest(np.timedelta64(11 * 60 + 29, "m")) - calculated_means = fixture_FSS.get_daily_means(values) + fixture_SubdailyScaler.set_nearest(np.timedelta64(11 * 60 + 29, "m")) + calculated_means = fixture_SubdailyScaler.get_daily_means(values) assert np.allclose(calculated_means, expected_means, equal_nan=True) @@ -744,8 +752,8 @@ def test_FSS_get_vals_nearest(fixture_FSS, values, expected_means): ), ], ) -def test_FSS_resample_subdaily( - fixture_FSS, +def test_SubdailyScaler_fill_daily_to_subdaily_previous( + fixture_SubdailyScaler, method_name, kwargs, update_point, @@ -755,15 +763,15 @@ def test_FSS_resample_subdaily( exp_values, fill_from, ): - """Test the calculation of subdaily samples using SubdailyScaler.""" + """Test fill_daily_to_subdaily using SubdailyScale with method previous.""" # Set the included observations - the different parameterisations here and for # the update point should all select the same update point. - func = getattr(fixture_FSS, method_name) + func = getattr(fixture_SubdailyScaler, method_name) func(**kwargs) with ctext_mngr as cman: - res = fixture_FSS.fill_daily_to_subdaily( + res = fixture_SubdailyScaler.fill_daily_to_subdaily( input_values, update_point=update_point, fill_from=fill_from ) @@ -829,20 +837,20 @@ def test_FSS_resample_subdaily( ), ], ) -def test_FSS_resample_subdaily_linear( - fixture_FSS, +def test_SubdailyScaler_fill_daily_to_subdaily_linear( + fixture_SubdailyScaler, update_point, input_values, exp_values, ): - """Test SubdailyScaler resampling to subdaily timescale by linear interpolation.""" + """Test fill_daily_to_subdaily using SubdailyScaler with method linear.""" # Set the included observations - fixture_FSS.set_window( + fixture_SubdailyScaler.set_window( window_center=np.timedelta64(13, "h"), half_width=np.timedelta64(1, "h") ) - res = fixture_FSS.fill_daily_to_subdaily( + res = fixture_SubdailyScaler.fill_daily_to_subdaily( input_values, update_point=update_point, kind="linear" ) From 1d917ea959c643a216da8ff652bb81c003caa392 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 18 Oct 2024 11:51:14 +0100 Subject: [PATCH 237/241] Adding previous_value to fill_daily_to_subdaily and testing --- pyrealm/pmodel/scaler.py | 69 ++++++++--- tests/unit/pmodel/test_subdailyscaler.py | 144 +++++++++++++++++++---- 2 files changed, 173 insertions(+), 40 deletions(-) diff --git a/pyrealm/pmodel/scaler.py b/pyrealm/pmodel/scaler.py index 4fa8d0a7..c7e9e7e2 100644 --- a/pyrealm/pmodel/scaler.py +++ b/pyrealm/pmodel/scaler.py @@ -407,6 +407,7 @@ def get_daily_means( def fill_daily_to_subdaily( self, values: NDArray, + previous_value: NDArray | None = None, update_point: str = "max", kind: str = "previous", fill_from: np.timedelta64 | None = None, @@ -419,45 +420,53 @@ def fill_daily_to_subdaily( axis of the `values` must be the same length as the number of days used to create the instance. + The update point defaults to the maximum time of day during the acclimation + window. It can also be set to the mean time of day, but note that this implies + that the plant predicts the daily values between the mean and max observation + time. The ``fill_from`` argument can be used to set the update point to an + arbitrary time of day. + Two interpolation kinds are currently implemented: * ``previous`` interpolates the daily value as a constant, until updating to the next daily value. This option will fill values until the end of the time - series. + series. The * ``linear`` interpolates linearly between the update points of the daily values. The interpolated values are held constant for the first day and then interpolated linearly: this is to avoid plants adapting optimally to future conditions. - The update point defaults to the maximum time of day during the acclimation - window. It can also be set to the mean time of day, but note that this implies - that the plant predicts the daily values between the mean and max observation - time. The ``fill_from`` argument can be used to set the update point to an - arbitrary time of day. + Subdaily observations before the update point on the first day of the time + series are filled with ``np.nan``. The ``previous_value`` argument can be used + to provide an alternative value, allowing time series to be processed in blocks, + but this option is only currently implemented for the ``previous`` + interpolation method. Args: values: An array with the first dimension matching the number of days in the - instances :class:`~pyrealm.pmodel.scaler.SubdailyScaler` object. + instances :class:`~pyrealm.pmodel.scaler.SubdailyScaler` object. + previous_value: An array with dimensions equal to a slice across the first + axis of the values array. update_point: The point in the acclimation window at which the plant updates - to the new daily value: one of 'mean' or 'max'. + to the new daily value: one of 'mean' or 'max'. kind: The kind of interpolation to use to fill between daily values: one of - 'previous' or 'linear', + 'previous' or 'linear', fill_from: As an alternative to ``update_point``, an - :class:`numpy.timedelta64` value giving the time of day from which to fill - values forward. + :class:`numpy.timedelta64` value giving the time of day from which to + fill values forward. """ if values.shape[0] != self.n_days: - raise ValueError("Values is not of length n_days on its first axis.") + raise ValueError("Values is not of length n_days on its first axis") if fill_from is not None: if not isinstance(fill_from, np.timedelta64): - raise ValueError("The fill_from argument must be a timedelta64 value.") + raise ValueError("The fill_from argument must be a timedelta64 value") # Convert to seconds and check it is in range _fill_from = fill_from.astype("timedelta64[s]") if not (_fill_from >= 0 and _fill_from < 24 * 60 * 60): - raise ValueError("The fill_from argument is not >= 0 and < 24 hours.") + raise ValueError("The fill_from argument is not >= 0 and < 24 hours") update_time = self.observation_dates + _fill_from @@ -468,8 +477,23 @@ def fill_daily_to_subdaily( else: raise ValueError("Unknown update point") - # Note that interp1d cannot handle datetime64 inputs, so need to interpolate - # using datetimes cast to integer types + # Check previous value settings - only allow with previous interpolation and + # check the previous value shape matches + if previous_value is not None: + if kind == "linear": + raise NotImplementedError( + "Using previous value with kind='linear' is not implemented" + ) + + # Use np.broadcast_shapes here to handle checking array shapes. This is + # mostly to catch the fact that () and (1,) are equivalent. + try: + np.broadcast_shapes(previous_value.shape, values.shape) + except ValueError: + raise ValueError( + "The input to previous_value is not congruent with " + "the shape of the observed data" + ) # Use fill_value to handle extrapolation before or after update point: # - previous will fill the last value forward to the end of the time series, @@ -479,8 +503,16 @@ def fill_daily_to_subdaily( # value until _after_ the update point. if kind == "previous": - fill_value = (None, values[-1]) + # The fill values here are used to extend the last daily value out to the + # end of the subdaily observations but also to fill any provided previous + # values for subdaily observations _before_ the first daily value. If + # the default previous value of None is supplied, this inserts np.nan as + # expected. + fill_value = (previous_value, values[-1]) elif kind == "linear": + # Shift the values forward by a day, inserting a copy of the first day at + # the start. This then avoids plants seeing the future and provides values + # up until the last observation. values = np.insert(values, 0, values[0], axis=0) update_time = np.append( update_time, update_time[-1] + np.timedelta64(1, "D") @@ -489,6 +521,8 @@ def fill_daily_to_subdaily( else: raise ValueError("Unsupported interpolation option") + # Note that interp1d cannot handle datetime64 inputs, so need to interpolate + # using datetimes cast to integer types interp_fun = interp1d( update_time.astype("int"), values, @@ -496,6 +530,7 @@ def fill_daily_to_subdaily( kind=kind, bounds_error=False, fill_value=fill_value, + assume_sorted=True, ) # TODO - The kind "previous" might be replaceable with bottleneck.push diff --git a/tests/unit/pmodel/test_subdailyscaler.py b/tests/unit/pmodel/test_subdailyscaler.py index 88e36de8..977095dc 100644 --- a/tests/unit/pmodel/test_subdailyscaler.py +++ b/tests/unit/pmodel/test_subdailyscaler.py @@ -686,27 +686,37 @@ def test_SubdailyScaler_get_vals_nearest( ], ) @pytest.mark.parametrize( - argnames=["ctext_mngr", "msg", "input_values", "exp_values", "fill_from"], + argnames=["input_values", "exp_values", "fill_from", "previous_value"], argvalues=[ pytest.param( - does_not_raise(), - None, np.array([1, 2, 3]), np.repeat([np.nan, 1, 2, 3], (26, 48, 48, 22)), None, + None, id="1D test", ), pytest.param( - does_not_raise(), - None, np.array([1, 2, 3]), np.repeat([1, 2, 3], (48, 48, 48)), np.timedelta64(0, "h"), + None, id="1D test - fill from", ), pytest.param( - does_not_raise(), + np.array([1, 2, 3]), + np.repeat([0, 1, 2, 3], (26, 48, 48, 22)), None, + np.array([0]), + id="1D test - previous value 1D", + ), + pytest.param( + np.array([1, 2, 3]), + np.repeat([0, 1, 2, 3], (26, 48, 48, 22)), + None, + np.array(0), + id="1D test - previous value 0D", + ), + pytest.param( np.array([[[1, 4], [7, 10]], [[2, 5], [8, 11]], [[3, 6], [9, 12]]]), np.repeat( a=[ @@ -719,11 +729,10 @@ def test_SubdailyScaler_get_vals_nearest( axis=0, ), None, - id="2D test", + None, + id="3D test", ), pytest.param( - does_not_raise(), - None, np.array([[[1, 4], [7, 10]], [[2, 5], [8, 11]], [[3, 6], [9, 12]]]), np.repeat( a=[ @@ -736,11 +745,26 @@ def test_SubdailyScaler_get_vals_nearest( axis=0, ), np.timedelta64(2, "h"), - id="2D test - fill from", + None, + id="3D test - fill from", ), pytest.param( - does_not_raise(), + np.array([[[1, 4], [7, 10]], [[2, 5], [8, 11]], [[3, 6], [9, 12]]]), + np.repeat( + a=[ + [[0, 3], [6, 9]], + [[1, 4], [7, 10]], + [[2, 5], [8, 11]], + [[3, 6], [9, 12]], + ], + repeats=[26, 48, 48, 22], + axis=0, + ), None, + np.array([[0, 3], [6, 9]]), + id="3D test - previous value 2D", + ), + pytest.param( np.array([[1, 4], [2, 5], [3, 6]]), np.repeat( a=[[np.nan, np.nan], [1, 4], [2, 5], [3, 6]], @@ -748,7 +772,8 @@ def test_SubdailyScaler_get_vals_nearest( axis=0, ), None, - id="3D test", + None, + id="2D test", ), ], ) @@ -757,28 +782,31 @@ def test_SubdailyScaler_fill_daily_to_subdaily_previous( method_name, kwargs, update_point, - ctext_mngr, - msg, input_values, exp_values, fill_from, + previous_value, ): - """Test fill_daily_to_subdaily using SubdailyScale with method previous.""" + """Test fill_daily_to_subdaily using SubdailyScale with method previous. + + The first parameterisation sets the exact same acclimation windows in a bunch of + different ways. The second paramaterisation provides inputs with different + dimensionality. + """ # Set the included observations - the different parameterisations here and for # the update point should all select the same update point. func = getattr(fixture_SubdailyScaler, method_name) func(**kwargs) - with ctext_mngr as cman: - res = fixture_SubdailyScaler.fill_daily_to_subdaily( - input_values, update_point=update_point, fill_from=fill_from - ) + res = fixture_SubdailyScaler.fill_daily_to_subdaily( + input_values, + update_point=update_point, + fill_from=fill_from, + previous_value=previous_value, + ) - if cman is not None: - assert str(cman.value) == msg - else: - assert np.allclose(res, exp_values, equal_nan=True) + assert np.allclose(res, exp_values, equal_nan=True) @pytest.mark.parametrize( @@ -855,3 +883,73 @@ def test_SubdailyScaler_fill_daily_to_subdaily_linear( ) assert np.allclose(res, exp_values, equal_nan=True) + + +@pytest.mark.parametrize( + argnames="inputs, outcome, msg", + argvalues=[ + pytest.param( + {"values": np.arange(12)}, + pytest.raises(ValueError), + "Values is not of length n_days on its first axis", + id="values wrong shape", + ), + pytest.param( + {"values": np.arange(3), "fill_from": 3}, + pytest.raises(ValueError), + "The fill_from argument must be a timedelta64 value", + id="fill_from not timedelta64", + ), + pytest.param( + {"values": np.arange(3), "fill_from": np.timedelta64(12, "D")}, + pytest.raises(ValueError), + "The fill_from argument is not >= 0 and < 24 hours", + id="fill_from too large", + ), + pytest.param( + {"values": np.arange(3), "fill_from": np.timedelta64(-1, "s")}, + pytest.raises(ValueError), + "The fill_from argument is not >= 0 and < 24 hours", + id="fill_from negative", + ), + pytest.param( + {"values": np.arange(3), "update_point": "noon"}, + pytest.raises(ValueError), + "Unknown update point", + id="unknown update point", + ), + pytest.param( + {"values": np.arange(3), "previous_value": np.array(1), "kind": "linear"}, + pytest.raises(NotImplementedError), + "Using previous value with kind='linear' is not implemented", + id="previous_value with linear", + ), + pytest.param( + {"values": np.arange(3), "previous_value": np.ones(4)}, + pytest.raises(ValueError), + "The input to previous_value is not congruent with " + "the shape of the observed data", + id="previous_value shape issue", + ), + pytest.param( + {"values": np.arange(3), "kind": "quadratic"}, + pytest.raises(ValueError), + "Unsupported interpolation option", + id="unsupported interpolation", + ), + ], +) +def test_SubdailyScaler_fill_daily_to_subdaily_failure_modes( + fixture_SubdailyScaler, inputs, outcome, msg +): + """Test fill_daily_to_subdaily using SubdailyScaler with method linear.""" + + # Set the included observations + fixture_SubdailyScaler.set_window( + window_center=np.timedelta64(13, "h"), half_width=np.timedelta64(1, "h") + ) + + with outcome as excep: + _ = fixture_SubdailyScaler.fill_daily_to_subdaily(**inputs) + + assert str(excep.value) == msg From 2bd9900fcf3ea72a8cedc456d3d05548a2927b51 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 18 Oct 2024 12:12:37 +0100 Subject: [PATCH 238/241] Added previous value into fill_daily_to_subdaily and added test to only allow use with previous interpolation --- pyrealm/pmodel/subdaily.py | 36 ++++++++++++++++++++++-------- tests/unit/pmodel/test_subdaily.py | 13 ++++------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 44f4c94d..24d871d9 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -398,6 +398,12 @@ def __init__( # Check the shape of previous realised values are congruent with a slice across # the time axis if previous_realised is not None: + if fill_kind != "previous": + raise NotImplementedError( + "Using previous_realised is only implemented for " + "fill_kind = 'previous'" + ) + # All variables should share the shape of a slice along the first axis of # the environmental forcings expected_shape = self.env.tc[0].shape @@ -406,32 +412,38 @@ def __init__( and (previous_realised[1].shape == expected_shape) and (previous_realised[2].shape == expected_shape) ): - raise Exception( + raise ValueError( "`previous_realised` entries have wrong shape in Subdaily PModel" ) else: - init_xi_real, init_vcmax_real, init_jmax_real = previous_realised + previous_xi_real, previous_vcmax25_real, previous_jmax25_real = ( + previous_realised + ) else: - init_xi_real, init_vcmax_real, init_jmax_real = [None, None, None] + previous_xi_real, previous_vcmax25_real, previous_jmax25_real = [ + None, + None, + None, + ] # 5) Calculate the realised daily values from the instantaneous optimal values self.xi_real: NDArray = memory_effect( self.pmodel_acclim.optchi.xi, - previous_values=init_xi_real, + previous_values=previous_xi_real, alpha=alpha, allow_holdover=allow_holdover, ) r"""Realised daily slow responses in :math:`\xi`""" self.vcmax25_real: NDArray = memory_effect( self.vcmax25_opt, - previous_values=init_vcmax_real, + previous_values=previous_vcmax25_real, alpha=alpha, allow_holdover=allow_holdover, ) r"""Realised daily slow responses in :math:`V_{cmax25}`""" self.jmax25_real: NDArray = memory_effect( self.jmax25_opt, - previous_values=init_jmax_real, + previous_values=previous_jmax25_real, alpha=alpha, allow_holdover=allow_holdover, ) @@ -440,9 +452,15 @@ def __init__( # 6) Fill the realised xi, jmax25 and vcmax25 from daily values back to the # subdaily timescale. - self.subdaily_vcmax25 = fs_scaler.fill_daily_to_subdaily(self.vcmax25_real) - self.subdaily_jmax25 = fs_scaler.fill_daily_to_subdaily(self.jmax25_real) - self.subdaily_xi = fs_scaler.fill_daily_to_subdaily(self.xi_real) + self.subdaily_xi = fs_scaler.fill_daily_to_subdaily( + self.xi_real, previous_value=previous_xi_real + ) + self.subdaily_vcmax25 = fs_scaler.fill_daily_to_subdaily( + self.vcmax25_real, previous_value=previous_vcmax25_real + ) + self.subdaily_jmax25 = fs_scaler.fill_daily_to_subdaily( + self.jmax25_real, previous_value=previous_jmax25_real + ) # 7) Adjust subdaily jmax25 and vcmax25 back to jmax and vcmax given the # actual subdaily temperatures. diff --git a/tests/unit/pmodel/test_subdaily.py b/tests/unit/pmodel/test_subdaily.py index d49a7787..471f60dd 100644 --- a/tests/unit/pmodel/test_subdaily.py +++ b/tests/unit/pmodel/test_subdaily.py @@ -191,17 +191,12 @@ def test_SubdailyPModel_previous_realised(be_vie_data_components): ), ) - # assert np.allclose( - # all_in_one_subdaily_pmodel.gpp, - # np.concat([part_1_subdaily_pmodel.gpp, part_2_subdaily_pmodel.gpp]), - # ) - - diff = all_in_one_subdaily_pmodel.gpp - np.concat( - [part_1_subdaily_pmodel.gpp, part_2_subdaily_pmodel.gpp] + assert np.allclose( + all_in_one_subdaily_pmodel.gpp, + np.concat([part_1_subdaily_pmodel.gpp, part_2_subdaily_pmodel.gpp]), + equal_nan=True, ) - assert np.nanmax(np.abs(diff)) == 0 - @pytest.mark.parametrize("ndims", [2, 3, 4]) def test_FSPModel_dimensionality(be_vie_data, ndims): From 4969af58a63cc7f75dbb9eaa28bc655102e8e457 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 18 Oct 2024 14:20:15 +0100 Subject: [PATCH 239/241] Updating and systematising NDArray typing --- pyrealm/constants/core_const.py | 20 +-- pyrealm/constants/pmodel_const.py | 8 +- pyrealm/core/hygro.py | 41 +++-- pyrealm/core/pressure.py | 5 +- pyrealm/core/solar.py | 4 +- pyrealm/core/utilities.py | 12 +- pyrealm/core/water.py | 30 ++-- pyrealm/demography/canopy.py | 8 +- pyrealm/demography/community.py | 4 +- pyrealm/demography/crown.py | 80 +++++----- pyrealm/demography/flora.py | 84 +++++----- pyrealm/demography/t_model_functions.py | 196 ++++++++++++------------ pyrealm/pmodel/competition.py | 39 +++-- pyrealm/pmodel/functions.py | 56 +++---- pyrealm/pmodel/isotopes.py | 17 +- pyrealm/pmodel/jmax_limitation.py | 8 +- pyrealm/pmodel/optimal_chi.py | 32 ++-- pyrealm/pmodel/pmodel.py | 36 ++--- pyrealm/pmodel/pmodel_environment.py | 36 +++-- pyrealm/pmodel/quantum_yield.py | 6 +- pyrealm/pmodel/scaler.py | 14 +- pyrealm/pmodel/subdaily.py | 66 ++++---- pyrealm/splash/evap.py | 26 ++-- pyrealm/splash/solar.py | 36 +++-- pyrealm/splash/splash.py | 42 +++-- pyrealm/tmodel.py | 90 +++++------ 26 files changed, 526 insertions(+), 470 deletions(-) diff --git a/pyrealm/constants/core_const.py b/pyrealm/constants/core_const.py index 97f7408c..935d5cfb 100644 --- a/pyrealm/constants/core_const.py +++ b/pyrealm/constants/core_const.py @@ -114,7 +114,7 @@ class CoreConst(ConstantsClass): :cite:t:`berger:1978a`.""" # Hygro constants - magnus_coef: NDArray[np.float32] = field( + magnus_coef: NDArray[np.float64] = field( default_factory=lambda: np.array((611.2, 17.62, 243.12)) ) """Three coefficients of the Magnus equation for saturated vapour pressure, @@ -132,7 +132,7 @@ class CoreConst(ConstantsClass): """Set the method used for calculating water density ('fisher' or 'chen').""" # Fisher Dial - fisher_dial_lambda: NDArray[np.float32] = field( + fisher_dial_lambda: NDArray[np.float64] = field( default_factory=lambda: np.array( [1788.316, 21.55053, -0.4695911, 0.003096363, -7.341182e-06] ) @@ -140,7 +140,7 @@ class CoreConst(ConstantsClass): r"""Coefficients of the temperature dependent polynomial for :math:`\lambda` in the Tumlirz equation.""" - fisher_dial_Po: NDArray[np.float32] = field( + fisher_dial_Po: NDArray[np.float64] = field( default_factory=lambda: np.array( [5918.499, 58.05267, -1.1253317, 0.0066123869, -1.4661625e-05] ) @@ -148,7 +148,7 @@ class CoreConst(ConstantsClass): """Coefficients of the temperature dependent polynomial for :math:`P_0` in the Tumlirz equation.""" - fisher_dial_Vinf: NDArray[np.float32] = field( + fisher_dial_Vinf: NDArray[np.float64] = field( default_factory=lambda: np.array( [ 0.6980547, @@ -168,7 +168,7 @@ class CoreConst(ConstantsClass): in the Tumlirz equation.""" # Chen water density - chen_po: NDArray[np.float32] = field( + chen_po: NDArray[np.float64] = field( default_factory=lambda: np.array( [ 0.99983952, @@ -186,7 +186,7 @@ class CoreConst(ConstantsClass): r"""Coefficients of the polynomial relationship of water density with temperature at 1 atm (:math:`P^0`, kg/m^3) from :cite:t:`chen:2008a`.""" - chen_ko: NDArray[np.float32] = field( + chen_ko: NDArray[np.float64] = field( default_factory=lambda: np.array( [19652.17, 148.1830, -2.29995, 0.01281, -4.91564e-5, 1.035530e-7] ) @@ -194,7 +194,7 @@ class CoreConst(ConstantsClass): r"""Polynomial relationship of bulk modulus of water with temperature at 1 atm (:math:`K^0`, kg/m^3) from :cite:t:`chen:2008a`.""" - chen_ca: NDArray[np.float32] = field( + chen_ca: NDArray[np.float64] = field( default_factory=lambda: np.array( [3.26138, 5.223e-4, 1.324e-4, -7.655e-7, 8.584e-10] ) @@ -202,7 +202,7 @@ class CoreConst(ConstantsClass): r"""Coefficients of the polynomial temperature dependent coefficient :math:`A` from :cite:t:`chen:2008a`.""" - chen_cb: NDArray[np.float32] = field( + chen_cb: NDArray[np.float64] = field( default_factory=lambda: np.array( [7.2061e-5, -5.8948e-6, 8.69900e-8, -1.0100e-9, 4.3220e-12] ) @@ -220,11 +220,11 @@ class CoreConst(ConstantsClass): huber_mu_ast: float = 1e-06 r"""Huber reference pressure (:math:`\mu_{ast}` 1.0e-6, Pa s)""" - huber_H_i: NDArray[np.float32] = field( + huber_H_i: NDArray[np.float64] = field( default_factory=lambda: np.array([1.67752, 2.20462, 0.6366564, -0.241605]) ) """Temperature dependent parameterisation of Hi in Huber.""" - huber_H_ij: NDArray[np.float32] = field( + huber_H_ij: NDArray[np.float64] = field( default_factory=lambda: np.array( [ [0.520094, 0.0850895, -1.08374, -0.289555, 0.0, 0.0], diff --git a/pyrealm/constants/pmodel_const.py b/pyrealm/constants/pmodel_const.py index 5e3746a6..fb5c7ebf 100644 --- a/pyrealm/constants/pmodel_const.py +++ b/pyrealm/constants/pmodel_const.py @@ -139,11 +139,11 @@ class PModelConst(ConstantsClass): # - note that kphio_C4 has been updated to account for an unintended double # 8 fold downscaling to account for the fraction of light reaching PS2. # from original values of [-0.008, 0.00375, -0.58e-4] - kphio_C4: NDArray[np.float32] = field( + kphio_C4: NDArray[np.float64] = field( default_factory=lambda: np.array((-0.064, 0.03, -0.000464)) ) """Quadratic scaling of Kphio with temperature for C4 plants""" - kphio_C3: NDArray[np.float32] = field( + kphio_C3: NDArray[np.float64] = field( default_factory=lambda: np.array((0.352, 0.022, -0.00034)) ) """Quadratic scaling of Kphio with temperature for C3 plants""" @@ -193,11 +193,11 @@ class PModelConst(ConstantsClass): """Exponent of the threshold function for Mengoli soil moisture""" # Unit cost ratio (beta) values for different CalcOptimalChi methods - beta_cost_ratio_prentice14: NDArray[np.float32] = field( + beta_cost_ratio_prentice14: NDArray[np.float64] = field( default_factory=lambda: np.array([146.0]) ) r"""Unit cost ratio for C3 plants (:math:`\beta`, 146.0).""" - beta_cost_ratio_c4: NDArray[np.float32] = field( + beta_cost_ratio_c4: NDArray[np.float64] = field( default_factory=lambda: np.array([146.0 / 9]) ) r"""Unit cost ratio for C4 plants (:math:`\beta`, 16.222).""" diff --git a/pyrealm/core/hygro.py b/pyrealm/core/hygro.py index e83880e6..fa48482d 100644 --- a/pyrealm/core/hygro.py +++ b/pyrealm/core/hygro.py @@ -12,7 +12,9 @@ from pyrealm.core.utilities import bounds_checker, evaluate_horner_polynomial -def calc_vp_sat(ta: NDArray, core_const: CoreConst = CoreConst()) -> NDArray: +def calc_vp_sat( + ta: NDArray[np.float64], core_const: CoreConst = CoreConst() +) -> NDArray[np.float64]: r"""Calculate vapour pressure of saturated air. This function calculates the vapour pressure of saturated air in kPa at a given @@ -56,8 +58,10 @@ def calc_vp_sat(ta: NDArray, core_const: CoreConst = CoreConst()) -> NDArray: def convert_vp_to_vpd( - vp: NDArray, ta: NDArray, core_const: CoreConst = CoreConst() -) -> NDArray: + vp: NDArray[np.float64], + ta: NDArray[np.float64], + core_const: CoreConst = CoreConst(), +) -> NDArray[np.float64]: """Convert vapour pressure to vapour pressure deficit. Args: @@ -86,8 +90,10 @@ def convert_vp_to_vpd( def convert_rh_to_vpd( - rh: NDArray, ta: NDArray, core_const: CoreConst = CoreConst() -) -> NDArray: + rh: NDArray[np.float64], + ta: NDArray[np.float64], + core_const: CoreConst = CoreConst(), +) -> NDArray[np.float64]: """Convert relative humidity to vapour pressure deficit. Args: @@ -124,8 +130,10 @@ def convert_rh_to_vpd( def convert_sh_to_vp( - sh: NDArray, patm: NDArray, core_const: CoreConst = CoreConst() -) -> NDArray: + sh: NDArray[np.float64], + patm: NDArray[np.float64], + core_const: CoreConst = CoreConst(), +) -> NDArray[np.float64]: """Convert specific humidity to vapour pressure. Args: @@ -149,8 +157,11 @@ def convert_sh_to_vp( def convert_sh_to_vpd( - sh: NDArray, ta: NDArray, patm: NDArray, core_const: CoreConst = CoreConst() -) -> NDArray: + sh: NDArray[np.float64], + ta: NDArray[np.float64], + patm: NDArray[np.float64], + core_const: CoreConst = CoreConst(), +) -> NDArray[np.float64]: """Convert specific humidity to vapour pressure deficit. Args: @@ -185,7 +196,9 @@ def convert_sh_to_vpd( # The following functions are integrated from the evap.py implementation of SPLASH v1. -def calc_saturation_vapour_pressure_slope(tc: NDArray) -> NDArray: +def calc_saturation_vapour_pressure_slope( + tc: NDArray[np.float64], +) -> NDArray[np.float64]: """Calculate the slope of the saturation vapour pressure curve. Calculates the slope of the saturation pressure temperature curve, following @@ -207,7 +220,7 @@ def calc_saturation_vapour_pressure_slope(tc: NDArray) -> NDArray: ) -def calc_enthalpy_vaporisation(tc: NDArray) -> NDArray: +def calc_enthalpy_vaporisation(tc: NDArray[np.float64]) -> NDArray[np.float64]: """Calculate the enthalpy of vaporization. Calculates the latent heat of vaporization of water as a function of @@ -224,7 +237,7 @@ def calc_enthalpy_vaporisation(tc: NDArray) -> NDArray: return 1.91846e6 * ((tc + 273.15) / (tc + 273.15 - 33.91)) ** 2 -def calc_specific_heat(tc: NDArray) -> NDArray: +def calc_specific_heat(tc: NDArray[np.float64]) -> NDArray[np.float64]: """Calculate the specific heat of air. Calculates the specific heat of air at a constant pressure (:math:`c_{pm}`, J/kg/K) @@ -257,8 +270,8 @@ def calc_specific_heat(tc: NDArray) -> NDArray: def calc_psychrometric_constant( - tc: NDArray, p: NDArray, core_const: CoreConst = CoreConst() -) -> NDArray: + tc: NDArray[np.float64], p: NDArray[np.float64], core_const: CoreConst = CoreConst() +) -> NDArray[np.float64]: r"""Calculate the psychrometric constant. Calculates the psychrometric constant (:math:`\lambda`, Pa/K) given the temperature diff --git a/pyrealm/core/pressure.py b/pyrealm/core/pressure.py index 2a2e44d5..ed8334c5 100644 --- a/pyrealm/core/pressure.py +++ b/pyrealm/core/pressure.py @@ -2,12 +2,15 @@ atmospheric pressure. """ # noqa D210, D415 +import numpy as np from numpy.typing import NDArray from pyrealm.constants import CoreConst -def calc_patm(elv: NDArray, core_const: CoreConst = CoreConst()) -> NDArray: +def calc_patm( + elv: NDArray[np.float64], core_const: CoreConst = CoreConst() +) -> NDArray[np.float64]: r"""Calculate atmospheric pressure from elevation. Calculates atmospheric pressure as a function of elevation with reference to the diff --git a/pyrealm/core/solar.py b/pyrealm/core/solar.py index 6fc0db38..0f7ea2ec 100644 --- a/pyrealm/core/solar.py +++ b/pyrealm/core/solar.py @@ -24,7 +24,9 @@ def calc_heliocentric_longitudes( - julian_day: NDArray, n_days: NDArray, core_const: CoreConst = CoreConst() + julian_day: NDArray[np.float64], + n_days: NDArray[np.float64], + core_const: CoreConst = CoreConst(), ) -> tuple[NDArray, NDArray]: """Calculate heliocentric longitude and anomaly. diff --git a/pyrealm/core/utilities.py b/pyrealm/core/utilities.py index 2e86d367..15ad9498 100644 --- a/pyrealm/core/utilities.py +++ b/pyrealm/core/utilities.py @@ -211,13 +211,13 @@ def _get_interval_functions(interval_type: str = "[]") -> tuple[np.ufunc, np.ufu def bounds_checker( - values: NDArray, + values: NDArray[np.float64], lower: float = -np.inf, upper: float = np.inf, interval_type: str = "[]", label: str = "", unit: str = "", -) -> NDArray: +) -> NDArray[np.float64]: r"""Check inputs fall within bounds. This is a simple pass through function that tests whether the values fall within @@ -255,7 +255,7 @@ def bounds_checker( def bounds_mask( - inputs: NDArray, + inputs: NDArray[np.float64], lower: float = -np.inf, upper: float = np.inf, interval_type: str = "[]", @@ -312,7 +312,7 @@ def bounds_mask( # modifying the original input. Using type if not np.issubdtype(inputs.dtype, np.floating): # Copies implicitly - outputs = inputs.astype(np.float32) + outputs = inputs.astype(np.float64) else: outputs = inputs.copy() @@ -336,7 +336,9 @@ def bounds_mask( return outputs -def evaluate_horner_polynomial(x: NDArray, cf: list | NDArray) -> NDArray: +def evaluate_horner_polynomial( + x: NDArray[np.float64], cf: list | NDArray +) -> NDArray[np.float64]: r"""Evaluates a polynomial with coefficients `cf` at `x` using Horner's method. Horner's method is a fast way to evaluate polynomials, especially for large degrees, diff --git a/pyrealm/core/water.py b/pyrealm/core/water.py index 72c7568b..953027c8 100644 --- a/pyrealm/core/water.py +++ b/pyrealm/core/water.py @@ -10,10 +10,10 @@ def calc_density_h2o_chen( - tc: NDArray, - p: NDArray, + tc: NDArray[np.float64], + p: NDArray[np.float64], core_const: CoreConst = CoreConst(), -) -> NDArray: +) -> NDArray[np.float64]: """Calculate the density of water using Chen et al 2008. This function calculates the density of water at a given temperature and pressure @@ -65,10 +65,10 @@ def calc_density_h2o_chen( def calc_density_h2o_fisher( - tc: NDArray, - patm: NDArray, + tc: NDArray[np.float64], + patm: NDArray[np.float64], core_const: CoreConst = CoreConst(), -) -> NDArray: +) -> NDArray[np.float64]: """Calculate water density. Calculates the density of water as a function of temperature and atmospheric @@ -124,11 +124,11 @@ def calc_density_h2o_fisher( def calc_density_h2o( - tc: NDArray, - patm: NDArray, + tc: NDArray[np.float64], + patm: NDArray[np.float64], core_const: CoreConst = CoreConst(), safe: bool = True, -) -> NDArray: +) -> NDArray[np.float64]: """Calculate water density. Calculates the density of water as a function of temperature and atmospheric @@ -179,11 +179,11 @@ def calc_density_h2o( def calc_viscosity_h2o( - tc: NDArray, - patm: NDArray, + tc: NDArray[np.float64], + patm: NDArray[np.float64], core_const: CoreConst = CoreConst(), simple: bool = False, -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate the viscosity of water. Calculates the viscosity of water (:math:`\eta`) as a function of temperature and @@ -247,11 +247,11 @@ def calc_viscosity_h2o( def calc_viscosity_h2o_matrix( - tc: NDArray, - patm: NDArray, + tc: NDArray[np.float64], + patm: NDArray[np.float64], core_const: CoreConst = CoreConst(), simple: bool = False, -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate the viscosity of water. Calculates the viscosity of water (:math:`\eta`) as a function of temperature and diff --git a/pyrealm/demography/canopy.py b/pyrealm/demography/canopy.py index 05c35631..ca961455 100644 --- a/pyrealm/demography/canopy.py +++ b/pyrealm/demography/canopy.py @@ -55,13 +55,13 @@ def __init__( """Total number of canopy layers.""" self.n_cohorts: int """Total number of cohorts in the canopy.""" - self.layer_heights: NDArray[np.float32] + self.layer_heights: NDArray[np.float64] """Column vector of the heights of canopy layers.""" - self.stem_relative_radius: NDArray[np.float32] + self.stem_relative_radius: NDArray[np.float64] """Relative radius values of stems at canopy layer heights.""" - self.stem_crown_area: NDArray[np.float32] + self.stem_crown_area: NDArray[np.float64] """Stem projected crown area at canopy layer heights.""" - self.stem_leaf_area: NDArray[np.float32] + self.stem_leaf_area: NDArray[np.float64] """Stem projected leaf area at canopy layer heights.""" self._calculate_canopy(community=community) diff --git a/pyrealm/demography/community.py b/pyrealm/demography/community.py index 11502f35..2f593471 100644 --- a/pyrealm/demography/community.py +++ b/pyrealm/demography/community.py @@ -353,7 +353,7 @@ class Community: flora: Flora # - arrays representing properties of cohorts - cohort_dbh_values: InitVar[NDArray[np.float32]] + cohort_dbh_values: InitVar[NDArray[np.float64]] cohort_n_individuals: InitVar[NDArray[np.int_]] cohort_pft_names: InitVar[NDArray[np.str_]] @@ -365,7 +365,7 @@ class Community: def __post_init__( self, - cohort_dbh_values: NDArray[np.float32], + cohort_dbh_values: NDArray[np.float64], cohort_n_individuals: NDArray[np.int_], cohort_pft_names: NDArray[np.str_], ) -> None: diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index 61a60ce1..f12aa1e7 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -13,9 +13,9 @@ def _validate_z_qz_args( - z: NDArray[np.float32], - stem_properties: list[NDArray[np.float32]], - q_z: NDArray[np.float32] | None = None, + z: NDArray[np.float64], + stem_properties: list[NDArray[np.float64]], + q_z: NDArray[np.float64] | None = None, ) -> None: """Shared validation of for crown function arguments. @@ -92,12 +92,12 @@ def _validate_z_qz_args( def calculate_relative_crown_radius_at_z( - z: NDArray[np.float32], - stem_height: NDArray[np.float32], - m: NDArray[np.float32], - n: NDArray[np.float32], + z: NDArray[np.float64], + stem_height: NDArray[np.float64], + m: NDArray[np.float64], + n: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate relative crown radius at a given height. The crown shape parameters ``m`` and ``n`` define the vertical distribution of @@ -140,10 +140,10 @@ def calculate_relative_crown_radius_at_z( def calculate_crown_radius( - q_z: NDArray[np.float32], - r0: NDArray[np.float32], + q_z: NDArray[np.float64], + r0: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate crown radius from relative crown radius and crown r0. The relative crown radius (:math:`q(z)`) at a given height :math:`z` describes the @@ -172,14 +172,14 @@ def calculate_crown_radius( def calculate_stem_projected_crown_area_at_z( - z: NDArray[np.float32], - q_z: NDArray[np.float32], - stem_height: NDArray[np.float32], - crown_area: NDArray[np.float32], - q_m: NDArray[np.float32], - z_max: NDArray[np.float32], + z: NDArray[np.float64], + q_z: NDArray[np.float64], + stem_height: NDArray[np.float64], + crown_area: NDArray[np.float64], + q_m: NDArray[np.float64], + z_max: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: """Calculate stem projected crown area above a given height. This function calculates the projected crown area of a set of stems with given @@ -219,16 +219,16 @@ def calculate_stem_projected_crown_area_at_z( def solve_community_projected_canopy_area( z: float, - stem_height: NDArray[np.float32], - crown_area: NDArray[np.float32], - m: NDArray[np.float32], - n: NDArray[np.float32], - q_m: NDArray[np.float32], - z_max: NDArray[np.float32], - n_individuals: NDArray[np.float32], + stem_height: NDArray[np.float64], + crown_area: NDArray[np.float64], + m: NDArray[np.float64], + n: NDArray[np.float64], + q_m: NDArray[np.float64], + z_max: NDArray[np.float64], + n_individuals: NDArray[np.float64], target_area: float = 0, validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: """Solver function for community wide projected canopy area. This function takes the number of individuals in each cohort along with the stem @@ -287,15 +287,15 @@ def solve_community_projected_canopy_area( def calculate_stem_projected_leaf_area_at_z( - z: NDArray[np.float32], - q_z: NDArray[np.float32], - stem_height: NDArray[np.float32], - crown_area: NDArray[np.float32], - f_g: NDArray[np.float32], - q_m: NDArray[np.float32], - z_max: NDArray[np.float32], + z: NDArray[np.float64], + q_z: NDArray[np.float64], + stem_height: NDArray[np.float64], + crown_area: NDArray[np.float64], + f_g: NDArray[np.float64], + q_m: NDArray[np.float64], + z_max: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: """Calculate projected leaf area above a given height. This function calculates the projected leaf area of a set of stems with given @@ -379,16 +379,16 @@ class CrownProfile: """A Flora or StemTraits instance providing plant functional trait data.""" stem_allometry: InitVar[StemAllometry] """A StemAllometry instance setting the stem allometries for the crown profile.""" - z: InitVar[NDArray[np.float32]] + z: InitVar[NDArray[np.float64]] """An array of vertical height values at which to calculate crown profiles.""" - relative_crown_radius: NDArray[np.float32] = field(init=False) + relative_crown_radius: NDArray[np.float64] = field(init=False) """An array of the relative crown radius of stems at z heights""" - crown_radius: NDArray[np.float32] = field(init=False) + crown_radius: NDArray[np.float64] = field(init=False) """An array of the actual crown radius of stems at z heights""" - projected_crown_area: NDArray[np.float32] = field(init=False) + projected_crown_area: NDArray[np.float64] = field(init=False) """An array of the projected crown area of stems at z heights""" - projected_leaf_area: NDArray[np.float32] = field(init=False) + projected_leaf_area: NDArray[np.float64] = field(init=False) """An array of the projected leaf area of stems at z heights""" # Information attributes @@ -401,7 +401,7 @@ def __post_init__( self, stem_traits: StemTraits | Flora, stem_allometry: StemAllometry, - z: NDArray[np.float32], + z: NDArray[np.float64], ) -> None: """Populate crown profile attributes from the traits, allometry and height.""" # Calculate relative crown radius diff --git a/pyrealm/demography/flora.py b/pyrealm/demography/flora.py index 41767d5f..a12463f9 100644 --- a/pyrealm/demography/flora.py +++ b/pyrealm/demography/flora.py @@ -46,8 +46,8 @@ def calculate_crown_q_m( - m: float | NDArray[np.float32], n: float | NDArray[np.float32] -) -> float | NDArray[np.float32]: + m: float | NDArray[np.float64], n: float | NDArray[np.float64] +) -> float | NDArray[np.float64]: """Calculate the crown scaling trait ``q_m``. The value of q_m is a constant crown scaling parameter derived from the ``m`` and @@ -66,8 +66,8 @@ def calculate_crown_q_m( def calculate_crown_z_max_proportion( - m: float | NDArray[np.float32], n: float | NDArray[np.float32] -) -> float | NDArray[np.float32]: + m: float | NDArray[np.float64], n: float | NDArray[np.float64] +) -> float | NDArray[np.float64]: r"""Calculate the z_m trait. The z_m proportion (:math:`p_{zm}`) is the constant proportion of stem height at @@ -267,45 +267,45 @@ class Flora: # - trait arrays name: NDArray[np.str_] = field(init=False) r"""The name of the plant functional type.""" - a_hd: NDArray[np.float32] = field(init=False) + a_hd: NDArray[np.float64] = field(init=False) r"""Initial slope of height-diameter relationship (:math:`a`, -)""" - ca_ratio: NDArray[np.float32] = field(init=False) + ca_ratio: NDArray[np.float64] = field(init=False) r"""Initial ratio of crown area to stem cross-sectional area (:math:`c`, -)""" - h_max: NDArray[np.float32] = field(init=False) + h_max: NDArray[np.float64] = field(init=False) r"""Maximum tree height (:math:`H_m`, m)""" - rho_s: NDArray[np.float32] = field(init=False) + rho_s: NDArray[np.float64] = field(init=False) r"""Sapwood density (:math:`\rho_s`, kg Cm-3)""" - lai: NDArray[np.float32] = field(init=False) + lai: NDArray[np.float64] = field(init=False) """Leaf area index within the crown (:math:`L`, -)""" - sla: NDArray[np.float32] = field(init=False) + sla: NDArray[np.float64] = field(init=False) r"""Specific leaf area (:math:`\sigma`, m2 kg-1 C)""" - tau_f: NDArray[np.float32] = field(init=False) + tau_f: NDArray[np.float64] = field(init=False) r"""Foliage turnover time (:math:`\tau_f`,years)""" - tau_r: NDArray[np.float32] = field(init=False) + tau_r: NDArray[np.float64] = field(init=False) r"""Fine-root turnover time (:math:`\tau_r`, years)""" - par_ext: NDArray[np.float32] = field(init=False) + par_ext: NDArray[np.float64] = field(init=False) r"""Extinction coefficient of photosynthetically active radiation (PAR) (:math:`k`, -)""" - yld: NDArray[np.float32] = field(init=False) + yld: NDArray[np.float64] = field(init=False) r"""Yield factor (:math:`y`, -)""" - zeta: NDArray[np.float32] = field(init=False) + zeta: NDArray[np.float64] = field(init=False) r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, kg C m-2)""" - resp_r: NDArray[np.float32] = field(init=False) + resp_r: NDArray[np.float64] = field(init=False) r"""Fine-root specific respiration rate (:math:`r_r`, year-1)""" - resp_s: NDArray[np.float32] = field(init=False) + resp_s: NDArray[np.float64] = field(init=False) r"""Sapwood-specific respiration rate (:math:`r_s`, year-1)""" - resp_f: NDArray[np.float32] = field(init=False) + resp_f: NDArray[np.float64] = field(init=False) r"""Foliage maintenance respiration fraction (:math:`r_f`, -)""" - m: NDArray[np.float32] = field(init=False) + m: NDArray[np.float64] = field(init=False) r"""Crown shape parameter (:math:`m`, -)""" - n: NDArray[np.float32] = field(init=False) + n: NDArray[np.float64] = field(init=False) r"""Crown shape parameter (:math:`n`, -)""" - f_g: NDArray[np.float32] = field(init=False) + f_g: NDArray[np.float64] = field(init=False) r"""Crown gap fraction (:math:`f_g`, -)""" - q_m: NDArray[np.float32] = field(init=False) + q_m: NDArray[np.float64] = field(init=False) """Scaling factor to derive maximum crown radius from crown area.""" - z_max_prop: NDArray[np.float32] = field(init=False) + z_max_prop: NDArray[np.float64] = field(init=False) """Proportion of stem height at which maximum crown radius is found.""" # - other instance attributes @@ -464,45 +464,45 @@ class StemTraits: # Instance trait attributes name: NDArray[np.str_] r"""The name of the plant functional type.""" - a_hd: NDArray[np.float32] + a_hd: NDArray[np.float64] r"""Initial slope of height-diameter relationship (:math:`a`, -)""" - ca_ratio: NDArray[np.float32] + ca_ratio: NDArray[np.float64] r"""Initial ratio of crown area to stem cross-sectional area (:math:`c`, -)""" - h_max: NDArray[np.float32] + h_max: NDArray[np.float64] r"""Maximum tree height (:math:`H_m`, m)""" - rho_s: NDArray[np.float32] + rho_s: NDArray[np.float64] r"""Sapwood density (:math:`\rho_s`, kg Cm-3)""" - lai: NDArray[np.float32] + lai: NDArray[np.float64] """Leaf area index within the crown (:math:`L`, -)""" - sla: NDArray[np.float32] + sla: NDArray[np.float64] r"""Specific leaf area (:math:`\sigma`, m2 kg-1 C)""" - tau_f: NDArray[np.float32] + tau_f: NDArray[np.float64] r"""Foliage turnover time (:math:`\tau_f`,years)""" - tau_r: NDArray[np.float32] + tau_r: NDArray[np.float64] r"""Fine-root turnover time (:math:`\tau_r`, years)""" - par_ext: NDArray[np.float32] + par_ext: NDArray[np.float64] r"""Extinction coefficient of photosynthetically active radiation (PAR) (:math:`k`, -)""" - yld: NDArray[np.float32] + yld: NDArray[np.float64] r"""Yield factor (:math:`y`, -)""" - zeta: NDArray[np.float32] + zeta: NDArray[np.float64] r"""Ratio of fine-root mass to foliage area (:math:`\zeta`, kg C m-2)""" - resp_r: NDArray[np.float32] + resp_r: NDArray[np.float64] r"""Fine-root specific respiration rate (:math:`r_r`, year-1)""" - resp_s: NDArray[np.float32] + resp_s: NDArray[np.float64] r"""Sapwood-specific respiration rate (:math:`r_s`, year-1)""" - resp_f: NDArray[np.float32] + resp_f: NDArray[np.float64] r"""Foliage maintenance respiration fraction (:math:`r_f`, -)""" - m: NDArray[np.float32] + m: NDArray[np.float64] r"""Crown shape parameter (:math:`m`, -)""" - n: NDArray[np.float32] + n: NDArray[np.float64] r"""Crown shape parameter (:math:`n`, -)""" - f_g: NDArray[np.float32] + f_g: NDArray[np.float64] r"""Crown gap fraction (:math:`f_g`, -)""" - q_m: NDArray[np.float32] + q_m: NDArray[np.float64] """Scaling factor to derive maximum crown radius from crown area.""" - z_max_prop: NDArray[np.float32] + z_max_prop: NDArray[np.float64] """Proportion of stem height at which maximum crown radius is found.""" # Post init attributes diff --git a/pyrealm/demography/t_model_functions.py b/pyrealm/demography/t_model_functions.py index dbedb70f..8cabeaa4 100644 --- a/pyrealm/demography/t_model_functions.py +++ b/pyrealm/demography/t_model_functions.py @@ -53,11 +53,11 @@ def _validate_t_model_args(pft_args: list[NDArray], size_args: list[NDArray]) -> def calculate_heights( - h_max: NDArray[np.float32], - a_hd: NDArray[np.float32], - dbh: NDArray[np.float32], + h_max: NDArray[np.float64], + a_hd: NDArray[np.float64], + dbh: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate tree height under the T Model. The height of trees (:math:`H`) are calculated from individual diameters at breast @@ -83,11 +83,11 @@ def calculate_heights( def calculate_dbh_from_height( - h_max: NDArray[np.float32], - a_hd: NDArray[np.float32], - stem_height: NDArray[np.float32], + h_max: NDArray[np.float64], + a_hd: NDArray[np.float64], + stem_height: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate diameter at breast height from stem height under the T Model. This function inverts the normal calculation of stem height (:math:`H`) from @@ -133,12 +133,12 @@ def calculate_dbh_from_height( def calculate_crown_areas( - ca_ratio: NDArray[np.float32], - a_hd: NDArray[np.float32], - dbh: NDArray[np.float32], - stem_height: NDArray[np.float32], + ca_ratio: NDArray[np.float64], + a_hd: NDArray[np.float64], + dbh: NDArray[np.float64], + stem_height: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate tree crown area under the T Model. The tree crown area (:math:`A_{c}`)is calculated from individual diameters at breast @@ -166,11 +166,11 @@ def calculate_crown_areas( def calculate_crown_fractions( - a_hd: NDArray[np.float32], - stem_height: NDArray[np.float32], - dbh: NDArray[np.float32], + a_hd: NDArray[np.float64], + stem_height: NDArray[np.float64], + dbh: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate tree crown fraction under the T Model. The crown fraction (:math:`f_{c}`)is calculated from individual diameters at breast @@ -195,11 +195,11 @@ def calculate_crown_fractions( def calculate_stem_masses( - rho_s: NDArray[np.float32], - stem_height: NDArray[np.float32], - dbh: NDArray[np.float32], + rho_s: NDArray[np.float64], + stem_height: NDArray[np.float64], + dbh: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate stem mass under the T Model. The stem mass (:math:`W_{s}`) is calculated from individual diameters at breast @@ -223,11 +223,11 @@ def calculate_stem_masses( def calculate_foliage_masses( - sla: NDArray[np.float32], - lai: NDArray[np.float32], - crown_area: NDArray[np.float32], + sla: NDArray[np.float64], + lai: NDArray[np.float64], + crown_area: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate foliage mass under the T Model. The foliage mass (:math:`W_{f}`) is calculated from the crown area (:math:`A_{c}`), @@ -251,13 +251,13 @@ def calculate_foliage_masses( def calculate_sapwood_masses( - rho_s: NDArray[np.float32], - ca_ratio: NDArray[np.float32], - stem_height: NDArray[np.float32], - crown_area: NDArray[np.float32], - crown_fraction: NDArray[np.float32], + rho_s: NDArray[np.float64], + ca_ratio: NDArray[np.float64], + stem_height: NDArray[np.float64], + crown_area: NDArray[np.float64], + crown_fraction: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate sapwood mass under the T Model. The sapwood mass (:math:`W_{\cdot s}`) is calculated from the individual crown area @@ -287,8 +287,8 @@ def calculate_sapwood_masses( def calculate_crown_z_max( - z_max_prop: NDArray[np.float32], stem_height: NDArray[np.float32] -) -> NDArray[np.float32]: + z_max_prop: NDArray[np.float64], stem_height: NDArray[np.float64] +) -> NDArray[np.float64]: r"""Calculate height of maximum crown radius. The height of the maximum crown radius (:math:`z_m`) is derived from the crown @@ -313,8 +313,8 @@ def calculate_crown_z_max( def calculate_crown_r0( - q_m: NDArray[np.float32], crown_area: NDArray[np.float32] -) -> NDArray[np.float32]: + q_m: NDArray[np.float64], crown_area: NDArray[np.float64] +) -> NDArray[np.float64]: r"""Calculate scaling factor for width of maximum crown radius. This scaling factor (:math:`r_0`) is derived from the crown shape parameters @@ -339,12 +339,12 @@ def calculate_crown_r0( def calculate_whole_crown_gpp( - potential_gpp: NDArray[np.float32], - crown_area: NDArray[np.float32], - par_ext: NDArray[np.float32], - lai: NDArray[np.float32], + potential_gpp: NDArray[np.float64], + crown_area: NDArray[np.float64], + par_ext: NDArray[np.float64], + lai: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate whole crown gross primary productivity. This function calculates individual GPP across the whole crown, given the individual @@ -373,10 +373,10 @@ def calculate_whole_crown_gpp( def calculate_sapwood_respiration( - resp_s: NDArray[np.float32], - sapwood_mass: NDArray[np.float32], + resp_s: NDArray[np.float64], + sapwood_mass: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate sapwood respiration. Calculates the total sapwood respiration (:math:`R_{\cdot s}`) given the individual @@ -398,10 +398,10 @@ def calculate_sapwood_respiration( def calculate_foliar_respiration( - resp_f: NDArray[np.float32], - whole_crown_gpp: NDArray[np.float32], + resp_f: NDArray[np.float64], + whole_crown_gpp: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate foliar respiration. Calculates the total foliar respiration (:math:`R_{f}`) given the individual crown @@ -425,12 +425,12 @@ def calculate_foliar_respiration( def calculate_fine_root_respiration( - zeta: NDArray[np.float32], - sla: NDArray[np.float32], - resp_r: NDArray[np.float32], - foliage_mass: NDArray[np.float32], + zeta: NDArray[np.float64], + sla: NDArray[np.float64], + resp_r: NDArray[np.float64], + foliage_mass: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate foliar respiration. Calculates the total fine root respiration (:math:`R_{r}`) given the individual @@ -455,13 +455,13 @@ def calculate_fine_root_respiration( def calculate_net_primary_productivity( - yld: NDArray[np.float32], - whole_crown_gpp: NDArray[np.float32], - foliar_respiration: NDArray[np.float32], - fine_root_respiration: NDArray[np.float32], - sapwood_respiration: NDArray[np.float32], + yld: NDArray[np.float64], + whole_crown_gpp: NDArray[np.float64], + foliar_respiration: NDArray[np.float64], + fine_root_respiration: NDArray[np.float64], + sapwood_respiration: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate net primary productivity. The net primary productivity (NPP, :math:`P_{net}`) is calculated as a plant @@ -507,13 +507,13 @@ def calculate_net_primary_productivity( def calculate_foliage_and_fine_root_turnover( - sla: NDArray[np.float32], - zeta: NDArray[np.float32], - tau_f: NDArray[np.float32], - tau_r: NDArray[np.float32], - foliage_mass: NDArray[np.float32], + sla: NDArray[np.float64], + zeta: NDArray[np.float64], + tau_f: NDArray[np.float64], + tau_r: NDArray[np.float64], + foliage_mass: NDArray[np.float64], validate: bool = True, -) -> NDArray[np.float32]: +) -> NDArray[np.float64]: r"""Calculate turnover costs. This function calculates the costs associated with the turnover of fine roots and @@ -544,19 +544,19 @@ def calculate_foliage_and_fine_root_turnover( def calculate_growth_increments( - rho_s: NDArray[np.float32], - a_hd: NDArray[np.float32], - h_max: NDArray[np.float32], - lai: NDArray[np.float32], - ca_ratio: NDArray[np.float32], - sla: NDArray[np.float32], - zeta: NDArray[np.float32], - npp: NDArray[np.float32], - turnover: NDArray[np.float32], - dbh: NDArray[np.float32], - stem_height: NDArray[np.float32], + rho_s: NDArray[np.float64], + a_hd: NDArray[np.float64], + h_max: NDArray[np.float64], + lai: NDArray[np.float64], + ca_ratio: NDArray[np.float64], + sla: NDArray[np.float64], + zeta: NDArray[np.float64], + npp: NDArray[np.float64], + turnover: NDArray[np.float64], + dbh: NDArray[np.float64], + stem_height: NDArray[np.float64], validate: bool = True, -) -> tuple[NDArray[np.float32], NDArray[np.float32], NDArray[np.float32]]: +) -> tuple[NDArray[np.float64], NDArray[np.float64], NDArray[np.float64]]: r"""Calculate growth increments. Given an estimate of net primary productivity (:math:`P_{net}`), less associated @@ -692,28 +692,28 @@ class StemAllometry: """ An instance of :class:`~pyrealm.demography.flora.Flora` or :class:`~pyrealm.demography.flora.StemTraits`, providing plant functional trait data for a set of stems.""" - at_dbh: InitVar[NDArray[np.float32]] + at_dbh: InitVar[NDArray[np.float64]] """An array of diameter at breast height values at which to predict stem allometry values.""" # Post init allometry attributes - dbh: NDArray[np.float32] = field(init=False) + dbh: NDArray[np.float64] = field(init=False) """Diameter at breast height (metres)""" - stem_height: NDArray[np.float32] = field(init=False) + stem_height: NDArray[np.float64] = field(init=False) """Stem height (metres)""" - crown_area: NDArray[np.float32] = field(init=False) + crown_area: NDArray[np.float64] = field(init=False) """Crown area (square metres)""" - crown_fraction: NDArray[np.float32] = field(init=False) + crown_fraction: NDArray[np.float64] = field(init=False) """Vertical fraction of the stem covered by the crown (-)""" - stem_mass: NDArray[np.float32] = field(init=False) + stem_mass: NDArray[np.float64] = field(init=False) """Stem mass (kg)""" - foliage_mass: NDArray[np.float32] = field(init=False) + foliage_mass: NDArray[np.float64] = field(init=False) """Foliage mass (kg)""" - sapwood_mass: NDArray[np.float32] = field(init=False) + sapwood_mass: NDArray[np.float64] = field(init=False) """Sapwood mass (kg)""" - crown_r0: NDArray[np.float32] = field(init=False) + crown_r0: NDArray[np.float64] = field(init=False) """Crown radius scaling factor (-)""" - crown_z_max: NDArray[np.float32] = field(init=False) + crown_z_max: NDArray[np.float64] = field(init=False) """Height of maximum crown radius (metres)""" # Information attributes @@ -723,7 +723,7 @@ class StemAllometry: """The number of stems.""" def __post_init__( - self, stem_traits: Flora | StemTraits, at_dbh: NDArray[np.float32] + self, stem_traits: Flora | StemTraits, at_dbh: NDArray[np.float64] ) -> None: """Populate the stem allometry attributes from the traits and size data.""" @@ -835,30 +835,30 @@ class StemAllocation: stem_allometry: InitVar[StemAllometry] """An instance of :class:`~pyrealm.demography.t_model_functions.StemAllometry` providing the stem size data for which to calculate allocation.""" - at_potential_gpp: InitVar[NDArray[np.float32]] + at_potential_gpp: InitVar[NDArray[np.float64]] """An array of potential gross primary productivity for each stem that should be allocated to respiration, turnover and growth.""" # Post init allometry attributes - potential_gpp: NDArray[np.float32] = field(init=False) + potential_gpp: NDArray[np.float64] = field(init=False) """Potential GPP per unit area (g C m2)""" - whole_crown_gpp: NDArray[np.float32] = field(init=False) + whole_crown_gpp: NDArray[np.float64] = field(init=False) """Estimated GPP across the whole crown (g C)""" - sapwood_respiration: NDArray[np.float32] = field(init=False) + sapwood_respiration: NDArray[np.float64] = field(init=False) """Allocation to sapwood respiration (g C)""" - foliar_respiration: NDArray[np.float32] = field(init=False) + foliar_respiration: NDArray[np.float64] = field(init=False) """Allocation to foliar respiration (g C)""" - fine_root_respiration: NDArray[np.float32] = field(init=False) + fine_root_respiration: NDArray[np.float64] = field(init=False) """Allocation to fine root respiration (g C)""" - npp: NDArray[np.float32] = field(init=False) + npp: NDArray[np.float64] = field(init=False) """Net primary productivity (g C)""" - turnover: NDArray[np.float32] = field(init=False) + turnover: NDArray[np.float64] = field(init=False) """Allocation to leaf and fine root turnover (g C)""" - delta_dbh: NDArray[np.float32] = field(init=False) + delta_dbh: NDArray[np.float64] = field(init=False) """Predicted increase in stem diameter from growth allocation (g C)""" - delta_stem_mass: NDArray[np.float32] = field(init=False) + delta_stem_mass: NDArray[np.float64] = field(init=False) """Predicted increase in stem mass from growth allocation (g C)""" - delta_foliage_mass: NDArray[np.float32] = field(init=False) + delta_foliage_mass: NDArray[np.float64] = field(init=False) """Predicted increase in foliar mass from growth allocation (g C)""" # Information attributes @@ -871,7 +871,7 @@ def __post_init__( self, stem_traits: Flora | StemTraits, stem_allometry: StemAllometry, - at_potential_gpp: NDArray[np.float32], + at_potential_gpp: NDArray[np.float64], ) -> None: """Populate stem allocation attributes from the traits, allometry and GPP.""" diff --git a/pyrealm/pmodel/competition.py b/pyrealm/pmodel/competition.py index 3be943b5..5c5755fb 100644 --- a/pyrealm/pmodel/competition.py +++ b/pyrealm/pmodel/competition.py @@ -12,8 +12,10 @@ def convert_gpp_advantage_to_c4_fraction( - gpp_adv_c4: NDArray, treecover: NDArray, c3c4_const: C3C4Const = C3C4Const() -) -> NDArray: + gpp_adv_c4: NDArray[np.float64], + treecover: NDArray[np.float64], + c3c4_const: C3C4Const = C3C4Const(), +) -> NDArray[np.float64]: r"""Convert C4 GPP advantage to C4 fraction. This function calculates an initial estimate of the fraction of C4 plants based on @@ -60,8 +62,8 @@ def convert_gpp_advantage_to_c4_fraction( def calculate_tree_proportion( - gppc3: NDArray, c3c4_const: C3C4Const = C3C4Const() -) -> NDArray: + gppc3: NDArray[np.float64], c3c4_const: C3C4Const = C3C4Const() +) -> NDArray[np.float64]: r"""Calculate the proportion of GPP from C3 trees. This function estimates the proportion of C3 trees in the community, which can then @@ -181,11 +183,11 @@ class C3C4Competition: def __init__( self, - gpp_c3: NDArray, - gpp_c4: NDArray, - treecover: NDArray, - below_t_min: NDArray, - cropland: NDArray, + gpp_c3: NDArray[np.float64], + gpp_c4: NDArray[np.float64], + treecover: NDArray[np.float64], + below_t_min: NDArray[np.float64], + cropland: NDArray[np.float64], c3c4_const: C3C4Const = C3C4Const(), ): # Check inputs are congruent @@ -198,7 +200,7 @@ def __init__( # annual total GPP estimates for C3 and C4 plants. This uses use # np.full to handle division by zero without raising warnings gpp_adv_c4 = np.full(self.shape, np.nan) - self.gpp_adv_c4: NDArray = np.divide( + self.gpp_adv_c4: NDArray[np.float64] = np.divide( gpp_c4 - gpp_c3, gpp_c3, out=gpp_adv_c4, where=gpp_c3 > 0 ) """The proportional advantage in GPP of C4 over C3 plants""" @@ -224,22 +226,22 @@ def __init__( # Step 5: remove cropland areas frac_c4[cropland] = np.nan # type: ignore - self.frac_c4: NDArray = frac_c4 + self.frac_c4: NDArray[np.float64] = frac_c4 """The estimated fraction of C4 plants.""" - self.gpp_c3_contrib: NDArray = gpp_c3 * (1 - self.frac_c4) + self.gpp_c3_contrib: NDArray[np.float64] = gpp_c3 * (1 - self.frac_c4) """The estimated contribution of C3 plants to GPP (gC m-2 yr-1)""" self.gpp_c4_contrib = gpp_c4 * self.frac_c4 """The estimated contribution of C4 plants to GPP (gC m-2 yr-1)""" # Define attributes used elsewhere - self.Delta13C_C3: NDArray + self.Delta13C_C3: NDArray[np.float64] r"""Contribution from C3 plants to (:math:`\Delta\ce{^13C}`, permil).""" - self.Delta13C_C4: NDArray + self.Delta13C_C4: NDArray[np.float64] r"""Contribution from C4 plants to (:math:`\Delta\ce{^13C}`, permil).""" - self.d13C_C3: NDArray + self.d13C_C3: NDArray[np.float64] r"""Contribution from C3 plants to (:math:`d\ce{^13C}`, permil).""" - self.d13C_C4: NDArray + self.d13C_C4: NDArray[np.float64] r"""Contribution from C3 plants to (:math:`d\ce{^13C}`, permil).""" def __repr__(self) -> str: @@ -247,7 +249,10 @@ def __repr__(self) -> str: return f"C3C4Competition(shape={self.shape})" def estimate_isotopic_discrimination( - self, d13CO2: NDArray, Delta13C_C3_alone: NDArray, Delta13C_C4_alone: NDArray + self, + d13CO2: NDArray[np.float64], + Delta13C_C3_alone: NDArray[np.float64], + Delta13C_C4_alone: NDArray[np.float64], ) -> None: r"""Estimate CO2 isotopic discrimination values. diff --git a/pyrealm/pmodel/functions.py b/pyrealm/pmodel/functions.py index 69f4c98e..a9f3938a 100644 --- a/pyrealm/pmodel/functions.py +++ b/pyrealm/pmodel/functions.py @@ -12,12 +12,12 @@ def calc_ftemp_arrh( - tk: NDArray, + tk: NDArray[np.float64], ha: float | NDArray, tk_ref: float | NDArray | None = None, pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate enzyme kinetics scaling factor. Calculates the temperature-scaling factor :math:`f` for enzyme kinetics following an @@ -81,9 +81,9 @@ def calc_ftemp_arrh( def calc_ftemp_inst_rd( - tc: NDArray, + tc: NDArray[np.float64], pmodel_const: PModelConst = PModelConst(), -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate temperature scaling of dark respiration. Calculates the temperature-scaling factor for dark respiration at a given @@ -123,14 +123,14 @@ def calc_ftemp_inst_rd( def calc_modified_arrhenius_factor( - tk: NDArray, + tk: NDArray[np.float64], Ha: float | NDArray, Hd: float | NDArray, deltaS: float | NDArray, tk_ref: float | NDArray, mode: str = "M2002", core_const: CoreConst = CoreConst(), -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate the modified Arrhenius factor with temperature for an enzyme. This function returns a temperature-determined factor expressing the rate of an @@ -198,8 +198,8 @@ def calc_modified_arrhenius_factor( def calc_ftemp_kphio( - tc: NDArray, c4: bool = False, pmodel_const: PModelConst = PModelConst() -) -> NDArray: + tc: NDArray[np.float64], c4: bool = False, pmodel_const: PModelConst = PModelConst() +) -> NDArray[np.float64]: r"""Calculate temperature dependence of quantum yield efficiency. Calculates the temperature dependence of the quantum yield efficiency, as a @@ -257,11 +257,11 @@ def calc_ftemp_kphio( def calc_gammastar( - tc: NDArray, - patm: NDArray, + tc: NDArray[np.float64], + patm: NDArray[np.float64], pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate the photorespiratory CO2 compensation point. Calculates the photorespiratory **CO2 compensation point** in absence of dark @@ -311,10 +311,10 @@ def calc_gammastar( def calc_ns_star( - tc: NDArray, - patm: NDArray, + tc: NDArray[np.float64], + patm: NDArray[np.float64], core_const: CoreConst = CoreConst(), -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate the relative viscosity of water. Calculates the relative viscosity of water (:math:`\eta^*`), given the standard @@ -355,11 +355,11 @@ def calc_ns_star( def calc_kmm( - tc: NDArray, - patm: NDArray, + tc: NDArray[np.float64], + patm: NDArray[np.float64], pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate the Michaelis Menten coefficient of Rubisco-limited assimilation. Calculates the Michaelis Menten coefficient of Rubisco-limited assimilation @@ -431,11 +431,11 @@ def calc_kmm( def calc_kp_c4( - tc: NDArray, - patm: NDArray, + tc: NDArray[np.float64], + patm: NDArray[np.float64], pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate the Michaelis Menten coefficient of PEPc. Calculates the Michaelis Menten coefficient of phosphoenolpyruvate carboxylase @@ -474,10 +474,10 @@ def calc_kp_c4( def calc_soilmstress_stocker( - soilm: NDArray, - meanalpha: NDArray = np.array(1.0), + soilm: NDArray[np.float64], + meanalpha: NDArray[np.float64] = np.array(1.0), pmodel_const: PModelConst = PModelConst(), -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate Stocker's empirical soil moisture stress factor. This function calculates a penalty factor :math:`\beta(\theta)` for well-watered GPP @@ -562,10 +562,10 @@ def calc_soilmstress_stocker( def calc_soilmstress_mengoli( - soilm: NDArray = np.array(1.0), - aridity_index: NDArray = np.array(1.0), + soilm: NDArray[np.float64] = np.array(1.0), + aridity_index: NDArray[np.float64] = np.array(1.0), pmodel_const: PModelConst = PModelConst(), -) -> NDArray: +) -> NDArray[np.float64]: r"""Calculate the Mengoli et al. empirical soil moisture stress factor. This function calculates a penalty factor :math:`\beta(\theta)` for well-watered GPP @@ -644,7 +644,9 @@ def calc_soilmstress_mengoli( return np.where(soilm >= psi, y, (y / psi) * soilm) -def calc_co2_to_ca(co2: NDArray, patm: NDArray) -> NDArray: +def calc_co2_to_ca( + co2: NDArray[np.float64], patm: NDArray[np.float64] +) -> NDArray[np.float64]: r"""Convert :math:`\ce{CO2}` ppm to Pa. Converts ambient :math:`\ce{CO2}` (:math:`c_a`) in part per million to Pascals, diff --git a/pyrealm/pmodel/isotopes.py b/pyrealm/pmodel/isotopes.py index 50caeaab..ca7da2f4 100644 --- a/pyrealm/pmodel/isotopes.py +++ b/pyrealm/pmodel/isotopes.py @@ -5,6 +5,7 @@ from warnings import warn +import numpy as np from numpy.typing import NDArray from pyrealm.constants import IsotopesConst @@ -42,8 +43,8 @@ class CalcCarbonIsotopes: def __init__( self, pmodel: PModel, - D14CO2: NDArray, - d13CO2: NDArray, + D14CO2: NDArray[np.float64], + d13CO2: NDArray[np.float64], isotopes_const: IsotopesConst = IsotopesConst(), ): # Check inputs are congruent @@ -57,22 +58,22 @@ def __init__( """Indicates if estimates calculated for C3 or C4 photosynthesis.""" # Attributes defined by methods below - self.Delta13C_simple: NDArray + self.Delta13C_simple: NDArray[np.float64] r"""Discrimination against carbon 13 (:math:`\Delta\ce{^{13}C}`, permil) excluding photorespiration.""" - self.Delta14C: NDArray + self.Delta14C: NDArray[np.float64] r"""Discrimination against carbon 13 (:math:`\Delta\ce{^{13}C}`, permil) including photorespiration.""" - self.Delta13C: NDArray + self.Delta13C: NDArray[np.float64] r"""Discrimination against carbon 14 (:math:`\Delta\ce{^{14}C}`, permil) including photorespiration.""" - self.d13C_leaf: NDArray + self.d13C_leaf: NDArray[np.float64] r"""Isotopic ratio of carbon 13 in leaves (:math:`\delta\ce{^{13}C}`, permil).""" - self.d14C_leaf: NDArray + self.d14C_leaf: NDArray[np.float64] r"""Isotopic ratio of carbon 14 in leaves (:math:`\delta\ce{^{14}C}`, permil).""" - self.d13C_wood: NDArray + self.d13C_wood: NDArray[np.float64] r"""Isotopic ratio of carbon 13 in wood (:math:`\delta\ce{^{13}C}`, permil), given a parameterized post-photosynthetic fractionation.""" diff --git a/pyrealm/pmodel/jmax_limitation.py b/pyrealm/pmodel/jmax_limitation.py index 27628f3f..cedc6793 100644 --- a/pyrealm/pmodel/jmax_limitation.py +++ b/pyrealm/pmodel/jmax_limitation.py @@ -89,14 +89,14 @@ def __init__( # Attributes populated by alternative method - two should always be populated by # the methods used below, but omega and omega_star only apply to smith19 - self.f_j: NDArray + self.f_j: NDArray[np.float64] """:math:`J_{max}` limitation factor, calculated using the method.""" - self.f_v: NDArray + self.f_v: NDArray[np.float64] """:math:`V_{cmax}` limitation factor, calculated using the method.""" - self.omega: NDArray | None = None + self.omega: NDArray[np.float64] | None = None """Component of :math:`J_{max}` calculation for method ``smith19`` (:cite:`Smith:2019dv`).""" - self.omega_star: NDArray | None = None + self.omega_star: NDArray[np.float64] | None = None """Component of :math:`J_{max}` calculation for method ``smith19`` (:cite:`Smith:2019dv`).""" diff --git a/pyrealm/pmodel/optimal_chi.py b/pyrealm/pmodel/optimal_chi.py index 3b5b5ba7..86513b09 100644 --- a/pyrealm/pmodel/optimal_chi.py +++ b/pyrealm/pmodel/optimal_chi.py @@ -110,23 +110,23 @@ def __init__( # default value as they must be populated by the set_beta and estimate_chi # methods, which are called below, and so will be populated before __init__ # returns. - self.beta: NDArray + self.beta: NDArray[np.float64] """The ratio of carboxylation to transpiration cost factors.""" - self.xi: NDArray + self.xi: NDArray[np.float64] r"""Defines the sensitivity of :math:`\chi` to the vapour pressure deficit, related to the carbon cost of water (Medlyn et al. 2011; Prentice et 2014).""" - self.chi: NDArray + self.chi: NDArray[np.float64] r"""The ratio of leaf internal to ambient :math:`\ce{CO2}` partial pressure (:math:`\chi`).""" - self.mc: NDArray + self.mc: NDArray[np.float64] r""":math:`\ce{CO2}` limitation factor for RuBisCO-limited assimilation (:math:`m_c`).""" - self.mj: NDArray + self.mj: NDArray[np.float64] r""":math:`\ce{CO2}` limitation factor for light-limited assimilation (:math:`m_j`).""" - self.ci: NDArray + self.ci: NDArray[np.float64] r"""The leaf internal :math:`\ce{CO2}` partial pressure (:math:`c_i`).""" - self.mjoc: NDArray + self.mjoc: NDArray[np.float64] r"""Ratio of :math:`m_j/m_c`.""" # Run the calculation methods after checking for any required variables @@ -144,7 +144,7 @@ def set_beta(self) -> None: """Set the beta values.""" @abstractmethod - def estimate_chi(self, xi_values: NDArray | None = None) -> None: + def estimate_chi(self, xi_values: NDArray[np.float64] | None = None) -> None: """Estimate xi, chi and other variables.""" def _check_requires(self) -> None: @@ -250,7 +250,7 @@ def set_beta(self) -> None: # leaf-internal-to-ambient CO2 partial pressure (ci/ca) ratio self.beta = self.pmodel_const.beta_cost_ratio_prentice14 - def estimate_chi(self, xi_values: NDArray | None = None) -> None: + def estimate_chi(self, xi_values: NDArray[np.float64] | None = None) -> None: """Estimate ``chi`` for C3 plants.""" if xi_values is not None: @@ -319,7 +319,7 @@ def set_beta(self) -> None: # leaf-internal-to-ambient CO2 partial pressure (ci/ca) ratio self.beta = self.pmodel_const.beta_cost_ratio_prentice14 - def estimate_chi(self, xi_values: NDArray | None = None) -> None: + def estimate_chi(self, xi_values: NDArray[np.float64] | None = None) -> None: """Estimate ``chi`` for C3 plants.""" if xi_values is not None: @@ -382,7 +382,7 @@ def set_beta(self) -> None: # leaf-internal-to-ambient CO2 partial pressure (ci/ca) ratio self.beta = self.pmodel_const.beta_cost_ratio_c4 - def estimate_chi(self, xi_values: NDArray | None = None) -> None: + def estimate_chi(self, xi_values: NDArray[np.float64] | None = None) -> None: """Estimate ``chi`` for C4 plants, setting ``mj`` and ``mc`` to 1.""" if xi_values is not None: _ = check_input_shapes(self.env.ca, xi_values) @@ -449,7 +449,7 @@ def set_beta(self) -> None: # leaf-internal-to-ambient CO2 partial pressure (ci/ca) ratio self.beta = self.pmodel_const.beta_cost_ratio_c4 - def estimate_chi(self, xi_values: NDArray | None = None) -> None: + def estimate_chi(self, xi_values: NDArray[np.float64] | None = None) -> None: """Estimate ``chi`` for C4 plants, setting ``mj`` and ``mc`` to 1.""" if xi_values is not None: _ = check_input_shapes(self.env.ca, xi_values) @@ -534,7 +534,7 @@ def set_beta(self) -> None: + self.pmodel_const.lavergne_2020_a_c3 ) - def estimate_chi(self, xi_values: NDArray | None = None) -> None: + def estimate_chi(self, xi_values: NDArray[np.float64] | None = None) -> None: """Estimate ``chi`` for C3 plants.""" if xi_values is not None: @@ -625,7 +625,7 @@ def set_beta(self) -> None: + self.pmodel_const.lavergne_2020_a_c4 ) - def estimate_chi(self, xi_values: NDArray | None = None) -> None: + def estimate_chi(self, xi_values: NDArray[np.float64] | None = None) -> None: """Estimate ``chi`` for C4 plants excluding photorespiration.""" # Calculate chi and xi as in Prentice 14 but removing gamma terms. @@ -702,7 +702,7 @@ def set_beta(self) -> None: # Calculate chi and xi as in Prentice 14 but removing gamma terms. self.beta = self.pmodel_const.beta_cost_ratio_c4 - def estimate_chi(self, xi_values: NDArray | None = None) -> None: + def estimate_chi(self, xi_values: NDArray[np.float64] | None = None) -> None: """Estimate ``chi`` for C4 plants excluding photorespiration.""" # Calculate chi and xi as in Prentice 14 but removing gamma terms. @@ -771,7 +771,7 @@ def set_beta(self) -> None: # Calculate chi and xi as in Prentice 14 but removing gamma terms. self.beta = self.pmodel_const.beta_cost_ratio_c4 - def estimate_chi(self, xi_values: NDArray | None = None) -> None: + def estimate_chi(self, xi_values: NDArray[np.float64] | None = None) -> None: """Estimate ``chi`` for C4 plants excluding photorespiration.""" # Calculate chi and xi as in Prentice 14 but removing gamma terms. diff --git a/pyrealm/pmodel/pmodel.py b/pyrealm/pmodel/pmodel.py index c3ce20ca..abad0e80 100644 --- a/pyrealm/pmodel/pmodel.py +++ b/pyrealm/pmodel/pmodel.py @@ -238,14 +238,14 @@ def __init__( # in Pascals, but more commonly reported in µmol mol-1. The standard equation # (ca - ci) / 1.6 expects inputs in ppm, so the pascal versions are back # converted here. - self.iwue: NDArray = (5 / 8 * (env.ca - self.optchi.ci)) / ( + self.iwue: NDArray[np.float64] = (5 / 8 * (env.ca - self.optchi.ci)) / ( 1e-6 * self.env.patm ) """Intrinsic water use efficiency (iWUE, µmol mol-1)""" # The basic calculation of LUE = phi0 * M_c * m with an added penalty term # for jmax limitation - self.lue: NDArray = ( + self.lue: NDArray[np.float64] = ( self.kphio.kphio * self.optchi.mj * self.jmaxlim.f_v @@ -258,14 +258,14 @@ def __init__( # no defaults and are only populated by estimate_productivity. Their getter # methods have a check to raise an informative error # ----------------------------------------------------------------------- - self._vcmax: NDArray - self._vcmax25: NDArray - self._rd: NDArray - self._jmax: NDArray - self._gpp: NDArray - self._gs: NDArray - self._ppfd: NDArray - self._fapar: NDArray + self._vcmax: NDArray[np.float64] + self._vcmax25: NDArray[np.float64] + self._rd: NDArray[np.float64] + self._jmax: NDArray[np.float64] + self._gpp: NDArray[np.float64] + self._gs: NDArray[np.float64] + self._ppfd: NDArray[np.float64] + self._fapar: NDArray[np.float64] def _check_estimated(self, varname: str) -> None: """Raise error when accessing unpopulated parameters. @@ -277,50 +277,50 @@ def _check_estimated(self, varname: str) -> None: raise RuntimeError(f"{varname} not calculated: use estimate_productivity") @property - def gpp(self) -> NDArray: + def gpp(self) -> NDArray[np.float64]: """Gross primary productivity (µg C m-2 s-1).""" self._check_estimated("gpp") return self._gpp @property - def vcmax(self) -> NDArray: + def vcmax(self) -> NDArray[np.float64]: """Maximum rate of carboxylation (µmol m-2 s-1).""" self._check_estimated("vcmax") return self._vcmax @property - def vcmax25(self) -> NDArray: + def vcmax25(self) -> NDArray[np.float64]: """Maximum rate of carboxylation at standard temperature (µmol m-2 s-1).""" self._check_estimated("vcmax25") return self._vcmax25 @property - def rd(self) -> NDArray: + def rd(self) -> NDArray[np.float64]: """Dark respiration (µmol m-2 s-1).""" self._check_estimated("rd") return self._rd @property - def jmax(self) -> NDArray: + def jmax(self) -> NDArray[np.float64]: """Maximum rate of electron transport (µmol m-2 s-1).""" self._check_estimated("jmax") return self._jmax @property - def gs(self) -> NDArray: + def gs(self) -> NDArray[np.float64]: """Stomatal conductance (µmol m-2 s-1).""" self._check_estimated("gs") return self._gs @property - def ppfd(self) -> NDArray: + def ppfd(self) -> NDArray[np.float64]: """Photosynthetic photon flux density (PPFD, µmol m-2 s-1).""" self._check_estimated("gs") return self._ppfd @property - def fapar(self) -> NDArray: + def fapar(self) -> NDArray[np.float64]: """Fraction of absorbed photosynthetically active radiation (:math:`f_{APAR}` unitless). """ # noqa: D205 diff --git a/pyrealm/pmodel/pmodel_environment.py b/pyrealm/pmodel/pmodel_environment.py index 34722c4c..a63083a7 100644 --- a/pyrealm/pmodel/pmodel_environment.py +++ b/pyrealm/pmodel/pmodel_environment.py @@ -75,27 +75,29 @@ class PModelEnvironment: def __init__( self, - tc: NDArray, - vpd: NDArray, - co2: NDArray, - patm: NDArray, - theta: NDArray | None = None, - rootzonestress: NDArray | None = None, - aridity_index: NDArray | None = None, - mean_growth_temperature: NDArray | None = None, + tc: NDArray[np.float64], + vpd: NDArray[np.float64], + co2: NDArray[np.float64], + patm: NDArray[np.float64], + theta: NDArray[np.float64] | None = None, + rootzonestress: NDArray[np.float64] | None = None, + aridity_index: NDArray[np.float64] | None = None, + mean_growth_temperature: NDArray[np.float64] | None = None, pmodel_const: PModelConst = PModelConst(), core_const: CoreConst = CoreConst(), ): self.shape: tuple = check_input_shapes(tc, vpd, co2, patm) # Validate and store the forcing variables - self.tc: NDArray = bounds_checker(tc, -25, 80, "[]", "tc", "°C") + self.tc: NDArray[np.float64] = bounds_checker(tc, -25, 80, "[]", "tc", "°C") """The temperature at which to estimate photosynthesis, °C""" - self.vpd: NDArray = bounds_checker(vpd, 0, 10000, "[]", "vpd", "Pa") + self.vpd: NDArray[np.float64] = bounds_checker(vpd, 0, 10000, "[]", "vpd", "Pa") """Vapour pressure deficit, Pa""" - self.co2: NDArray = bounds_checker(co2, 0, 1000, "[]", "co2", "ppm") + self.co2: NDArray[np.float64] = bounds_checker(co2, 0, 1000, "[]", "co2", "ppm") """CO2 concentration, ppm""" - self.patm: NDArray = bounds_checker(patm, 30000, 110000, "[]", "patm", "Pa") + self.patm: NDArray[np.float64] = bounds_checker( + patm, 30000, 110000, "[]", "patm", "Pa" + ) """Atmospheric pressure, Pa""" # Guard against calc_density issues @@ -112,7 +114,7 @@ def __init__( "zero or explicitly set to np.nan" ) - self.ca: NDArray = calc_co2_to_ca(self.co2, self.patm) + self.ca: NDArray[np.float64] = calc_co2_to_ca(self.co2, self.patm) """Ambient CO2 partial pressure, Pa""" self.gammastar = calc_gammastar( @@ -140,13 +142,13 @@ def __init__( # Easy to add the attributes dynamically, but bounds checking less # obvious. - self.theta: NDArray + self.theta: NDArray[np.float64] """Volumetric soil moisture (m3/m3)""" - self.rootzonestress: NDArray + self.rootzonestress: NDArray[np.float64] """Rootzone stress factor (experimental) (-)""" - self.aridity_index: NDArray + self.aridity_index: NDArray[np.float64] """Climatological aridity index as PET/P (-)""" - self.mean_growth_temperature: NDArray + self.mean_growth_temperature: NDArray[np.float64] """Mean temperature > 0°C during growing degree days (°C)""" if theta is not None: diff --git a/pyrealm/pmodel/quantum_yield.py b/pyrealm/pmodel/quantum_yield.py index 63ece4be..9a7b0c8d 100644 --- a/pyrealm/pmodel/quantum_yield.py +++ b/pyrealm/pmodel/quantum_yield.py @@ -146,7 +146,7 @@ def __init__( "of reference kphio values" ) - self.reference_kphio: NDArray = reference_kphio + self.reference_kphio: NDArray[np.float64] = reference_kphio """The kphio reference value for the method.""" self.use_c4: bool = use_c4 """Use a C4 parameterisation if available.""" @@ -154,7 +154,7 @@ def __init__( # Declare attributes populated by methods. These are typed but not assigned a # default value as they must are populated by the subclass specific # calculate_kphio method, which is called below to populate the values. - self.kphio: NDArray + self.kphio: NDArray[np.float64] """The calculated intrinsic quantum yield of photosynthesis.""" # Run the calculation methods after checking for any required variables @@ -300,7 +300,7 @@ class QuantumYieldSandoval( defaulting to the ratio of 1/9 in the absence of a Q cycle :cite:`long:1993a`. """ - def peak_quantum_yield(self, aridity: NDArray) -> NDArray: + def peak_quantum_yield(self, aridity: NDArray[np.float64]) -> NDArray[np.float64]: """Calculate the peak quantum yield as a function of the aridity index. Args: diff --git a/pyrealm/pmodel/scaler.py b/pyrealm/pmodel/scaler.py index 4fa8d0a7..382ac2b8 100644 --- a/pyrealm/pmodel/scaler.py +++ b/pyrealm/pmodel/scaler.py @@ -69,7 +69,7 @@ class SubdailyScaler: def __init__( self, - datetimes: NDArray, + datetimes: NDArray[np.datetime64], ) -> None: # Datetime validation. The inputs must be: # - one dimensional datetime64 @@ -306,7 +306,7 @@ def set_nearest(self, time: np.timedelta64) -> None: # self.method = "Around max" - def pad_values(self, values: NDArray) -> NDArray: + def pad_values(self, values: NDArray[np.float64]) -> NDArray[np.float64]: """Pad values array to full days. This method takes an array representing daily values and pads the first and @@ -329,7 +329,7 @@ def pad_values(self, values: NDArray) -> NDArray: return np.pad(values, padding_dims, constant_values=(np.nan, np.nan)) - def get_window_values(self, values: NDArray) -> NDArray: + def get_window_values(self, values: NDArray[np.float64]) -> NDArray[np.float64]: """Extract acclimation window values for a variable. This method takes an array of values which has the same shape along the first @@ -368,8 +368,8 @@ def get_window_values(self, values: NDArray) -> NDArray: return values_by_day[:, self.include, ...] def get_daily_means( - self, values: NDArray, allow_partial_data: bool = False - ) -> NDArray: + self, values: NDArray[np.float64], allow_partial_data: bool = False + ) -> NDArray[np.float64]: """Get the daily means of a variable during the acclimation window. This method extracts values from a given variable during a defined acclimation @@ -406,11 +406,11 @@ def get_daily_means( def fill_daily_to_subdaily( self, - values: NDArray, + values: NDArray[np.float64], update_point: str = "max", kind: str = "previous", fill_from: np.timedelta64 | None = None, - ) -> NDArray: + ) -> NDArray[np.float64]: """Resample daily variables onto the subdaily time scale. This method takes an array representing daily values and interpolates those diff --git a/pyrealm/pmodel/subdaily.py b/pyrealm/pmodel/subdaily.py index 0367ce38..8a83b3f1 100644 --- a/pyrealm/pmodel/subdaily.py +++ b/pyrealm/pmodel/subdaily.py @@ -41,8 +41,8 @@ def memory_effect( - values: NDArray, alpha: float = 0.067, allow_holdover: bool = False -) -> NDArray: + values: NDArray[np.float64], alpha: float = 0.067, allow_holdover: bool = False +) -> NDArray[np.float64]: r"""Apply a memory effect to a variable. Three key photosynthetic parameters (:math:`\xi`, :math:`V_{cmax25}` and @@ -104,7 +104,7 @@ def memory_effect( # Initialise the output storage and set the first values to be a slice along the # first axis of the input values - memory_values = np.empty_like(values, dtype=np.float32) + memory_values = np.empty_like(values, dtype=np.float64) memory_values[0] = values[0] # Handle the data if there are no missing data, @@ -231,8 +231,8 @@ def __init__( self, env: PModelEnvironment, fs_scaler: SubdailyScaler, - fapar: NDArray, - ppfd: NDArray, + fapar: NDArray[np.float64], + ppfd: NDArray[np.float64], method_optchi: str = "prentice14", method_jmaxlim: str = "wang17", method_kphio: str = "temperature", @@ -380,15 +380,15 @@ def __init__( ) # 5) Calculate the realised daily values from the instantaneous optimal values - self.xi_real: NDArray = memory_effect( + self.xi_real: NDArray[np.float64] = memory_effect( self.pmodel_acclim.optchi.xi, alpha=alpha, allow_holdover=allow_holdover ) r"""Realised daily slow responses in :math:`\xi`""" - self.vcmax25_real: NDArray = memory_effect( + self.vcmax25_real: NDArray[np.float64] = memory_effect( self.vcmax25_opt, alpha=alpha, allow_holdover=allow_holdover ) r"""Realised daily slow responses in :math:`V_{cmax25}`""" - self.jmax25_real: NDArray = memory_effect( + self.jmax25_real: NDArray[np.float64] = memory_effect( self.jmax25_opt, alpha=alpha, allow_holdover=allow_holdover ) r"""Realised daily slow responses in :math:`J_{max25}`""" @@ -402,13 +402,19 @@ def __init__( # 7) Adjust subdaily jmax25 and vcmax25 back to jmax and vcmax given the # actual subdaily temperatures. subdaily_tk = self.env.tc + self.env.core_const.k_CtoK - self.subdaily_vcmax: NDArray = self.subdaily_vcmax25 * calc_ftemp_arrh( - tk=subdaily_tk, ha=self.env.pmodel_const.subdaily_vcmax25_ha + self.subdaily_vcmax: NDArray[np.float64] = ( + self.subdaily_vcmax25 + * calc_ftemp_arrh( + tk=subdaily_tk, ha=self.env.pmodel_const.subdaily_vcmax25_ha + ) ) """Estimated subdaily :math:`V_{cmax}`.""" - self.subdaily_jmax: NDArray = self.subdaily_jmax25 * calc_ftemp_arrh( - tk=subdaily_tk, ha=self.env.pmodel_const.subdaily_jmax25_ha + self.subdaily_jmax: NDArray[np.float64] = ( + self.subdaily_jmax25 + * calc_ftemp_arrh( + tk=subdaily_tk, ha=self.env.pmodel_const.subdaily_jmax25_ha + ) ) """Estimated subdaily :math:`J_{max}`.""" @@ -421,7 +427,9 @@ def __init__( """Estimated subdaily :math:`c_i`.""" # Calculate Ac, J and Aj at subdaily scale to calculate assimilation - self.subdaily_Ac: NDArray = self.subdaily_vcmax * self.optimal_chi.mc + self.subdaily_Ac: NDArray[np.float64] = ( + self.subdaily_vcmax * self.optimal_chi.mc + ) """Estimated subdaily :math:`A_c`.""" iabs = fapar * ppfd @@ -430,11 +438,11 @@ def __init__( 1 + ((4 * self.kphio.kphio * iabs) / self.subdaily_jmax) ** 2 ) - self.subdaily_Aj: NDArray = (subdaily_J / 4) * self.optimal_chi.mj + self.subdaily_Aj: NDArray[np.float64] = (subdaily_J / 4) * self.optimal_chi.mj """Estimated subdaily :math:`A_j`.""" # Calculate GPP and convert from mol to gC - self.gpp: NDArray = ( + self.gpp: NDArray[np.float64] = ( np.minimum(self.subdaily_Aj, self.subdaily_Ac) * self.env.core_const.k_c_molmass ) @@ -535,8 +543,8 @@ def __init__( self, env: PModelEnvironment, fs_scaler: SubdailyScaler, - ppfd: NDArray, - fapar: NDArray, + ppfd: NDArray[np.float64], + fapar: NDArray[np.float64], alpha: float = 1 / 15, allow_holdover: bool = False, kphio: float = 1 / 8, @@ -618,11 +626,11 @@ def __init__( ) # Calculate the realised values from the instantaneous optimal values - self.vcmax25_real: NDArray = memory_effect( + self.vcmax25_real: NDArray[np.float64] = memory_effect( self.vcmax25_opt, alpha=alpha, allow_holdover=allow_holdover ) r"""Realised daily slow responses in :math:`V_{cmax25}`""" - self.jmax25_real: NDArray = memory_effect( + self.jmax25_real: NDArray[np.float64] = memory_effect( self.jmax25_opt, alpha=alpha, allow_holdover=allow_holdover ) r"""Realised daily slow responses in :math:`J_{max25}`""" @@ -661,18 +669,24 @@ def __init__( self.jmax25_real, fill_from=fill_from ) - self.subdaily_vcmax: NDArray = self.subdaily_vcmax25 * calc_ftemp_arrh( - tk=subdaily_tk, ha=self.env.pmodel_const.subdaily_vcmax25_ha + self.subdaily_vcmax: NDArray[np.float64] = ( + self.subdaily_vcmax25 + * calc_ftemp_arrh( + tk=subdaily_tk, ha=self.env.pmodel_const.subdaily_vcmax25_ha + ) ) """Estimated subdaily :math:`V_{cmax}`.""" - self.subdaily_jmax: NDArray = self.subdaily_jmax25 * calc_ftemp_arrh( - tk=subdaily_tk, ha=self.env.pmodel_const.subdaily_jmax25_ha + self.subdaily_jmax: NDArray[np.float64] = ( + self.subdaily_jmax25 + * calc_ftemp_arrh( + tk=subdaily_tk, ha=self.env.pmodel_const.subdaily_jmax25_ha + ) ) """Estimated subdaily :math:`J_{max}`.""" # Calculate Ac, J and Aj at subdaily scale to calculate assimilation - self.subdaily_Ac: NDArray = ( + self.subdaily_Ac: NDArray[np.float64] = ( self.subdaily_vcmax * (self.subdaily_ci - self.env.gammastar) / (self.subdaily_ci + self.env.kmm) @@ -688,7 +702,7 @@ def __init__( 1 + ((4 * self.kphio.kphio * iabs) / self.subdaily_jmax) ** 2 ) - self.subdaily_Aj: NDArray = ( + self.subdaily_Aj: NDArray[np.float64] = ( (subdaily_J / 4) * (self.subdaily_ci - self.env.gammastar) / (self.subdaily_ci + 2 * self.env.gammastar) @@ -696,7 +710,7 @@ def __init__( """Estimated subdaily :math:`A_j`.""" # Calculate GPP, converting from mol m2 s1 to grams carbon m2 s1 - self.gpp: NDArray = ( + self.gpp: NDArray[np.float64] = ( np.minimum(self.subdaily_Aj, self.subdaily_Ac) * self.env.core_const.k_c_molmass ) diff --git a/pyrealm/splash/evap.py b/pyrealm/splash/evap.py index 501f9eab..281720ff 100644 --- a/pyrealm/splash/evap.py +++ b/pyrealm/splash/evap.py @@ -49,29 +49,29 @@ class DailyEvapFluxes: solar: DailySolarFluxes pa: InitVar[NDArray] tc: InitVar[NDArray] - kWm: NDArray = field(default_factory=lambda: np.array([150.0])) + kWm: NDArray[np.float64] = field(default_factory=lambda: np.array([150.0])) core_const: CoreConst = field(default_factory=lambda: CoreConst()) - sat: NDArray = field(init=False) + sat: NDArray[np.float64] = field(init=False) """Slope of saturation vapour pressure temperature curve, Pa/K""" - lv: NDArray = field(init=False) + lv: NDArray[np.float64] = field(init=False) """Enthalpy of vaporization, J/kg""" - pw: NDArray = field(init=False) + pw: NDArray[np.float64] = field(init=False) """Density of water, kg/m^3""" - psy: NDArray = field(init=False) + psy: NDArray[np.float64] = field(init=False) """Psychrometric constant, Pa/K""" - econ: NDArray = field(init=False) + econ: NDArray[np.float64] = field(init=False) """Water-to-energy conversion factor""" - cond: NDArray = field(init=False) + cond: NDArray[np.float64] = field(init=False) """Daily condensation, mm""" - eet_d: NDArray = field(init=False) + eet_d: NDArray[np.float64] = field(init=False) """Daily equilibrium evapotranspiration (EET), mm""" - pet_d: NDArray = field(init=False) + pet_d: NDArray[np.float64] = field(init=False) """Daily potential evapotranspiration (PET), mm""" - rx: NDArray = field(init=False) + rx: NDArray[np.float64] = field(init=False) """Variable substitute, (mm/hr)/(W/m^2)""" - def __post_init__(self, pa: NDArray, tc: NDArray) -> None: + def __post_init__(self, pa: NDArray[np.float64], tc: NDArray[np.float64]) -> None: """Calculate invariant components of evapotranspiration. The post_init method calculates the components of the evaporative fluxes that @@ -107,8 +107,8 @@ def __post_init__(self, pa: NDArray, tc: NDArray) -> None: self.rx = (3.6e6) * (1.0 + self.core_const.k_w) * self.econ def estimate_aet( - self, wn: NDArray, day_idx: int | None = None, only_aet: bool = True - ) -> NDArray | tuple[NDArray, NDArray, NDArray]: + self, wn: NDArray[np.float64], day_idx: int | None = None, only_aet: bool = True + ) -> NDArray[np.float64] | tuple[NDArray, NDArray, NDArray]: """Estimate actual evapotranspiration. This method estimates the daily actual evapotranspiration (AET, mm/day), given diff --git a/pyrealm/splash/solar.py b/pyrealm/splash/solar.py index 3613fe0a..fc1e1831 100644 --- a/pyrealm/splash/solar.py +++ b/pyrealm/splash/solar.py @@ -37,39 +37,43 @@ class DailySolarFluxes: tc: InitVar[NDArray] core_const: CoreConst = field(default_factory=lambda: CoreConst()) - nu: NDArray = field(init=False) + nu: NDArray[np.float64] = field(init=False) """True heliocentric anomaly, degrees""" - lambda_: NDArray = field(init=False) + lambda_: NDArray[np.float64] = field(init=False) """True heliocentric longitude, degrees""" - dr: NDArray = field(init=False) + dr: NDArray[np.float64] = field(init=False) """Distance factor, -""" - delta: NDArray = field(init=False) + delta: NDArray[np.float64] = field(init=False) """Declination angle, degrees""" - ru: NDArray = field(init=False) + ru: NDArray[np.float64] = field(init=False) """Intermediate variable, unitless""" - rv: NDArray = field(init=False) + rv: NDArray[np.float64] = field(init=False) """Intermediate variable, unitless""" - hs: NDArray = field(init=False) + hs: NDArray[np.float64] = field(init=False) """Sunset hour angle, degrees""" - ra_d: NDArray = field(init=False) + ra_d: NDArray[np.float64] = field(init=False) """Daily extraterrestrial solar radiation, J/m^2""" - tau: NDArray = field(init=False) + tau: NDArray[np.float64] = field(init=False) """Transmittivity, unitless""" - ppfd_d: NDArray = field(init=False) + ppfd_d: NDArray[np.float64] = field(init=False) """Daily PPFD, mol/m^2""" - rnl: NDArray = field(init=False) + rnl: NDArray[np.float64] = field(init=False) """Net longwave radiation, W/m^2""" - rw: NDArray = field(init=False) + rw: NDArray[np.float64] = field(init=False) """Intermediate variable, W/m^2""" - hn: NDArray = field(init=False) + hn: NDArray[np.float64] = field(init=False) """Net radiation cross-over hour angle, degrees""" - rn_d: NDArray = field(init=False) + rn_d: NDArray[np.float64] = field(init=False) """Daytime net radiation, J/m^2""" - rnn_d: NDArray = field(init=False) + rnn_d: NDArray[np.float64] = field(init=False) """Nighttime net radiation (rnn_d), J/m^2""" def __post_init__( - self, lat: NDArray, elv: NDArray, sf: NDArray, tc: NDArray + self, + lat: NDArray[np.float64], + elv: NDArray[np.float64], + sf: NDArray[np.float64], + tc: NDArray[np.float64], ) -> None: """Populates key fluxes from input variables.""" diff --git a/pyrealm/splash/splash.py b/pyrealm/splash/splash.py index d7116609..79c0230f 100644 --- a/pyrealm/splash/splash.py +++ b/pyrealm/splash/splash.py @@ -57,13 +57,13 @@ class SplashModel: def __init__( self, - lat: NDArray, - elv: NDArray, - sf: NDArray, - tc: NDArray, - pn: NDArray, + lat: NDArray[np.float64], + elv: NDArray[np.float64], + sf: NDArray[np.float64], + tc: NDArray[np.float64], + pn: NDArray[np.float64], dates: Calendar, - kWm: NDArray = np.array([150.0]), + kWm: NDArray[np.float64] = np.array([150.0]), core_const: CoreConst = CoreConst(), ): # Check input sizes are congurent @@ -76,23 +76,31 @@ def __init__( if len(dates) != self.shape[0]: raise ValueError("Number of dates must match the first dimension of inputs") - self.elv: NDArray = elv + self.elv: NDArray[np.float64] = elv """The elevation of sites.""" - self.lat: NDArray = bounds_checker(lat, -90, 90, label="lat", unit="°") + self.lat: NDArray[np.float64] = bounds_checker( + lat, -90, 90, label="lat", unit="°" + ) """The latitude of sites.""" - self.sf: NDArray = bounds_checker(sf, 0, 1, label="sf") + self.sf: NDArray[np.float64] = bounds_checker(sf, 0, 1, label="sf") """The sunshine fraction (0-1) of daily observations.""" - self.tc: NDArray = bounds_checker(tc, -25, 80, label="tc", unit="°C") + self.tc: NDArray[np.float64] = bounds_checker( + tc, -25, 80, label="tc", unit="°C" + ) """The air temperature in °C of daily observations.""" - self.pn: NDArray = bounds_checker(pn, 0, 1e3, label="pn", unit="mm/day") + self.pn: NDArray[np.float64] = bounds_checker( + pn, 0, 1e3, label="pn", unit="mm/day" + ) """The precipitation in mm of daily observations.""" self.dates: Calendar = dates """The dates of observations along the first array axis.""" - self.kWm: NDArray = bounds_checker(kWm, 0, 1e4, label="kWm", unit="mm") + self.kWm: NDArray[np.float64] = bounds_checker( + kWm, 0, 1e4, label="kWm", unit="mm" + ) """The maximum soil water capacity for sites.""" # TODO - potentially allow _actual_ climatic pressure data as an input - self.pa: NDArray = calc_patm(elv, core_const=core_const) + self.pa: NDArray[np.float64] = calc_patm(elv, core_const=core_const) """The atmospheric pressure at sites, derived from elevation""" # Calculate the daily solar fluxes - these are invariant across the simulation @@ -109,12 +117,12 @@ def __init__( def estimate_initial_soil_moisture( # noqa: max-complexity=12 self, - wn_init: NDArray | None = None, + wn_init: NDArray[np.float64] | None = None, max_iter: int = 10, max_diff: float = 1.0, return_convergence: bool = False, verbose: bool = False, - ) -> NDArray: + ) -> NDArray[np.float64]: """Estimate initial soil moisture. This method uses the first year of data provided to a SplashModel instance to @@ -222,7 +230,7 @@ def estimate_initial_soil_moisture( # noqa: max-complexity=12 return wn_start def estimate_daily_water_balance( - self, previous_wn: NDArray, day_idx: int | None = None + self, previous_wn: NDArray[np.float64], day_idx: int | None = None ) -> tuple[NDArray, NDArray, NDArray]: r"""Estimate the daily water balance. @@ -286,7 +294,7 @@ def estimate_daily_water_balance( def calculate_soil_moisture( self, - wn_init: NDArray, + wn_init: NDArray[np.float64], ) -> tuple[NDArray, NDArray, NDArray]: """Calculate the soil moisture, AET and runoff from a SplashModel. diff --git a/pyrealm/tmodel.py b/pyrealm/tmodel.py index 35739d42..416c53c5 100644 --- a/pyrealm/tmodel.py +++ b/pyrealm/tmodel.py @@ -47,7 +47,7 @@ class TTree: def __init__( self, - diameters: NDArray, + diameters: NDArray[np.float64], traits: TModelTraits = TModelTraits(), ) -> None: self.traits: TModelTraits = traits @@ -55,33 +55,33 @@ def __init__( # The diameter is used to define all of the geometric scaling # based on the trait parameters. - self._diameter: NDArray - self._height: NDArray - self._crown_fraction: NDArray - self._crown_area: NDArray - self._mass_stm: NDArray - self._mass_fol: NDArray - self._mass_swd: NDArray + self._diameter: NDArray[np.float64] + self._height: NDArray[np.float64] + self._crown_fraction: NDArray[np.float64] + self._crown_area: NDArray[np.float64] + self._mass_stm: NDArray[np.float64] + self._mass_fol: NDArray[np.float64] + self._mass_swd: NDArray[np.float64] self.reset_diameters(diameters) # Growth is then applied by providing estimated gpp using the # calculate_growth() method, which populates the following: self.growth_calculated: bool = False - self._gpp_raw: NDArray - self._gpp_actual: NDArray - self._npp: NDArray - self._resp_swd: NDArray - self._resp_frt: NDArray - self._resp_fol: NDArray - self._turnover: NDArray - self._d_mass_s: NDArray - self._d_mass_fr: NDArray - self._delta_d: NDArray - self._delta_mass_stm: NDArray - self._delta_mass_frt: NDArray - - def _check_growth_calculated(self, property: str) -> NDArray: + self._gpp_raw: NDArray[np.float64] + self._gpp_actual: NDArray[np.float64] + self._npp: NDArray[np.float64] + self._resp_swd: NDArray[np.float64] + self._resp_frt: NDArray[np.float64] + self._resp_fol: NDArray[np.float64] + self._turnover: NDArray[np.float64] + self._d_mass_s: NDArray[np.float64] + self._d_mass_fr: NDArray[np.float64] + self._delta_d: NDArray[np.float64] + self._delta_mass_stm: NDArray[np.float64] + self._delta_mass_frt: NDArray[np.float64] + + def _check_growth_calculated(self, property: str) -> NDArray[np.float64]: """Helper function to return growth values if calculated. This acts as a gatekeeper to make sure that a growth property is not returned @@ -96,101 +96,101 @@ def _check_growth_calculated(self, property: str) -> NDArray: return getattr(self, property) @property - def diameter(self) -> NDArray: + def diameter(self) -> NDArray[np.float64]: """Individual diameter (m).""" return self._diameter @property - def height(self) -> NDArray: + def height(self) -> NDArray[np.float64]: """Individual height (m).""" return self._height @property - def crown_fraction(self) -> NDArray: + def crown_fraction(self) -> NDArray[np.float64]: """Individual crown fraction (unitless).""" return self._crown_fraction @property - def crown_area(self) -> NDArray: + def crown_area(self) -> NDArray[np.float64]: """Individual crown area (m2).""" return self._crown_area @property - def mass_swd(self) -> NDArray: + def mass_swd(self) -> NDArray[np.float64]: """Individual softwood mass (kg).""" return self._mass_swd @property - def mass_stm(self) -> NDArray: + def mass_stm(self) -> NDArray[np.float64]: """Individual stem mass (kg).""" return self._mass_stm @property - def mass_fol(self) -> NDArray: + def mass_fol(self) -> NDArray[np.float64]: """Individual foliage mass (kg).""" return self._mass_fol @property - def gpp_raw(self) -> NDArray: + def gpp_raw(self) -> NDArray[np.float64]: """Raw gross primary productivity.""" return self._check_growth_calculated("_gpp_raw") @property - def gpp_actual(self) -> NDArray: + def gpp_actual(self) -> NDArray[np.float64]: """Actual gross primary productivity.""" return self._check_growth_calculated("_gpp_actual") @property - def resp_swd(self) -> NDArray: + def resp_swd(self) -> NDArray[np.float64]: """Individual softwood respiration costs.""" return self._check_growth_calculated("_resp_swd") @property - def resp_frt(self) -> NDArray: + def resp_frt(self) -> NDArray[np.float64]: """Individual fine root respiration costs.""" return self._check_growth_calculated("_resp_frt") @property - def resp_fol(self) -> NDArray: + def resp_fol(self) -> NDArray[np.float64]: """Individual foliar respiration costs.""" return self._check_growth_calculated("_resp_fol") @property - def npp(self) -> NDArray: + def npp(self) -> NDArray[np.float64]: """Net primary productivity.""" return self._check_growth_calculated("_npp") @property - def turnover(self) -> NDArray: + def turnover(self) -> NDArray[np.float64]: """Plant turnover.""" return self._check_growth_calculated("_turnover") @property - def d_mass_s(self) -> NDArray: + def d_mass_s(self) -> NDArray[np.float64]: """Individual relative change in mass.""" return self._check_growth_calculated("_d_mass_s") @property - def d_mass_fr(self) -> NDArray: + def d_mass_fr(self) -> NDArray[np.float64]: """Individual relative change in fine root mass.""" return self._check_growth_calculated("_d_mass_fr") @property - def delta_d(self) -> NDArray: + def delta_d(self) -> NDArray[np.float64]: """Individual change in diameter.""" return self._check_growth_calculated("_delta_d") @property - def delta_mass_stm(self) -> NDArray: + def delta_mass_stm(self) -> NDArray[np.float64]: """Individual total change in stem mass.""" return self._check_growth_calculated("_delta_mass_stm") @property - def delta_mass_frt(self) -> NDArray: + def delta_mass_frt(self) -> NDArray[np.float64]: """Individual total change in fine root mass.""" return self._check_growth_calculated("_delta_mass_frt") - def reset_diameters(self, values: NDArray) -> None: + def reset_diameters(self, values: NDArray[np.float64]) -> None: """Reset the stem diameters for the T model. The set_diameter method can be used to reset the diameter values and then uses @@ -239,7 +239,7 @@ def reset_diameters(self, values: NDArray) -> None: # Flag any calculated growth values as outdated self.growth_calculated = False - def calculate_growth(self, gpp: NDArray) -> None: + def calculate_growth(self, gpp: NDArray[np.float64]) -> None: """Calculate growth predictions given a GPP estimate. This method updates the instance with predicted changes in tree geometry, mass @@ -318,8 +318,8 @@ def calculate_growth(self, gpp: NDArray) -> None: def grow_ttree( - gpp: NDArray, - d_init: NDArray, + gpp: NDArray[np.float64], + d_init: NDArray[np.float64], time_axis: int, traits: TModelTraits = TModelTraits(), outvars: tuple[str, ...] = ("diameter", "height", "crown_area", "delta_d"), From 24c1ada9b6a56df5ac4e67382d791a7d6af2bc66 Mon Sep 17 00:00:00 2001 From: David Orme Date: Fri, 18 Oct 2024 14:51:45 +0100 Subject: [PATCH 240/241] More numpy nitpicks - what is up with intersphinx here? --- docs/source/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index 9c3a2970..1d22c055 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -96,6 +96,7 @@ class MyReferenceStyle(AuthorYearReferenceStyle): ("py:class", "numpy._typing._array_like._ScalarType_co"), ("py:class", "numpy._typing._generic_alias.ScalarType"), ("py:class", "numpy.float32"), + ("py:class", "numpy.float64"), ("py:class", "numpy.int64"), ("py:class", "numpy.timedelta64"), ("py:class", "numpy.bool_"), From 6270aee574ed14e1f6dba0f5351b1168bc38372f Mon Sep 17 00:00:00 2001 From: David Orme Date: Mon, 21 Oct 2024 14:40:39 +0100 Subject: [PATCH 241/241] Link to crown profile attributes --- pyrealm/demography/crown.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyrealm/demography/crown.py b/pyrealm/demography/crown.py index 0f1d43ed..90481507 100644 --- a/pyrealm/demography/crown.py +++ b/pyrealm/demography/crown.py @@ -439,7 +439,8 @@ def get_crown_xy( Args: crown_profile: A crown profile instance stem_allometry: The stem allometry instance used to create the crown profile - attr: The crown profile attribute to plot + attr: The crown profile attribute to plot (see + :class:`~pyrealm.demography.crown.CrownProfile`) stem_offsets: An optional array of offsets to add to the midline of stems. two_sided: Should the plotting data show a two sided canopy. as_xy: Should the plotting data be returned as a single XY array.