Skip to content

560 new calculation for accounting of root distribution on the transpiration #591

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

Open
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

ccarouge
Copy link
Member

@ccarouge ccarouge commented Jun 30, 2025

CABLE

Thank you for submitting a pull request to the CABLE Project.

Description

Fixes #560

A few changes come with this pull request:

  • harmonise the calculation of the amount of soil water removed by canopy transpiration between cbl_dryLeaf.F90 and cbl_remove_trans.F90.
  • Use the amount of water calculated in cbl_dryLeaf.F90 and stored in ssnow%evapfbl to update the soil water content in cbl_remove_trans.F90 instead of recalculating it. It's simplifies the code and has a very minor impact.
  • Remove unused canopy%evapfbl, only keep ssnow%evapfbl and give it a double precision. The precision change is in the groundwater updates that has started this work.
  • Change the calculation to use wbliq instead of wb so the calculation only takes into account the liquid water amount. EDIT: Changed the calculations of fwsoil to use wbliq consistently.
  • Change the calculation to use zse_vec and swilt_vec to make the same calculation work for standard and groundwater. It introduces the use of the *_vec variables in the main part of the code. The alternative is to create copies of 2 subroutines and some interfaces to handle the different dimensions and precisions. It seems overly complex for something that small. I'm also thinking we will want to carry only one version of the soil properties at some point. However, that's open for discussion. zse_vec wasn't properly initialised in CABLE and I have corrected that. I have introduced the initialisation to ESM1.6 and it is already correct in AM3. swilt_vec is initialised correctly in all current applications. If we go with this version of the code, I'll test it works in the coupled applications as well.

I also looked at getrex_1d used in the Haverd2013 case. There are 2 versions in CABLE (cbl_dryLeaf.F90 and cable_sli_roots.F90). Unfortunately, they have slightly diverged from each other. For the moment, I have simply added a warning to the code documentation with a list of the differences I have found. But I didn't want to make this PR bigger than required. I'll leave that part to another time.

Testing

  • Are the changes non bitwise-compatible with the main branch because of a bug fix or a feature being newly implemented or improved? If yes, add the link to the modelevaluation.org analysis versus the main branch or equivalent results below this line.

modelevaluation results

In addition to the benchcab testing, I've also tested the effect of various steps.

Changing to use wbliq has the largest effect for points with icy fraction, differences at Hyytalia for all soil layers:
EDIT: Figure updated with the fwsoil calculation changes.

SoilMoist_diff_wbliq_fwsoil

Harmonising the calculations between the canopy and soil has the second largest effect, differences at Tumbarumba for the top soil layer:

soil_moist_diff_new_calc_dryleaf

Please add a reviewer when ready for review.


📚 Documentation preview 📚: https://cable--591.org.readthedocs.build/en/591/

@ccarouge ccarouge force-pushed the 560-New-calculation-for-accounting-of-root-distribution-on-the-transpiration branch from 6dda783 to 4d0093f Compare June 30, 2025 05:39
@ccarouge ccarouge marked this pull request as ready for review June 30, 2025 06:23
@ccarouge ccarouge requested review from har917, a team and SeanBryan51 and removed request for a team June 30, 2025 06:23
@har917
Copy link
Collaborator

har917 commented Jun 30, 2025

@ccarouge I'll look through in detail later - nothing major jumped out so far except

  • I need to remind myself why we had canopy%evapfbl and ssnow%evapfbl
  • how to handle the intersection/commonality with bits in the GW code

Nevertheless 'we' do need to resolve why the intel build and markdown tests have failed before this can go further.

One question - how encompassing do you want this issue to go? We could easily extend it to include rationalising the evaluation of %fwet (different in three places - EDIT: no its not! We've resolved this already - I was looking at an older branch) and ensuring some consistency around whether local variables are just memory, ALLOCATABLE and/or POINTERS (cf gswmin in cbl_dryleaf)

@har917
Copy link
Collaborator

har917 commented Jul 1, 2025

@ccarouge Could you add some plots of the water balance (out%wbal) to this PR - so from trunk and test branches. Aside from the neatness of removing clutter in the code - this is where the impact of these changes will be seen.

Copy link
Collaborator

@har917 har917 left a comment

Choose a reason for hiding this comment

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

@ccarouge Looks mostly okay from a science component:

  1. I do wonder whether we should extend this to cover consistency changes in fwsoil
  2. We do need to think how to deal with diff(k=ms)/=0.0 at the end of remove_trans should be handled (quite likely given the inconsistencies in fwsoil)

Technically - there's the broken markdown and build - I also suspect that MPI is broken since the KIND for ssnow%evapfbl has changed and so I would have expected that the r1len's need to go to r2len

@@ -7222,13 +7208,6 @@ SUBROUTINE master_restart_types (comm, canopy, air, bgc)
! & types(bidx), ierr)
! blocks(bidx) = 1

