Conversation
…ew eco-cobalt code
Brings in the mesozooplankton 200m diagnostic fixes (14ef4fb, b389801, 9e0bfda) and the allocation/deallocation consistency fixes (8195fae). Conflict resolution: - jprod_mesozoo_200 / f_mesozoo_200: took the dev/eco-cobalt content (vertically migrating crustacean zooplankton included, with their gut and metabolite nitrogen, plus the drho_dzt fix) expressed with the named zooplankton IDs this branch introduced. The tunicates are deliberately excluded: these diagnostics target the COPEPOD database, whose net sampling does not retain gelatinous zooplankton. - Zooplankton deallocation guard: kept this branch's "if (zoo(n)%does_dvm)" rather than the numeric "n == 4 .or. n == 5", since large tunicates now migrate and would otherwise have their gut and metabolite arrays left unallocated. Both branches had independently added deallocate(zoo(n)%jmetabo_n); the duplicate was dropped. Also in this commit: - Fix an allocated-vs-registered mismatch introduced by the WIP commit. The SMT and LGT diagnostic blocks were generated from the vmLgz block, so their *_100 ids were registered while the allocation and computation loops still ran over n = 2,5. cobalt_send_diag loops over all NUM_ZOO groups and reads the array whenever the id is registered, making this an unallocated read at the first diagnostic write. The 100m zooplankton arrays are now allocated, computed and deallocated over the full group range, with registration alone deciding what reaches the output. - Register jzloss_n_100 and jprod_don_100 for both tunicate groups. - Port jprod_tunicate_200 and f_tunicate_200 from GZ-COBALT, the gelatinous counterparts to the mesozoo pair, accumulated in the existing 200m integration loops. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
k_clear_gut and k_temp_gut were among seven zooplankton parameters that are declared and read but never initialized on dev/eco-cobalt. The WIP merge filled them from the Dam and Peterson (1988) gut evacuation relationship; replace that estimate with the values actually used in the COBALTv2-DVM code these routines descend from (M. Poupon, pers. comm. 2024): k_clear_gut 16.85 -> 8.0 day-1 k_temp_gut 2.37 -> 4.32 day-1 degC-1 k_clear_met was already 1.0 day-1, which matches, so it is unchanged. The two forms cross near 4.5 degC. Above that the Poupon values clear guts faster (about 94 vs 64 day-1 at 20 degC, i.e. roughly 15 vs 22 min residence time), so this shortens gut residence and weakens active transport in warm water relative to the previous defaults. All seven groups take these defaults, including the large tunicates. Salp gut passage is not copepod gut passage, and since LGT both migrates and produces the fast-sinking pellets, k_clear_gut_lgt and k_temp_gut_lgt are flagged in-code as retuning candidates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
does_dvm guards the allocation of the 21 gut and metabolite arrays, but 60
accesses to those arrays sat outside any guard, so setting does_dvm to
.false. for a group that has them would write into unallocated memory. The
first such access, the g_tracer_get_values fetch of nlgt_met, would corrupt
memory silently without bounds checking or abort cleanly with -fcheck=all.
Guard the three clusters where those arrays are touched, per group so that
vmmdz, vmlgz and lgt can be switched independently:
- the gut and metabolite tracer fetches
- the vmove setters for the gut and metabolite tracers (note that the
biomass vmove array is allocated for every group, so that setter stays
unconditional)
- the gut and metabolite tendency assembly
Tracer registration is deliberately left unconditional. Keeping the tracer
list fixed means restart files stay interchangeable between the migrating
and non-migrating configurations, which is the point of running them as a
pair. A group whose migration is off simply leaves its gut and metabolite
tracers untouched at their initial values, contributing zero to the mass
budget.
Also reject an unsupported configuration up front. does_dvm can only be
enabled for the three groups that own gut and metabolite tracers; enabling
it elsewhere would load ingestion into a gut that is never carried or
cleared and die later with an opaque nitrogen imbalance. Fail in
user_add_params instead, where the cause is legible. The parameter block
comment claiming migration "can be switched on for any group from the
parameter file" was wrong and has been corrected.
This is pure gating: no code line was removed or reordered, so with all
three groups migrating the model executes exactly as before.
Enables the non-migrating large tunicate experiment, in which LGT egests
where it feeds as it did in GZ-COBALT. Note that swim_max_lgt should also
be set to 0 for that run: the non-migrating branch of section 3.2.4 still
derives a swimming speed from swim_max, and nlgt carries move_vertical, so
LGT would otherwise still rise at night and sink by day without any of the
gut machinery.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cherry-picked from 15e766d, with two adjustments for this branch. The registration block conflicted: 15e766d changed only longname and units, while this branch had independently switched the group indices to named constants and added the two tunicate groups. Kept this branch's structure and applied the metadata change to all seven groups. jmetabo_n is sent with no rho_dzt factor, so the units are mol N kg-1 s-1 and ", layer integral" was wrong. 15e766d guards the send with "n .eq. 4 .or. n .eq. 5". On this branch LGT also has does_dvm = .true. by default, and jmetabo_n is allocated under that flag (generic_COBALT.F90:9471), so the literal indices would leave jmetabo_nLgt permanently dead and would read unallocated memory if does_dvm_vmmdz were ever set .false. Guard on zoo(n)%does_dvm instead, which is what the adjacent comment already claimed. Also corrects two longnames that read "vertically small/large tunicates", a leftover from copy-pasting the migrating-group text. Verified on mac-m1/osx-gnu/repro: builds clean; 2-day BATS run closes all five element budgets at imbalance_tolerance = 1e-9; jmetabo_nvmMdz, jmetabo_nvmLgz and jmetabo_nLgt all produce data while jmetabo_nSmz is correctly absent; ocean.stats and all tracer fields bitwise unchanged. (cherry picked from commit 15e766d) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cherry-picked from 49d4056 on dev/eco-cobalt. The generic_tracer.F90 hunk applied as-is; the cobalt_send_diag.F90 fix was reapplied to the same six lines rather than patched, because this branch's copies of the surrounding blocks differ. cobalt_send_diag.F90 computes tot_layer_int_c, _poc and _n as whole-array expressions over (:,:,:), but the six migrating-zooplankton terms were indexed (i,j,k,tau). Outside the i/j/k loops those variables are stale -- zero on a cold start -- so with bounds checking the run aborts on the first diagnostic call: Fortran runtime error: Index '0' of dimension 3 of array 'cobalt%p_nvmmdz' below lower bound of 1 Without bounds checking it silently reads out of bounds instead. The tot_layer_int_p block immediately below already used (:,:,:,tau) for the same tracers, which is what the other three should have been. generic_tracer.F90 documents why any DVM configuration must set use_Press_et_al_tridiag_solver = .true.: only the Press branch of g_tracer_vertdiff_G sign-splits the vertical motion into max(sink,0)/min(sink,0), so the default GOLD branch does not conserve mass for upward (negative vmove) swimming. Left .false. with migrating groups active, generic_COBALT aborts almost at once on a nitrogen or carbon source/sink imbalance. The default stays .false. so non-DVM configurations keep their existing answers. (cherry picked from commit 49d4056) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ankton (NOAA-CEFI-Regional-Ocean-Modeling#177) * Added DVM to COBALTv3 * revert unintended changes * line spacing * reverting unintended changes to FMS_coupler_util * missing parentheses * removed duplicate declarations of kirr_hp and hp_phi_vis * mesozooplankton 200-m integrated biomass should also include vertically migrating zooplankton * fixed errors in last commit * bug fix for drho_dzt * fix inconsistencies with allocation/deallocation * clean up jmetabo diagnostics, pass dvm zooplankton jmetabo_n to g_send_data. bug found by claude opus 5. * bug fixes and improved comments on using Press algorithm * adding parameter calls for a range of COBALT-dvm variables --------- Co-authored-by: Mathieu A. Poupon <mpoupon@tiger3.princeton.edu>
cefi/dev/eco-cobalt's tip (80e5c6e, "Implement upward and downward swimming for vertically migrating zooplankton (NOAA-CEFI-Regional-Ocean-Modeling#177)") is a squash-merge whose content is byte-identical to what this branch already had prior to the dev/cefi merge (verified via `git diff 80e5c6e 6a6fb45` on the touched files, which is empty). All resulting conflicts here were the earlier zoo/prey identifier rename touching the same lines as that squash commit; resolved by keeping this branch's already-correct content. This merge exists to make 80e5c6e an ancestor so the push to cefi/dev/eco-cobalt is a fast-forward rather than requiring a force-push.
…merge feature/gz-cobalt-merge already carries an extended, generalized version of dev/eco-cobalt's DVM/named-parameter work (adding tunicate groups SMT and LGT, generic dvm_* tracking machinery keyed by zoo(n)%does_dvm instead of hardcoded vmmd_*/vmlg_* variables, and NUM_ZOO/NUM_PREY-wide loops that rely on cobalt_reg_diag registration rather than hardcoded group ranges). Almost every conflict was this branch's content being a superset of dev/eco-cobalt's; resolved by keeping this branch's version throughout, consistent with the guidance in TODO.eco-cobalt.md. One substantive (non-naming) difference was found and preserved: phi_det has been redefined on this branch from "fraction of ingestion routed to detritus" (dev/eco-cobalt, under a fixed 30% egestion budget) to "fraction of egested material routed to detritus" (this branch, consistent with the variable assim_eff Michaelis-Menten bioenergetics this branch already has and dev/eco-cobalt lacks) — the two are not numerically interchangeable, so dev/eco-cobalt's phi_det formulas/defaults were not merged in.
jessluo
force-pushed
the
feature/gz-cobalt-merge
branch
from
September 15, 2026 21:05
8a48f0b to
a5b7fb1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[WIP] Merge GZ-COBALT into eco-cobalt: gelatinous zooplankton with diel vertical migration
Merges the two generations of COBALT development into a single "ecologically heavy" model: COBALTv3 + diel vertical migration (COBALT-DVM, now in
dev/eco-cobalt) gains the two tunicate groups, food-dependent assimilation efficiency, and fast-sinking iron detritus from GZ-COBALT, with the large tunicates both migrating vertically and producing fast-sinking fecal pellets. This work was done with assistance from Claude Opus 5.Base:
dev/eco-cobalt· Diff: +2,868 / −1,230 across 4 files · 4 commitsdev/eco-cobaltis currently 1 commit ahead (15e766d, thejmetabo_ndiagnostic fix) — see Follow-ups.Background
Two lines of COBALT development needed reconciling:
dev/eco-cobalt— COBALTv3 (4 phytoplankton, 3 zooplankton, fast-sinking N and P detritus) plus Mathieu Poupon's diel vertical migration work, which added two vertically migrating zooplankton groups (vmmdz,vmlgz) carrying gut and metabolite pools.The merge target is 7 zooplankton groups in which large tunicates migrate and short-circuit the biological pump via dense fecal pellets and salp falls.
Design decisions
SMZ=1, MDZ=2, LGZ=3, VMMDZ=4, VMLGZ=5, SMT=6, LGT=7zoo%does_dvmlogicalphi_*become fractions of egestion summing to 1.0, not fractions of total ingestion.phi_det_si, no AE factor)phi_arespphi_nh4/phi_po4and fast-sinking Si were left out as out of scope.mesozoo_200scopetunicate_200.The AE ↔ gge_max equivalence
Worth recording, because it governs how the legacy groups behave. GZ's metabolism reduces exactly to
COBALTv3's when AE is constant:
The defaults
AE = 0.7,phi_aresp = 0.3therefore reproduce the previousgge_max = 0.4forsmz/mdz/lgz. The two formulations still differ in one respect — see Answer changes.
What changed
cobalt_types.F90NUM_ZOO5 → 7,NUM_PREY11 → 13.SMZ…LGTandPREY_DIAZO…PREY_DET, replacing bare numeric indices throughout.does_dvm,agg,frac_fast_det,ipa_smt,ipa_lgt, plusjaggloss_n/pandjprod_{n,p,fe}det_fastarrays and their diagnostic ids.generic_COBALT_typegains thefedet_fastfamily, tunicate tendency/pointer members, andjprod_tunicate_200/f_tunicate_200.Ecology (
generic_COBALT.F90)food1/food2switching idiom withnamed prey indices. Tunicates enter the carnivory side of switching for mdz/lgz/vmmdz/vmlgz and are
added to higher-predator switching (smt with the medium size class, lgt with the large).
frac_fast_detsplitting detritus between the standard and fast-sinking pools. Migrating groups still route
egestion through gut clearance rather than directly from ingestion.
agg, quadratic, no stress dependence) routed entirely to thefast-sinking pools. Required adding
zoo%aggandzoo%jaggloss_n/pto the v3 zooplankton type,which had no zooplankton aggregation at all.
dvm_prey_wgtmask, soLGT migrates. Gated on
does_dvmthroughout.fedet_fastend to end: production from zooplankton and higher-predatoregestion,
jfe_ads_fastscavenging (with the half-the-available-iron limiter shared across bothdetrital pools so they compete for the same dissolved pool),
jremin_fedet_faston the fast Npool's own specific rate, source/sink assembly, and bottom flux.
fedet_fastand the LGT gut pools to Feand Si.
Diagnostics
85 new registered fields: full SMT and LGT sets mirroring vmLgz, per-group aggregation and
fast-detritus production (registered in a loop rather than group by group), the fast-iron fluxes, and
jprod_tunicate_200/tunicate_200ported from GZ-COBALT as the JeDI-comparable counterparts to theCOPEPOD-comparable mesozoo pair.
Pre-existing bugs found and fixed
These were latent on
dev/eco-cobaltand are unrelated to the tunicates, but had to be resolved tomake the merge coherent.
1.
zoo%assim_effwas computed but never used. It was calculated each timestep and registered asa diagnostic, but no flux consumed it — the maths still used a static
1 − phi_det − phi_ldon − phi_sldon − phi_srdon. This is why thephi_*rescaling and the egestionrewrite had to land together rather than as separable steps.
2. Seven zooplankton parameters were declared and read but never initialized:
k_clear_gut,k_temp_gut,k_clear_met,assim_eff_max,assim_eff_min,kae,phi_aresp. The first threedrive the live gut/metabolite path, so
vmmdzandvmlgzwere integrating on uninitialized memory.All seven are now registered. Gut evacuation constants use the values from the COBALTv2-DVM code these
routines descend from (Poupon et al. 2024):
k_clear_gut = 8.0 day⁻¹,k_temp_gut = 4.32 day⁻¹ °C⁻¹,k_clear_met = 1.0 day⁻¹.3. Sixty unguarded accesses to migrator-only arrays.
does_dvmguards the allocation of the 21gut and metabolite arrays, but accesses in three clusters — tracer fetches,
vmovesetters, andtendency assembly — sat outside any guard. Benign on
dev/eco-cobalt, where migration was notswitchable; fatal once it became a parameter. Now guarded per group.
Adaptations required by the convention change
Calcite and aragonite production.
jprod_cadet_arag/jprod_cadet_calcusedzoo%phi_detdirectly as "the proportion of consumed material that ends up as detritus" — correct while
phi_detwas a fraction of ingestion. Under the new convention it needed
(1 − AE)·phi_det; without thatchange calcite production would have roughly tripled.
Answer changes
Expected, and not a regression: the legacy groups will not reproduce
dev/eco-cobaltbit-for-bit even with tunicates switched off. The unified scheme applies N/P colimitation as
min(I_N, I_P/q)up front, whereas v3 applied a phosphorus cap after computing production. Smalldrift is expected; large drift means something else is wrong.
jprod_mesozoo_200andf_mesozoo_200now include the migrating crustacean groups (fromdev/eco-cobalt), so both rise relative to pre-merge runs.Gut residence times shorten in warm water relative to the WIP commit's initial Dam & Peterson
estimate: the two forms cross near 4.5 °C, and at 20 °C the adopted values give ~94 vs ~64 day⁻¹
(≈15 vs ≈22 min), which weakens active transport in the tropics and subtropics.
New model interface
9 prognostic tracers:
nsmt,nlgt,nlgt_gut,plgt_gut,felgt_gut,silgt_gut,nlgt_met,fedet_fast,fedet_fast_btf.146 new namelist parameters, chiefly: full trait sets for
smtandlgt;assim_eff_max,assim_eff_min,kae,phi_aresp,agg,frac_fast_det,does_dvm, and the three gut/metabolitekinetic constants for all seven groups; 26 new innate prey availabilities.
Restart compatibility: the new tracers are prognostic and
TRACERS_MAY_REINITdefaults to.false., so restarting from a pre-merge restart file is a fatal error. Cold-starting fromGENERIC_TRACER_IC_FILEis the supported path. Note thatnsmtandnlgtneed non-zero valuesin that file: zero biomass is an absorbing state, since ingestion and basal respiration both carry
zoo%f_nas a multiplicative factor, so they would remain identically zero for the whole run. Thegut, metabolite and
fedet_fastpools are fine starting at zero.Configuration notes
does_dvmmay only be enabled forvmmdz,vmlgzandlgt— the three groups that own gut andmetabolite tracers. Enabling it elsewhere is now rejected at initialization with an explicit message
rather than dying later with an opaque nitrogen imbalance.
Switching it off is fully supported and enables two useful sensitivity experiments:
swim_max_lgt = 0.0does_dvm_lgt = .false.andswim_max_lgt = 0.0Both settings are needed for the second: the non-migrating branch still derives a swimming speed from
swim_max, andnlgtcarriesmove_vertical, so LGT would otherwise still oscillate vertically withnone of the gut machinery.
Tracer registration is deliberately not conditional on
does_dvm, so the tracer list — and hencerestart file contents — stays identical between the migrating and non-migrating configurations, which
is what makes them directly comparable.
Testing status
Done: all four modified files pass
gfortran -fsyntax-only, andgeneric_COBALT.F90compiles at-O1 -Wall, against throwaway stub modules for the twelve FMS/MOM6 dependencies. This validates blockstructure, every variable and derived-type component name, and array ranks across the whole diff,
including the programmatically generated diagnostic and ingestion blocks. A warning comparison against
dev/eco-cobaltunder identical stubs shows no new warnings. Thedoes_dvmguarding commit wasadditionally verified to be pure gating: a line-by-line comparison ignoring comments and whitespace
confirms zero code lines removed or reordered, so the default configuration is unchanged.
Not done — this has never been built against real FMS/MOM6, and has never been run. The stub check
cannot catch argument disagreement with real FMS interfaces.
Suggested sequence:
imax_smt = imax_lgt = 0) anddo_fastsinking = .true.. Sincethe merge altered the egestion and production maths for all seven groups, this separates "did the
refactor break the existing model?" from "do the new groups behave?" The pre/post N, P, C, Fe and Si
conservation checks in
generic_COBALT_update_from_sourceare the primary test — they callmpp_error(FATAL, …)pastimbalance_tolerance, so a run that survives them exercises nearly allthe new flux routing.
jprod_ndet_fast_Lgt, and a diel cycle invmove_Lgtmatching vmmdz/vmlgz.jfe_ads_fastandjremin_fedet_fastare non-zero and the Fe budget still closes.Known limitations and follow-ups
into a different food web. They are a starting point, not a calibration.
k_clear_gut/k_temp_gutare the crustaceannumbers. Salp gut passage differs, and since LGT both migrates and produces the fast-sinking
pellets, these directly control how much salp flux reaches depth. Flagged in-code as retuning
candidates.
bresp×0.9 for migrators. Poupon's COBALTv2-DVM scaled migrator basal respiration to 90% ofthe resident equivalent, presumably because the DVM path adds a swimming cost on top.
eco-cobaltcarries the unscaled values. Unresolved: port bug or deliberate?
inconsistent in places. Harmless — every array is now allocated for every group, so a mismatch costs
a missing-value field rather than a crash — but worth a tidy-up pass.
gge_maxis still registered but no longer used for zooplankton. Left in place with a commentrather than removed, to avoid breaking existing parameter files.
dev/eco-cobaltis 1 commit ahead (15e766d,jmetabo_n). Should merge cleanly; the send itadds is guarded on numeric group indices and should become
does_dvmhere so LGT is included.Commits
9b8811ffedet_fast, salp falls, generalized DVM, mass balance. ~2,700 lines.946acbbdev/eco-cobalt. Resolves themesozoo_200and deallocation-guard conflicts; fixes a 100 m allocated-vs-registered mismatch introduced by9b8811f; ports the tunicate 200 m diagnostics.7cf40b6e934fc1does_dvma valid off-switch: guard the three access clusters, reject unsupported configurations, correct a misleading comment.