///|
/// Selection policy for exporting a review-ready event catalog.
pub struct EventSelectionPolicy {
minimum_magnitude : Double
minimum_confidence : Double
minimum_stations : Int
minimum_separation_seconds : Double
maximum_depth_km : Double
}
///|
/// Return a practical production selection policy.
pub fn default_event_selection_policy() -> EventSelectionPolicy {
{
minimum_magnitude: 0.0,
minimum_confidence: 0.5,
minimum_stations: 2,
minimum_separation_seconds: 0.0,
maximum_depth_km: 700.0,
}
}
///|
/// Filter catalog entries by quality and physical constraints.
pub fn select_catalog_entries(
catalog : EventCatalog,
policy : EventSelectionPolicy,
) -> Array[CatalogEntry] {
let selected = catalog.entries.filter(entry => {
entry.magnitude >= policy.minimum_magnitude &&
entry.confidence >= policy.minimum_confidence &&
entry.station_count >= policy.minimum_stations &&
entry.depth_km <= policy.maximum_depth_km
})
if policy.minimum_separation_seconds <= 0.0 {
return selected
}
let sorted = selected.copy()
sorted.sort_by((left, right) => {
if left.origin_time < right.origin_time {
-1
} else if left.origin_time > right.origin_time {
1
} else {
0
}
})
let result : Array[CatalogEntry] = Array::new()
for entry in sorted {
let separated = result.is_empty() ||
(entry.origin_time - result[result.length() - 1].origin_time).abs() >=
policy.minimum_separation_seconds
if separated {
result.push(entry)
}
}
result
}
///|
/// Return the largest event in a selected catalog.
pub fn strongest_selected_entry(entries : Array[CatalogEntry]) -> CatalogEntry? {
if entries.is_empty() {
return None
}
let mut best = entries[0]
for entry in entries {
if entry.magnitude > best.magnitude {
best = entry
}
}
Some(best)
}
///|
/// Return an event density in entries per day.
pub fn selected_event_rate(entries : Array[CatalogEntry]) -> Double {
if entries.length() < 2 {
0.0
} else {
let times = entries.map(entry => entry.origin_time)
let duration = maximum_sample(times) - minimum_sample(times)
if duration <= 0.0 {
0.0
} else {
entries.length().to_double() * 86400.0 / duration
}
}
}
///|
/// Format a selection policy.
pub fn event_selection_policy_text(policy : EventSelectionPolicy) -> String {
"min_magnitude=" +
policy.minimum_magnitude.to_string() +
" min_confidence=" +
policy.minimum_confidence.to_string() +
" min_stations=" +
policy.minimum_stations.to_string() +
" min_separation=" +
policy.minimum_separation_seconds.to_string() +
" max_depth=" +
policy.maximum_depth_km.to_string()
}