bidx = bidx + 1
Copy link
Collaborator

Choose a reason for hiding this comment

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

This change here is consistent with the intent of the PR but it highlights something missing (I think)

Since you've changed the TYPE of ssnow%evapfbl you should also need to change the length of the associated MPI declarations (should be r2len not r1len) - I don't see these changes in the changeset.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Collaborator

Choose a reason for hiding this comment

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

Just a check - does the blen(bidx) = r1len at line 2513 also need changing?

Copy link
Member Author

Choose a reason for hiding this comment

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

I believe the line 2513 you are referring to has been removed. It was for canopy%evapfbl that I removed. Line 2513 now has the MPI code for canopy%epot.

Copy link
Member Author

Choose a reason for hiding this comment

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

I can't find any reference to ssnow%evapfbl in mpimaster or mpiworker that is using r1len anymore.

Copy link
Collaborator

@SeanBryan51 SeanBryan51 Jul 9, 2025

Choose a reason for hiding this comment

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

This call to MPI_Type_Create_hvector seems to be creating something (types(bidx)?) based on bidx being an r1len variable at this point in the sequence - but that's no longer valid.

I think this must have been fine since the kind was not specified for canopy%evapfbl and defaulted to r1.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@SeanBryan51 But would it be fine with the PR's changes given that bidx is pointing (not in the sense of a POINTER) to ssnow%evapfbl which is now r_2?

Copy link
Member Author

Choose a reason for hiding this comment

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

@har917 , bidx is only used as an array index. types is an array and we add the information for evapfbl in vector form to that array (my guess is that it stores some kind of total length in bytes). The index used for types does not change depending on the type of the variable (r_2 or r_1). types contains INTEGERs, so I'd assume the integer for a r_2 array is bigger than for a r_1 array but it's still only 1 number that only needs to be stored in one place in the types array. So bidx (the index counter for the types array) is still incrementing by one. And we only need one element of the types array types(bidx) to store the information.

Copy link
Collaborator

Choose a reason for hiding this comment

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

My concern isn't really bidx or types but blen(bidx) - this seems (e.g. line 5659) to be used when setting up how the workers-masters will communicate. So setting this up to have the length 1 or r1len when %evapfbl is an r2len double precision REAL seems ... odd.

However - some of the variables are clearly being dealt with differently - see line 1983 for veg%froot which also does the call to MPI_Type_Create_hvector then blen(bidx)=1 - so there is some consistency (even if I don't follow the why).

Perhaps what I'm really getting at here is that this probably needs a short MPI test of just the change in KIND on ssnow%evapfbl separated out from the rest of the science change (? - more work though).

Copy link
Collaborator

Choose a reason for hiding this comment

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

@SeanBryan51 But would it be fine with the PR's changes given that bidx is pointing (not in the sense of a POINTER) to ssnow%evapfbl which is now r_2?

Yes I think so as long as worker_cable_params is consistent with how the blocks have been organised in master_cable_params (i.e. blen and bidx) there should be no issues, and this looks to be the case.

@ccarouge ccarouge requested a review from har917 July 2, 2025 04:18
@ccarouge
Copy link
Member Author

ccarouge commented Jul 2, 2025

@har917 For the broken link checker and the broken build in the automated tests, it's not caused by this PR so it's going to be fixed in #594

SUM(veg%froot * MAX(0.0,MIN(1.0, REAL(ssnow%wb) - &
SPREAD(soil%swilt, 2, ms))),2) /(soil%sfc-soil%swilt))
SUM(veg%froot * MAX(0.0,MIN(1.0, REAL((ssnow%wbliq) - &
SPREAD(soil%swilt, 2, ms)))),2) /(soil%sfc-soil%swilt))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure I like the use of SPREAD(soil%swilt,2,ms) here - or %sfc- %swilt in the denominator. Seems inconsistent with the push to use either normal or _vec forms consistently ...

