Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .github/workflows/cpp-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,10 @@ jobs:
return 1;
}
// The R layer's arbitrated reference for this operating point, loosely
// compared for the same reason profit is below.
if (std::fabs(g[0].grad[0] - 0.0209349) > 1e-5) {
// compared for the same reason profit is below. ⚠️ COPY THIS FROM
// tests/testthat/gradient_golden.tsv WHENEVER RESULTS MOVE -- the
// `interior-1layer` / `vcmax_25` / `A` cell. Do not re-derive it.
if (std::fabs(g[0].grad[0] - 0.0209510) > 1e-5) {
return 1;
}
l.set_physiology(roots, 900, {2.0}, soil_depth,
Expand All @@ -235,7 +237,11 @@ jobs:
// tolerances. (The value here read 2.5158434693939866 until #33, which
// is 2.2e-08 off the golden row and inside the tolerance, so it never
// failed; corrected so it cannot be mistaken for the golden value.)
return std::fabs(l.profit_ - 2.5158434915102319) < 1e-6 ? 0 : 1;
//
// ⚠️ COPY THIS FROM THE GOLDEN FILE WHENEVER RESULTS MOVE -- it is the
// psi_soil=2, ppfd=900, vpd=2, T=25, layers=1 row. No local build
// compiles this program, so forgetting it is green locally and red in CI.
return std::fabs(l.profit_ - 2.517156924533102) < 1e-6 ? 0 : 1;
}
EOF
cmake -B build \
Expand Down
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: phylloptim
Title: Leaf Gas Exchange with Explicit Plant Hydraulics
Version: 0.3.0
Version: 0.4.0
Authors@R: c(
person("Isaac", "Towers", , "", "aut",
comment = "Author of the leaf gas exchange and hydraulics model"),
Expand Down
38 changes: 38 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
# phylloptim 0.4.0

## One molar mass of water, so the kg <-> mol conversions are reciprocal (#51) — MOVES RESULTS

`kg_to_mol_h2o` was 55.4939 and `kg_per_mol_h2o` was 0.018015 — two constants naming
the same physical quantity in opposite directions, disagreeing by **0.0277%**, used in
opposite halves of the model. The demand side converted transpiration kg -> mol with
the first; the supply side converted uptake mol -> kg with the second. So a water flux
pushed through both did not come back. The header said the discrepancy was deliberate,
"kept at the historical 0.018015 to preserve results".

**Which one was wrong is not a matter of convention, which is what let this be settled
rather than argued.** 55.4939 is 1/0.018020, i.e. it encodes a molar mass of 18.0200
g/mol. The molar mass of water is 18.015 g/mol — from the standard atomic weights,
2(1.008) + 15.999. So `0.018015` is the physical value and the forward constant was the
odd one. There is now one `molar_mass_h2o = 0.018015` and both old names are derived
from it, reciprocal by construction; both names are kept because plant `using`-declares
both.

Note this is the **larger** of the two possible moves — unifying the other way would
have preserved more digits by adopting a molar mass water does not have.

**Blast radius.** 3710 of 5184 golden cells, median relative move 9.4e-05, and **3377
of the 3710 move by no more than 2x the constant's own 2.77e-04** — i.e. the bulk is
that constant propagating. The largest **absolute** move anywhere in the file is
1.6e-03. The 184 cells whose relative move exceeds 1e-03 are near-zero quantities: the
worst, 2.7e-02, is `profit` = 0.0088 at a 40 C five-layer point where benefit nearly
cancels cost. Recorded gradients: 60 of 100 cells, median 3.2e-04, worst 2.9e-03.
⚠️ That worst is the same order as the gradient file's own cross-platform disagreement
(~2.3e-03), so **off macOS/arm64 this change is not cleanly separable from noise in
that file.**

Directionally: the forward constant rose 0.0277%, so conductance per unit transpiration
rose with it, and the leaf buys slightly more carbon for the same water.

⚠️ **plant's `LinkingTo: phylloptim (>= 0.2.0)` floor is now three minor versions
stale**, and this is a results change it should be able to require. `>= 0.4.0`.

# phylloptim 0.3.0

⚠️ **This section was headed `0.2.1` until now, and the renumbering is the point of
Expand Down
2 changes: 1 addition & 1 deletion R/fingerprint.R
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ leaf_behaviour_fingerprint <- function() {
# ⚠️ GENERATED. Regenerate with tools/fingerprint.R after regenerating a golden
# file, and never by hand -- test-fingerprint.R recomputes it and fails on a
# mismatch, which is the whole mechanism.
"7a0f1e194fc8"
"e4f5a6ebd157"
}

# The digest itself, in one place so the exported constant above, the regeneration
Expand Down
16 changes: 10 additions & 6 deletions inst/include/phylloptim/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,16 @@ inline constexpr double ko_ha = 36.38e3;
// Leaf::umol_per_mol_to_Pa_, derived from atm_kpa_. The old `0.1013` was 101.3
// kPa hard-coded; don't reinstate it.

// mol H2o kg ^-1
inline constexpr double kg_to_mol_h2o = 55.4939;
// kg mol^-1: molar mass of water, for converting molar water flux back to kg.
// (Intentionally distinct from 1/kg_to_mol_h2o, which it does not exactly equal;
// kept at the historical 0.018015 to preserve results.)
inline constexpr double kg_per_mol_h2o = 0.018015;
// The molar mass of water -- 18.015 g/mol, from the standard atomic weights -- and
// the ONE place it is written down. Both conversion directions derive from it, so
// they are reciprocal by construction; do not reintroduce a second literal (#51).
//
// Both names below are kept because plant `using`-declares both.
inline constexpr double molar_mass_h2o = 0.018015; // kg mol^-1
// kg mol^-1, for converting a molar water flux back to kg.
inline constexpr double kg_per_mol_h2o = molar_mass_h2o;
// mol H2O kg^-1 -- the reciprocal, now genuinely so.
inline constexpr double kg_to_mol_h2o = 1.0 / molar_mass_h2o;
// mol mol ^-1 / (umol mol ^-1)
inline constexpr double umol_to_mol = 1e-6;
// Pa kPa^-1
Expand Down
Loading
Loading