Skip to content

eCLM Farmyard Manure Fixes - #153

Draft
jjokella wants to merge 2228 commits into
masterfrom
eCLM_FYM_fixes_merged_with_master
Draft

jjokella wants to merge 2228 commits into
masterfrom
eCLM_FYM_fixes_merged_with_master

Conversation

@jjokella

@jjokella jjokella commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Draft PR in eCLM for original code from @tboas found here: https://github.com/tboas/eCLM/tree/eCLM_FYM_fixes

Compared to eCLM_FYM_fixes, I have merged the current eCLM master into eCLM_FYM_fixes_merged_with_master in order to be able to compile and run eCLM-PDAF.

Note: The 2228 commits of this branch are due to it being based on CLM5 rather than eCLM, so one has to rather look at the Files changed and later the PR is supposed to be squashed.

ekluzek and others added 30 commits November 14, 2019 23:04
A few fixes and extend mksurfdata to set PFT/CFT fractions but use veg-cover from dataset
…ulations and has time-stamps at the mid-point of the month
…the input soilm dataset, cycle so that the data isn't modified and CTSM just runs for that point, rather than doing a strange modification to it by using the missing value data from the file, also if h2osoi_vol_prs is large set to spval rather than using it, these two changes resolve: #832 #833
apply this diff rgknox/fates_next_api_5.0.21...escomp/fates_next_api
This updates fates from sci.1.27.1_api.7.3.0 to sci.1.30.0_api.8.0.0.
Some answer changes needed for prescribed soil-moisture. And clm4_5 defaults for 1850 Nitrogen deposition and or urbantv
settings were made to be consistent with clm5_0.
Fates next api uninitialized hlm_model_day fix
Updated default fates parameter file for new api 8.1.0 format.
tboas and others added 26 commits July 21, 2026 11:19
- Add use_fruittree logical flag (default .false.) to clm_varctl.F90
- Add to clm_inparm namelist and MPI broadcast in controlMod.F90
- Guard all apple/perennial/fruittree param reads in pftconMod.F90:
  perennial, mulch_pruning, pftpar20, pftpar28, arootf2, aleafstor,
  transplant, lfmat, grnrp, crequ, crit_temp, ndays_stor
- When .false. (default): all arrays zeroed, old 79-PFT param file works
- When .true.: reads fruittree params from paramfile as before
- expected_pftnames(35/36): citrus when .false., apple when .true.
pftconMod.F90:
- Add use_fruittree namelist flag (default .false.)
- Guard all fruittree param reads: perennial, mulch_pruning, pftpar20/28,
  arootf2, aleafstor, transplant, lfmat, grnrp, crequ, crit_temp, ndays_stor,
  prune_fr, nstem, taper, cc_leaf/lstem/dstem/other, fm_*, fsr_pft, fd_pft,
  planting/harvest dates
- Restore ntrp_soybean/nirrig_trp_soybean declarations and index assignment
- Restore ncitrus/nirrig_citrus for backward compat with old param file
- Guard expected_pftnames(35/36): apple when use_fruittree, citrus otherwise
- Guard expected_pftnames(77/78): covercrop when use_covercropping,
  tropical_soybean otherwise
- Initialize expected_pftnames(:) to blank before filling
- Skip validation for blank slots
- napple/nirrig_apple initialized to -1 (inactive when use_fruittree=.false.)
- Add nirrig_trp_soybean + nirrig_citrus to irrigated validation check

CNPhenologyMod.F90:
- Guard CropPhenologyInit fruittree date block with use_fruittree
- Add use_fruittree to use clm_varctl in CNPhenology and CropPhenologyInit
- ntrp_soybean/nirrig_trp_soybean restored in use statements and logic

CNNDynamicsMod.F90:
- ntrp_soybean/nirrig_trp_soybean restored in use statement and logic
dynHarvestMod.F90:
- Replace harvest-triggered switch with 3 fixed calendar dates:
  Jan 1 (summer->summer), Mar 1 (covercrop->cash crop), Oct 1 (post-harvest)
- Use get_curr_date instead of harvdate check
- Guard with npcropmin instead of covercrop flag

