[Animal] Fix DIM=1 Skipped - #3206
Open
allisterakun wants to merge 7 commits into
Open
Conversation
Contributor
|
Current Coverage: 99% Mypy errors on skip_dim_1 branch: 1137 |
Contributor
|
🚨 Please update the changelog. This PR cannot be merged until |
Contributor
|
Current Coverage: 99% Mypy errors on skip_dim_1 branch: 1137 |
Contributor
|
🚨 Please update the changelog. This PR cannot be merged until |
allisterakun
marked this pull request as ready for review
August 18, 2026 15:17
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.
Fixes the off-by-one error where cow milking history skipped DIM = 1 on calving day, causing every lactation's first record to start at DIM = 2 instead of DIM = 1.
Context
Issue(s) closed by this pull request: closes #3021.
What
_is_calving_today()method toAnimal— returnsTruewhen the cow is dry (days_in_milk == 0), pregnant, anddays_in_pregnancy == gestation_length, indicating that the reproduction update later in the routine will start a new lactation.just_calved: bool = Falsefield toMilkProductionInputsdataclass, with documentation explaining it bridges the ordering gap between milking and reproduction updates.Animal.daily_milking_update()to passjust_calved=self._is_calving_today()in theMilkProductionInputsconstructor.record_first_day_in_milk(days_born, time)method toMilkProduction— computes milk production at DIM = 1 using Wood's curve, generates the daily milk variance, calculates nutrient contents (crude protein, true protein, fat, lactose), and writes a DIM = 1 record to the milking history.perform_daily_milking_update()inMilkProduction— whenis_milkingisFalsebutjust_calvedisTrue, callsrecord_first_day_in_milk()and returns early instead of writing a dry-day record.perform_daily_milking_update()andperform_daily_milking_update_without_history()— changedcalculate_daily_milk_productionto usemilk_production_outputs.days_in_milk(the already-incremented value) instead ofmilk_production_inputs.days_in_milk, fixing the one-day rightward shift between the Wood's curve index and the DIM label.Animal.transition_heiferIII_to_cow()to callself.milk_production.record_first_day_in_milk(self.days_born, time)after setting Wood parameters, so that heifers transitioning to cows also get a DIM = 1 record on the calving day.test_is_calving_todaycovering: dry cow at end of gestation (True), dry cow not yet at gestation length (False), dry non-pregnant (False), and still-lactating at end of gestation (False).test_daily_milking_update_passes_just_calved_flagverifying the flag is forwarded to the milking update.test_perform_daily_milking_update_records_dim_1_when_just_calvedverifying thatrecord_first_day_in_milkis called whenjust_calved=Trueandis_milking=False.test_record_first_day_in_milkverifying production is computed at DIM = 1, nutrient contents are refreshed, and a single DIM = 1 history record is appended.test_transition_heiferIII_to_cowto mock and assertrecord_first_day_in_milkis called.Why
The root cause was an ordering dependency in
Animal.daily_routines: the milking update ran before the reproduction update. On the calving day, the cow entered withdays_in_milk = 0(still dry). The milking update sawis_milking = Falseand wrote a dry-day record (DIM = 0). Then the reproduction update detected the birth and setdays_in_milk = 1. The next simulation day, milking ran with input DIM = 1, incremented to 2, and wrote the first real production record stamped DIM = 2. This meant DIM = 1 never appeared in the milking history, the Wood's curve was evaluated at the wrong DIM values throughout the lactation, and only 304 records were written instead of 305.How
Rather than reordering the daily routines (which could have other ordering dependencies), the fix uses a look-ahead flag. The new
_is_calving_today()method checks whether the reproduction update will start a new lactation later in the routine. Thisjust_calvedflag is passed intoMilkProductionInputs. Inperform_daily_milking_update(), when the cow is not yet milking butjust_calvedisTrue, the method callsrecord_first_day_in_milk()to compute and record DIM = 1 production, then returns early — avoiding the dry-day record. Additionally, the Wood's curve input was corrected from the pre-incrementmilk_production_inputs.days_in_milkto the post-incrementmilk_production_outputs.days_in_milk, aligning the curve evaluation with the DIM label. For heiferIII-to-cow transitions,record_first_day_in_milkis called directly after setting Wood parameters.Test plan
test_is_calving_todaycovering all four branches (dry at gestation end, dry not at gestation end, dry non-pregnant, lactating at gestation end).test_daily_milking_update_passes_just_calved_flagverifying the flag reaches the milking inputs.test_perform_daily_milking_update_records_dim_1_when_just_calvedverifyingrecord_first_day_in_milkis called and output DIM stays 0.test_record_first_day_in_milkverifying production at DIM = 1, nutrient content refresh, and a single DIM = 1 history record.test_transition_heiferIII_to_cowto assertrecord_first_day_in_milkis called with correct arguments.Input Changes
Output Changes
Filter