ground_motion_lib/writers.rs
1//! # Data Writers for GMPE Output Files
2//!
3//! This module provides utilities for writing ground motion prediction results
4//! (as [`GmpePoint`] instances) to delimited text files.
5//!
6//! ## Features
7//!
8//! - Serialize computed GMPE values for site points into CSV or other delimited formats.
9//! - Configurable delimiter support (e.g., tab, comma).
10//! - Optionally writes header rows.
11//!
12//! ## Primary Functions
13//!
14//! - [`write_gmpe_points`]: Writes a vector of [`GmpePoint`] instances to a delimited file.
15//!
16//! ## Example Output Format (tab-delimited)
17//!
18//! ```text
19//! lon lat value kind
20//! 142.600 50.100 0.789 Pga
21//! 142.700 50.200 0.923 Pga
22//! ```
23//!
24//! ## See Also
25//!
26//! - [`crate::gmm::GmpePoint`]
27//! - [`csv`](https://docs.rs/csv/)
28
29use crate::gmm::GmpePoint;
30use csv::WriterBuilder;
31use std::error::Error;
32use std::fs::File;
33use std::path::Path;
34
35/// Writes a list of [`GmpePoint`] instances to a delimited text file.
36///
37/// This function serializes a list of ground motion prediction results into a file
38/// with a configurable delimiter. Each [`GmpePoint`] is written as a CSV row,
39/// including a header row describing the columns.
40///
41/// # Type Parameters
42///
43/// * `P` — A type convertible to a [`Path`] reference (e.g., `&str`, `PathBuf`).
44///
45/// # Arguments
46///
47/// * `path` — The output file path.
48/// * `delim` — Delimiter character for the file (e.g., `b','` for comma, `b'\t'` for tab).
49/// * `points` — A slice of [`GmpePoint`] instances to write.
50///
51/// # Returns
52///
53/// * `Ok(())` if writing was successful.
54/// * An error boxed as `Box<dyn Error>` if file I/O or serialization fails.
55///
56/// # Example
57///
58/// ```rust
59/// use ground_motion_lib::writers::write_gmpe_points;
60/// use ground_motion_lib::gmm::{GmpePoint, GmpePointKind};
61///
62/// let points = vec![
63/// GmpePoint { lon: 10.0, lat: 20.0, value: 0.5, kind: GmpePointKind::Pga },
64/// GmpePoint { lon: 15.0, lat: 25.0, value: 0.8, kind: GmpePointKind::Pga },
65/// ];
66///
67/// write_gmpe_points("output.csv", b'\t', &points).unwrap();
68/// ```
69///
70/// # Errors
71///
72/// Returns an error if:
73/// - The file cannot be created or opened.
74/// - Any [`GmpePoint`] instance fails to serialize.
75pub fn write_gmpe_points<P: AsRef<Path>>(
76 path: P,
77 delim: u8,
78 points: &[GmpePoint],
79) -> Result<(), Box<dyn Error>> {
80 // Open the file in write mode, create if doesn't exist
81 let file = File::create(path)?;
82
83 // Build a CSV writer with the specified delimiter and no headers
84 let mut wtr = WriterBuilder::new()
85 .delimiter(delim)
86 .has_headers(true)
87 .from_writer(file);
88
89 // Serialize each GmpePoint struct as a CSV record
90 for point in points {
91 wtr.serialize(point)?;
92 }
93
94 // Ensure all data is flushed to the file
95 wtr.flush()?;
96 Ok(())
97}