dynCovercropFileMod.F90:
- Add active_ivt_patch pointer for IVT history output
- Initialize IVT from patch%itype at startup
- Update IVT every timestep in dyncovercrop_interp
- Switch uses pct_cft_cur (current year) not pct_cft_next

dynSubgridDriverMod.F90:
- Call dyncovercrop_interp in main time loop (not only init)

CNPhenologyMod.F90:
- Update covercropping wrapper to pass curr_mon/curr_day

CNBalanceCheckMod.F90:
- Relax C/N balance error thresholds to 1e-1 for rotation switches
Implements file-driven crop rotation via transient_landuse_file.
Three calendar switch dates: Jan 1, Mar 1, Oct 1.
Oct 1 uses next-year CFT and skips if crop currently alive.
IVT registered as history field (avgflag=I) for rotation verification.
C/N balance thresholds relaxed to 100 gC/m² for rotation timesteps.
use_fruittree flag added for backward compat with apple param file.
use_covercropping flag guards all rotation logic.
- Calendar switches replaced by post-harvest switch only
- covercropping_postharvest: new subroutine in dynHarvestMod
- covercrop_switch_ivt: resets xsmrpool, onset/offset flags on switch
- pftconMod: planting dates now read outside use_fruittree block
- CNPhenologyMod: planting jday init outside use_fruittree block
- WW mono now working (TLAI 3-5, annual replanting)
- Rotation IVT switching working but SB/summer crops show TLAI=0
- Reset peaklai on switch: carrying peaklai=1 from the previous crop makes
  CNPhenologyMod (~line 2731) clamp hui up to huigrain on the first live
  timestep, so 'hui < huigrain' is permanently false and the new crop never
  enters phase 2 -- no leaf emergence, no onset, leafc_xfer never drains.
- Stop zeroing huigrain/gddmaturity: CropPhenology derives both at planting;
  zeroing them makes the same gate impossible to satisfy.
- Onset/offset flag resets removed (carried over from working tree).

Verified: all 8 rotation years (2011-2018) now grow and harvest, with
GRAINC_TO_FOOD nonzero once per crop. Previously 2014-2017 had flat-zero
LEAFC and TLAI.
- Mar 31: if the standing crop is not this year's entry in the rotation file it
  is a cover crop; force it through harvest (gddmaturity/huigrain = 0) so the
  residue is partitioned with the cover crop's own lf_flab/fcel/flig.
- Apr 1: switch itype to this year's crop; CropPhenology plants it in its own
  window (spring crops from Apr 15).
- Sep 1: switch unconditionally to next year's crop. Autumn-sown crops
  establish in their Sep-Nov window; spring-sown crops cannot plant in autumn
  so the patch stays bare over winter.
- Act only on the first timestep of each day.
- Deleted covercropping_postharvest and the CNPhenologyMod wrapper.
- Factored the dominant-CFT lookup into covercrop_target_ivt.

Rotation now matches derus_rotation_landuse.nc in all 8 years 2011-2018, with
exactly one GRAINC_TO_FOOD pulse per year. Previously 2016 double-harvested and
2013/14 sowed a winter wheat that was ploughed in unproductively.
- CNPhenologyMod: sugar beet and potato now use gddmaturity = hybgdd directly
  instead of min(gdd020, hybgdd). gdd020 at Selhausen is ~1400, which capped
  beet maturity and forced a ~90-day season with a July lift.
- dynHarvestMod: autumn sowing is attempted on Sep 1, Oct 15 and Nov 15 rather
  than Sep 1 only. A beet now maturing in Sep-Oct is still croplive on Sep 1,
  so the single attempt skipped and the following winter crop was never sown
  (2015 and 2018 grew nothing).

With clm5_params_rotation_SBtuned_WBfromWW_v1.nc (beet laimx 3.5->5.5,
gddmin 300->100, lfemerg 0.2->0.08, grnfill 0.7->0.45, hybgdd 2000->2200,
mxmat 400->210; winter barley adopting calibrated winter wheat parameters):

  year  crop           TLAI before -> after   harvest
  2011  sugar beet     3.35 -> 5.26           Aug
  2014  sugar beet     2.63 -> 5.12           Sep
  2016  winter barley  0.27 -> 6.59           Jul
  2017  sugar beet     2.95 -> 5.08           Sep

