use super::funejson::Value; use super::math_round_div::round_div; use super::math_round_float::round_float; /// Seed rate (kg/ha) = target plants/m² x TGW (g) / expected establishment (%). /// /// The TGW is taken to the centigram and the establishment is in basis points, /// so kg/ha is exactly plants x centigrams / basis points and is rounded once. /// Doing it in floats gets 100 x 1.15 / 100 = 1.1499999999999999, which rounds /// to 1.1 kg/ha instead of 1.2. /// /// # Panics /// Panics when an argument is out of range. pub fn seed_rate(target_plants_per_square_metre: i64, thousand_grain_weight_grams: f64, establishment_basis_points: i64) -> SeedRate { let plants = target_plants_per_square_metre; if !(1..=100000).contains(&plants) { panic!("targetPlantsPerSquareMetre must be a whole number from 1 to 100000, received {}", plants); } let tgw = thousand_grain_weight_grams; if !tgw.is_finite() || tgw <= 0.0 || tgw > 1000.0 { panic!("thousandGrainWeightGrams must be a finite number greater than 0 and at most 1000, received {}", tgw); } let centigrams = (round_float(tgw, 2) * 100.0).round() as i64; if centigrams < 1 { panic!("thousandGrainWeightGrams must be at least 0.01 grams, received {}", tgw); } let bp = establishment_basis_points; if !(1..=10000).contains(&bp) { panic!("establishmentBasisPoints must be a whole number from 1 to 10000, received {}", bp); } SeedRate { kg_per_hectare: round_div(plants * centigrams * 10, bp, "half-up") as f64 / 10.0, seeds_per_square_metre: round_div(plants * 100000, bp, "half-up") as f64 / 10.0, } } pub fn seed_rate_to_value(s: &SeedRate) -> Value { Value::obj(vec![ ("kgPerHectare", Value::Float(s.kg_per_hectare)), ("seedsPerSquareMetre", Value::Float(s.seeds_per_square_metre)), ]) } fn whole(v: &Value, message: &str) -> i64 { match v { Value::Int(i) => *i, _ => panic!("{}, received {:?}", message, v), } } pub fn fune_vector(args: &[Value]) -> Value { let plants = whole(&args[0], "targetPlantsPerSquareMetre must be a whole number from 1 to 100000"); let bp = whole(&args[2], "establishmentBasisPoints must be a whole number from 1 to 10000"); seed_rate_to_value(&seed_rate(plants, args[1].as_f64(), bp)) }