use crate::data::petekio::{canonical_mnemonic, WellCurveInput};
fn is_effective_porosity(mnemonic: &str) -> bool {
canonical_mnemonic(mnemonic) == "PHIE"
}
fn is_effective_sw(mnemonic: &str) -> bool {
canonical_mnemonic(mnemonic) == "SW"
}
#[must_use]
pub fn petro_samples(curves: &[WellCurveInput]) -> Vec<(f64, f64, f64)> {
let mut well_ids: Vec<&str> = Vec::new();
for c in curves {
if !well_ids.contains(&c.well_id.as_str()) {
well_ids.push(&c.well_id);
}
}
let mut out = Vec::new();
for wid in well_ids {
let phi = curves
.iter()
.find(|c| c.well_id == wid && is_effective_porosity(&c.mnemonic));
let sw = curves
.iter()
.find(|c| c.well_id == wid && is_effective_sw(&c.mnemonic));
let (Some(phi), Some(sw)) = (phi, sw) else {
continue; };
let n = phi.values.len().min(sw.values.len()).min(phi.xyz.len());
for i in 0..n {
let [x, y, z] = phi.xyz[i];
let (p, s) = (phi.values[i], sw.values[i]);
if x.is_finite() && y.is_finite() && z.is_finite() && p.is_finite() && s.is_finite() {
out.push((z, p, s));
}
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
use crate::data::petekio::Provenance;
fn curve(mnemonic: &str, vals: Vec<f64>, zs: Vec<f64>) -> WellCurveInput {
WellCurveInput {
well_id: "A1".to_string(),
mnemonic: mnemonic.to_string(),
md: zs.clone(),
values: vals,
xyz: zs.iter().map(|&z| [100.0, 200.0, z]).collect(),
provenance: Provenance::HardData,
}
}
#[test]
fn pairs_phie_and_sw_skipping_nan() {
let phie = curve(
"PHIE",
vec![0.24, f64::NAN, 0.21],
vec![8000.0, 8010.0, 8020.0],
);
let sw = curve("SW", vec![0.28, 0.30, 0.31], vec![8000.0, 8010.0, 8020.0]);
let s = petro_samples(&[phie, sw]);
assert_eq!(s, vec![(8000.0, 0.24, 0.28), (8020.0, 0.21, 0.31)]);
}
#[test]
fn unpositioned_xyz_is_dropped() {
let mut phie = curve("PHIE", vec![0.24, 0.22], vec![8000.0, 8010.0]);
phie.xyz[1] = [f64::NAN; 3]; let sw = curve("SW", vec![0.28, 0.30], vec![8000.0, 8010.0]);
let s = petro_samples(&[phie, sw]);
assert_eq!(s, vec![(8000.0, 0.24, 0.28)]);
}
#[test]
fn no_sw_curve_yields_nothing() {
let phie = curve("PHIE", vec![0.24], vec![8000.0]);
assert!(petro_samples(&[phie]).is_empty());
}
#[test]
fn resolves_vendor_mnemonic_variants_through_canonical() {
let phi = curve("EFFPHI", vec![0.24, 0.21], vec![8000.0, 8020.0]);
let sw = curve("SUWI", vec![0.28, 0.31], vec![8000.0, 8020.0]);
let s = petro_samples(&[phi, sw]);
assert_eq!(s, vec![(8000.0, 0.24, 0.28), (8020.0, 0.21, 0.31)]);
}
#[test]
fn total_porosity_is_not_folded_into_effective() {
let phit = curve("PHIT", vec![0.30, 0.28], vec![8000.0, 8020.0]);
let sw = curve("SW", vec![0.28, 0.31], vec![8000.0, 8020.0]);
assert!(petro_samples(&[phit, sw]).is_empty());
}
}