RUFAS.routines.animal.animal_manager module#
- class RUFAS.routines.animal.animal_manager.AnimalManager(data: Dict[str, Any], feed: Feed, weather: Weather, time: RufasTime, feed_emissions_estimator: PurchasedFeedEmissionsEstimator = None)#
Bases:
object
Manages all animal routines (i.e. calling daily updates, allocating animals to pens, etc). Stores a list of all animals and pens in the simulation as well as an instance of the LifeCycleManager class in order to update the animals’ life cycles.
- DEFAULT_NUM_STALLS_BY_COMBINATION = {AnimalCombination.CALF: 110, AnimalCombination.CLOSE_UP: 200, AnimalCombination.GROWING: 800, AnimalCombination.GROWING_AND_CLOSE_UP: 500, AnimalCombination.LAC_COW: 850}#
- ANIMAL_GROUPING_SCENARIO: AnimalGroupingScenario#
- classmethod set_animal_grouping_scenario(scenario: AnimalGroupingScenario) None #
Sets the animal grouping scenario to the given scenario.
Parameters#
- scenarioAnimalGroupingScenario
The scenario to set the animal grouping scenario to.
Returns#
None
- static get_animal_config(data)#
- __init__(data: Dict[str, Any], feed: Feed, weather: Weather, time: RufasTime, feed_emissions_estimator: PurchasedFeedEmissionsEstimator = None) None #
Initializes the pens and animals in the simulation with data from the JSON file by calling init_pens() and init_animals(). Creates instance of LifeCycleManager class and sets up the animal environment.
Parameters#
- dataDict[str, Any]
dictionary with animal information from the input JSON file
- feedFeed
instance of the Feed class
- weatherWeather
instance of the Weather class
- timeRufasTime
instance of the RufasTime class
- feed_emissions_estimatorPurchasedFeedEmissionsEstimator, default=None
Instance of the PurchasedFeedEmissionsEstimator class.
- property animals_by_type#
- init_pens(all_pen_data: list, manure_management_scenarios: Dict[str, Any]) None #
Populates the list of pens with the information from the input json file.
Parameters#
- all_pen_data: list[dict[str, Any]]
List containing information about the pens.
- manure_management_scenariosDict[str, Any]
Dictionary containing information about the manure management scenarios.
- init_animals(herd_data: Dict[str, Any]) None #
Populates the list of animals with the information from the input JSON file: constructs the calves, heiferI’s, heiferII’s, heiferIII’s, and cows (the desired amounts of each is specified by @data), then calls life_cycle_manager’s initialize_herd() with those numbers to create instances of the animals. The nutrient requirements are calculated and the animals are allocated to pens.
Parameters#
- herd_data: Dict[str, Any]
A dictionary containing information about the herd.
- _print_animal_num_warnings(herd_data: Dict[str, Any]) None #
- If simulate_animals is false, creates warnings if there are more than 0 animals for any of the animal types,
and logs how many warnings were generated
Otherwise, if simulate_animals is true, logs that it is true
Parameters#
- herd_dataDict[str, Any]
dictionary containing information about the herd
- init_nutrient_rqmts(weather: Weather, time: RufasTime, feed: Feed) None #
Calculates initial nutrient requirements at the beginning of the simulation for initial pen allocation. For the nutrient requirements of cows, the average walking distance of all the pens initialized is used.
Parameters#
- feedFeed
an instance of the Feed class defined in feed.py
- weatherWeather
instance of the Weather class
- timeRufasTime
instance of the RufasTime class
- avg_pen_dist() Tuple[float, float] #
Calculates the average distance from a pen to the milking parlor.
Returns#
Tuple : (average vertical distance from milking parlor, average horizontal distance from milking parlor)
- calc_nutrient_rqmts(calves: List[Calf], heiferIs: List[HeiferI], heiferIIs: List[HeiferII], heiferIIIs: List[HeiferIII], cows: List[Cow], feed: Feed, current_temperature: float) None #
Calls each animal’s method to calculate its nutrient requirements.
Parameters#
- calvesList[Calf],
List of calves.
- heiferIsList[HeiferI],
List of heifer Is.
- heiferIIsList[HeiferII],
List of heifer IIs.
- heiferIIIsList[HeiferIII],
List of heifer IIIs.
- cowsList[Cow]
List of cows.
- feedFeed
Instance of the Feed class.
- current_temperaturefloat
The temperature on the current day.
- reset_milk_production_reduction(pen: Pen) None #
Resets reduction value for milk production to 0.0 for all animals in the given pen.
- The milk_production_reduction attribute is a value generated in ration_driver.py,
in cases where a ration cannot be formulated such that it meets animal requirements
Parameters#
- penPen
Pen object.
- fully_update_animal_to_pen_id_map() None #
Updates the entire animal_to_pen_id_map dictionary so that each animal’s ID is associated with the pen that animal is in.
- classmethod _get_dry_cows(cows: List[Cow]) List[Cow] #
Return a list of dry cows from a list of cows.
Here, a dry cow can be either far-off dry or close-up dry.
Parameters#
- cowsList[Cow]
List of cows to filter dry cows from.
Returns#
- List[Cow]
List of dry cows.
- classmethod _get_lactating_cows(cows: List[Cow]) List[Cow] #
Return a list of lactating cows from a list of cows.
Parameters#
- cowsList[Cow]
List of cows to filter lactating cows from.
Returns#
- List[Cow]
List of lactating cows.
- classmethod _group_pens_by_animal_combination(all_pens: List[Pen]) Dict[AnimalCombination, List[Pen]] #
Group a list of pens by animal combination.
Parameters#
- all_pensList[Pen]
List of pens to group by animal combination.
Returns#
- Dict[AnimalCombination, List[Pen]]
Dictionary of pens grouped by animal combination.
- classmethod _calc_max_animal_spaces_per_pen(num_stalls: int, max_stocking_density: float) int #
Calculate the maximum number of animal spaces available per pen.
Parameters#
- num_stallsint
The number of stalls in the pen. Must be greater than or equal to 0.
- max_stocking_densityfloat
The maximum stocking density for the pen. Must be greater than or equal to 0.
Returns#
- int
The maximum number of animal spaces available in the pen.
Raises#
- ValueError
If the number of stalls or maximum stocking density is less than 0.
Examples#
>>> AnimalManager._calc_max_animal_spaces_per_pen(num_stalls=10, max_stocking_density=1.5) 15 >>> AnimalManager._calc_max_animal_spaces_per_pen(num_stalls=5, max_stocking_density=2.0) 10
- classmethod _calc_animal_space_shortage(num_animals: int, pens: List[Pen]) int #
Calculate the shortage of animal spaces given the number of animals and a list of pens.
Parameters#
- num_animalsint
The total number of animals to be accommodated.
- pensList[Pen]
A list of Pen objects representing the available pens.
Returns#
- int
The shortage of animal spaces. If there is a shortage, this will be a positive integer.
- classmethod _create_duplicate_pen(pen_id: int, animal_combination: AnimalCombination, num_stalls: int, max_stocking_density: float, reference_pen: Pen) Pen #
Duplicate a Pen object using a handful of parameters and a reference Pen.
Parameters#
- pen_idint
The unique identifier for the pen.
- animal_combinationAnimalCombination
The animal combination for the pen.
- num_stallsint
The number of stalls in the pen.
- max_stocking_densityfloat
The maximum stocking density for the pen.
- reference_penPen
Pen object that has more animals than available space.
Returns#
- Pen
A new Pen object with the specified parameters and duplicate values for other attributes of reference pen.
- _create_additional_pens_for_potential_space_shortage(num_animals: int, pens: List[Pen], animal_combination: AnimalCombination, start_pen_id: int = 0) List[Pen] #
Create a list of additional pens to accommodate potential animal space shortage.
This method defines the first pen in the pens list as the ‘reference’ pen, which means that it uses those attributes as a template for the creation of new pens. This assumes the incoming pen list is uniform, as they are the same AnimalCombination.
Parameters#
- num_animalsint
The total number of animals to be accommodated.
- pensList[Pen]
A list of Pen objects representing the currently available pens.
- animal_combinationAnimalCombination
The animal combination for the new default pens.
- start_pen_idint, default=0
The starting pen ID for the new pens.
Returns#
- List[Pen]
A list of new default Pen objects to accommodate the potential animal space shortage.
- classmethod _calc_density(num_animals: int, num_spaces: int) float #
Calculate the animal density in pens given the number of animals and spaces.
Parameters#
- num_animalsint
The number of animals in the pen. Must be a non-negative integer.
- num_spacesint
The number of spaces in the pen to hold the animals. Must be a positive integer.
Returns#
- float
The animal density, calculated as the ratio of the number of animals to the number of spaces available.
Raises#
- ValueError
If num_animals is negative. IF num_spaces is non-positive.
Notes#
This method does not raise an error if the number of animals is greater than the number of spaces. Instead, it returns a density greater than 1.0.
- classmethod _allocate_animals_to_pens_helper(animals: List[Calf | HeiferI | HeiferII | HeiferIII | Cow], pens: List[Pen]) None #
Allocate animals to pens based on overall density while preventing overcrowding.
This method distributes the animals among the available pens, ensuring that the density in each pen matches the overall density as closely as possible.
Parameters#
- animalsList[Union[Calf, HeiferI, HeiferII, HeiferIII, Cow]]
A list of animal to be allocated to pens.
- pensList[Pen]
A list of Pen objects representing the available pens. All these pens should have the same animal combination.
Returns#
None
- classmethod execute_allocation_plan(allocation_plan: List[int], animals: List[Calf | HeiferI | HeiferII | HeiferIII | Cow], animal_pens: List[Pen]) None #
Execute an allocation plan to distribute animals into pens according to the given plan.
This method iterates over the provided allocation plan and updates each pen with the specified number of animals.
Parameters#
- allocation_planList[int]
A list of integers representing the number of animals to be allocated to each pen. The length of the allocation_plan list must match the number of pens in animal_pens.
- animalsList[Union[Calf, HeiferI, HeiferII, HeiferIII, Cow]]
A list of animals to be allocated among the pens.
- animal_pensList[Pen]
A list of Pen objects representing the pens to which animals will be allocated.
Returns#
None
Raises#
- ValueError
If the length of the allocation plan does not match the number of pens. If the sum of the allocation plan does not match the number of animals.
- classmethod plan_animal_allocation(num_animals: int, max_spaces_in_pens: List[int]) List[int] #
- Make an allocation plan to move animals to pens and match pen density as closely as possible
to the overall density.
General rules: 1. The number of animals allocated to each pen cannot exceed the maximum number of spaces available in that pen. 2. The total number of animals allocated to all pens must be equal to num_animals. 3. The density in each pen must be as close as possible to the overall density. 4. Generally, it is expected that the density in each pen will be slightly greater than or equal to the overall density, except the last pen. 5. The last pen considered by the algorithm is the pen with the highest allocation limit. 6. That last pen will hold the remaining animals, likely resulting in a density that is lower than
the overall density.
Notes#
The overall density is calculated as the ratio of the total number of animals to the total number of spaces. The allocation limit of a pen math.ceil(overall_density * max_spaces_in_pens[i]). It is the smallest integer greater than or equal to the overall density multiplied by the maximum number of spaces in that pen. This ensures that the individual pen density will be the same as the overall density or only slightly higher due to the addition of exactly one extra animal.
Here, allocating animals to the pens with the higher allocation limits last gives a more even density distribution across all pens, because those with lower allocation limits will get filled first and won’t be ignored.
An alternative approach would be to allocate animals to the pens with the higher allocation limits first. This would use up the animal count more quickly, so the later the allocation, the fewer animals are left to allocate. Depending on the dynamics between the given numbers, some pens may end up with a very low density.
Parameters#
- num_animalsint
The total number of animals to allocate. Must be a non-negative integer and not be greater than the total number of spaces.
- max_spaces_in_pensList[int]
A list of integers representing the number of maximum spaces in each pen. Each integer must be positive.
Returns#
- List[int]
A list of integers representing the allocation of animals in each pen. Each integer will be less than or equal to math.ceil(overall_density * max_spaces_in_pens[i])].
Raises#
- ValueError
If the number of animals is greater than the total number of spaces.
Examples#
>>> AnimalManager.plan_animal_allocation(num_animals=90, max_spaces_in_pens=[50, 30, 20]) [45, 27, 18]
>>> AnimalManager.plan_animal_allocation(num_animals=70, max_spaces_in_pens=[50, 30, 20]) [35, 21, 14]
>>> AnimalManager.plan_animal_allocation(num_animals=47, max_spaces_in_pens=[50, 30, 20]) [22, 15, 10]
- allocate_animals_to_pens() None #
Allocate animals to pens based on the current animal population and the number of pens available. New default pens will be created if necessary. This method distributes the animals among the pens, ensuring that the animal density of each pen matches the overall density as closely as possible.
Returns#
None
- _sort_animals_before_allocation() None #
Sort lactating cows by days in milk in increasing order.
- clear_pens() None #
Removes animals from pens for re-allocation. This is part of the routines that happen every ration interval.
- calc_manure_excretion(feed: Feed, methane_model: str) None #
Calls each animal’s method to calculate manure excretion to find the total for each pen. This is part of the routines that happen every ration interval.
Parameters#
- feedFeed
instance of the feed class
- methane_modelstr
Methane model used for methane emission calculations
- sum_daily_milk(cows: List[Cow]) float #
sums the daily milk production across all cows
Parameters#
- cows: List
List of cows in the animal manager class.
Returns#
float: The total milk produced in the herd (kg milk/day)
- gather_pen_history(animal_type_list: List[Calf | HeiferI | HeiferII | HeiferIII | Cow]) None #
Updates pen history data for a given animal type.
Checks the current pen ID and pen composition of all animals for a given animal class, and then updates the pen history for that type using the update_pen_history() method.
Parameters#
- animal_type_listList[Union[Calf, HeiferI, HeiferII, HeiferIII, Cow]]
List of animals.
- collect_pen_manure_data() list[PenManureData] #
Returns the manure information from all pens in PenManureData.
- record_pen_history() None #
Records the pen history of all the animals.
- calc_p_rqmts() None #
Calls each pen’s method to calculate each animal’s phosphorus requirements. This method is called daily.
- daily_p_update() None #
Calls each pen’s method to calculate each animal’s daily phosphorus update. This method is called daily.
- end_ration_interval() bool #
Checks if a new ration should be formulated for the current simulation_day.
- Returns: True if today is the day a new ration has to be formulated,
False otherwise.
- classmethod _calc_phosphorus_concentration(animals: List[Calf | HeiferI | HeiferII | HeiferIII | Cow]) float #
Calculate the phosphorus concentration of a group of animals.
Parameters#
- animals
A list of animals.
Returns#
- float
The phosphorus concentration of the group of animals.
- _update_phosphorus_concentrations() None #
Update the phosphorus concentration for each animal type.
Returns#
None
- _handle_pen_ration(feed: Feed, pen: Pen) None #
Calculate the ration for each pen at the given interval and update the ration for each animal in the pen.
Notes#
It is important to set the variable ration_per_animal for each pen object. This forms the basis for scaling the ration for each pen based on the current number of animals in the pen.
Parameters#
- feedFeed
Instance of the Feed class
- penPen
Instance of Pen class.
- classmethod _get_animal_types_in_pen(pen: Pen) Set[AnimalType] #
Get the animal types in the pen.
Notes#
This method returns a set of animal types. By definition of a set, there will be no repeats. Note that removing an animal from a pen doesn’t necessarily mean that we can remove the animal’s type from the set, because there may still be other animals with the same type in the pen. Therefore, to improve efficiency, if there is a need to remove multiple animals at the same time, this method should be called after all the animals have been removed.
Parameters#
- penPen
The pen to get the animal types from.
Returns#
- Set
The set of animal types in the pen.
- classmethod _determine_classes_in_pen(pen: Pen) Set[str] #
Get the classes of animals in the pen.
Parameters#
- penPen
The pen to get the classes of animals from.
Returns#
- Set
The set of classes of animals in the pen.
- _get_animals_snapshot() Dict[str, set] #
Create a snapshot of the current state of all the animals in the system.
This function generates a dictionary that maps each animal group name to a set of animals within that group. Additionally, it includes a mapping from each animal’s ID to its associated animal combination as determined by the current ANIMAL_GROUPING_SCENARIO.
The snapshot dictionary serves as a summary of the current state of all animals in the system, allowing for efficient comparison of animal states before and after life cycle’s updates.
Returns#
- dict
A dictionary with the following structure: - ‘calves’: a set containing all calves currently in the system. - ‘heiferIs’: a set containing all heiferIs currently in the system. - ‘heiferIIs’: a set containing all heiferIIs currently in the system. - ‘heiferIIIs’: a set containing all heiferIIIs currently in the system. - ‘cows’: a set containing all cows currently in the system. - ‘animal_combination_by_id’: a dictionary mapping each animal’s ID to its
associated animal combination according to the current ANIMAL_GROUPING_SCENARIO.
- _handle_removed_animals_after_update(animals_snapshot_before_update: Dict[str, set | Dict], animals_snapshot_after_update: Dict[str, set | Dict]) None #
Dict[str, Dict[Union[Calf | HeiferI | HeiferII | HeiferIII]]] Identifies and handles animals that were present prior to the update, but not afterwards.
This function detects any animals that have been removed between updates (e.g., due to graduation, being sold, or being culled), and then updates the internal state accordingly by calling ‘_remove_animal_from_pen_and_id_map’ for each removed animal.
Parameters#
- animals_snapshot_before_updateDict[str, set | Dict]
A snapshot of the state of all the animals before the update. This dictionary uses animal class names as keys (‘calves’, ‘heiferIs’, etc.) and sets of animal instances as values.
- animals_snapshot_after_updateDict[str, set | Dict]
A snapshot of the state of all the animals after the update. This dictionary should have the same structure as animals_snapshot_before_update.
Returns#
- None
This function doesn’t return any value. Its purpose is to modify the internal state of the class instance by calling ‘_remove_animal_from_pen_and_id_map’ for each animal that has been removed.
- _handle_animals_with_unchanged_class_and_changed_combination(animals_snapshot_before_update: Dict[str, set | Dict], animals_snapshot_after_update: Dict[str, set | Dict], feed: Feed, current_temperature: float)#
Handle animals that didn’t change their classes but changed their animal combination.
The reason for the change in animal combination is that the animal’s physiological states have changed. Because each pen is associated with a specific animal combination, the animal needs to be moved to a different pen with the new animal combination.
For example, a cow can be in the dry state or lactating state, but depending on the current state of the cow, she can be in a different pen with a different animal combination.
Parameters#
- animals_snapshot_before_updateDict[str, set | Dict]
Snapshot of the animals before the update. This should be a dictionary with animal class names as keys and sets of animals as values. There should also be a special key ‘animal_combination_by_id’ that maps animal IDs to their animal combinations.
- animals_snapshot_after_updateDict[str, set | Dict]
Snapshot of the animals after the update. This should be a dictionary with the same structure as animals_snapshot_before_update.
- feedFeed
Instance of the Feed class.
- current_temperaturefloat
Current temperature.
Returns#
- None
This function does not return anything. It operates by side effects, changing the assignments of animals to pens.
- _handle_graduated_animals(animals_snapshot_before_update: Dict[str, set | Dict], animals_snapshot_after_update: Dict[str, set | Dict], feed: Feed, current_temperature: float) None #
- Finds animals that have graduated (moved from one class to another), moves them between pens,
and updates pen id map accordingly.
Parameters#
- animals_snapshot_before_updateDict[str, set | Dict]
Snapshot of the animals before the update. This should be a dictionary with animal class names as keys and sets of animals as values. There should also be a special key ‘animal_combination_by_id’ that maps animal IDs to their animal combinations.
- animals_snapshot_after_updateDict[str, set | Dict]
Snapshot of the animals after the update. This should be a dictionary with the same structure as animals_snapshot_before_update.
- feedFeed
instance of the Feed class defined in feed.py.
- current_temperaturefloat
The temperature on the current day.
- _handle_newly_added_animals(new_animals: List[Calf | HeiferI | HeiferII | HeiferIII | Cow], feed: Feed, current_temperature: float) None #
For all new animals, adds animal to a pen, and updates the pen id map.
Parameters#
- animalList[Union[Calf, HeiferI, HeiferII, HeiferIII, Cow]]
One of the possible animal types.
- feedFeed
instance of the Feed class defined in feed.py.
- current_temperaturefloat
The temperature on the current day.
- _remove_animal_from_pen_and_id_map(animal: Calf | HeiferI | HeiferII | HeiferIII | Cow) None #
Removes animal from its current pen, and removes it from the pen id map.
Parameters#
- animalUnion[Calf, HeiferI, HeiferII, HeiferIII, Cow]
One of the possible animal types.
- _add_animal_to_pen_and_id_map(animal: Calf | HeiferI | HeiferII | HeiferIII | Cow, feed: Feed, current_temperature: float) None #
Adds animal to pen with lowest stocking density, and updates the pen id map accordingly.
Parameters#
- animalUnion[Calf, HeiferI, HeiferII, HeiferIII, Cow]
One of the possible animal types.
- feedFeed
instance of the Feed class defined in feed.py.
- current_temperaturefloat
The temperature on the current day.
- daily_updates(feed: Feed, weather: Weather, time: RufasTime) None #
Execute the daily routines relating to Animals. All animals are updated through the life_cycle_manager’s daily_update() method. The daily phosphorus calculations are also done. If it is the end of the ration interval, the animals are allocated to new pens and the ration & manure calculations are done.
It is important that the Pen class has the ability to add and remove one animal at a time and adjust relevant variables accordingly based solely on the addition or removal of that animal.
Parameters#
- feedFeed
instance of the Feed class defined in feed.py
- weatherWeather
instance of the Weather class
- timeRufasTime
instance of the RufasTime class
- _record_culling_stats() None #
Record the culling stats of cows.