use crate::domain::hfbi::{AnagraficaHFBI, CampionamentoHFBI, GruppoEcoHFBI};
use crate::domain::posf32::PositiveF32;
use std::collections::HashSet;
pub fn calc_dmig(campione: &CampionamentoHFBI, anagrafica: &AnagraficaHFBI) -> Result<f32, String> {
let bmig = calc_bmig(campione, anagrafica)?;
let mut specie = HashSet::new();
for cattura in campione {
match cattura.specie.gruppo_eco {
GruppoEcoHFBI::Diadromi | GruppoEcoHFBI::MigratoriMarini => {
specie.insert(cattura.specie.codice_specie.as_str());
}
_ => {}
}
}
let smig = specie.len();
if smig == 0 {
return Ok(0.0);
}
if smig == 1 {
return Ok(0.01);
}
let dmig = (((smig as f32 - 1.0) / bmig.ln()) + 1.0).ln();
Ok((1000.0 * dmig).round() / 1000.0)
}
fn calc_bmig(campione: &CampionamentoHFBI, anagrafica: &AnagraficaHFBI) -> Result<f32, String> {
let width = anagrafica.get_larghezza_media();
let length = anagrafica.get_lunghezza_media();
let width_checked = PositiveF32::new(width).map_err(|e| e.to_string())?;
let length_checked = PositiveF32::new(length).map_err(|e| e.to_string())?;
let area: f32 = *width_checked * *length_checked;
let mut biomig = 0.0;
for specie in campione {
match specie.specie.gruppo_eco {
GruppoEcoHFBI::Diadromi | GruppoEcoHFBI::MigratoriMarini => biomig += specie.peso,
_ => {}
}
}
Ok((biomig / area) * 100.0)
}
#[cfg(test)]
mod dmig_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_specie_record(
codice_specie: &'static str,
gruppo_eco: GruppoEcoHFBI,
peso: f32,
) -> RecordHFBI {
RecordHFBI {
specie: SpecieHFBI {
nome_comune: "Test Specie".to_string(),
codice_specie: codice_specie.to_string(),
autoctono: true,
gruppo_eco,
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_bmig_empty_input() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new(vec![]);
let res = calc_bmig(&campione, &anagrafica)
.expect("Area fields of anagrafica should be positive and finite");
assert!((res - 0.0).abs() < EPSILON);
}
#[test]
fn test_bmig_zero_area() {
let anagrafica = create_test_anagrafica(10.0, 0.0); let campione = CampionamentoHFBI::new(vec![create_specie_record(
"SP1",
GruppoEcoHFBI::Diadromi,
100.0,
)]);
let res = calc_bmig(&campione, &anagrafica);
assert!(res.is_err());
}
#[test]
fn test_bmig_standard_case() {
let anagrafica = create_test_anagrafica(20.0, 5.0); let campione = CampionamentoHFBI::new(vec![
create_specie_record("SP1", GruppoEcoHFBI::Diadromi, 150.0), create_specie_record("SP2", GruppoEcoHFBI::ResidentiDiEstuario, 100.0), create_specie_record("SP3", GruppoEcoHFBI::MigratoriMarini, 50.0), ]);
let expected = 200.0_f32;
let result = calc_bmig(&campione, &anagrafica)
.expect("Area fields of anagrafica should be positive and finite");
assert!((result - expected).abs() < EPSILON);
}
#[test]
fn test_dmig_smig_is_zero() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new(vec![create_specie_record(
"SP1",
GruppoEcoHFBI::ResidentiDiEstuario,
100.0,
)]);
let result = calc_dmig(&campione, &anagrafica)
.expect("Area fields of anagrafica should be positive and finite");
assert!((result - 0.0).abs() < EPSILON);
}
#[test]
fn test_dmig_smig_is_one() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new(vec![
create_specie_record("SP1", GruppoEcoHFBI::Diadromi, 100.0),
create_specie_record("SP1", GruppoEcoHFBI::Diadromi, 50.0), ]);
let result = calc_dmig(&campione, &anagrafica)
.expect("Area fields of anagrafica should be positive and finite");
assert!((result - 0.01).abs() < EPSILON);
}
#[test]
fn test_dmig_bmig_is_infinity() {
let anagrafica = create_test_anagrafica(10.0, 0.0); let campione = CampionamentoHFBI::new(vec![
create_specie_record("SP1", GruppoEcoHFBI::Diadromi, 100.0),
create_specie_record("SP2", GruppoEcoHFBI::MigratoriMarini, 50.0),
]);
let result = calc_dmig(&campione, &anagrafica);
assert!(result.is_err());
}
#[test]
fn test_dmig_standard_case_smig_greater_than_one() {
let anagrafica = create_test_anagrafica(20.0, 5.0); let campione = CampionamentoHFBI::new(vec![
create_specie_record("SP1", GruppoEcoHFBI::Diadromi, 150.0),
create_specie_record("SP2", GruppoEcoHFBI::MigratoriMarini, 250.0),
create_specie_record("SP1", GruppoEcoHFBI::Diadromi, 50.0), create_specie_record("SP3", GruppoEcoHFBI::ResidentiDiEstuario, 300.0), ]);
let bmig = 451.0_f32.ln();
let smig = 2.0_f32;
let expected = (1000.0 * (((smig - 1.0) / bmig) + 1.0).ln()).round() / 1000.0;
let result = calc_dmig(&campione, &anagrafica)
.expect("Area fields of anagrafica should be positive and finite");
assert!((result - expected).abs() < EPSILON);
}
}