Skip to content

Updated minimum intake of lactating and dry cows to literature-based bound#2793

Open
tomhuhh wants to merge 58 commits intodevfrom
refine-minimum-dry-dmi
Open

Updated minimum intake of lactating and dry cows to literature-based bound#2793
tomhuhh wants to merge 58 commits intodevfrom
refine-minimum-dry-dmi

Conversation

@tomhuhh
Copy link
Collaborator

@tomhuhh tomhuhh commented Mar 2, 2026

This PR
(1) updates the RuFaS-wide minimum dry matter intake (DMI) bound for lactating and dry cows (clipping mechanism; temporarily in manure_excretion_calculator.py, until clipping is moved to the DMI prediction stage);
(2) adds a manure-excretion warning message in the log when the predicted DMI (post-clipping) falls below the empirical domain of the underlying manure equations to address the request in #434, without affecting manure calculations.

Context

Issue(s) closed by this pull request: closes #434

What

  • Update RuFaS-wide minimum DMI constants for lactating and dry cows (AnimalModuleConstants.MINIMUM_DMI_LACT, MINIMUM_DMI_DRY) to literature-based values (literature-average / dataset-minimum used in the referenced equations) to provide a consistent global lower bound on intake. This constraint is temporarily located in manure_excretion_calculator.py to prevent calculation errors, and future implementation (Review and define pen-level DMI bounds (calves/heifers/dry/lact) for future RuFaS updates #2832) will relocate this constraint to the whole model level (post DMI prediction).
  • Add a manure-excretion warning: in ManureExcretionCalculator, emit a warning when the pen-level predicted DMI used for manure excretion falls below the equation-specific literature bound for that animal class (lact vs dry). The warning reports predicted vs effective (clipped) DMI and clipping frequency (warn-once with running counters) so users are aware of the percentage of downstream manure VS/N predictions that are calculated with DMI outside the equation-specific literature bound.

Why

  • Literature datasets used to derive the excretion equations do not fully cover extremely low DMI cases; warnings provide more confidence and defensibility to RuFaS outcomes.
  • To address these, in this PR, we modified minimum DMI bounds for manure excretion to prevent calculation errors, and temporarily kept this logic inside manure_excretion_calculator.py. We also added more permanent tracking and logging of instances where RuFaS-predicted DMI (after clipping to the global minimum) falls outside the range of DMI values used to develop the VS excretion equation.

How

  • Update RuFaS-wide minimum DMI constants for lactating and dry cows

    • Set AnimalModuleConstants.MINIMUM_DMI_LACT and AnimalModuleConstants.MINIMUM_DMI_DRY to literature-based values used as the model-wide lower bound for intake.
    • Add AnimalModuleConstants.MINIMUM_DMI_LACT_FOR_MANURE_VS and AnimalModuleConstants.MINIMUM_DMI_DRY_FOR_MANURE_VS for the warning message set-up
  • Add a manure-excretion warning

    • Add a small helper (e.g., _track_and_warn_dmi_clip) that:
      • triggers only when dmi_predicted < MINIMUM_DMI_*FOR_MANURE_VS,
      • logs a warning via OutputManager.add_warning(...)

Test plan

  1. Create a minimal output-filter JSON (VS excretion for LAC_COW + DRY_COW, plus housing/storage/total manure CH4).
  2. Run example freestall scenario on dev and export only those variables.
  3. Fetch + checkout PR Updated minimum intake of lactating and dry cows to literature-based bound #2793, run same scenario + filter.
  4. Compare annual totals (last 365 d) for lactating & dry-cow VS excretion and total manure CH4 (and by housing/storage) between branches.
  5. Check if there is any warnings in the log file.

Input Changes

• N/A

Output Changes

  • N/A

Filter

{
  "multiple": [
    {
      "name": "Total milk (kg; last 365 d)",
      "filters": ["AnimalModuleReporter.report_herd_statistics_data.daily_milk_production"],
      "vertical_aggregation": "sum",
      "slice_start": -365
    },

    {
      "name": "Milking cows (avg over last 365 d)",
      "filters": ["AnimalModuleReporter.report_daily_animal_population.num_lactating_cows"],
      "vertical_aggregation": "average",
      "slice_start": -365
    },
    {
      "name": "Close-up animals (avg over last 365 d)",
      "filters": ["AnimalModuleReporter.report_daily_animal_population.num_(heiferIIIs|dry_cows)"],
      "vertical_aggregation": "average",
      "horizontal_aggregation": "sum",
      "slice_start": -365
    },

    {
      "name": "LAC DMI total (kg/day) avg over last 365 d",
      "filters": ["AnimalModuleReporter.report_daily_ration_per_pen.ration_daily_feed_totals_.*_LAC_COW"],
      "variables": ["dry_matter_intake_total"],
      "vertical_aggregation": "average",
      "horizontal_aggregation": "sum",
      "slice_start": -365
    },
    {
      "name": "LAC DMI total (kg/day) SD over last 365 d",
      "filters": ["AnimalModuleReporter.report_daily_ration_per_pen.ration_daily_feed_totals_.*_LAC_COW"],
      "variables": ["dry_matter_intake_total"],
      "vertical_aggregation": "SD",
      "horizontal_aggregation": "sum",
      "slice_start": -365
    },

    {
      "name": "CLOSE_UP DMI total (kg/day) avg over last 365 d",
      "filters": ["AnimalModuleReporter.report_daily_ration_per_pen.ration_daily_feed_totals_.*_CLOSE_UP"],
      "variables": ["dry_matter_intake_total"],
      "vertical_aggregation": "average",
      "horizontal_aggregation": "sum",
      "slice_start": -365
    },
    {
      "name": "CLOSE_UP DMI total (kg/day) SD over last 365 d",
      "filters": ["AnimalModuleReporter.report_daily_ration_per_pen.ration_daily_feed_totals_.*_CLOSE_UP"],
      "variables": ["dry_matter_intake_total"],
      "vertical_aggregation": "SD",
      "horizontal_aggregation": "sum",
      "slice_start": -365
    },

    {
      "name": "LAC DMI per cow (kg/cow/d) avg (approx)",
      "cross_references": [
        "LAC DMI total \\(kg/day\\) avg over last 365 d_ver_hor_agg.*",
        "Milking cows \\(avg over last 365 d\\)_ver_agg.*"
      ],
      "horizontal_aggregation": "division",
      "horizontal_order": [
        "LAC DMI total \\(kg/day\\) avg over last 365 d_ver_hor_agg.*",
        "Milking cows \\(avg over last 365 d\\)_ver_agg.*"
      ]
    },
    {
      "name": "LAC DMI per cow (kg/cow/d) SD (approx)",
      "cross_references": [
        "LAC DMI total \\(kg/day\\) SD over last 365 d_ver_hor_agg.*",
        "Milking cows \\(avg over last 365 d\\)_ver_agg.*"
      ],
      "horizontal_aggregation": "division",
      "horizontal_order": [
        "LAC DMI total \\(kg/day\\) SD over last 365 d_ver_hor_agg.*",
        "Milking cows \\(avg over last 365 d\\)_ver_agg.*"
      ]
    },

    {
      "name": "CLOSE_UP DMI per animal (kg/animal/d) avg (approx)",
      "cross_references": [
        "CLOSE_UP DMI total \\(kg/day\\) avg over last 365 d_ver_hor_agg.*",
        "Close-up animals \\(avg over last 365 d\\)_ver_hor_agg.*"
      ],
      "horizontal_aggregation": "division",
      "horizontal_order": [
        "CLOSE_UP DMI total \\(kg/day\\) avg over last 365 d_ver_hor_agg.*",
        "Close-up animals \\(avg over last 365 d\\)_ver_hor_agg.*"
      ]
    },
    {
      "name": "CLOSE_UP DMI per animal (kg/animal/d) SD (approx)",
      "cross_references": [
        "CLOSE_UP DMI total \\(kg/day\\) SD over last 365 d_ver_hor_agg.*",
        "Close-up animals \\(avg over last 365 d\\)_ver_hor_agg.*"
      ],
      "horizontal_aggregation": "division",
      "horizontal_order": [
        "CLOSE_UP DMI total \\(kg/day\\) SD over last 365 d_ver_hor_agg.*",
        "Close-up animals \\(avg over last 365 d\\)_ver_hor_agg.*"
      ]
    },

    {
      "name": "LAC manure VS (kg/yr; last 365 d)",
      "filters": ["AnimalModuleReporter.report_manure_excretions.LAC_COW_.*_volatile_solids"],
      "vertical_aggregation": "sum",
      "horizontal_aggregation": "sum",
      "horizontal_first": false,
      "slice_start": -365
    },
    {
      "name": "Close-up (incl dry cows) manure VS (kg/yr; last 365 d)",
      "filters": ["AnimalModuleReporter.report_manure_excretions.CLOSE_UP_.*_volatile_solids"],
      "vertical_aggregation": "sum",
      "horizontal_aggregation": "sum",
      "horizontal_first": false,
      "slice_start": -365
    },

    {
      "name": "Total housing manure CH4 (kg/yr; last 365 d)",
      "filters": ["Manure.SingleStreamHandler.*housing_methane_emissions"],
      "vertical_aggregation": "sum",
      "horizontal_aggregation": "sum",
      "horizontal_first": false,
      "slice_start": -365
    },
    {
      "name": "Total storage manure CH4 (kg/yr; last 365 d)",
      "filters": ["Manure.Storage.*storage_methane$", ".*methane_leakage_mass"],
      "vertical_aggregation": "sum",
      "horizontal_aggregation": "sum",
      "horizontal_first": false,
      "slice_start": -365
    }
  ]
}

tomhuhh and others added 4 commits March 2, 2026 13:42
Import OutputManager and add lightweight DMI clipping telemetry to ManureExcretionCalculator.

Introduces class-level counters and a _track_and_warn_dmi_clip static method that records total/below-min/clipped counts per animal kind (lact/dry), emits a single aggregated warning per kind via OutputManager.add_warning, and raises on unexpected kinds.

Functions calculate_lactating_cow_manure and calculate_dry_cow_manure now preserve the original dry_matter_intake in dry_matter_intake_original, apply the existing minimum DMI clipping, and call the tracker with context information.

This reduces log spam while providing cumulative diagnostics about DMI clipping behavior.
@github-actions github-actions bot force-pushed the refine-minimum-dry-dmi branch from 8665d4a to 5594c26 Compare March 2, 2026 19:17
@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

Current Coverage: 99%

Mypy errors on refine-minimum-dry-dmi branch: 1684
Mypy errors on dev branch: 1684
No difference in error counts

@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

🚨 Please update the changelog. This PR cannot be merged until changelog.md is updated.

tomhuhh and others added 5 commits March 2, 2026 14:24
Remove the separate n_below_min counter and simplify DMI clipping logic in ManureExcretionCalculator.

Warnings are now emitted only when clipping is applied (dmi < floor), at most once per animal class, and the warning text/label was updated ("minimum floor" → "literature minimum" and warning title changed).

The cumulative message now reports only clipped counts and the _dmi_clip_stats entries drop the n_below_min field.
@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

Current Coverage: 99%

Mypy errors on refine-minimum-dry-dmi branch: 1686
Mypy errors on dev branch: 1684
2 more errors on refine-minimum-dry-dmi branch

@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

🚨 Please update the changelog. This PR cannot be merged until changelog.md is updated.
🚨 Flake8 linting errors were found. Please fix the linting issues.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Current Coverage: 99%

Mypy errors on refine-minimum-dry-dmi branch: 1686
Mypy errors on dev branch: 1684
2 more errors on refine-minimum-dry-dmi branch

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

🚨 Please update the changelog. This PR cannot be merged until changelog.md is updated.
🚨 Flake8 linting errors were found. Please fix the linting issues.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Current Coverage: 99%

Mypy errors on refine-minimum-dry-dmi branch: 1686
Mypy errors on dev branch: 1684
2 more errors on refine-minimum-dry-dmi branch

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

🚨 Please update the changelog. This PR cannot be merged until changelog.md is updated.
🚨 Flake8 linting errors were found. Please fix the linting issues.

@tomhuhh
Copy link
Collaborator Author

tomhuhh commented Mar 3, 2026

To evaluate the PR, I went through 2 series of tests:

  1. I set the 'annual_milk_yield' variable in the animal.json file as 10% of the baseline production, at 131,420 kg/yr. The resulted DMI for lactating cows was 16.5 (+/- 0.59) kg/d per cow. This is way higher than the literature-based bound, at 3.94 kg/d per cow.

Given that the DMI of lactating cows has such as narrow variation, in normal scenarios, it would be unlikely for it to drop below 3.94 kg/d per cow, and similarly for dry cows.

  1. I applied a temporary code switch that multiplies DMIest by a factor (e.g., 0.2) for the stress run. This resulted in different production and environmental outcomes.

dev + stress (factor=0.2):

• LAC manure VS: 30,990 kg/yr
• CLOSE_UP manure VS: 7,207 kg/yr
• Housing CH₄: 333 kg/yr
• Storage CH₄: 3,153 kg/yr

PR #2793 + stress (factor=0.2):

• LAC manure VS: 31,084 kg/yr
• CLOSE_UP manure VS: 12,549 kg/yr
• Housing CH₄: 333 kg/yr
• Storage CH₄: 3,243 kg/yr

These results showed that PR #2793’s higher intake floors (3.94 lact, 7.1 dry) increase the clamped DMI compared to dev, especially for CLOSE_UP/dry cows → higher VS and slightly higher storage CH₄.

I also got the warning messages in output/logs as follows:

"Predicted DMI for manure excretion is below the literature minimum for dry cows (DMI=3.277 kg/d < 7.100 kg/d). Clipping applied to 7.100 kg/d. Cumulative so far: clipped 1/1 (100.0%)."

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Current Coverage: 99%

Mypy errors on refine-minimum-dry-dmi branch: 1686
Mypy errors on dev branch: 1684
2 more errors on refine-minimum-dry-dmi branch

@github-actions github-actions bot force-pushed the refine-minimum-dry-dmi branch from 884543d to a55e7ba Compare March 6, 2026 15:52
@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

Current Coverage: 99%

Mypy errors on refine-minimum-dry-dmi branch: 1426
Mypy errors on dev branch: 1424
2 more errors on refine-minimum-dry-dmi branch

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

🚨 Flake8 linting errors were found. Please fix the linting issues.

tomhuhh and others added 4 commits March 6, 2026 12:55
Wrap and tidy docstrings for DMI-related constants in RUFAS/biophysical/animal/animal_module_constants.py (MINIMUM_DMI_LACT, MINIMUM_DMI_DRY, MINIMUM_DMI_HEIFER, MINIMUM_DMI_CALF, MINIMUM_DMI_LACT_FOR_MANURE_VS, MINIMUM_DMI_DRY_FOR_MANURE_VS). Adjusted line breaks and removed trailing whitespace for consistency; no functional changes.
@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

Current Coverage: 99%

Mypy errors on refine-minimum-dry-dmi branch: 1426
Mypy errors on dev branch: 1424
2 more errors on refine-minimum-dry-dmi branch

dry_matter_intake = nutrient_amounts.dry_matter
dmi_predicted = nutrient_amounts.dry_matter
dry_matter_intake = dmi_predicted
dry_matter_intake = max(dry_matter_intake, AnimalModuleConstants.MINIMUM_DMI_LACT)
Copy link
Contributor

@elle-andreen elle-andreen Mar 6, 2026

Choose a reason for hiding this comment

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

I'm not sure if I misunderstood where we landed in discussing the global vs. literature minimums, but my thought here is if we've set a global minimum for DMI and the predicted DMI is below that, we should not be clipping DMI for manure excretion and instead should be returning an error. The same applies to dry cows below.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hi @elle-andreen! Great point here.

After checking with @KFosterReed this morning, we decided to leave the clipping logic inside the manure excretion calculator for now and remove it when we implement the clipping logic where DMI is predicted.

The clipping unlikely changes any downstream results given how low these MINIMUM values are.

That said, I could not recall what was decided for the error messages when predicted DMI is below average literature minimum (and if there will be any error messages). I have recorded my notes from the other day in #434. I agree with you that we could implement an error message if the predicted DMI is below average literature minimum, and I can draft an issue for it but that will be in a separate PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If we want absolutely no risks of changing model behavior, I can set the values of MINIMUM_DMI_LACT and MINIMUM_DMI_DRY as 2 kg/d per cow in this PR and leave animal type-specific minimum DMI values to be updated in issue #2832.

Comment on lines +74 to +76
floor = AnimalModuleConstants.MINIMUM_DMI_LACT_FOR_MANURE_VS
else:
floor = AnimalModuleConstants.MINIMUM_DMI_DRY_FOR_MANURE_VS
Copy link
Contributor

Choose a reason for hiding this comment

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

This is very confusing to me. We're providing a warning and stats about clipping DMI, including a floor value, but the floor given here is not actually what we're clipping the DMI value to. We're warning the user that DMI is < 7.1 but not informing the user that we've clipped DMI to 6.06 or 3.6, not 7.1 kg. I also see in #2835 that the documentation was updated to list the lower bound as 7.1 kg. Is this the intended behavior?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hello @elle-andreen!

Yes—the intent is to provide a warning when the predicted DMI (post-clipping) falls below the equation-based lower bound, while still allowing the simulation to continue (this was the original request in #434). The log message is meant to inform users that manure VS is being calculated using a % of DMI that is below the equation bounds.

The clipping logic currently remains in the manure excretion calculator temporarily. As mentioned in my previous response, it will need to be removed once the clipping logic is implemented at the DMI prediction step, as documented in issue #2832.

To summarize, there are two types of minimum DMI thresholds:

  1. Universal minimum DMI – currently implemented through clipping in the manure excretion calculator (temporarily, until clipping is moved to the DMI prediction stage).
  2. Equation-specific minimum DMI – does not affect calculations; it only triggers a warning message in the log when the predicted DMI (post-clipping) falls below the equation bounds.

I hope this clarifies. Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks Haowen. I think it's the order of operations here (i.e. what is happening in this PR vs. what is intended to happen long term) that is making this confusing. I would definitely recommend including components of your comment above in the PR description as appropriate, the description reads as if RuFaS-wide DMI bounds are fully implemented in this PR. The 'why' in the PR description being more specific to what is actually happening here would also be helpful for clarity (i.e., adding temporary minimum DMI bounds for manure excretion to prevent calculation errors, and adding more permanent tracking and logging of instances where RuFaS-predicted DMI (after clipping to the global minimum) falls outside the range of DMI values used to develop the VS excretion equation).

Ignoring the clipping portion that will be changing in the future, this looks good to me otherwise! My only remaining suggestion would be to update the docstring for _track_and_warn_dmi_clip to be a little more detailed. I see Niko left some suggestions, I am happy to test this PR on my end once the changes are finalized.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hi Elle — I updated the PR description to clarify that we’re temporarily placing the RuFaS-wide minimum DMI within manure_excretion_calculator.py. I also expanded the helper’s docstring and renamed _track_and_warn_dmi_clip to _track_and_warn_dmi_threshold to avoid implying we modify DMI. Let me know if you have further feedback on this PR. Thanks!

Copy link
Collaborator

@ew3361zh ew3361zh left a comment

Choose a reason for hiding this comment

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

Nice work here Haowen. I left some initial feedback this first round since it looks like there is some conversation still happening on the scientific side. My general feedback would be to keep things simple and within the context of abstraction - only create helper functions/classes/custom typing for things needed in multiple uses/contexts. If it's a one-time use, it's probably fine to just type it using the existing datatypes. And use the existing nomenclature whenever possible - (e.g. use info_maps instead of context).

Comment on lines +29 to +31
@staticmethod
def _safe_pct(n: int, d: int) -> float:
return (100.0 * n / d) if d else 0.0
Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably not necessary to create a function here as it looks like it's only used in a warning message. If it's really necessary to check this, I'd do it within the emit_dmi_below_min_summary() method.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point, Niko — I removed _safe_pct and compute the percentage inline in emit_dmi_below_min_summary() since it’s only used there.

Comment on lines +47 to +48
dmi_predicted : float
Predicted DMI before clipping (kg/day).
Copy link
Collaborator

Choose a reason for hiding this comment

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

If this isn't needed in the function, you can leave it out.

Comment on lines +51 to +52
context : dict[str, Any]
info_map-like context for OutputManager warnings.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same with this, it's unreferenced in the function so it's likely unnecessary to have it as a function arg.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch, Niko for the last two comments — I removed dmi_predicted and context since they weren’t used, and updated the call sites and docstring accordingly.

stats["n_below_min"] += 1

@staticmethod
def emit_dmi_below_min_summary(context: dict[str, Any]) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there a reason to not call this arg info_map? It would be more consistent with other use in RUFAS.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks Niko! I updated to info_map for consistency with other OutputManager calls across RUFAS.

tomhuhh and others added 11 commits March 20, 2026 15:54
Rename the internal helper _track_and_warn_dmi_clip to _track_and_warn_dmi_threshold and update its docstring to clarify that it records occurrences where effective DMI falls below the literature minimum (tracked per herd type) and does not modify DMI values. Update call sites for lactating and dry DMI clipping to use the new name. No functional behavior changes, just naming and documentation improvements for clearer intent.
Remove the _DMIBelowMinStats TypedDict and the _DMI_KIND Literal type; replace with a plain dict[str, dict[str, int]] for _dmi_below_min_stats and use str for the kind parameter in _track_and_warn_dmi_threshold. Also drop unused typing imports (Final, Literal, TypedDict). No behavioral changes, just simplified type annotations.
Remove the _safe_pct static helper and inline the percentage calculation in _track_and_warn_dmi_threshold. The code now computes pct_below with a divide-by-zero guard and updates the warning message to use this local value. Small refactor to simplify the logic while preserving existing behavior.
Simplify ManureExcretionCalculator._track_and_warn_dmi_threshold by removing unused parameters dmi_predicted and context and updating its docstring. Update call sites in lactating and dry cow manure calculations to only pass kind and dmi_effective. This cleans up the API and removes redundant data passing while preserving the existing DMI threshold tracking logic.
Rename ManureExcretionCalculator.emit_dmi_below_min_summary parameter from `context` to `info_map` and forward `info_map` to OutputManager.add_warning. Update unit tests to match the internal rename from `_track_and_warn_dmi_clip` to `_track_and_warn_dmi_threshold`, adjust the test name, and update calls to the new method signature.
@tomhuhh
Copy link
Collaborator Author

tomhuhh commented Mar 20, 2026

Hi @elle-andreen @ew3361zh — I believe I’ve addressed your review comments (PR description, naming, typing simplifications, docstring updates, and argument cleanup). The PR is updated and ready for another look. Thanks!

@github-actions
Copy link
Contributor

Current Coverage: 99%

Mypy errors on refine-minimum-dry-dmi branch: 1214
Mypy errors on dev branch: 1214
No difference in error counts

@github-actions
Copy link
Contributor

🚨 Please update the changelog. This PR cannot be merged until changelog.md is updated.

@github-actions
Copy link
Contributor

Current Coverage: 99%

Mypy errors on refine-minimum-dry-dmi branch: 1214
Mypy errors on dev branch: 1214
No difference in error counts

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.

Low Intake Warning for Dry Cows

4 participants