-
Notifications
You must be signed in to change notification settings - Fork 282
Replace manual unit conversions with ud_convert() for consistency across models #3719
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
infotroph
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this! Can you describe how you tested these changes? I ask because I see a few issues here that should have produced obvious error messages in a test run. The issues themselves are minor and will be easy to fix, but since unit conversions can be surprisingly tricky it's important to know at review time that someone has actually run the code and looked at its output.
|
hi @infotroph Thanks for the review and for pointing this out.
Thanks for the reminder !! |
Co-authored-by: Chris Black <chris@ckblack.org>
Co-authored-by: Chris Black <chris@ckblack.org>
|
Hi @infotroph |
| @@ -0,0 +1,49 @@ | |||
| # Test script to validate unit conversion changes | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for including tests! Unit tests like this should be placed in the tests/testthat folder of the appropriate package and not to the top-level tests folder, which is used for whole-system test material (and is due for a reorg/cleanout, but that's a separate issue). For tests of ud_convert itself, the appropriate package is PEcAn.utils so they should be added to the existing base/utils/tests/testthat/test-ud_convert.R.
I also request using standard testthat expectations rather than rolling your own comparison machinery -- this entire script is basically equivalent to
expect_equal(ud_convert(100, "g/m2", "kg/m2"), 0.1) # eg DALEC/SIPNET C pools
expect_equal(ud_convert(86400, "g/m2/d", "kg/m2/s"), 0.001) # eg DALEC/SIPNET C fluxes
expect_equal(ud_convert(10, "Mg/ha", "kg/m2"), 1) # eg GDAY pools
expect_equal(ud_convert(1000, "J/mol", "kJ/mol"), 1) # eg photosynthesis params
| # Regression tests for unit conversion refactoring | ||
| # Run with: testthat::test_dir("tests/testthat", filter = "test_model_conversions") | ||
|
|
||
| source("test_model_conversions.R") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete this file -- test_model_conversions.R belongs in base/utils/tests/testthat, which already has an existing testthat.R
| # Pool conversions (mass only) | ||
| expect_equal(ud_convert(100, "g/m2", "kg/m2"), 0.1) | ||
| expect_equal(ud_convert(1000, "g/m2", "kg/m2"), 1.0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think we need to check the same unit conversion at multiple values -- Most of the actual conversion machinery is provided by the external units package and we trust them to test their own implementation, so our goal here should be to verify support for units that are important to us rather than to exhaustively test specific input values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or in less words: "Let's only check each unit pair once"
| @@ -0,0 +1,71 @@ | |||
| context("Unit Conversion Refactoring Tests") | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above that these tests belong in base/utils/tests/testthat/test-ud_convert.R
| expect_error(ud_convert(100, "gC/m2", "kgC/m2")) | ||
| expect_error(ud_convert(86400, "gC/m2/d", "kgC/m2/s")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that you're taking a problem seen during development and trying to turn it into a test! But I don't think these expectations are useful to us -- they will only fail if udunits does learn how to parse C, and alas having the test case here won't keep users from making the same typo elsewhere.
It's possible that C is a common enough special case that it'd be nice for PEcAn's ud_convert to handle it explicitly (either converting it correctly or throwing a more informative error), but I suspect that would be a lot of tricky work for little practical gain.
| # But these (without 'C') should work | ||
| expect_equal(ud_convert(100, "g/m2", "kg/m2"), 0.1) | ||
| expect_equal(ud_convert(86400, "g/m2/d", "kg/m2/s"), 0.001, tolerance = 1e-10) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
already checked above
Co-authored-by: Chris Black <chris@ckblack.org>
Co-authored-by: Chris Black <chris@ckblack.org>
Co-authored-by: Chris Black <chris@ckblack.org>
Co-authored-by: Chris Black <chris@ckblack.org>
Co-authored-by: Chris Black <chris@ckblack.org>
Co-authored-by: Chris Black <chris@ckblack.org>
Co-authored-by: Chris Black <chris@ckblack.org>
Description
This PR standardizes dimensional unit conversions by replacing manual arithmetic with the centralized helper function PEcAn.utils::ud_convert() where appropriate. This reduces maintenance burden, improves readability, and minimizes the risk of unit conversion errors.
The changes focus strictly on dimensional unit conversions (mass, time, energy, area) and intentionally exclude model-specific scaling, biological constants, and timestep-dependent logic, per project guidance.
Summary of Changes
NOT CHANGED
Fixes - #3712