... but okay scientifically.

Copy link
Member Author

Choose a reason for hiding this comment

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

For fwsoil calculations, I've only changed wb to wbliq and didn't change the use of the parameters. So what you see here for swilt and sfc is what is already in main.

I feel we will need to decide on one form of the soil parameters (2D or 1D) and change everything to that. Because I was changing remove_trans() code, I introduced the _vec forms to avoid code duplications. But I would generally hold off in expanding this unless it greatly simplifies the code, until we decide which form we keep.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry, forget what I said above @har917 , I didn't check on the context of the code.

The reason I didn't use the _vec form here is I don't know how the non-linear calculation is supposed to work with a vertical profile in soil properties.

I've noticed the groundwater code does not solve the problem.
It could be we need to calculate a rwater term for each soil layer and sum at the end?

Anyway, this is beyond the current PR, I believe.

Copy link
Collaborator

Choose a reason for hiding this comment

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

In the first instance I would be going with

rwater = MAX(1.0e-9,                                                  &
         SUM(veg%froot * MAX(0.0,MIN(1.0, (REAL(ssnow%wbliq) -        &
         soil%swilt_vec)/(soil%sfc_vec-soil%swilt_vec)  )) , 2)

which I think is the direct equivalent once you substitute in the _vec forms filled with the single layer values.

I was 'simply' trying to avoid this need to carry both single and _vec forms of the soil parameters (and we really shouldn't need the REAL() here either - or perhaps we need it but with an explicit change to a KIND(r1))

Copy link
Member Author

@ccarouge ccarouge Jul 9, 2025

Choose a reason for hiding this comment

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

My problem is the rest of the algorithm:

rwater = soil%swilt + rwater * (soil%sfc-soil%swilt)
xi(:,1) = soil%swilt
xi(:,2) = soil%swilt + (soil%sfc - soil%swilt)/2.0
xi(:,3) = soil%sfc
ti(:,1) = 0.
ti(:,2) = 0.9
ti(:,3) = 1.0
si(:,1) = (rwater - xi(:,2)) / ( xi(:,1) - xi(:,2)) * &
(rwater - xi(:,3)) / ( xi(:,1) - xi(:,3))
si(:,2) = (rwater - xi(:,1)) / ( xi(:,2) - xi(:,1)) * &
(rwater - xi(:,3)) / ( xi(:,2) - xi(:,3))
si(:,3) = (rwater - xi(:,1)) / ( xi(:,3) - xi(:,1)) * &
(rwater - xi(:,2)) / ( xi(:,3) - xi(:,2))
DO j=1,mp
IF (rwater(j) < soil%sfc(j) - 0.02) &
fwsoil(j) = MAX(0.,MIN(1., ti(j,1)*si(j,1) + &
ti(j,2)*si(j,2) + ti(j,3)*si(j,3)))

The way it is written relies on swilt and sfc being scalars. If they vary in depth, then my guess is we need to add a loop on the soil layers and sum at the end. But I don't know if the ti values should be kept as 0, 0.9 and 1 in that case.

I certainly don't want to introduce the _vec form for only half of the function and the scalar form for the rest.

Copy link
Collaborator

@har917 har917 left a comment

Choose a reason for hiding this comment

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

almost there - I think there still one bit in the MPI code that's not quite correct.

@ccarouge ccarouge requested a review from har917 July 8, 2025 23:57
Co-authored-by: Sean Bryan <39685865+SeanBryan51@users.noreply.github.com>
Copy link
Collaborator

@SeanBryan51 SeanBryan51 left a comment

Choose a reason for hiding this comment

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

The rest of the changes look good to me.

Copy link
Collaborator

@har917 har917 left a comment

Choose a reason for hiding this comment

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

@ccarouge I'm happy with the science - and @SeanBryan51 is okay with the rest of the technical changes (barring coupled model stuff).

@ccarouge
Copy link
Member Author

Thanks for approving. Unfortunately, I believe this has to wait until we get the library build ticked off. At least, I need to talk to Lachlan before merging in code changes that modify the results!

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.

New calculation for accounting of root distribution on the transpiration
3 participants