use crate::domain::hfbi::{AnagraficaHFBI, CampionamentoHFBI};
pub fn calc_ddom(campionamento: &CampionamentoHFBI, anagrafica: &AnagraficaHFBI) -> f32 {
let (s90, b90): (u32, f32) = calc_s90_b90(campionamento, anagrafica);
let ddom = (((s90 as f32 - 1.0) / b90) + 1.0).ln();
(1000.0 * ddom).round() / 1000.0
}
fn calc_s90_b90(campionamento: &CampionamentoHFBI, anagrafica: &AnagraficaHFBI) -> (u32, f32) {
let mut biomassa_tot = 0.0;
for cattura in campionamento {
biomassa_tot += cattura.peso;
}
let biomassa_90 = biomassa_tot * 0.9;
let mut n_specie_90: u32 = 0;
let mut biomassa_tmp: f32 = 0.0;
for cattura in campionamento.sorted_by_peso_desc() {
biomassa_tmp += cattura.peso;
n_specie_90 += 1;
if biomassa_tmp > biomassa_90 {
break;
}
}
let area: f32 = anagrafica.get_lunghezza_media() * anagrafica.get_larghezza_media();
let b90: f32 = ((biomassa_90 / area) * 100.0 + 1.0).ln();
(n_specie_90, b90)
}
#[cfg(test)]
mod ddom_private_tests {
use super::*;
use crate::domain::hfbi::{
AnagraficaHFBI, CampionamentoHFBI, GruppoEcoHFBI, GruppoTrofHFBI, HabitatHFBI, RecordHFBI,
SpecieHFBI, StagioneHFBI, TipoLagunaCostieraHFBI,
};
use crate::domain::location::Location;
const EPSILON: f32 = 1e-6;
fn create_test_anagrafica(lunghezza: f32, larghezza: f32) -> AnagraficaHFBI {
AnagraficaHFBI::new_raw_unchecked(
"TestStazione".to_string(),
"TestCorpoIdrico".to_string(),
Location {
regione: "Test".to_string(),
provincia: "Test".to_string(),
},
"01/01/2025".to_string(),
TipoLagunaCostieraHFBI::MAt1,
StagioneHFBI::Primavera,
HabitatHFBI::NonVegetato,
lunghezza,
larghezza,
)
}
fn create_dummy_record(peso: f32) -> RecordHFBI {
RecordHFBI {
specie: SpecieHFBI {
nome_comune: "Dummy".to_string(),
codice_specie: "DM".to_string(),
autoctono: true,
gruppo_eco: GruppoEcoHFBI::ResidentiDiEstuario,
gruppo_trofico: GruppoTrofHFBI {
microbentivori: 0.0,
macrobentivori: 0.0,
iperbentivori: 0.0,
erbivori: 0.0,
detritivori: 0.0,
planctivori: 0.0,
onnivori: 0.0,
},
},
numero_individui: 1,
peso,
}
}
#[test]
fn test_s90_b90_order_invariant() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new_raw_unsorted(vec![
create_dummy_record(1.0),
create_dummy_record(1.0),
create_dummy_record(900.0),
]);
let sorted = CampionamentoHFBI::new_raw_unsorted(vec![
create_dummy_record(900.0),
create_dummy_record(1.0),
create_dummy_record(1.0),
]);
let (n_specie_90, b90) = calc_s90_b90(&campione, &anagrafica);
let (n_specie_90_sorted, b90_sorted) = calc_s90_b90(&sorted, &anagrafica);
assert!((b90 - b90_sorted).abs() < EPSILON);
assert!(n_specie_90 == n_specie_90_sorted);
}
#[test]
fn test_ddom_order_invariant() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new_raw_unsorted(vec![
create_dummy_record(1.0),
create_dummy_record(1.0),
create_dummy_record(900.0),
]);
let sorted = CampionamentoHFBI::new_raw_unsorted(vec![
create_dummy_record(900.0),
create_dummy_record(1.0),
create_dummy_record(1.0),
]);
let ddom = calc_ddom(&campione, &anagrafica);
let ddom_sorted = calc_ddom(&sorted, &anagrafica);
assert!((ddom - ddom_sorted).abs() < EPSILON);
}
#[test]
fn test_s90_b90_empty_input() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new(vec![]);
let (s90, b90) = calc_s90_b90(&campione, &anagrafica);
assert_eq!(s90, 0);
assert!((b90 - 0.0).abs() < EPSILON);
}
#[test]
fn test_s90_b90_single_species() {
let anagrafica = create_test_anagrafica(10.0, 10.0); let campione = CampionamentoHFBI::new(vec![create_dummy_record(200.0)]);
let (s90, b90) = calc_s90_b90(&campione, &anagrafica);
assert_eq!(s90, 1);
let expected_b90 = 181.0_f32.ln();
assert!((b90 - expected_b90).abs() < EPSILON);
}
#[test]
fn test_s90_b90_zero_area() {
let anagrafica = create_test_anagrafica(10.0, 0.0); let campione = CampionamentoHFBI::new(vec![create_dummy_record(100.0)]);
let (s90, b90) = calc_s90_b90(&campione, &anagrafica);
assert_eq!(s90, 1);
assert!(b90.is_infinite());
}
#[test]
fn test_ddom_empty_input() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new(vec![]);
let result = calc_ddom(&campione, &anagrafica);
assert!(result.is_nan());
}
#[test]
fn test_ddom_single_species() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new(vec![create_dummy_record(100.0)]);
let result = calc_ddom(&campione, &anagrafica);
assert!((result - 0.0).abs() < EPSILON);
}
#[test]
fn test_ddom_zero_area() {
let anagrafica = create_test_anagrafica(10.0, 0.0); let campione =
CampionamentoHFBI::new(vec![create_dummy_record(100.0), create_dummy_record(50.0)]);
let result = calc_ddom(&campione, &anagrafica);
assert!((result - 0.0).abs() < EPSILON);
}
#[test]
fn test_ddom_standard_case() {
let anagrafica = create_test_anagrafica(10.0, 10.0); let campione = CampionamentoHFBI::new(vec![
create_dummy_record(100.0),
create_dummy_record(50.0),
create_dummy_record(30.0),
create_dummy_record(20.0), ]);
let s90 = 4.0_f32;
let b90 = 181.0_f32.ln();
let expected_result = (1000.0 * (((s90 - 1.0) / b90) + 1.0).ln()).round() / 1000.0;
let actual_result = calc_ddom(&campione, &anagrafica);
assert!((actual_result - expected_result).abs() < EPSILON);
}
}