Skip to content

Reactant LandModel without vegetation - #157

Open
maximilian-gelbrecht wants to merge 31 commits into
mainfrom
mg/reactant-landmodel
Open

Reactant LandModel without vegetation#157
maximilian-gelbrecht wants to merge 31 commits into
mainfrom
mg/reactant-landmodel

Conversation

@maximilian-gelbrecht

Copy link
Copy Markdown
Collaborator

This ensures Reactant compatibility of a LandModel without vegetation.

Comment thread src/processes/soil/hydrology/soil_hydraulic_closures.jl
Comment thread src/processes/soil/hydrology/soil_hydraulic_properties.jl
"""
function initialize!(state, grid, ::ImplicitSkinTemperature, args...)
set!(state.skin_temperature, state.ground_temperature)
interior(state.skin_temperature) .= interior(state.ground_temperature) # Now set! for better Reactant compat, set! might make a CPU detour

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.

The comment doesn't match the change here. Why do we need to stop using set!? I would rather keep that.

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.

It's just a typo "No set!".

The problem is that set! might make CPU detours and the interpolation isn't fully Reactant compatible.

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.

Did you create an Oceananigans issue about that?

I don't see any reason why set! should make CPU detours when setting a Field to another Field.

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.

No, not yet

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.

Ok, then please do that and link it here, and add a TODO comment in the code.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Indeed, it should have. Except that reactant defines its own set_to_field!

So the somewhat funny situation is that the Reactant extension of set_to_field! actually causes set! to fail with Reactant, when it would otherwise succeed.

It's fixed in a new PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also on this:

I don't believe that anything should go to CPU though. That should only happen if the target is on CPU.

we hit CPU only for interpolation (which isn't yet supported with Reactant), which is what we fall back to if we decide that broadcasting / copying will not work.

@maximilian-gelbrecht maximilian-gelbrecht Aug 14, 2026

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.

Thanks Greg!

I reverted to set! and it's not yet working here end-to-end, I'll investigate a bit later.

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.

Ah sorry, stupid me, I only added the branch in the main and normal test env of Terrarium and not in the Reactant test env. It does actually work.

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.

Ah sorry, stupid me, I only added the branch in the main and normal test env of Terrarium and not in the Reactant test env. It does actually work.

bgroenks96
bgroenks96 previously approved these changes Aug 4, 2026

@bgroenks96 bgroenks96 left a comment

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.

Looks overall good, just look at the set! thing. That would be problematic if Reactant can't handle that.

@maximilian-gelbrecht
maximilian-gelbrecht marked this pull request as draft August 4, 2026 08:22
@maximilian-gelbrecht

maximilian-gelbrecht commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

Oh I thought this would already pass but it turns out there is another upstream Oceananigans Reactant issue with boundary conditions that we hit here. I converted this to draft for now.

The main problem is the 2D indexing of Fields as it seems.

I need to sit down and look at this properly to understand exactly what we need and maybe fix the issue upstream in Oceananigans.

@bgroenks96
bgroenks96 dismissed their stale review August 4, 2026 08:39

Needs further investigation

Comment thread src/solvers/newton.jl
StableHLO raise pass cannot lift. An unrolled loop raises cleanly.
- **Reverse-mode AD**: a fixed trip count avoids a dynamically-sized tape.
"""
struct NewtonSolver{NF, iterations} end

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.

Why? We already had a Newton solver before and got rid of it in favor of RootSolvers.jl.

Can't you just disable the convergence test for the RootSolvers one?

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.

Also, this is again something that should be fixed with a custom rule... the AD system should not be differentiating through the iterations.

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.

No custom rules with Reactant, but you are probably right with RootSolvers.

@bgroenks96 bgroenks96 Aug 4, 2026

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 there any documentation or roadmap anywhere about custom rules? I can't find anything, and I find this really concerning.

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.

I am not terribly concerned around it as even the worst case of just differentiating through the maximum itertation number might not be that bad. But we are also not alone with this CliMA/Oceananigans.jl#5844

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.

@olivierbonte I also attempted it (not sure if I pushed it to my fork) and ran into the same issues. I gave up after a couple of hours. I don't think it's entirely an issue of RootSolvers.jl being incompatible; in theory Reactant can handle data-dependent loops. But I hit a point where it looked like bugs in Reactant/StableHLO and just gave up.

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.

Alright, fixed point iteration for Reactant for now sounds reasonable!
Good to know you also gave it a shot @bgroenks96! I'll try to look at it a bit more if I find the time, but not sure If I will get the AD working. Do you think there is value in trying to get a PR merged in RootSolvers.jl that works for forward evaluations (but not yet for Enzyme)? Because that I think should work

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.

If the changes to the code are not too substantial, I would try it. But the CliMA project is pretty explicitly disinterested in AD so I doubt they will accept a major rewrite for Reactant.

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.

If you can reduce it to a Reactant MWE if something isn't working that would be great as well though, we should absolutely post it in their repo. Usually responses are quick.

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.

CliMA/RootSolvers.jl#99 now works for primal evaluations. Enzyme autodiff still WIP

@bgroenks96

Copy link
Copy Markdown
Collaborator

The main problem is the 2D indexing of Fields as it seems.

It would not be so objectionable to do field[i, j, 1] rather than field[i, j] everywhere. We already have to do this anyway when using setindex!.

@maximilian-gelbrecht

Copy link
Copy Markdown
Collaborator Author

The main problem is the 2D indexing of Fields as it seems.

It would not be so objectionable to do field[i, j, 1] rather than field[i, j] everywhere. We already have to do this anyway when using setindex!.

The culprit is in Oceananigans though CliMA/Oceananigans.jl#5846

@maximilian-gelbrecht

Copy link
Copy Markdown
Collaborator Author

The main problem is the 2D indexing of Fields as it seems.

It would not be so objectionable to do field[i, j, 1] rather than field[i, j] everywhere. We already have to do this anyway when using setindex!.

The culprit is in Oceananigans though CliMA/Oceananigans.jl#5846

This issue is resolved (but not yet released).

I'll pick up this PR when I find some time, maybe on the way home from JuliaCon.

Comment thread src/utils/kernel_utils.jl
@maximilian-gelbrecht
maximilian-gelbrecht marked this pull request as ready for review August 13, 2026 14:14
@maximilian-gelbrecht

Copy link
Copy Markdown
Collaborator Author

This works now. I would keep the fixed iteration NewtonSolver as a temporary solution for Reactant until we have something different figured out (like RootSolvers.jl compatability).

@olivierbonte

Copy link
Copy Markdown
Collaborator

@maximilian-gelbrecht have you tried the RootSolvers.jl version at CliMA/RootSolvers.jl#99? This was working okay for normal (non AD) reactant code evaluations but haven't tried it yet within Terrarium.

@maximilian-gelbrecht

Copy link
Copy Markdown
Collaborator Author

Further Oceananigans issues that blocked the vegetation model are addressed in CliMA/Oceananigans.jl#5880

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants