///|
/// A compact export row for event catalog interchange.
pub struct CatalogExportRow {
id : Int
origin_time : Double
latitude : Double
longitude : Double
depth_km : Double
magnitude : Double
station_count : Int
confidence : Double
quality : String
}
///|
/// Return a quality label from catalog completeness and station support.
pub fn catalog_entry_quality(entry : CatalogEntry) -> String {
if entry.confidence >= 0.8 && entry.station_count >= 4 {
"high"
} else if entry.confidence >= 0.5 && entry.station_count >= 2 {
"medium"
} else {
"low"
}
}
///|
/// Convert catalog entries into stable export rows.
pub fn catalog_export_rows(catalog : EventCatalog) -> Array[CatalogExportRow] {
catalog.entries.map(entry => {
id: entry.id,
origin_time: entry.origin_time,
latitude: entry.latitude,
longitude: entry.longitude,
depth_km: entry.depth_km,
magnitude: entry.magnitude,
station_count: entry.station_count,
confidence: entry.confidence,
quality: catalog_entry_quality(entry),
})
}
///|
/// Serialize catalog rows as an extended CSV table.
pub fn catalog_export_csv(rows : Array[CatalogExportRow]) -> String {
let mut output = "id,origin_time,latitude,longitude,depth_km,magnitude,station_count,confidence,quality\n"
for row in rows {
output = output +
row.id.to_string() +
"," +
row.origin_time.to_string() +
"," +
row.latitude.to_string() +
"," +
row.longitude.to_string() +
"," +
row.depth_km.to_string() +
"," +
row.magnitude.to_string() +
"," +
row.station_count.to_string() +
"," +
row.confidence.to_string() +
"," +
row.quality +
"\n"
}
output
}
///|
/// Export catalog rows as a GeoJSON-like FeatureCollection string.
pub fn catalog_export_geojson(rows : Array[CatalogExportRow]) -> String {
let mut output = "{\"type\":\"FeatureCollection\",\"features\":["
for index = 0; index < rows.length(); index = index + 1 {
let row = rows[index]
if index > 0 {
output += ","
}
output += "{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[" +
row.longitude.to_string() +
"," +
row.latitude.to_string() +
"]},\"properties\":{"
output += "\"id\":" +
row.id.to_string() +
",\"origin_time\":" +
row.origin_time.to_string() +
",\"depth_km\":" +
row.depth_km.to_string() +
",\"magnitude\":" +
row.magnitude.to_string() +
",\"confidence\":" +
row.confidence.to_string() +
",\"quality\":\"" +
row.quality +
"\"}}"
}
output + "]}"
}
///|
/// Return rows sorted by descending magnitude.
pub fn sort_catalog_rows_by_magnitude(
rows : Array[CatalogExportRow],
) -> Array[CatalogExportRow] {
let result = rows.copy()
result.sort_by((left, right) => {
if left.magnitude > right.magnitude {
-1
} else if left.magnitude < right.magnitude {
1
} else {
left.id - right.id
}
})
result
}
///|
/// Return rows selected for a review queue.
pub fn catalog_review_queue(
rows : Array[CatalogExportRow],
minimum_magnitude : Double,
) -> Array[CatalogExportRow] {
sort_catalog_rows_by_magnitude(
rows.filter(row => {
row.magnitude >= minimum_magnitude || row.quality == "low"
}),
)
}
///|
/// Count events in quality bands.
pub fn catalog_quality_counts(rows : Array[CatalogExportRow]) -> Array[Int] {
[
rows.filter(row => row.quality == "high").length(),
rows.filter(row => row.quality == "medium").length(),
rows.filter(row => row.quality == "low").length(),
]
}
///|
/// Format catalog export statistics.
pub fn catalog_export_summary(rows : Array[CatalogExportRow]) -> String {
let counts = catalog_quality_counts(rows)
"rows=" +
rows.length().to_string() +
" high=" +
counts[0].to_string() +
" medium=" +
counts[1].to_string() +
" low=" +
counts[2].to_string()
}