All 8 years match the prescribed rotation with one harvest each.
manure_lignin_frac was declared as a parameter in CNPhenologyMod but never
referenced. Litter partitioning of manure carbon is controlled by
manure_fmet / manure_fcel / manure_flig from cfert_inparm, read in
CNNDynamicsMod. Two parameters nominally controlling the same quantity, one
of them unused, is misleading.
- PCT_CFT_WINTER in the transient land-use file gives each year an explicit
  cover-crop entry, independent of the main crop sequence.
- Autumn sowing is attempted on four dates and accepted only if the date falls
  inside the target crop's own planting window, so an early catch crop follows
  a cereal and a late one can follow a root crop lifted in October.
- A late cover-crop sowing is suppressed when an autumn-sown main crop follows,
  so a winter cereal is not locked out of the patch.
- Supports summer->summer, summer->winter->summer, summer->cover->summer and
  summer->cover->winter.

Verified on a synthetic DE-RuS rotation (sugar beet - potato - maize, cover
crop every winter, 2011-2018): 8/8 years match the prescribed sequence and
8/8 winters carry a cover crop.
use_grainproduct is a namelist flag that covercrop_switch_ivt was rewriting
per patch. With one patch that happened to work; with many, the last switch
processed sets it for the whole domain, suppressing grain-product accounting
everywhere until another switch overwrites it. It also silently overrode the
user's namelist setting.

  - pftconMod: new is_covercrop(ivt)
  - covercrop_switch_ivt no longer writes the flag
  - each read site tests use_grainproduct .and. .not. is_covercrop(ivt(p)):
    CNPhenologyMod litter routing and CNGrainToProductPools, CNVegCarbonFluxType
    litfall, CNCIsoFluxMod litter routing and crop-product assignment

dyncovercrop_interp re-read the rotation file every timestep -- 17520 reads per
simulated year at dtime=1800s. Reads are now cached on the year index;
set_current_year and the IVT history update stay outside the guard.

covercropping_update walked every patch on every timestep. The switch-date test
(is_rotation_switch_date) and the once-per-day test are hoisted above the loop.

Removed the dead manure_lignin_frac declaration, superseded by manure_flig
from cfert_inparm.

None of these should change single-point results; regression against
JR_DE-RuS_synthrot pending.
Twelve write(iulog,...) statements in CNPhenologyMod (vernalization_old,
vernalization_2, the frost-tolerance block) and CNFUNMod (fun_cn_flex_c)
executed once per patch per timestep. At a single point this is harmless. On
the DE009 domain (1,052,898 grid cells, 512 ranks) they produced 57 GB of log
output per attempt, slowed the model roughly fivefold relative to the stock
build, and were the likely cause of repeated memory kills at timestep 1295.

The statements are commented rather than deleted so the diagnostics remain
available for point-scale debugging.

Also disabled IVT_TRACK in dynCovercropFileMod, which wrote every timestep.
SWITCH_DEBUG is retained: it fires only on actual rotation switches.
The Oct-15 termination branch (clear a cover crop ahead of the next
winter crop) fired whenever the standing live crop merely differed
from next year's rotation target, with no check that the standing
patch was actually a cover crop. On a plain two-crop rotation with no
cover crop between phases (e.g. wheat -> rye), this force-terminated
the main crop mid-season -- zeroing gddmaturity/huigrain -- and leaked
carbon that CNBalanceCheckMod does not account for.

Restrict the branch to ncovercrop_1/ncovercrop_2 patches only.

@kvrigor kvrigor left a comment •

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.

These additional files should not be merged in master:

docs/params/*
docs/tools/*
README_*

We can pull useful info from those files and write them here as we move along in this PR. Also we could remove these files later once the review is almost done.

@kvrigor kvrigor linked an issue Oct 23, 2026 that may be closed by this pull request
5 tasks

This branch has not been deployed

No deployments
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.

Farmyard Manure merge strategy