Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
188 commits
Select commit Hold shift + click to select a range
8855e85
Initial changes
matthew7838 Oct 20, 2025
2b1d8e0
Updated properties
matthew7838 Oct 20, 2025
56133f9
Merge branch 'dev' into maintain-herd
matthew7838 Oct 21, 2025
d75e3b1
Working implementation
matthew7838 Oct 24, 2025
ddd13c5
Changes to track lactation predictions
matthew7838 Oct 28, 2025
16881ab
Merge branch 'dev' into maintain-herd
matthew7838 Nov 3, 2025
a0bb502
mvp
matthew7838 Nov 4, 2025
ac0a87b
MVP with correct reporting
matthew7838 Nov 4, 2025
86e4d67
Updated open lot inputs
matthew7838 Nov 4, 2025
f063d83
Updated changelog.md
matthew7838 Nov 4, 2025
16e954b
Cleared some mypy and updated original tests
matthew7838 Nov 5, 2025
a488e0c
Merge branch 'dev' into maintain-herd
matthew7838 Nov 5, 2025
8aca097
Fix for code factor error
matthew7838 Nov 5, 2025
30018e0
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Nov 5, 2025
3706b26
Combined predictions and improved naming
matthew7838 Nov 10, 2025
99e0163
Merge branch 'dev' into maintain-herd
matthew7838 Nov 10, 2025
26e610a
codefactor
matthew7838 Nov 10, 2025
c88a19b
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Nov 10, 2025
e4397df
Merge branch 'dev' into maintain-herd
matthew7838 Nov 12, 2025
ad37042
Merge branch 'dev' into maintain-herd
matthew7838 Nov 25, 2025
fb42f6c
Merge ad37042d9e45afa06a11dac7761b698e23f56edb into 6960daa64495e625e…
matthew7838 Nov 25, 2025
60d41a2
Apply Black Formatting
github-actions[bot] Nov 25, 2025
ba60e44
Update badges on README
matthew7838 Nov 25, 2025
9e4603f
checkout
matthew7838 Nov 25, 2025
37414b1
Changes to the comparison logic
matthew7838 Nov 26, 2025
caaa4b8
Merge 37414b13368178bae182bf1aa815ce2246038fbb into d51bbc26959b25d2c…
matthew7838 Nov 26, 2025
8066eb3
Apply Black Formatting
github-actions[bot] Nov 26, 2025
3c65eb7
Changes to the comparison logic
matthew7838 Nov 26, 2025
2976d43
Merge branch 'dev' into maintain-herd
matthew7838 Dec 1, 2025
1387fb3
Merge 2976d431504c7b85231b1d2c6b5e3b4f233e5ab0 into dfaf1f6d39ce10b66…
matthew7838 Dec 1, 2025
3f01e6f
Apply Black Formatting
github-actions[bot] Dec 1, 2025
f085873
Update badges on README
matthew7838 Dec 1, 2025
8210b1b
First fix
matthew7838 Dec 1, 2025
0efe3dc
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Dec 1, 2025
58c4d93
Merge 0efe3dcd2fba8540a79aba06f819a6a884847803 into dfaf1f6d39ce10b66…
matthew7838 Dec 1, 2025
f9da875
Apply Black Formatting
github-actions[bot] Dec 1, 2025
a6c4cec
Merge branch 'dev' into maintain-herd
matthew7838 Dec 9, 2025
ddcda7d
Merge a6c4cec581abf9939ad49fc5a6897cbf7a6f9560 into 0f70b6d6861cd656e…
matthew7838 Dec 9, 2025
b5cf1e4
Apply Black Formatting
github-actions[bot] Dec 9, 2025
eeb6135
Update badges on README
matthew7838 Dec 9, 2025
209a845
checkout
matthew7838 Dec 10, 2025
14f610f
Resolved failing seed issues
matthew7838 Dec 11, 2025
9a68586
Merge 14f610f28ccfac04d84f587546f5d185ddd5a69b into 0f70b6d6861cd656e…
matthew7838 Dec 11, 2025
81c374f
Apply Black Formatting
github-actions[bot] Dec 11, 2025
774713e
Update badges on README
matthew7838 Dec 11, 2025
44f3d21
updated properties
matthew7838 Dec 11, 2025
b6f4ebd
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Dec 11, 2025
4ddbd01
Merge b6f4ebdec6ef3576b64606f7dbba4706c6d1ca35 into 0f70b6d6861cd656e…
matthew7838 Dec 11, 2025
c70f11b
Apply Black Formatting
github-actions[bot] Dec 11, 2025
39cc88a
Merge branch 'dev' into maintain-herd
matthew7838 Dec 18, 2025
a1752a5
Merge 39cc88a9541de44c4a4d8724f5ac9da4dd782991 into 8aa77165b92c24e9c…
matthew7838 Dec 18, 2025
eeee541
Apply Black Formatting
github-actions[bot] Dec 18, 2025
8b0403e
Update badges on README
matthew7838 Dec 18, 2025
ffb3a7b
Merge branch 'dev' into maintain-herd
matthew7838 Jan 6, 2026
0a96168
Merge ffb3a7bf85a8d287f65adfd5734356dccad31708 into 92b62590bb2593321…
matthew7838 Jan 6, 2026
188c76b
Apply Black Formatting
github-actions[bot] Jan 6, 2026
16dcaca
Update badges on README
matthew7838 Jan 6, 2026
a59e024
Merge branch 'dev' into maintain-herd
matthew7838 Jan 20, 2026
30bbee7
Merge a59e024ac1f47d4708678119e9edd6f95b9dc6fb into 3d0cbe959bd89a064…
matthew7838 Jan 20, 2026
84d7fba
Apply Black Formatting
github-actions[bot] Jan 20, 2026
c824f88
Update badges on README
matthew7838 Jan 20, 2026
eb64291
Added required herd info modification
matthew7838 Jan 20, 2026
692b7d4
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Jan 22, 2026
a8a4507
Modified tests for cow selling logic
matthew7838 Jan 22, 2026
d2d6b28
Modified tests for cow selling logic
matthew7838 Jan 22, 2026
2e7303d
Merge branch 'dev' into maintain-herd
matthew7838 Jan 22, 2026
170ede6
Merge 2e7303d5ad03b640dc7b31e896edffe73c2fde13 into b7f2f16930bdbd538…
matthew7838 Jan 22, 2026
87c6828
Apply Black Formatting
github-actions[bot] Jan 22, 2026
17091fb
Update badges on README
matthew7838 Jan 22, 2026
f534bc2
Fixed flake8
matthew7838 Jan 23, 2026
0dd62e1
Merge branch 'dev' into maintain-herd
matthew7838 Jan 23, 2026
e349421
Merge 0dd62e1dca9e9187e30d51157f632f32aca41d75 into 1b1228e9bbfa982e7…
matthew7838 Jan 23, 2026
73c823c
Apply Black Formatting
github-actions[bot] Jan 23, 2026
a69ad12
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Jan 23, 2026
c7d5dd2
Removed unused lines
matthew7838 Jan 23, 2026
b8cccaa
Merge c7d5dd2b52d25620258c56cfa93faf158125d1a1 into 1b1228e9bbfa982e7…
matthew7838 Jan 23, 2026
81e7ff7
Apply Black Formatting
github-actions[bot] Jan 23, 2026
d5b90ba
Removed ME305
matthew7838 Jan 23, 2026
658160e
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Jan 23, 2026
af88c1b
Merge 658160e4c741119b3418009e9e13b98a060dc437 into 1b1228e9bbfa982e7…
matthew7838 Jan 23, 2026
7b423ee
Apply Black Formatting
github-actions[bot] Jan 23, 2026
5ca9b85
Removed ME305
matthew7838 Jan 23, 2026
ea70ed0
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Jan 23, 2026
495aaab
Merge ea70ed04363ee915463e61bcd083291c782bf19a into 1b1228e9bbfa982e7…
matthew7838 Jan 23, 2026
1ec06fc
Apply Black Formatting
github-actions[bot] Jan 23, 2026
6531f08
Update badges on README
matthew7838 Jan 23, 2026
1dcd0ad
Removed ME305
matthew7838 Jan 23, 2026
faf3268
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Jan 23, 2026
65e44ad
Merge faf32687df9db5c8b2c209c185dc07985bd40c74 into 1b1228e9bbfa982e7…
matthew7838 Jan 23, 2026
e3fd934
Apply Black Formatting
github-actions[bot] Jan 23, 2026
1ea5481
Removed ME305
matthew7838 Jan 23, 2026
4681fd7
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Jan 23, 2026
a47c6f8
Merge 4681fd7b9af1c14faeba6759564983c3902ca145 into 1b1228e9bbfa982e7…
matthew7838 Jan 23, 2026
0642c6b
Apply Black Formatting
github-actions[bot] Jan 23, 2026
68de240
Update badges on README
matthew7838 Jan 23, 2026
80f8e12
Fixed flake8
matthew7838 Jan 24, 2026
7984718
Merge 80f8e12c0aed3101d7e763921caca8b229d1286f into 1b1228e9bbfa982e7…
matthew7838 Jan 24, 2026
36812d0
Apply Black Formatting
github-actions[bot] Jan 24, 2026
064e23b
Update badges on README
matthew7838 Jan 24, 2026
22f2264
Fixed herd exit nums
matthew7838 Jan 28, 2026
0de79ad
Merge 22f2264fc2c7a5ccf617b0478edc63a1586fad07 into 1b1228e9bbfa982e7…
matthew7838 Jan 28, 2026
d772b1b
Apply Black Formatting
github-actions[bot] Jan 28, 2026
e78a58d
Removed old logic
matthew7838 Jan 28, 2026
417b437
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Jan 28, 2026
f5ef130
Merge 417b437f022d74687984bafe9e8577a59493a614 into 1b1228e9bbfa982e7…
matthew7838 Jan 28, 2026
7167ec5
Apply Black Formatting
github-actions[bot] Jan 28, 2026
0c25657
Merge branch 'dev' into maintain-herd
matthew7838 Feb 25, 2026
e90423b
Merge 0c2565744442cfef2af4bf522514f715cd1ec935 into 826c7d8d59f00ca1c…
matthew7838 Feb 25, 2026
919c331
Apply Black Formatting
github-actions[bot] Feb 25, 2026
e4892d1
Update badges on README
matthew7838 Feb 25, 2026
320021d
Merge branch 'dev' into maintain-herd
matthew7838 Feb 26, 2026
03dd948
Merge 320021d7b947daf068d9597c36227a446f006ed2 into a9c01952e978becb9…
matthew7838 Feb 26, 2026
1d15c54
Apply Black Formatting
github-actions[bot] Feb 26, 2026
fdff74a
Input changes
matthew7838 Feb 26, 2026
a798088
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Feb 27, 2026
cf4831f
All changes
matthew7838 Feb 27, 2026
983cbe8
Merge cf4831f394f72b472c553d0d08d67e034e658be5 into a9c01952e978becb9…
matthew7838 Feb 27, 2026
e45bab9
Apply Black Formatting
github-actions[bot] Feb 27, 2026
64633df
All changes
matthew7838 Mar 2, 2026
1fb04eb
Reducing mypy
matthew7838 Mar 2, 2026
98065fe
Merge 1fb04eba72261aa5ebd988505ebd7dda488d07db into a9c01952e978becb9…
matthew7838 Mar 2, 2026
c2d8100
Apply Black Formatting
github-actions[bot] Mar 2, 2026
1b1158c
Update badges on README
matthew7838 Mar 2, 2026
ae7113a
Merge branch 'dev' into maintain-herd
matthew7838 Mar 4, 2026
19fa7c7
Merge ae7113ae31bde755d61f047572a1e440229880b3 into 9c8b2bd6c40619bba…
matthew7838 Mar 4, 2026
5686041
Apply Black Formatting
github-actions[bot] Mar 4, 2026
5458ac9
Merge branch 'dev' into maintain-herd
matthew7838 Mar 9, 2026
11b1658
Merge 5458ac90407d278fa182ee09157b9e11410bcde8 into 84b364221cc411053…
matthew7838 Mar 9, 2026
43e11e1
Apply Black Formatting
github-actions[bot] Mar 9, 2026
d68be91
Merge branch 'dev' into maintain-herd
matthew7838 Mar 9, 2026
b6ca016
Merge d68be9127bf201d7ed31bbe934b706c7c83f870d into 82d90af580b955d3f…
matthew7838 Mar 9, 2026
4002e3d
Apply Black Formatting
github-actions[bot] Mar 9, 2026
273e86d
Update input/metadata/properties/default.json
matthew7838 Mar 10, 2026
0324bae
Merge 273e86d23997f5efa4e018ab770ef303bc26c43a into 82d90af580b955d3f…
matthew7838 Mar 10, 2026
5975eb8
Apply Black Formatting
github-actions[bot] Mar 10, 2026
c5cf711
Merge branch 'dev' into maintain-herd
matthew7838 Mar 11, 2026
f743a1d
Merge c5cf711d351262c04c446f5d8e290be20d8ddf58 into 81112aff00f30f568…
matthew7838 Mar 11, 2026
3f353f0
Apply Black Formatting
github-actions[bot] Mar 11, 2026
d0a9cdf
Addressed Niko's comments
matthew7838 Mar 11, 2026
3c6c8bf
Merge d0a9cdfd2010307770c13435464781a3a3a6955c into 81112aff00f30f568…
matthew7838 Mar 11, 2026
d89a142
Apply Black Formatting
github-actions[bot] Mar 11, 2026
beda934
Update badges on README
matthew7838 Mar 11, 2026
601dd64
Update input/data/animal/example_freestall_animal.json
matthew7838 Mar 11, 2026
c713e21
Merge 601dd648f561654b6b93665f87d1e5c8b48935f5 into 81112aff00f30f568…
matthew7838 Mar 11, 2026
b33d8f6
Apply Black Formatting
github-actions[bot] Mar 11, 2026
2007bd2
Julie's and part of Allister's comments
matthew7838 Mar 11, 2026
111acac
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Mar 11, 2026
654b9bd
Addressed all comments
matthew7838 Mar 11, 2026
f8efa17
Merge 654b9bd73b768044be5a86eddc32d30017dbf0b4 into 81112aff00f30f568…
matthew7838 Mar 11, 2026
61a1b20
Apply Black Formatting
github-actions[bot] Mar 11, 2026
737122c
Addressed final comments
matthew7838 Mar 13, 2026
fb9b69a
Merge 737122cd05215a7d24e81ac58aa2494ca47a0c1e into 81112aff00f30f568…
matthew7838 Mar 13, 2026
1688dd2
Apply Black Formatting
github-actions[bot] Mar 13, 2026
1390881
Merge branch 'dev' into maintain-herd
matthew7838 Mar 23, 2026
12827f2
Merge 1390881046ff98a57836611b1d9dda0b740b8f57 into 19a697be425755d8b…
matthew7838 Mar 23, 2026
faac9b9
Apply Black Formatting
github-actions[bot] Mar 23, 2026
fac6959
Update badges on README
matthew7838 Mar 23, 2026
4cb5ef9
Added warning for no production cows
matthew7838 Mar 23, 2026
cb8d42a
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Mar 23, 2026
4d5f1d3
Merge cb8d42a8a72e100eaf6200e44cce4355fe36c45f into 19a697be425755d8b…
matthew7838 Mar 23, 2026
a37c302
Apply Black Formatting
github-actions[bot] Mar 23, 2026
1ac3511
Update badges on README
matthew7838 Mar 23, 2026
042e62a
Fixed flake8
matthew7838 Mar 23, 2026
bff8447
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Mar 23, 2026
e0eb727
Merge bff8447d98b99139d40811c846f59660ef204dee into 19a697be425755d8b…
matthew7838 Mar 23, 2026
36f46c3
Apply Black Formatting
github-actions[bot] Mar 23, 2026
d4660bb
Update badges on README
matthew7838 Mar 23, 2026
0d65c2c
Fixed a small bug
matthew7838 Mar 24, 2026
7848abb
Merge remote-tracking branch 'origin/maintain-herd' into maintain-herd
matthew7838 Mar 24, 2026
3989ba9
Merge 7848abbf420082b9b433cbbb19a7606abf8e532a into 19a697be425755d8b…
matthew7838 Mar 24, 2026
4850bef
Apply Black Formatting
github-actions[bot] Mar 24, 2026
e7436d0
Updated Julie's warning throwing criteria
matthew7838 Mar 25, 2026
d3db9bd
Merge branch 'dev' into maintain-herd
matthew7838 Mar 25, 2026
00bc6ee
Merge d3db9bdb1db9c4edb4827806707a8bc4bbb42992 into 4378126e6300c54f7…
matthew7838 Mar 25, 2026
0b7f40b
Apply Black Formatting
github-actions[bot] Mar 25, 2026
b52a078
Update badges on README
matthew7838 Mar 25, 2026
10d970b
Merge branch 'dev' into maintain-herd
matthew7838 Mar 26, 2026
934f2ff
Merge 10d970bed6c935b6df58b0430c59b81b04886f98 into 9111d83f613b2835a…
matthew7838 Mar 26, 2026
3da4094
Apply Black Formatting
github-actions[bot] Mar 26, 2026
1e1080b
Update badges on README
matthew7838 Mar 26, 2026
110f855
Merge branch 'dev' into maintain-herd
matthew7838 Mar 27, 2026
8100c10
Merge 110f855d202a0591be97576c9048cfec5362860d into bd875f9d4ef28e4fd…
matthew7838 Mar 27, 2026
bd18c4f
Apply Black Formatting
github-actions[bot] Mar 27, 2026
2cbcbb3
Update badges on README
matthew7838 Mar 27, 2026
f120e30
Merge branch 'dev' into maintain-herd
matthew7838 Mar 31, 2026
008a274
Merge f120e30a876977935869571d202086a26b18e583 into 7b090b9c17b481f1c…
matthew7838 Mar 31, 2026
b91280b
Apply Black Formatting
github-actions[bot] Mar 31, 2026
ea88a6f
Update badges on README
matthew7838 Mar 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[![Flake8](https://img.shields.io/badge/Flake8-passed-brightgreen)](https://github.com/RuminantFarmSystems/MASM/actions/workflows/combined_format_lint_test_mypy.yml)
[![Pytest](https://img.shields.io/badge/Pytest-passed-brightgreen)](https://github.com/RuminantFarmSystems/MASM/actions/workflows/combined_format_lint_test_mypy.yml)
[![Coverage](https://img.shields.io/badge/Coverage-99%25-brightgreen)](https://github.com/RuminantFarmSystems/MASM/actions/workflows/combined_format_lint_test_mypy.yml)
[![Mypy](https://img.shields.io/badge/Mypy-1195%20errors-red)](https://github.com/RuminantFarmSystems/MASM/actions/workflows/combined_format_lint_test_mypy.yml)
[![Mypy](https://img.shields.io/badge/Mypy-1194%20errors-red)](https://github.com/RuminantFarmSystems/MASM/actions/workflows/combined_format_lint_test_mypy.yml)


# RuFaS: Ruminant Farm Systems
Expand Down
8 changes: 0 additions & 8 deletions RUFAS/biophysical/animal/animal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1748,14 +1748,6 @@ def animal_life_stage_update(self, time: RufasTime) -> tuple[AnimalStatus, NewBo
self.cull_reason = animal_constants.DEATH_CULL
animal_status = AnimalStatus.DEAD

if (
self.animal_type.is_cow
and self.reproduction.do_not_breed
and self.milk_production.daily_milk_produced < AnimalConfig.cull_milk_production
):
self.cull_reason = animal_constants.LOW_PROD_CULL
self.sold_at_day = time.simulation_day
animal_status = AnimalStatus.SOLD
return animal_status, newborn_calf_config

def _evaluate_calf_for_heiferI(self) -> bool:
Expand Down
4 changes: 0 additions & 4 deletions RUFAS/biophysical/animal/animal_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ class AnimalConfig:
Maximum day at which a heifer is culled if not pregnant, (simulation days).
do_not_breed_time : int
The duration after which breeding is stopped, (simulation days).
cull_milk_production : int
The threshold milk production below which cows are culled, (simulation days).
semen_type : str
Types of semen used for reproduction, e.g., "conventional", (unitless).
male_calf_rate_conventional_semen : float
Expand Down Expand Up @@ -193,7 +191,6 @@ class AnimalConfig:
dry_off_day_of_pregnancy: int = 218
heifer_reproduction_cull_day: int = 500
do_not_breed_time: int = 185
cull_milk_production: int = 30

semen_type: str = "conventional"
male_calf_rate_conventional_semen: float = 0.53
Expand Down Expand Up @@ -392,7 +389,6 @@ def initialize_animal_config(cls) -> None:
cls.dry_off_day_of_pregnancy = animal_config_data["management_decisions"]["days_in_preg_when_dry"]
cls.heifer_reproduction_cull_day = animal_config_data["management_decisions"]["heifer_repro_cull_time"]
cls.do_not_breed_time = animal_config_data["management_decisions"]["do_not_breed_time"]
cls.cull_milk_production = animal_config_data["management_decisions"]["cull_milk_production"]

cls.semen_type = animal_config_data["management_decisions"]["semen_type"]
cls.male_calf_rate_conventional_semen = animal_config_data["farm_level"]["calf"][
Expand Down
8 changes: 7 additions & 1 deletion RUFAS/biophysical/animal/animal_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
# heifer repro
INJECT_CIDR = "inject CIDR"

# herd size management
MIN_DIM_FOR_REMOVAL = 60
"""Minimum days in milk required for a cow to be eligible for removal."""
MAX_DAYS_IN_PREG_FOR_REMOVAL = 180
"""Maximum pregnancy duration for a cow to be eligible for removal."""

# presynch protocols
PRESYNCH_PERIOD_START = "Presynch period started"
PRESYNCH_PERIOD_END = "Presynch period ended"
Expand Down Expand Up @@ -86,7 +92,7 @@

# culling
HEIFER_REPRO_CULL = "culled for heifer reproductive problem"
LOW_PROD_CULL = "culled for low production"
OVERSUPPLY_CULL = "culled for herd resize"
DEATH_CULL = "culled for death"
LAMENESS_CULL = "culled for lameness"
INJURY_CULL = "culled for injury"
Expand Down
6 changes: 3 additions & 3 deletions RUFAS/biophysical/animal/animal_module_reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,8 +596,8 @@ def report_herd_statistics_data(cls, herd_statistics: HerdStatistics, simulation
"data_origin": [("HerdManager", "daily_update")],
}
om.add_variable(
"sold_heiferIII_oversupply_num",
herd_statistics.sold_heiferIII_oversupply_num,
"sold_cow_oversupply_num",
herd_statistics.sold_cow_oversupply_num,
dict(info_map, **{"units": MeasurementUnits.ANIMALS}),
)
om.add_variable(
Expand Down Expand Up @@ -841,7 +841,7 @@ def report_herd_statistics_data(cls, herd_statistics: HerdStatistics, simulation
)
cull_reason_stats_units = {
animal_constants.DEATH_CULL: MeasurementUnits.UNITLESS,
animal_constants.LOW_PROD_CULL: MeasurementUnits.UNITLESS,
animal_constants.OVERSUPPLY_CULL: MeasurementUnits.UNITLESS,
animal_constants.LAMENESS_CULL: MeasurementUnits.UNITLESS,
animal_constants.INJURY_CULL: MeasurementUnits.UNITLESS,
animal_constants.MASTITIS_CULL: MeasurementUnits.UNITLESS,
Expand Down
12 changes: 6 additions & 6 deletions RUFAS/biophysical/animal/data_types/herd_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ class HerdStatistics:
Number of stillborn calves during a specific period, (unitless).
sold_calf_num : int
Number of calves sold during a specific period, (unitless).
sold_heiferIII_oversupply_num : int
Number of surplus "Heifer III" animals sold, (unitless).
sold_cow_oversupply_num : int
Number of surplus cow sold, (unitless).
bought_heifer_num : int
Number of heifers purchased during a specific period, (unitless).
sold_heiferII_num : int
Expand Down Expand Up @@ -178,7 +178,7 @@ class HerdStatistics:

stillborn_calf_num = 0
sold_calf_num = 0
sold_heiferIII_oversupply_num = 0
sold_cow_oversupply_num = 0
bought_heifer_num = 0
sold_heiferII_num = 0
cow_herd_exit_num = 0
Expand Down Expand Up @@ -256,7 +256,7 @@ def __init__(self) -> None:
}
self.cull_reason_stats = {
animal_constants.DEATH_CULL: 0,
animal_constants.LOW_PROD_CULL: 0,
animal_constants.OVERSUPPLY_CULL: 0,
animal_constants.LAMENESS_CULL: 0,
animal_constants.INJURY_CULL: 0,
animal_constants.MASTITIS_CULL: 0,
Expand All @@ -270,7 +270,7 @@ def __init__(self) -> None:
self.avg_age_for_parity = {"1": 0, "2": 0, "3": 0, "4": 0, "5": 0, "greater_than_5": 0}
self.cull_reason_stats_percent = {
animal_constants.DEATH_CULL: 0.0,
animal_constants.LOW_PROD_CULL: 0.0,
animal_constants.OVERSUPPLY_CULL: 0.0,
animal_constants.LAMENESS_CULL: 0.0,
animal_constants.INJURY_CULL: 0.0,
animal_constants.MASTITIS_CULL: 0.0,
Expand Down Expand Up @@ -313,7 +313,7 @@ def reset_daily_stats(self) -> None:

self.stillborn_calf_num = 0
self.sold_calf_num = 0
self.sold_heiferIII_oversupply_num = 0
self.sold_cow_oversupply_num = 0
self.bought_heifer_num = 0
self.sold_heiferII_num = 0
self.cow_herd_exit_num = 0
Expand Down
162 changes: 94 additions & 68 deletions RUFAS/biophysical/animal/herd_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ def __init__(

self.herd_statistics = HerdStatistics()
self.herd_statistics.herd_num = animal_config_data["herd_information"]["herd_num"]
self.adjustment_period = animal_config_data["herd_information"]["herd_size_adjustment_period"]
self.selling_threshold = animal_config_data["herd_information"]["herd_size_sell_threshold"]
self.buying_threshold = animal_config_data["herd_information"]["herd_size_buy_threshold"]
self.herd_reproduction_statistics = HerdReproductionStatistics()

self.housing = animal_config_data["housing"]
Expand Down Expand Up @@ -274,19 +277,6 @@ def phosphorus_concentration_by_animal_class(self) -> dict[AnimalType, float]:

return phosphorus_concentration_by_animal_class

@property
def current_herd_size(self) -> int:
"""
Calculates the current size of the herd based on the number of heiferIIIs and cows.

Returns
-------
int
The current size of the herd.

"""
return len(self.heiferIIIs) + len(self.cows)

@property
def heiferII_events_by_id(self) -> dict[str, AnimalEvents]:
"""
Expand Down Expand Up @@ -601,18 +591,35 @@ def daily_routines(

self._update_stillborn_calf_statistics(stillborn_newborn_calves)

removed_animals += self._check_if_heifers_need_to_be_sold(simulation_day=time.simulation_day)
newly_added_animals = self._check_if_replacement_heifers_needed(time=time)
self._update_herd_structure(
graduated_animals=graduated_animals,
newborn_calves=newborn_calves,
newly_added_animals=newly_added_animals,
removed_animals=removed_animals,
available_feeds=available_feeds,
current_day_conditions=weather.get_current_day_conditions(time),
total_inventory=total_inventory,
simulation_day=time.simulation_day,
)
adjust_herd_size: bool = time.simulation_day > 0 and time.simulation_day % self.adjustment_period == 0
if adjust_herd_size:
removed_animals += self._check_if_cows_need_to_be_sold(
simulation_day=time.simulation_day, removed_animal=removed_animals
)
self._update_sold_and_died_cow_statistics(removed_animals)
newly_added_animals = self._check_if_replacement_heifers_needed(time=time)

self._update_herd_structure(
graduated_animals=graduated_animals,
newborn_calves=newborn_calves,
newly_added_animals=newly_added_animals,
removed_animals=removed_animals,
available_feeds=available_feeds,
current_day_conditions=weather.get_current_day_conditions(time),
total_inventory=total_inventory,
simulation_day=time.simulation_day,
)
else:
self._update_herd_structure(
graduated_animals=graduated_animals,
newborn_calves=newborn_calves,
newly_added_animals=[],
removed_animals=removed_animals,
available_feeds=available_feeds,
current_day_conditions=weather.get_current_day_conditions(time),
total_inventory=total_inventory,
simulation_day=time.simulation_day,
)

self.record_pen_history(time.simulation_day)
enteric_methane_emission_by_pen: dict[str, float] = {}
Expand All @@ -625,6 +632,25 @@ def daily_routines(

self.update_herd_statistics()

no_milk_cow_num = len(
[
cow
for cow in self.cows
if cow.milk_production.daily_milk_produced == 0 and cow.is_milking and cow.days_in_milk > 1
]
)

if no_milk_cow_num > 0:
self.om.add_warning(
"Warning: Lactating cows with no production.",
f"There are {no_milk_cow_num} lactating cows with no milking production on simulation"
f" day {time.simulation_day}.",
info_map={
"class": self.__class__.__name__,
"function": self.daily_routines.__name__,
"simulation_day": time.simulation_day,
},
)
AnimalModuleReporter.report_enteric_methane_emission(enteric_methane_emission_by_pen)
AnimalModuleReporter.report_daily_animal_population(self.herd_statistics, time.simulation_day)
AnimalModuleReporter.report_herd_statistics_data(self.herd_statistics, time.simulation_day)
Expand Down Expand Up @@ -657,8 +683,7 @@ def _report_ration(self, simulation_day: int) -> None:

def _create_newborn_calf(self, newborn_calf_config: NewBornCalfValuesTypedDict, simulation_day: int) -> Animal:
"""
Creates a new newborn calf instance and records its entry event in the herd if it
is not sold.
Creates a new newborn calf instance and records its entry event in the herd if it is not sold.

Parameters
----------
Expand All @@ -679,50 +704,49 @@ def _create_newborn_calf(self, newborn_calf_config: NewBornCalfValuesTypedDict,
newborn_calf.events.add_event(newborn_calf.days_born, simulation_day, animal_constants.ENTER_HERD)
return newborn_calf

def _check_if_heifers_need_to_be_sold(
self,
simulation_day: int,
) -> list[Animal]:
"""
Checks if surplus heifers need to be sold based on herd size.
def _get_cow_removal_index(self, removed_animal: list[Animal]) -> int | None:
"""Finds the indices of cows with the lowest daily milk production among cows that meet the specified
days-in-milk and days-pregnant criteria."""
eligible_indices = []

This method evaluates if the current number of heifers and cows exceeds a
specified threshold (defined as 3% over the herd statistics' target
herd size). If the threshold is surpassed, heiferIIIs are removed from the
herd until the herd size falls within the acceptable range.
for index, cow in enumerate(self.cows):
if cow in removed_animal:
continue
eligible_for_removal = (
cow.days_in_milk > animal_constants.MIN_DIM_FOR_REMOVAL
and cow.days_in_pregnancy < animal_constants.MAX_DAYS_IN_PREG_FOR_REMOVAL
)
if eligible_for_removal:
eligible_indices.append(index)

Parameters
----------
simulation_day : int
The simulation day on which the check and potential sale is conducted.
if not eligible_indices:
return None

Returns
-------
list[Animal]
A list of heiferIIIs to be sold.
return min(eligible_indices, key=lambda i: self.cows[i].milk_production.daily_milk_produced)

"""
def _check_if_cows_need_to_be_sold(self, simulation_day: int, removed_animal: list[Animal]) -> list[Animal]:
"""Checks if surplus cows need to be sold based on herd size."""
animals_removed: list[Animal] = []
while (
self.current_herd_size > self.herd_statistics.herd_num * animal_constants.SELLING_THRESHOLD
and len(self.heiferIIIs) > 0
):
removed_heiferIII = self.heiferIIIs.pop()
animals_removed.append(removed_heiferIII)
removed_heiferIII.sold_at_day = simulation_day
self.herd_statistics.sold_heiferIIIs_info.append(
SoldAnimalTypedDict(
id=removed_heiferIII.id,
animal_type=removed_heiferIII.animal_type.value,
sold_at_day=removed_heiferIII.sold_at_day,
body_weight=removed_heiferIII.body_weight,
cull_reason="NA",
days_in_milk="NA",
parity="NA",

while len(self.cows) > self.selling_threshold and len(self.cows) > 0:
remove_index = self._get_cow_removal_index(removed_animal)

if remove_index is None:
info_map = {
"class": self.__class__.__name__,
"function": self._check_if_cows_need_to_be_sold.__name__,
"simulation_day": simulation_day,
}
self.om.add_error(
"Unable to adjust herd size", "There are no cow that's qualified to be sold.", info_map
)
)
self.herd_statistics.sold_heiferIII_oversupply_num += 1
self.herd_statistics.heiferIII_num -= 1
break

removed_cow = self.cows.pop(remove_index)
removed_cow.sold_at_day = simulation_day
removed_cow.cull_reason = "culled for herd resize"
animals_removed.append(removed_cow)

return animals_removed

def _check_if_replacement_heifers_needed(self, time: RufasTime) -> list[Animal]:
Expand All @@ -746,9 +770,7 @@ def _check_if_replacement_heifers_needed(self, time: RufasTime) -> list[Animal]:
"""
animals_added: list[Animal] = []
while (
self.current_herd_size + self.herd_statistics.bought_heifer_num
< self.herd_statistics.herd_num * animal_constants.BUYING_THRESHOLD
and time.simulation_day > 1
len(self.cows) + self.herd_statistics.bought_heifer_num < self.buying_threshold and time.simulation_day > 1
):
if len(self.replacement_market) == 0:
break
Expand Down Expand Up @@ -1810,6 +1832,7 @@ def _update_sold_and_died_cow_statistics(self, sold_and_died_cows: list[Animal])
sum_cow_culling_age = self.herd_statistics.avg_cow_culling_age * self.herd_statistics.cow_herd_exit_num + sum(
[cow.days_born for cow in sold_and_died_cows]
)
self.herd_statistics.cow_num -= len(sold_and_died_cows)
self.herd_statistics.cow_herd_exit_num += len(sold_and_died_cows)
self.herd_statistics.avg_cow_culling_age = (
(sum_cow_culling_age / self.herd_statistics.cow_herd_exit_num)
Expand All @@ -1834,6 +1857,9 @@ def _update_sold_and_died_cow_statistics(self, sold_and_died_cows: list[Animal])
[cow for cow in sold_and_died_cows if cow.cull_reason == cull_reason]
)

oversupply_cows_num = sum(cow.cull_reason == animal_constants.OVERSUPPLY_CULL for cow in sold_and_died_cows)
self.herd_statistics.sold_cow_oversupply_num += oversupply_cows_num

sold_cows: list[Animal] = [cow for cow in sold_and_died_cows if cow.cull_reason != animal_constants.DEATH_CULL]
self.herd_statistics.sold_cows_info += [
SoldAnimalTypedDict(
Expand Down
4 changes: 2 additions & 2 deletions RUFAS/biophysical/field/soil/infiltration.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def infiltrate(self, rainfall: float) -> None:

# --- static methods ---
@staticmethod
def _determine_first_moisture_condition_parameter(second_moisture_condition: float):
def _determine_first_moisture_condition_parameter(second_moisture_condition: float) -> float:
"""
Determine the curve number for dry (wilting point) conditions.

Expand All @@ -125,7 +125,7 @@ def _determine_first_moisture_condition_parameter(second_moisture_condition: flo
return second_moisture_condition - (top / bottom)

@staticmethod
def _determine_third_moisture_condition_parameter(second_moisture_condition: float):
def _determine_third_moisture_condition_parameter(second_moisture_condition: float) -> float:
"""
Determine the curve number for wet (field capacity) conditions.

Expand Down
Loading