Skip to content

Fix bugs in the Tree Recruitment Scheme with seedling dynamics - #1572

Open
r-ward wants to merge 20 commits into
NGEET:mainfrom
r-ward:trs_debug
Open

Fix bugs in the Tree Recruitment Scheme with seedling dynamics#1572
r-ward wants to merge 20 commits into
NGEET:mainfrom
r-ward:trs_debug

Conversation

@r-ward

@r-ward r-ward commented May 27, 2026

Copy link
Copy Markdown

Description:

Fixes several bugs that cause the model to crash when running FATES with the Tree Recruitment Scheme (TRS; namelist option fates_regeneration_model = 'trs').

Bug fixes:

#1499 - Fix PAR fraction calculations (normalization by patch area was previously missing, causing NaN errors)
#1500 - Skip updating seedling layer SMP running mean on first model day (host model SMP spike leads to 100% seedling mortality; the host model spike itself is a separate issue: ESCOMP/CTSM#3584 (comment))
#1501 - Fix initial value for sdlng_mort_par (was set to temp_init_veg, should be init_seedling_par)
#1504 - Add rate caps for TRS seedling emergence and decay rates so that they cannot exceed 1; rates > 1 unrealistically drive the TRS seedling pool negative, eventually crashing the model

Collaborators:

@rgknox @glemieux

Expectation of Answer Changes:

Results using other regeneration models (default, trs_no_seed_dyn) are unchanged, results will differ when using fates_regeneration_model='trs' (model previously crashed)

image

Description of generative AI usage (as necessary)

None

Checklist

If this is your first time contributing, please read the CONTRIBUTING document.

All checklist items must be checked to enable merging this pull request:

Contributor

  • The in-code documentation has been updated with descriptive comments
  • The documentation has been assessed to determine if updates are necessary
  • Describe use of generative AI (if necessary)

Integrator

  • FATES PASS/FAIL regression tests were run
  • Evaluation of test results for answer changes was performed and results provided
  • FATES-CLM6 Code Freeze: satellite phenology regression tests are b4b

If satellite phenology regressions are not b4b, please hold merge and notify the FATES development team.

Documentation

Test Results:

CTSM (or) E3SM (specify which) test hash-tag:

CTSM (or) E3SM (specify which) baseline hash-tag:

FATES baseline hash-tag:

Test Output:

Rachel Ward and others added 19 commits October 27, 2025 14:07
Changesd par_high_frac and par_low_frac to normalize total_canopy_area by area (m2). Previously, using absolute area produced negative values, causing NaNs in seedling light calculations (negative raised to a fractional power).
… (mdd).

Host model soil matric potential spikes (~negative billions) on day 1. This spike is remembered by running means. When an inflated mdd is passed to the quadratic function to calculate mortality rate from moisture stress, mortality rates > 100%.
…egative? Check by printing from SeedDecay, SeedGerm, PreDisturbanceIntegrateLiter, and recruitment subroutines
…l day to avoid host model spike in smp at initialization
…d_germ_in from exceeding available seed after accounting for inputs and decay
Remove diagnostic blocks from EDPhysiologyMod and FatesInterfaceMod that were added during degubbing of TRS.
seedling_emerg_rate is now calculated and then capped, consistent with the capping of seedling_h2o_mort_rate in SeedDecay
… seed_germ pool

Prevent the TRS transition rate factor (seedling_light_rec_a * sdling2sap_par^seedling_light_rec_b) from exceeding 1. A transition rate factor >1  would allow mass_avail to exceed the seed_germ pool, driving seed_germ negative.
Four TRS rates are capped at 1 (seedling_h2o_mort_rate, total_seedling_mort_rate, seedling_emerg_rate, sdlng2sap_rate) to prevent the TRS construction pool (seed_germ) from going negative. When rates exceed 1, the cap is still enforced but the uncapped value is written to the log
litt%seed_in_extern(pft) - litt%seed_decay(pft)

! Cap germination at available seed to prevent negative seed pool
litt%seed_germ_in(pft) = min(litt%seed_germ_in(pft), net_seed_available)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@r-ward , I'm wondering if this seed_germ_in could potentially be negative. I don't think it can since seed decay is the only negative term in net_seed_available, and it is by definition a fraction of seed mass. Can you verify this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Correct, seed_germ_in is never negative. Although, I guess it is possible for the flux to go negative if fates_recruit_seed_germination_rate or fates_trs_seedling_a_emerg were erroneously set as negative values. Maybe there should be a check on this in FatesCheckParams (I see for example a check against values of seed_dispersal_fraction < 0). I could add something similar. What do you think?

Comment thread biogeochem/EDPhysiologyMod.F90 Outdated
! deficit days, if rate exceeds 1 write to fates log

if (seedling_h2o_mort_rate > 1.0_r8) then
write(fates_log(), *) 'TRS seedling_h2o_mort_rate > 1', &

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logging messages that don't have terminations associated with them are most helpful in my experience while actively debugging. Another alternative is to use FatesWarn() which will count the times this situation triggers and summarize at the end of a run. Another alternative would be create a history variable that tracks the mort rate in this situation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Makes sense, will remove. I'm working on a separate PR to add history variables for some TRS-specific output; I'll add history variables or FatesWarn() messages there.

Comment thread biogeochem/EDPhysiologyMod.F90 Outdated
seedling_h2o_mort_rate + &
(EDPftvarcon_inst%background_seedling_mort(pft) * years_per_day)
if (total_seedling_mort_rate > 1.0_r8) then
write(fates_log(), *) 'TRS total seedling mortality rate > 1', &

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

same comment as above

! initialization spike in smp to running means
if (hlm_model_day > 2.0_r8) then
call cpatch%sdlng_mdd(pft)%p%UpdateRMean(new_seedling_mdd)
call cpatch%sdlng_emerg_smp(pft)%p%UpdateRMean(new_seedling_layer_smp)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We want to make sure that hlm_model_day is continuous across restarts. If for some reason someone is running two day restarts, and hlm_model_day is resetting each time, this running mean will never increment with meaningful data.

While I don't think SMP spikes are unexpected at the beginning of a simulation, and your move to ignore them makes sense. But I also wanted to check in regarding frozen soils. I think there was some discussion of it here:

#1500

SHould we apply some filters to prevent calculations when soils are frozen?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Ok, I see. Re: frozen soils - I think you're right that we need some conditionality, but I don't think we should stop calculations when soils are frozen. We could do something analogous to the phenology code (https://github.com/r-ward/fates/blob/3b58472a513e39fcb8d0dafc7bc0ae31b91f6e95/biogeochem/EDPhysiologyMod.F90#L1222)) and use a lower bound value similar to smp_lwr_bound for cases where check_layer_water finds no liquid water. Frozen conditions are physiologically dry, so I think that makes sense (although really we should implement behavior dependent on moisture and chilling degree days for temperate/boreal forest uses of TRS).

In the tropics, though, using an smp_lwr_bound during the SMP initialization spike suppresses germination and inflates seedling mortality for weeks/months, so this fix alone doesn't work.

Can we differentiate real frozen soils from initialization/erroneous freezing by adding a check on soil temperature? If soil temperature is warm and there is no liquid water, skip the calculations. If soil temperature is freezing, and there is no liquid water, use an smp_lwr_bound. @lmkueppers - what do you think?

@github-project-automation github-project-automation Bot moved this from Finding Reviewers to Under Review in FATES Pull Request Planning and Status Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Under Review

Development

Successfully merging this pull request may close these issues.

3 participants