-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add ADG calculator, tests, and CLI infrastructure * Import ADG for doctest * Fix ADG doctest * Added FCR Calculations and tests * Added feed efficiency rating
- Loading branch information
1 parent
cd30659
commit a9c618d
Showing
13 changed files
with
371 additions
and
5 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
use anyhow::{anyhow, Context, Result}; | ||
use clap::Parser; | ||
use livestock_rs::{calculators::feed::{efficiency::calculate_feed_efficiency, fcr::calculate_fcr}, types::LivestockType}; | ||
|
||
#[derive(Parser, Debug)] | ||
#[command( | ||
arg_required_else_help(true), | ||
about = "Calculate Feed Efficiency for livestock.", | ||
long_about = " | ||
Calculate Feed Efficiency for livestock. | ||
The Feed Efficiency is a measure of how well livestock convert feed into body mass. It is | ||
calculated using the Feed Conversion Ratio (FCR) of the animal. | ||
The formula is: | ||
Feed Efficiency = 1 / FCR | ||
where: | ||
- `Feed Efficiency` is the efficiency of feed conversion. | ||
- `FCR` is the Feed Conversion Ratio of the animal. | ||
# Example | ||
Calculate the Feed Efficiency for an animal with a FCR of 2.0: | ||
``` | ||
stocktools feed-efficiency --fcr 2.0 --livestock-type Cattle | ||
``` | ||
The result will be `0.5`, which means the animal converted feed with an efficiency of 0.5. This is very good for cattle. | ||
" | ||
)] | ||
pub struct FeedEfficiencySubcommand { | ||
#[arg(help = "Amount of feed intake (in kg or lbs)", long, short = 'i')] | ||
feed_intake: Option<f64>, | ||
#[arg(help = "Weight gain of livestock (in kg or lbs)", long, short = 'g')] | ||
weight_gain: Option<f64>, | ||
#[arg(help = "Feed efficiency ratio (FCR)", long)] | ||
fcr: Option<f64>, | ||
#[arg( | ||
long, | ||
help = "The type of livestock.", | ||
short = 't', | ||
)] | ||
livestock_type: LivestockType, | ||
} | ||
|
||
impl FeedEfficiencySubcommand { | ||
pub fn run(&self) -> Result<()> { | ||
// ensure that we either have feed intake and weight gain or FCR | ||
let fcr = match (self.feed_intake, self.weight_gain, self.fcr) { | ||
(Some(feed_intake), Some(weight_gain), None) => { | ||
calculate_fcr(feed_intake, weight_gain).context( | ||
"Failed to calculate FCR, which is required if feed intake and weight gain are provided. | ||
FCR is needed to calculate feed efficiency.", | ||
)? | ||
} | ||
(None, None, Some(fcr)) => fcr, | ||
_ => { | ||
return Err(anyhow!( | ||
"Either feed intake and weight gain or FCR must be provided." | ||
)) | ||
} | ||
}; | ||
|
||
let feed_efficiency = calculate_feed_efficiency(fcr, self.livestock_type.clone()).with_context(|| format!( | ||
"Failed to calculate feed efficiency with FCR: {} and livestock type: {:?}.", | ||
fcr, self.livestock_type | ||
))?; | ||
|
||
println!(" "); | ||
println!("Feed Efficiency Rating: {:?}", feed_efficiency.rating); | ||
println!("FCR: {:.2}", feed_efficiency.value); | ||
println!("{:?} should aim for a FCR between {:.2} and {:.2}.", self.livestock_type, feed_efficiency.avg_min_fcr, feed_efficiency.avg_max_fcr); | ||
println!(" "); | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
use anyhow::{Context, Result}; | ||
use clap::Parser; | ||
use livestock_rs::calculators::feed::fcr::calculate_fcr; | ||
|
||
#[derive(Parser, Debug)] | ||
#[command( | ||
arg_required_else_help(true), | ||
about = "Calculate Feed Conversion Ratio (FCR) for livestock.", | ||
long_about = " | ||
Calculate Feed Conversion Ratio (FCR) for livestock. | ||
The Feed Conversion Ratio (FCR) is a measure of feed efficiency that indicates the amount of | ||
feed required to produce a unit of weight gain in livestock. It is calculated by dividing the | ||
amount of feed consumed by the weight gain of the animal. | ||
The formula is: | ||
FCR = feed_intake / weight_gain | ||
where: | ||
- `FCR` is the feed conversion ratio as a ratio of feed intake to weight gain. | ||
- `feed_intake` is the amount of feed consumed by the animal (in kg or lbs). | ||
- `weight_gain` is the weight gain of the animal (in kg or lbs). | ||
# Example | ||
Calculate the FCR for an animal that consumes 100 kg of feed and gains 150 kg: | ||
``` | ||
livestock fcr -i 100 -g 150 | ||
``` | ||
The result will be `0.67`, which means the animal required 0.67 kg of feed per kg of weight gain. | ||
" | ||
)] | ||
pub struct FcrSubcommand { | ||
#[arg(help = "Amount of feed intake (in kg or lbs)", long, short = 'i')] | ||
feed_intake: f64, | ||
#[arg(help = "Weight gain of livestock (in kg or lbs)", long, short = 'g')] | ||
weight_gain: f64, | ||
} | ||
|
||
impl FcrSubcommand { | ||
pub fn run(&self) -> Result<()> { | ||
let fcr = calculate_fcr(self.feed_intake, self.weight_gain) | ||
.context("Failed to calculate FCR.")?; | ||
|
||
println!("Feed Conversion Ratio (FCR): {:.2}", fcr); | ||
Ok(()) | ||
} | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
use anyhow::{ensure, Result}; | ||
use crate::types::LivestockType; | ||
|
||
#[derive(Debug, Eq, PartialEq)] | ||
pub enum FeedEfficiencyRating { | ||
Poor, | ||
Average, | ||
Good, | ||
} | ||
|
||
#[derive(Debug, PartialEq)] | ||
pub struct FeedEfficiency { | ||
pub rating: FeedEfficiencyRating, | ||
pub value: f64, | ||
pub avg_min_fcr: f64, | ||
pub avg_max_fcr: f64 | ||
} | ||
|
||
/// Calculate Feed Efficiency for livestock. | ||
/// | ||
/// # Arguments | ||
/// - `fcr`: Feed Conversion Ratio (FCR) of the animal. | ||
/// - `livestock_type`: The type of livestock. | ||
/// | ||
/// # Returns | ||
/// The feed efficiency of the animal. | ||
/// | ||
/// # Example | ||
/// ``` | ||
/// use livestock_rs::calculators::feed::efficiency::{calculate_feed_efficiency, FeedEfficiency, FeedEfficiencyRating}; | ||
/// use livestock_rs::types::LivestockType; | ||
/// | ||
/// let fcr = 10.0; | ||
/// let livestock_type = LivestockType::Cattle; | ||
/// | ||
/// let feed_efficiency = calculate_feed_efficiency(fcr, livestock_type).unwrap(); | ||
/// | ||
/// // The feed efficiency is average for a FCR of 10.0 for cattle. | ||
/// assert_eq!(feed_efficiency.rating, FeedEfficiencyRating::Average); | ||
/// | ||
/// ``` | ||
/// | ||
pub fn calculate_feed_efficiency(fcr: f64, livestock_type: LivestockType) -> Result<FeedEfficiency> { | ||
ensure!(fcr > 0.0, "Feed Conversion Ratio (FCR) must be greater than 0."); | ||
|
||
// Feed efficiency values for different animals. | ||
// | ||
// Source: <https://www.farmbrite.com/post/feed-conversion-ratio-calculator> | ||
let (min_fcr, max_fcr) = match livestock_type { | ||
LivestockType::Cattle => (8.0, 12.0), | ||
LivestockType::Goat | LivestockType::Sheep => (4.5, 5.5), | ||
LivestockType::Swine => (3.0, 3.9), | ||
LivestockType::Chicken => (1.5, 2.0), | ||
LivestockType::Rabbit => (3.5, 5.0), | ||
}; | ||
|
||
let feed_efficiency = if fcr > max_fcr { | ||
FeedEfficiency { | ||
rating: FeedEfficiencyRating::Poor, | ||
value: fcr, | ||
avg_min_fcr: min_fcr, | ||
avg_max_fcr: max_fcr | ||
} | ||
} else if fcr < min_fcr { | ||
FeedEfficiency { | ||
rating: FeedEfficiencyRating::Good, | ||
value: fcr, | ||
avg_min_fcr: min_fcr, | ||
avg_max_fcr: max_fcr | ||
} | ||
} else { | ||
FeedEfficiency { | ||
rating: FeedEfficiencyRating::Average, | ||
value: fcr, | ||
avg_min_fcr: min_fcr, | ||
avg_max_fcr: max_fcr | ||
} | ||
}; | ||
|
||
Ok(feed_efficiency) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::types::LivestockType; | ||
|
||
#[test] | ||
fn test_calculate_feed_efficiency() { | ||
let feed_efficiency_test_cases = [ | ||
(10.0, LivestockType::Cattle, FeedEfficiencyRating::Average), | ||
(4.0, LivestockType::Cattle, FeedEfficiencyRating::Good), | ||
(2.0, LivestockType::Cattle, FeedEfficiencyRating::Good), | ||
(15.0, LivestockType::Cattle, FeedEfficiencyRating::Poor), | ||
(5.0, LivestockType::Goat, FeedEfficiencyRating::Average), | ||
(4.5, LivestockType::Goat, FeedEfficiencyRating::Average), | ||
(5.5, LivestockType::Goat, FeedEfficiencyRating::Average), | ||
(3.0, LivestockType::Swine, FeedEfficiencyRating::Average), | ||
(3.9, LivestockType::Swine, FeedEfficiencyRating::Average), | ||
(1.5, LivestockType::Chicken, FeedEfficiencyRating::Average), | ||
(2.0, LivestockType::Chicken, FeedEfficiencyRating::Average), | ||
(3.5, LivestockType::Rabbit, FeedEfficiencyRating::Average), | ||
(5.0, LivestockType::Rabbit, FeedEfficiencyRating::Average), | ||
]; | ||
|
||
for (fcr, livestock_type, expected) in feed_efficiency_test_cases.iter() { | ||
let result = calculate_feed_efficiency(*fcr, livestock_type.clone()); | ||
assert!(result.is_ok()); | ||
assert_eq!(result.unwrap().rating, *expected); | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_calculate_feed_efficiency_zero_fcr() { | ||
let result = calculate_feed_efficiency(0.0, LivestockType::Cattle); | ||
assert!(result.is_err()); | ||
} | ||
} |
Oops, something went wrong.