use crate::domain::hfbi::{AnagraficaHFBI, CampionamentoHFBI, GruppoEcoHFBI};
use crate::domain::posf32::PositiveF32;
pub fn calc_dhzp(campione: &CampionamentoHFBI, anagrafica: &AnagraficaHFBI) -> Result<f32, String> {
let mut shzp = 0.0;
let bhzp = calc_bhzp(campione, anagrafica)?;
for specie in campione {
match specie.specie.gruppo_eco {
GruppoEcoHFBI::Diadromi
| GruppoEcoHFBI::MigratoriMarini
| GruppoEcoHFBI::ResidentiDiEstuario => {
shzp += specie.specie.gruppo_trofico.iperbentivori;
}
_ => {}
}
}
let epsilon: f32 = 1e-6;
if shzp.abs() < epsilon {
return Ok(0.0);
}
if (shzp - 0.2).abs() < epsilon {
return Ok(0.01);
}
let dhzp = (((shzp - 0.2) / bhzp.ln()) + 1.0).ln();
Ok((1000.0 * dhzp).round() / 1000.0)
}
fn calc_bhzp(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 biohzp = 0.0;
for specie in campione {
match specie.specie.gruppo_eco {
GruppoEcoHFBI::Diadromi
| GruppoEcoHFBI::MigratoriMarini
| GruppoEcoHFBI::ResidentiDiEstuario => {
biohzp += specie.peso * (specie.specie.gruppo_trofico.iperbentivori)
}
_ => {}
}
}
Ok((biohzp / area) * 100.0)
}
#[cfg(test)]
mod dhzp_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(
gruppo_eco: GruppoEcoHFBI,
peso: f32,
iperbentivori: f32,
) -> RecordHFBI {
RecordHFBI {
specie: SpecieHFBI {
nome_comune: "Test Specie".to_string(),
codice_specie: "TS".to_string(),
autoctono: true,
gruppo_eco,
gruppo_trofico: GruppoTrofHFBI {
iperbentivori,
microbentivori: 0.0,
macrobentivori: 0.0,
erbivori: 0.0,
detritivori: 0.0,
planctivori: 0.0,
onnivori: 0.0,
},
},
numero_individui: 1,
peso,
}
}
#[test]
fn test_bhzp_empty_input() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new(vec![]);
let res = calc_bhzp(&campione, &anagrafica)
.expect("Area fields of anagrafica should be positive and finite");
assert!((res - 0.0).abs() < EPSILON);
}
#[test]
fn test_bhzp_zero_area() {
let anagrafica = create_test_anagrafica(10.0, 0.0); let campione = CampionamentoHFBI::new(vec![create_specie_record(
GruppoEcoHFBI::ResidentiDiEstuario,
100.0,
1.0,
)]);
let res = calc_bhzp(&campione, &anagrafica);
assert!(res.is_err());
}
#[test]
fn test_bhzp_standard_case() {
let anagrafica = create_test_anagrafica(20.0, 5.0); let campione = CampionamentoHFBI::new(vec![
create_specie_record(GruppoEcoHFBI::ResidentiDiEstuario, 50.0, 0.5), create_specie_record(GruppoEcoHFBI::OccasionaliMarini, 100.0, 1.0), create_specie_record(GruppoEcoHFBI::MigratoriMarini, 100.0, 0.75), ]);
let expected = 100.0_f32;
let result = calc_bhzp(&campione, &anagrafica)
.expect("Area fields of anagrafica should be positive and finite");
assert!((result - expected).abs() < EPSILON);
}
#[test]
fn test_dhzp_shzp_is_zero() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new(
vec![create_specie_record(
GruppoEcoHFBI::ResidentiDiEstuario,
100.0,
0.0,
)],
);
let res = calc_dhzp(&campione, &anagrafica)
.expect("Area fields of anagrafica should be positive and finite");
assert!((res - 0.0).abs() < EPSILON);
}
#[test]
fn test_dhzp_shzp_is_point_two() {
let anagrafica = create_test_anagrafica(100.0, 5.0);
let campione = CampionamentoHFBI::new(vec![
create_specie_record(GruppoEcoHFBI::Diadromi, 100.0, 0.1),
create_specie_record(GruppoEcoHFBI::MigratoriMarini, 50.0, 0.1),
]);
let res = calc_dhzp(&campione, &anagrafica)
.expect("Area fields of anagrafica should be positive and finite");
assert!((res - 0.01).abs() < EPSILON);
}
#[test]
fn test_dhzp_bhzp_is_infinity() {
let anagrafica = create_test_anagrafica(10.0, 0.0); let campione = CampionamentoHFBI::new(vec![create_specie_record(
GruppoEcoHFBI::ResidentiDiEstuario,
100.0,
0.5,
)]);
let res = calc_dhzp(&campione, &anagrafica);
assert!(res.is_err());
}
#[test]
fn test_dhzp_standard_calculation() {
let anagrafica = create_test_anagrafica(10.0, 5.0); let campione = CampionamentoHFBI::new(vec![
create_specie_record(GruppoEcoHFBI::ResidentiDiEstuario, 100.0, 0.5),
create_specie_record(GruppoEcoHFBI::MigratoriMarini, 200.0, 1.0),
create_specie_record(GruppoEcoHFBI::OccasionaliMarini, 50.0, 0.8), ]);
let bhzp = 501.0_f32.ln();
let shzp = 1.5_f32;
let expected = (1000.0 * (((shzp - 0.2) / bhzp) + 1.0).ln()).round() / 1000.0;
let result = calc_dhzp(&campione, &anagrafica)
.expect("Area fields of anagrafica should be positive and finite");
assert!((result - expected).abs() < EPSILON);
}
}