Skip to content

Make the Leaf dynamics differentiable#12

Merged
SarahAlidoost merged 35 commits into
mainfrom
leaf_dynamics
Sep 18, 2025
Merged

Make the Leaf dynamics differentiable#12
SarahAlidoost merged 35 commits into
mainfrom
leaf_dynamics

Conversation

@SarahAlidoost
Copy link
Copy Markdown
Collaborator

relates #8

@cwmeijer
Copy link
Copy Markdown
Collaborator

cwmeijer commented Aug 28, 2025

I've installed the package and ran the tests. All 10 of them pass. So that's a good start. Will look at the actual code next week.

I also see ruff is complaining about ANN101 and ANN102 that seem to be configured somewhere to be ignored, while these rules no longer exist and are from older versions of ruff. I made a PR for this: #14

cwmeijer added a commit to NLeSC/python-template that referenced this pull request Sep 1, 2025
[ANN101](https://docs.astral.sh/ruff/rules/missing-type-self/) and [ANN102](https://docs.astral.sh/ruff/rules/missing-type-cls/) have been removed and referencing them in the config causes warnings to be printed when ruff is run.

See also WUR-AI/diffWOFOST#12 (comment)
Copy link
Copy Markdown
Collaborator

@cwmeijer cwmeijer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a great PR! 🎖Very neat!
I made some comments. Some are suggestions for possible improvements and others are more points for you to think about (or discuss together) before you decide to merge.
I also created a PR with a tiny refactoring of a single file in your code. Was easier to do than to explain. See #15 . I think that should be merged into this branch before merging your whole PR into main.
I hope it is helpful for you!

Comment thread tests/physical_models/crop/test_leaf_dynamics.py Outdated
Comment thread tests/physical_models/crop/test_leaf_dynamics.py
Comment thread src/diffwofost/physical_models/crop/leaf_dynamics.py
@SarahAlidoost SarahAlidoost marked this pull request as ready for review September 1, 2025 12:27
@SarahAlidoost
Copy link
Copy Markdown
Collaborator Author

I've installed the package and ran the tests. All 10 of them pass. So that's a good start. Will look at the actual code next week.

I also see ruff is complaining about ANN101 and ANN102 that seem to be configured somewhere to be ignored, while these rules no longer exist and are from older versions of ruff. I made a PR for this: #14

thanks! 👍 we can merge #14

@SarahAlidoost
Copy link
Copy Markdown
Collaborator Author

I think this is a great PR! 🎖Very neat! I made some comments. Some are suggestions for possible improvements and others are more points for you to think about (or discuss together) before you decide to merge. I also created a PR with a tiny refactoring of a single file in your code. Was easier to do than to explain. See #15 . I think that should be merged into this branch before merging your whole PR into main. I hope it is helpful for you!

Thanks for the comments and helpful suggestions. I addressed your comments:

Comment thread tests/physical_models/crop/test_leaf_dynamics.py
Comment thread src/diffwofost/physical_models/crop/leaf_dynamics.py Outdated
TWLV = Any(default_value=torch.tensor(-99.0, dtype=DTYPE))

class RateVariables(RatesTemplate):
GRLV = Any(default_value=torch.tensor(0.0, dtype=DTYPE))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in original these were initialized at -99.0

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. In PCSE, class attributes default to -99.0, but rate variables are initialized to zero, see here. So in practice, those -99.0 values never actually get used.

TBASE = Any(default_value=[torch.tensor(-99.0, dtype=DTYPE)])
PERDL = Any(default_value=[torch.tensor(-99.0, dtype=DTYPE)])
TDWI = Any(default_value=[torch.tensor(-99.0, dtype=DTYPE)])
SLATB = AfgenTrait() # FIXEME
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FIXME

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR was about two parameters of leaf_dynamics; TDWI and SPAN. In the next iteration, the rest will be fixed.

key/value pairs
"""
self.kiosk = kiosk
# TODO check if parvalues are already torch.nn.Parameters
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this TODO still active?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, currently, there are no checks on the parameters since we are not using Traits anymore. This should be fixed in the next iterations.

# CALCULATE INITIAL STATE VARIABLES
# check for required external variables
_exist_required_external_variables(self.kiosk)
# TODO check if external variables are already torch tensors
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this TODO still active?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, the same as above.

self.states.LVAGE = tLVAGE

@prepare_states
def _set_variable_LAI(self, nLAI): # FIXEME
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this FIXEME?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function, as a BMI function, might not be used in any application that requires differentiability. For now, I kept it, but will most probably be removed.

Copy link
Copy Markdown
Collaborator

@michielkallenberg michielkallenberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice work! Great. I left some minor comments; feel very much free to ignore.

from pcse.base.parameter_providers import ParameterProvider
from pcse.engine import Engine
from pcse.models import Wofost72_PP
from diffwofost.physical_models.crop.leaf_dynamics import WOFOST_Leaf_Dynamics
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

, WeatherDataProviderTestHelper

span = torch.nn.Parameter(torch.tensor(30, dtype=torch.float64))
numerical_grad = calculate_numerical_grad("SPAN", span, "TWLV") # this is Δloss/Δspan

assert numerical_grad == 0.0
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test seems not entirely complete

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, it is fixed now.

assert_almost_equal(numerical_grad, grads.item(), decimal=3)


class TestDiffLeafDynamicsSPAN:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conssider making this more generic; there is a bit of code repetion.

Copy link
Copy Markdown
Collaborator Author

@SarahAlidoost SarahAlidoost Sep 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point. While there’s some duplication, it helps keep each test clear and maintainable on its own. I’d keep them as-is unless in a future iteration, we see a need for reuse.

self.TERMINAL_OUTPUT_VARS = []


class EngineTestHelper(Engine):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bit of code repetition from the original class.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct. This file will be improved later.

@SarahAlidoost
Copy link
Copy Markdown
Collaborator Author

Very nice work! Great. I left some minor comments; feel very much free to ignore.

Thanks for the review and comments/suggestions.

@SarahAlidoost SarahAlidoost merged commit d8a5a56 into main Sep 18, 2025
8 of 10 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in DeltaCrop: epic1 and epic2 Sep 18, 2025
@SarahAlidoost SarahAlidoost deleted the leaf_dynamics branch September 18, 2025 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants