From 7484d444447f820927eb3a060f0461c18df14169 Mon Sep 17 00:00:00 2001 From: simonsantama Date: Wed, 11 Mar 2026 20:33:24 +0000 Subject: [PATCH 1/4] Adds 59.5 of sfpe --- crates/python_api/docs/api/sfpe-handbook.rst | 66 ++++++++++++++++++- crates/python_api/src/sfpe_handbook.rs | 2 + .../chapter_50/equation_50_17.rs | 2 +- .../chapter_50/equation_50_20.rs | 2 +- .../src/sfpe_handbook/chapter_59.rs | 25 +++++++ .../chapter_59/equation_59_10.rs | 36 ++++++++++ .../chapter_59/equation_59_11.rs | 36 ++++++++++ .../sfpe_handbook/chapter_59/equation_59_5.rs | 39 +++++++++++ .../sfpe_handbook/chapter_59/equation_59_6.rs | 36 ++++++++++ .../sfpe_handbook/chapter_59/equation_59_7.rs | 36 ++++++++++ .../sfpe_handbook/chapter_59/equation_59_8.rs | 36 ++++++++++ .../sfpe_handbook/chapter_59/equation_59_9.rs | 36 ++++++++++ .../src/chapter_50/equation_50_16.rs | 2 +- .../src/chapter_50/equation_50_17.rs | 7 +- crates/sfpe_handbook/src/chapter_59.rs | 7 ++ .../src/chapter_59/equation_59_10.rs | 22 +++++++ .../src/chapter_59/equation_59_11.rs | 22 +++++++ .../src/chapter_59/equation_59_5.rs | 30 +++++++++ .../src/chapter_59/equation_59_6.rs | 22 +++++++ .../src/chapter_59/equation_59_7.rs | 22 +++++++ .../src/chapter_59/equation_59_8.rs | 22 +++++++ .../src/chapter_59/equation_59_9.rs | 22 +++++++ crates/sfpe_handbook/src/lib.rs | 1 + 23 files changed, 526 insertions(+), 5 deletions(-) create mode 100644 crates/python_api/src/sfpe_handbook/chapter_59.rs create mode 100644 crates/python_api/src/sfpe_handbook/chapter_59/equation_59_10.rs create mode 100644 crates/python_api/src/sfpe_handbook/chapter_59/equation_59_11.rs create mode 100644 crates/python_api/src/sfpe_handbook/chapter_59/equation_59_5.rs create mode 100644 crates/python_api/src/sfpe_handbook/chapter_59/equation_59_6.rs create mode 100644 crates/python_api/src/sfpe_handbook/chapter_59/equation_59_7.rs create mode 100644 crates/python_api/src/sfpe_handbook/chapter_59/equation_59_8.rs create mode 100644 crates/python_api/src/sfpe_handbook/chapter_59/equation_59_9.rs create mode 100644 crates/sfpe_handbook/src/chapter_59.rs create mode 100644 crates/sfpe_handbook/src/chapter_59/equation_59_10.rs create mode 100644 crates/sfpe_handbook/src/chapter_59/equation_59_11.rs create mode 100644 crates/sfpe_handbook/src/chapter_59/equation_59_5.rs create mode 100644 crates/sfpe_handbook/src/chapter_59/equation_59_6.rs create mode 100644 crates/sfpe_handbook/src/chapter_59/equation_59_7.rs create mode 100644 crates/sfpe_handbook/src/chapter_59/equation_59_8.rs create mode 100644 crates/sfpe_handbook/src/chapter_59/equation_59_9.rs diff --git a/crates/python_api/docs/api/sfpe-handbook.rst b/crates/python_api/docs/api/sfpe-handbook.rst index 8253ffd9..dbeb1d97 100644 --- a/crates/python_api/docs/api/sfpe-handbook.rst +++ b/crates/python_api/docs/api/sfpe-handbook.rst @@ -137,4 +137,68 @@ Equation 50.20 - Visibility Through Smoke (Percent Obscuration) .. automodule:: ofire.sfpe_handbook.chapter_50.equation_50_20 :members: :undoc-members: - :show-inheritance: \ No newline at end of file + :show-inheritance: + +Chapter 59 +---------- + +.. automodule:: ofire.sfpe_handbook.chapter_59 + :members: + :undoc-members: + :show-inheritance: + +Equation 59.5 +~~~~~~~~~~~~~ + +.. automodule:: ofire.sfpe_handbook.chapter_59.equation_59_5 + :members: + :undoc-members: + :show-inheritance: + +Equation 59.6 +~~~~~~~~~~~~~ + +.. automodule:: ofire.sfpe_handbook.chapter_59.equation_59_6 + :members: + :undoc-members: + :show-inheritance: + +Equation 59.7 +~~~~~~~~~~~~~ + +.. automodule:: ofire.sfpe_handbook.chapter_59.equation_59_7 + :members: + :undoc-members: + :show-inheritance: + +Equation 59.8 +~~~~~~~~~~~~~ + +.. automodule:: ofire.sfpe_handbook.chapter_59.equation_59_8 + :members: + :undoc-members: + :show-inheritance: + +Equation 59.9 +~~~~~~~~~~~~~ + +.. automodule:: ofire.sfpe_handbook.chapter_59.equation_59_9 + :members: + :undoc-members: + :show-inheritance: + +Equation 59.10 +~~~~~~~~~~~~~~ + +.. automodule:: ofire.sfpe_handbook.chapter_59.equation_59_10 + :members: + :undoc-members: + :show-inheritance: + +Equation 59.11 +~~~~~~~~~~~~~~ + +.. automodule:: ofire.sfpe_handbook.chapter_59.equation_59_11 + :members: + :undoc-members: + :show-inheritance: diff --git a/crates/python_api/src/sfpe_handbook.rs b/crates/python_api/src/sfpe_handbook.rs index e7819f46..f8cf8474 100644 --- a/crates/python_api/src/sfpe_handbook.rs +++ b/crates/python_api/src/sfpe_handbook.rs @@ -1,5 +1,6 @@ pub mod chapter_14; pub mod chapter_50; +pub mod chapter_59; use pyo3::prelude::*; use pyo3::wrap_pymodule; @@ -14,5 +15,6 @@ use pyo3::wrap_pymodule; pub fn sfpe_handbook(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_wrapped(wrap_pymodule!(chapter_14::chapter_14))?; m.add_wrapped(wrap_pymodule!(chapter_50::chapter_50))?; + m.add_wrapped(wrap_pymodule!(chapter_59::chapter_59))?; Ok(()) } diff --git a/crates/python_api/src/sfpe_handbook/chapter_50/equation_50_17.rs b/crates/python_api/src/sfpe_handbook/chapter_50/equation_50_17.rs index 3a72c4fa..3fe71356 100644 --- a/crates/python_api/src/sfpe_handbook/chapter_50/equation_50_17.rs +++ b/crates/python_api/src/sfpe_handbook/chapter_50/equation_50_17.rs @@ -43,4 +43,4 @@ fn stairwell_temperature(t_0: f64, eta: f64, t_b: f64) -> PyResult { pub fn equation_50_17(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(stairwell_temperature, m)?)?; Ok(()) -} \ No newline at end of file +} diff --git a/crates/python_api/src/sfpe_handbook/chapter_50/equation_50_20.rs b/crates/python_api/src/sfpe_handbook/chapter_50/equation_50_20.rs index 2f2c6ba0..f28b274a 100644 --- a/crates/python_api/src/sfpe_handbook/chapter_50/equation_50_20.rs +++ b/crates/python_api/src/sfpe_handbook/chapter_50/equation_50_20.rs @@ -43,4 +43,4 @@ fn visibility(k: f64, l: f64, lambda: f64) -> PyResult { pub fn equation_50_20(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(visibility, m)?)?; Ok(()) -} \ No newline at end of file +} diff --git a/crates/python_api/src/sfpe_handbook/chapter_59.rs b/crates/python_api/src/sfpe_handbook/chapter_59.rs new file mode 100644 index 00000000..c09cd0e1 --- /dev/null +++ b/crates/python_api/src/sfpe_handbook/chapter_59.rs @@ -0,0 +1,25 @@ +pub mod equation_59_10; +pub mod equation_59_11; +pub mod equation_59_5; +pub mod equation_59_6; +pub mod equation_59_7; +pub mod equation_59_8; +pub mod equation_59_9; + +use pyo3::prelude::*; +use pyo3::wrap_pymodule; + +#[pymodule] +/// Chapter 59 - Placeholder equations. +/// +/// This chapter contains placeholder equations that will be implemented. +pub fn chapter_59(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_wrapped(wrap_pymodule!(equation_59_5::equation_59_5))?; + m.add_wrapped(wrap_pymodule!(equation_59_6::equation_59_6))?; + m.add_wrapped(wrap_pymodule!(equation_59_7::equation_59_7))?; + m.add_wrapped(wrap_pymodule!(equation_59_8::equation_59_8))?; + m.add_wrapped(wrap_pymodule!(equation_59_9::equation_59_9))?; + m.add_wrapped(wrap_pymodule!(equation_59_10::equation_59_10))?; + m.add_wrapped(wrap_pymodule!(equation_59_11::equation_59_11))?; + Ok(()) +} diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_10.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_10.rs new file mode 100644 index 00000000..a5ef16c7 --- /dev/null +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_10.rs @@ -0,0 +1,36 @@ +use pyo3::prelude::*; + +#[pyfunction] +/// Placeholder for equation 59.10. +/// +/// This function is a placeholder and will be implemented with the actual +/// equation logic. +/// +/// .. math:: +/// +/// \text{TODO: Add equation} +/// +/// where: +/// +/// - TODO: Add variable definitions +/// +/// Args: +/// TODO: Add arguments +/// +/// Returns: +/// float: TODO: Add return description +/// +/// Example: +/// >>> import ofire +/// >>> # TODO: Add example when equation is implemented +fn equation_59_10_placeholder() -> PyResult { + Err(pyo3::exceptions::PyNotImplementedError::new_err( + "Equation 59.10 is not yet implemented", + )) +} + +#[pymodule] +pub fn equation_59_10(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(pyo3::wrap_pyfunction!(equation_59_10_placeholder, m)?)?; + Ok(()) +} diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_11.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_11.rs new file mode 100644 index 00000000..f8c4b3be --- /dev/null +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_11.rs @@ -0,0 +1,36 @@ +use pyo3::prelude::*; + +#[pyfunction] +/// Placeholder for equation 59.11. +/// +/// This function is a placeholder and will be implemented with the actual +/// equation logic. +/// +/// .. math:: +/// +/// \text{TODO: Add equation} +/// +/// where: +/// +/// - TODO: Add variable definitions +/// +/// Args: +/// TODO: Add arguments +/// +/// Returns: +/// float: TODO: Add return description +/// +/// Example: +/// >>> import ofire +/// >>> # TODO: Add example when equation is implemented +fn equation_59_11_placeholder() -> PyResult { + Err(pyo3::exceptions::PyNotImplementedError::new_err( + "Equation 59.11 is not yet implemented", + )) +} + +#[pymodule] +pub fn equation_59_11(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(pyo3::wrap_pyfunction!(equation_59_11_placeholder, m)?)?; + Ok(()) +} diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_5.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_5.rs new file mode 100644 index 00000000..fee6ca21 --- /dev/null +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_5.rs @@ -0,0 +1,39 @@ +use pyo3::prelude::*; + +use openfire::sfpe_handbook::chapter_59::equation_59_5 as rust_equation_59_5; + +#[pyfunction] +/// Calculates pedestrian travel speed along a path (Equation 59.5). +/// +/// .. math:: +/// +/// S = k - akD +/// +/// where: +/// +/// - :math:`S` is the speed along the line of travel +/// - :math:`k` is the speed constant from Table 59.2 +/// - :math:`a` is the unit conversion constant (0.266 for SI, 2.86 for imperial) +/// - :math:`D` is the population density in persons per unit area +/// +/// Args: +/// k (float): Speed constant from Table 59.2 +/// a (float): Unit conversion constant (0.266 for SI, 2.86 for imperial) +/// d (float): Population density (persons per unit area) +/// +/// Returns: +/// float: Speed S along the line of travel +/// +/// Example: +/// >>> import ofire +/// >>> result = ofire.sfpe_handbook.chapter_59.equation_59_5.travel_speed(1.19, 0.266, 0.5) +/// >>> print(f"{result:.3f} m/s") +fn travel_speed(k: f64, a: f64, d: f64) -> PyResult { + Ok(rust_equation_59_5::travel_speed(k, a, d)) +} + +#[pymodule] +pub fn equation_59_5(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(pyo3::wrap_pyfunction!(travel_speed, m)?)?; + Ok(()) +} diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_6.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_6.rs new file mode 100644 index 00000000..e4fecaf5 --- /dev/null +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_6.rs @@ -0,0 +1,36 @@ +use pyo3::prelude::*; + +#[pyfunction] +/// Placeholder for equation 59.6. +/// +/// This function is a placeholder and will be implemented with the actual +/// equation logic. +/// +/// .. math:: +/// +/// \text{TODO: Add equation} +/// +/// where: +/// +/// - TODO: Add variable definitions +/// +/// Args: +/// TODO: Add arguments +/// +/// Returns: +/// float: TODO: Add return description +/// +/// Example: +/// >>> import ofire +/// >>> # TODO: Add example when equation is implemented +fn equation_59_6_placeholder() -> PyResult { + Err(pyo3::exceptions::PyNotImplementedError::new_err( + "Equation 59.6 is not yet implemented", + )) +} + +#[pymodule] +pub fn equation_59_6(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(pyo3::wrap_pyfunction!(equation_59_6_placeholder, m)?)?; + Ok(()) +} diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_7.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_7.rs new file mode 100644 index 00000000..fe991aee --- /dev/null +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_7.rs @@ -0,0 +1,36 @@ +use pyo3::prelude::*; + +#[pyfunction] +/// Placeholder for equation 59.7. +/// +/// This function is a placeholder and will be implemented with the actual +/// equation logic. +/// +/// .. math:: +/// +/// \text{TODO: Add equation} +/// +/// where: +/// +/// - TODO: Add variable definitions +/// +/// Args: +/// TODO: Add arguments +/// +/// Returns: +/// float: TODO: Add return description +/// +/// Example: +/// >>> import ofire +/// >>> # TODO: Add example when equation is implemented +fn equation_59_7_placeholder() -> PyResult { + Err(pyo3::exceptions::PyNotImplementedError::new_err( + "Equation 59.7 is not yet implemented", + )) +} + +#[pymodule] +pub fn equation_59_7(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(pyo3::wrap_pyfunction!(equation_59_7_placeholder, m)?)?; + Ok(()) +} diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_8.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_8.rs new file mode 100644 index 00000000..4c86d59a --- /dev/null +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_8.rs @@ -0,0 +1,36 @@ +use pyo3::prelude::*; + +#[pyfunction] +/// Placeholder for equation 59.8. +/// +/// This function is a placeholder and will be implemented with the actual +/// equation logic. +/// +/// .. math:: +/// +/// \text{TODO: Add equation} +/// +/// where: +/// +/// - TODO: Add variable definitions +/// +/// Args: +/// TODO: Add arguments +/// +/// Returns: +/// float: TODO: Add return description +/// +/// Example: +/// >>> import ofire +/// >>> # TODO: Add example when equation is implemented +fn equation_59_8_placeholder() -> PyResult { + Err(pyo3::exceptions::PyNotImplementedError::new_err( + "Equation 59.8 is not yet implemented", + )) +} + +#[pymodule] +pub fn equation_59_8(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(pyo3::wrap_pyfunction!(equation_59_8_placeholder, m)?)?; + Ok(()) +} diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_9.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_9.rs new file mode 100644 index 00000000..86843347 --- /dev/null +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_9.rs @@ -0,0 +1,36 @@ +use pyo3::prelude::*; + +#[pyfunction] +/// Placeholder for equation 59.9. +/// +/// This function is a placeholder and will be implemented with the actual +/// equation logic. +/// +/// .. math:: +/// +/// \text{TODO: Add equation} +/// +/// where: +/// +/// - TODO: Add variable definitions +/// +/// Args: +/// TODO: Add arguments +/// +/// Returns: +/// float: TODO: Add return description +/// +/// Example: +/// >>> import ofire +/// >>> # TODO: Add example when equation is implemented +fn equation_59_9_placeholder() -> PyResult { + Err(pyo3::exceptions::PyNotImplementedError::new_err( + "Equation 59.9 is not yet implemented", + )) +} + +#[pymodule] +pub fn equation_59_9(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_function(pyo3::wrap_pyfunction!(equation_59_9_placeholder, m)?)?; + Ok(()) +} diff --git a/crates/sfpe_handbook/src/chapter_50/equation_50_16.rs b/crates/sfpe_handbook/src/chapter_50/equation_50_16.rs index 8ca1c1c5..5ee7ebf1 100644 --- a/crates/sfpe_handbook/src/chapter_50/equation_50_16.rs +++ b/crates/sfpe_handbook/src/chapter_50/equation_50_16.rs @@ -28,4 +28,4 @@ mod tests { let expected = 2.035971223; assert!((result - expected).abs() < 1e-6); } -} \ No newline at end of file +} diff --git a/crates/sfpe_handbook/src/chapter_50/equation_50_17.rs b/crates/sfpe_handbook/src/chapter_50/equation_50_17.rs index 79c8523e..3b58b4dd 100644 --- a/crates/sfpe_handbook/src/chapter_50/equation_50_17.rs +++ b/crates/sfpe_handbook/src/chapter_50/equation_50_17.rs @@ -3,7 +3,12 @@ pub fn stairwell_temperature(t_0: f64, eta: f64, t_b: f64) -> f64 { } #[cfg(not(coverage))] -pub fn stairwell_temperature_equation(t_s: String, t_0: String, eta: String, t_b: String) -> String { +pub fn stairwell_temperature_equation( + t_s: String, + t_0: String, + eta: String, + t_b: String, +) -> String { format!("{} = {} + {} \\times ( {} - {} )", t_s, t_0, eta, t_b, t_0) } diff --git a/crates/sfpe_handbook/src/chapter_59.rs b/crates/sfpe_handbook/src/chapter_59.rs new file mode 100644 index 00000000..ee9a40c2 --- /dev/null +++ b/crates/sfpe_handbook/src/chapter_59.rs @@ -0,0 +1,7 @@ +pub mod equation_59_10; +pub mod equation_59_11; +pub mod equation_59_5; +pub mod equation_59_6; +pub mod equation_59_7; +pub mod equation_59_8; +pub mod equation_59_9; diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_10.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_10.rs new file mode 100644 index 00000000..7d00921e --- /dev/null +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_10.rs @@ -0,0 +1,22 @@ +/// Placeholder for equation 59.10 calculation. +/// +/// TODO: Implement the actual equation logic. +pub fn equation_59_10_placeholder() -> f64 { + todo!("Implement equation 59.10") +} + +#[cfg(not(coverage))] +pub fn equation_59_10_equation() -> &'static str { + "TODO: Add equation string" +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[ignore = "placeholder - implement when equation is added"] + fn test_equation_59_10() { + // TODO: Add test when equation is implemented + } +} diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_11.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_11.rs new file mode 100644 index 00000000..3cb8ba61 --- /dev/null +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_11.rs @@ -0,0 +1,22 @@ +/// Placeholder for equation 59.11 calculation. +/// +/// TODO: Implement the actual equation logic. +pub fn equation_59_11_placeholder() -> f64 { + todo!("Implement equation 59.11") +} + +#[cfg(not(coverage))] +pub fn equation_59_11_equation() -> &'static str { + "TODO: Add equation string" +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[ignore = "placeholder - implement when equation is added"] + fn test_equation_59_11() { + // TODO: Add test when equation is implemented + } +} diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_5.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_5.rs new file mode 100644 index 00000000..2e063f94 --- /dev/null +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_5.rs @@ -0,0 +1,30 @@ +/// Calculates pedestrian travel speed along a path (Equation 59.5). +/// +/// # Arguments +/// +/// * `k` - Speed constant from Table 59.2 (units depend on unit system) +/// * `a` - Unit conversion constant (0.266 for SI, 2.86 for imperial) +/// * `d` - Population density in persons per unit area +/// +/// # Returns +/// +/// Speed S along the line of travel +pub fn travel_speed(k: f64, a: f64, d: f64) -> f64 { + k - a * k * d +} + +#[cfg(not(coverage))] +pub fn travel_speed_equation(s: String, k: String, a: String, d: String) -> String { + format!("{} = {} - {} \\cdot {} \\cdot {}", s, k, a, k, d) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_travel_speed_generic() { + let result = travel_speed(1.4, 0.266, 0.7); + assert!((result - 1.13932).abs() < 1e-6); + } +} diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_6.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_6.rs new file mode 100644 index 00000000..8c763d0a --- /dev/null +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_6.rs @@ -0,0 +1,22 @@ +/// Placeholder for equation 59.6 calculation. +/// +/// TODO: Implement the actual equation logic. +pub fn equation_59_6_placeholder() -> f64 { + todo!("Implement equation 59.6") +} + +#[cfg(not(coverage))] +pub fn equation_59_6_equation() -> &'static str { + "TODO: Add equation string" +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[ignore = "placeholder - implement when equation is added"] + fn test_equation_59_6() { + // TODO: Add test when equation is implemented + } +} diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_7.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_7.rs new file mode 100644 index 00000000..f3ced8c8 --- /dev/null +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_7.rs @@ -0,0 +1,22 @@ +/// Placeholder for equation 59.7 calculation. +/// +/// TODO: Implement the actual equation logic. +pub fn equation_59_7_placeholder() -> f64 { + todo!("Implement equation 59.7") +} + +#[cfg(not(coverage))] +pub fn equation_59_7_equation() -> &'static str { + "TODO: Add equation string" +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[ignore = "placeholder - implement when equation is added"] + fn test_equation_59_7() { + // TODO: Add test when equation is implemented + } +} diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_8.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_8.rs new file mode 100644 index 00000000..a8d03be0 --- /dev/null +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_8.rs @@ -0,0 +1,22 @@ +/// Placeholder for equation 59.8 calculation. +/// +/// TODO: Implement the actual equation logic. +pub fn equation_59_8_placeholder() -> f64 { + todo!("Implement equation 59.8") +} + +#[cfg(not(coverage))] +pub fn equation_59_8_equation() -> &'static str { + "TODO: Add equation string" +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[ignore = "placeholder - implement when equation is added"] + fn test_equation_59_8() { + // TODO: Add test when equation is implemented + } +} diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_9.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_9.rs new file mode 100644 index 00000000..43664f29 --- /dev/null +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_9.rs @@ -0,0 +1,22 @@ +/// Placeholder for equation 59.9 calculation. +/// +/// TODO: Implement the actual equation logic. +pub fn equation_59_9_placeholder() -> f64 { + todo!("Implement equation 59.9") +} + +#[cfg(not(coverage))] +pub fn equation_59_9_equation() -> &'static str { + "TODO: Add equation string" +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[ignore = "placeholder - implement when equation is added"] + fn test_equation_59_9() { + // TODO: Add test when equation is implemented + } +} diff --git a/crates/sfpe_handbook/src/lib.rs b/crates/sfpe_handbook/src/lib.rs index 3ca79850..59930f31 100644 --- a/crates/sfpe_handbook/src/lib.rs +++ b/crates/sfpe_handbook/src/lib.rs @@ -1,2 +1,3 @@ pub mod chapter_14; pub mod chapter_50; +pub mod chapter_59; From c24918ac5d90b5c068497562ac76c10ff5194ab4 Mon Sep 17 00:00:00 2001 From: simonsantama Date: Wed, 11 Mar 2026 20:54:08 +0000 Subject: [PATCH 2/4] Adds equation 59.6 --- .../sfpe_handbook/chapter_59/equation_59_6.rs | 30 +++++++++++-------- .../src/chapter_59/equation_59_6.rs | 29 ++++++++++++------ 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_6.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_6.rs index e4fecaf5..45dd4a0d 100644 --- a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_6.rs +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_6.rs @@ -1,36 +1,40 @@ use pyo3::prelude::*; +use openfire::sfpe_handbook::chapter_59::equation_59_6 as rust_equation_59_6; + #[pyfunction] -/// Placeholder for equation 59.6. +/// Calculates specific flow of evacuating persons (Equation 59.6). /// -/// This function is a placeholder and will be implemented with the actual -/// equation logic. +/// Specific flow is the flow of evacuating persons past a point in the exit +/// route per unit of time per unit of effective width. /// /// .. math:: /// -/// \text{TODO: Add equation} +/// F_s = S \cdot D /// /// where: /// -/// - TODO: Add variable definitions +/// - :math:`F_s` is the specific flow (persons/min/ft or persons/s/m of effective width) +/// - :math:`S` is the speed along the line of travel (from Equation 59.5) +/// - :math:`D` is the population density (persons per unit area) /// /// Args: -/// TODO: Add arguments +/// s (float): Speed along the line of travel (m/s or ft/min) +/// d (float): Population density (persons/m² or persons/ft²) /// /// Returns: -/// float: TODO: Add return description +/// float: Specific flow Fs (persons/s/m or persons/min/ft of effective width) /// /// Example: /// >>> import ofire -/// >>> # TODO: Add example when equation is implemented -fn equation_59_6_placeholder() -> PyResult { - Err(pyo3::exceptions::PyNotImplementedError::new_err( - "Equation 59.6 is not yet implemented", - )) +/// >>> result = ofire.sfpe_handbook.chapter_59.equation_59_6.specific_flow(1.0, 0.5) +/// >>> print(f"{result:.2f} persons/s/m") +fn specific_flow(s: f64, d: f64) -> PyResult { + Ok(rust_equation_59_6::specific_flow(s, d)) } #[pymodule] pub fn equation_59_6(m: &Bound<'_, PyModule>) -> PyResult<()> { - m.add_function(pyo3::wrap_pyfunction!(equation_59_6_placeholder, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(specific_flow, m)?)?; Ok(()) } diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_6.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_6.rs index 8c763d0a..dd916b0c 100644 --- a/crates/sfpe_handbook/src/chapter_59/equation_59_6.rs +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_6.rs @@ -1,13 +1,23 @@ -/// Placeholder for equation 59.6 calculation. +/// Calculates specific flow of evacuating persons (Equation 59.6). /// -/// TODO: Implement the actual equation logic. -pub fn equation_59_6_placeholder() -> f64 { - todo!("Implement equation 59.6") +/// Specific flow is the flow of evacuating persons past a point in the exit +/// route per unit of time per unit of effective width. +/// +/// # Arguments +/// +/// * `s` - Speed along the line of travel (from Equation 59.5) +/// * `d` - Population density in persons per unit area +/// +/// # Returns +/// +/// Specific flow Fs (persons/min/ft or persons/s/m of effective width) +pub fn specific_flow(s: f64, d: f64) -> f64 { + s * d } #[cfg(not(coverage))] -pub fn equation_59_6_equation() -> &'static str { - "TODO: Add equation string" +pub fn specific_flow_equation(fs: String, s: String, d: String) -> String { + format!("{} = {} \\cdot {}", fs, s, d) } #[cfg(test)] @@ -15,8 +25,9 @@ mod tests { use super::*; #[test] - #[ignore = "placeholder - implement when equation is added"] - fn test_equation_59_6() { - // TODO: Add test when equation is implemented + fn test_specific_flow() { + // S = 1.0 m/s, D = 0.5 persons/m² -> Fs = 0.5 persons/s/m + let result = specific_flow(1.0, 0.5); + assert!((result - 0.5).abs() < 1e-6); } } From 2576f3bc4cb5804059fb61ef22c1f5f2fe2d693e Mon Sep 17 00:00:00 2001 From: simonsantama Date: Wed, 11 Mar 2026 21:07:35 +0000 Subject: [PATCH 3/4] Adds equation 59.7 --- .../sfpe_handbook/chapter_59/equation_59_7.rs | 32 +++++++++++-------- .../sfpe_handbook/chapter_59/equation_59_8.rs | 31 ++++++++++-------- .../src/chapter_59/equation_59_7.rs | 30 +++++++++++------ .../src/chapter_59/equation_59_8.rs | 31 ++++++++++++------ 4 files changed, 80 insertions(+), 44 deletions(-) diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_7.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_7.rs index fe991aee..6219b7b3 100644 --- a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_7.rs +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_7.rs @@ -1,36 +1,42 @@ use pyo3::prelude::*; +use openfire::sfpe_handbook::chapter_59::equation_59_7 as rust_equation_59_7; + #[pyfunction] -/// Placeholder for equation 59.7. +/// Calculates specific flow by combining Equations 59.5 and 59.6 (Equation 59.7). /// -/// This function is a placeholder and will be implemented with the actual -/// equation logic. +/// This equation combines the travel speed equation (59.5) with the specific +/// flow equation (59.6) to express specific flow directly in terms of density. /// /// .. math:: /// -/// \text{TODO: Add equation} +/// F_s = (1 - aD) \cdot k \cdot D /// /// where: /// -/// - TODO: Add variable definitions +/// - :math:`F_s` is the specific flow (persons/min/ft or persons/s/m of effective width) +/// - :math:`a` is the unit conversion constant (0.266 for SI, 2.86 for imperial) +/// - :math:`D` is the population density (persons per unit area) +/// - :math:`k` is the speed constant from Table 59.2 /// /// Args: -/// TODO: Add arguments +/// a (float): Unit conversion constant (0.266 for SI units, 2.86 for imperial units) +/// d (float): Population density (persons/m² or persons/ft²) +/// k (float): Speed constant from Table 59.2 /// /// Returns: -/// float: TODO: Add return description +/// float: Specific flow Fs (persons/s/m or persons/min/ft of effective width) /// /// Example: /// >>> import ofire -/// >>> # TODO: Add example when equation is implemented -fn equation_59_7_placeholder() -> PyResult { - Err(pyo3::exceptions::PyNotImplementedError::new_err( - "Equation 59.7 is not yet implemented", - )) +/// >>> result = ofire.sfpe_handbook.chapter_59.equation_59_7.specific_flow(0.266, 0.5, 1.19) +/// >>> print(f"{result:.4f} persons/s/m") +fn specific_flow(a: f64, d: f64, k: f64) -> PyResult { + Ok(rust_equation_59_7::specific_flow(a, d, k)) } #[pymodule] pub fn equation_59_7(m: &Bound<'_, PyModule>) -> PyResult<()> { - m.add_function(pyo3::wrap_pyfunction!(equation_59_7_placeholder, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(specific_flow, m)?)?; Ok(()) } diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_8.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_8.rs index 4c86d59a..0450d9a5 100644 --- a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_8.rs +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_8.rs @@ -1,36 +1,41 @@ use pyo3::prelude::*; +use openfire::sfpe_handbook::chapter_59::equation_59_8 as rust_equation_59_8; + #[pyfunction] -/// Placeholder for equation 59.8. +/// Calculates the flow rate of persons passing a point in an exit route (Equation 59.8). /// -/// This function is a placeholder and will be implemented with the actual -/// equation logic. +/// The calculated flow is the predicted flow rate of persons passing a particular +/// point in an exit route. This equation assumes the achievable flow rate through +/// a component is directly proportional to its width. /// /// .. math:: /// -/// \text{TODO: Add equation} +/// F_c = F_s \cdot W_e /// /// where: /// -/// - TODO: Add variable definitions +/// - :math:`F_c` is the calculated flow (persons/min or persons/s) +/// - :math:`F_s` is the specific flow (persons/min/ft or persons/s/m of effective width) +/// - :math:`W_e` is the effective width of the component being traversed (ft or m) /// /// Args: -/// TODO: Add arguments +/// fs (float): Specific flow (persons/min/ft or persons/s/m of effective width) +/// we (float): Effective width of the component being traversed (ft or m) /// /// Returns: -/// float: TODO: Add return description +/// float: Calculated flow Fc (persons/min or persons/s) /// /// Example: /// >>> import ofire -/// >>> # TODO: Add example when equation is implemented -fn equation_59_8_placeholder() -> PyResult { - Err(pyo3::exceptions::PyNotImplementedError::new_err( - "Equation 59.8 is not yet implemented", - )) +/// >>> result = ofire.sfpe_handbook.chapter_59.equation_59_8.calculated_flow(1.3, 1.5) +/// >>> print(f"{result:.2f} persons/s") +fn calculated_flow(fs: f64, we: f64) -> PyResult { + Ok(rust_equation_59_8::calculated_flow(fs, we)) } #[pymodule] pub fn equation_59_8(m: &Bound<'_, PyModule>) -> PyResult<()> { - m.add_function(pyo3::wrap_pyfunction!(equation_59_8_placeholder, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(calculated_flow, m)?)?; Ok(()) } diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_7.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_7.rs index f3ced8c8..52edb317 100644 --- a/crates/sfpe_handbook/src/chapter_59/equation_59_7.rs +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_7.rs @@ -1,13 +1,24 @@ -/// Placeholder for equation 59.7 calculation. +/// Calculates specific flow by combining Equations 59.5 and 59.6 (Equation 59.7). /// -/// TODO: Implement the actual equation logic. -pub fn equation_59_7_placeholder() -> f64 { - todo!("Implement equation 59.7") +/// This equation combines the travel speed equation (59.5) with the specific +/// flow equation (59.6) to express specific flow directly in terms of density. +/// +/// # Arguments +/// +/// * `a` - Unit conversion constant (0.266 for SI units, 2.86 for imperial units) +/// * `d` - Population density in persons per unit area +/// * `k` - Speed constant from Table 59.2 +/// +/// # Returns +/// +/// Specific flow Fs (persons/min/ft or persons/s/m of effective width) +pub fn specific_flow(a: f64, d: f64, k: f64) -> f64 { + (1.0 - a * d) * k * d } #[cfg(not(coverage))] -pub fn equation_59_7_equation() -> &'static str { - "TODO: Add equation string" +pub fn specific_flow_equation(fs: String, a: String, d: String, k: String) -> String { + format!("{} = (1 - {} \\cdot {}) \\cdot {} \\cdot {}", fs, a, d, k, d) } #[cfg(test)] @@ -15,8 +26,9 @@ mod tests { use super::*; #[test] - #[ignore = "placeholder - implement when equation is added"] - fn test_equation_59_7() { - // TODO: Add test when equation is implemented + fn test_specific_flow_combined() { + let result = specific_flow(0.266, 0.5, 1.4); + assert!((result - 0.6069).abs() < 1e-6); } + } diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_8.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_8.rs index a8d03be0..a938007a 100644 --- a/crates/sfpe_handbook/src/chapter_59/equation_59_8.rs +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_8.rs @@ -1,13 +1,24 @@ -/// Placeholder for equation 59.8 calculation. +/// Calculates the flow rate of persons passing a point in an exit route (Equation 59.8). /// -/// TODO: Implement the actual equation logic. -pub fn equation_59_8_placeholder() -> f64 { - todo!("Implement equation 59.8") +/// The calculated flow is the predicted flow rate of persons passing a particular +/// point in an exit route. This equation assumes the achievable flow rate through +/// a component is directly proportional to its width. +/// +/// # Arguments +/// +/// * `fs` - Specific flow (persons/min/ft or persons/s/m of effective width) +/// * `we` - Effective width of the component being traversed (ft or m) +/// +/// # Returns +/// +/// Calculated flow Fc (persons/min or persons/s) +pub fn calculated_flow(fs: f64, we: f64) -> f64 { + fs * we } #[cfg(not(coverage))] -pub fn equation_59_8_equation() -> &'static str { - "TODO: Add equation string" +pub fn calculated_flow_equation(fc: String, fs: String, we: String) -> String { + format!("{} = {} \\cdot {}", fc, fs, we) } #[cfg(test)] @@ -15,8 +26,10 @@ mod tests { use super::*; #[test] - #[ignore = "placeholder - implement when equation is added"] - fn test_equation_59_8() { - // TODO: Add test when equation is implemented + fn test_calculated_flow() { + // Fs = 1.3 persons/s/m, We = 1.5 m -> Fc = 1.95 persons/s + let result = calculated_flow(1.3, 1.5); + assert!((result - 1.95).abs() < 1e-6); } + } From 62d89c74a0c35e52a7145dd21f69d043c2777fb0 Mon Sep 17 00:00:00 2001 From: simonsantama Date: Wed, 11 Mar 2026 21:14:59 +0000 Subject: [PATCH 4/4] implements equation 59-9 --- .../sfpe_handbook/chapter_59/equation_59_9.rs | 38 +++++++++----- .../src/chapter_59/equation_59_9.rs | 50 +++++++++++++++---- 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_9.rs b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_9.rs index 86843347..f2b1ea7f 100644 --- a/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_9.rs +++ b/crates/python_api/src/sfpe_handbook/chapter_59/equation_59_9.rs @@ -1,36 +1,48 @@ use pyo3::prelude::*; +use openfire::sfpe_handbook::chapter_59::equation_59_9 as rust_equation_59_9; + #[pyfunction] -/// Placeholder for equation 59.9. +/// Calculates flow rate by combining Equations 59.7 and 59.8 (Equation 59.9). /// -/// This function is a placeholder and will be implemented with the actual -/// equation logic. +/// This equation combines the specific flow equation (59.7) with the calculated +/// flow equation (59.8) to express flow rate directly in terms of the fundamental +/// parameters. /// /// .. math:: /// -/// \text{TODO: Add equation} +/// F_c = (1 - aD) \cdot k \cdot D \cdot W_e /// /// where: /// -/// - TODO: Add variable definitions +/// - :math:`F_c` is the calculated flow (persons/min or persons/s) +/// - :math:`a` is constant (0.266 for SI, 2.86 for imperial) +/// - :math:`D` is the population density (persons per unit area) +/// - :math:`k` is the constant from Table 59.2 +/// - :math:`W_e` is the effective width of the component (ft or m) +/// +/// Fc is in persons/min when k = k1 (from Table 59.2), D is in persons/ft², and We is in ft. +/// Fc is in persons/s when k = k2 (from Table 59.2), D is in persons/m², and We is in m. /// /// Args: -/// TODO: Add arguments +/// a (float): Unit constant (0.266 for SI units, 2.86 for imperial units) +/// d (float): Population density (persons/m² or persons/ft²) +/// k (float): Constant from Table 59.2 +/// we (float): Effective width of the component being traversed (ft or m) /// /// Returns: -/// float: TODO: Add return description +/// float: Calculated flow Fc (persons/min or persons/s) /// /// Example: /// >>> import ofire -/// >>> # TODO: Add example when equation is implemented -fn equation_59_9_placeholder() -> PyResult { - Err(pyo3::exceptions::PyNotImplementedError::new_err( - "Equation 59.9 is not yet implemented", - )) +/// >>> result = ofire.sfpe_handbook.chapter_59.equation_59_9.calculated_flow(0.266, 0.5, 1.40, 1.2) +/// >>> print(f"{result:.4f} persons/s") +fn calculated_flow(a: f64, d: f64, k: f64, we: f64) -> PyResult { + Ok(rust_equation_59_9::calculated_flow(a, d, k, we)) } #[pymodule] pub fn equation_59_9(m: &Bound<'_, PyModule>) -> PyResult<()> { - m.add_function(pyo3::wrap_pyfunction!(equation_59_9_placeholder, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(calculated_flow, m)?)?; Ok(()) } diff --git a/crates/sfpe_handbook/src/chapter_59/equation_59_9.rs b/crates/sfpe_handbook/src/chapter_59/equation_59_9.rs index 43664f29..06fbd030 100644 --- a/crates/sfpe_handbook/src/chapter_59/equation_59_9.rs +++ b/crates/sfpe_handbook/src/chapter_59/equation_59_9.rs @@ -1,13 +1,29 @@ -/// Placeholder for equation 59.9 calculation. +/// Calculates flow rate by combining Equations 59.7 and 59.8 (Equation 59.9). /// -/// TODO: Implement the actual equation logic. -pub fn equation_59_9_placeholder() -> f64 { - todo!("Implement equation 59.9") +/// This equation combines the specific flow equation (59.7) with the calculated +/// flow equation (59.8) to express flow rate directly in terms of the fundamental +/// parameters. +/// +/// # Arguments +/// +/// * `a` - Unit conversion constant (0.266 for SI units, 2.86 for imperial units) +/// * `d` - Population density in persons per unit area +/// * `k` - Speed constant from Table 59.2 +/// * `we` - Effective width of the component being traversed +/// +/// # Returns +/// +/// Calculated flow Fc (persons/min when using imperial units, persons/s when using SI units) +pub fn calculated_flow(a: f64, d: f64, k: f64, we: f64) -> f64 { + (1.0 - a * d) * k * d * we } #[cfg(not(coverage))] -pub fn equation_59_9_equation() -> &'static str { - "TODO: Add equation string" +pub fn calculated_flow_equation(fc: String, a: String, d: String, k: String, we: String) -> String { + format!( + "{} = (1 - {} \\cdot {}) \\cdot {} \\cdot {} \\cdot {}", + fc, a, d, k, d, we + ) } #[cfg(test)] @@ -15,8 +31,24 @@ mod tests { use super::*; #[test] - #[ignore = "placeholder - implement when equation is added"] - fn test_equation_59_9() { - // TODO: Add test when equation is implemented + fn test_calculated_flow() { + // Using SI units: a = 0.266, D = 0.5 persons/m², k = 1.40 m/s, We = 1.2 m + // Fc = (1 - 0.266 * 0.5) * 1.40 * 0.5 * 1.2 = 0.867 * 0.84 = 0.72828 + let result = calculated_flow(0.266, 0.5, 1.40, 1.2); + assert!((result - 0.72828).abs() < 1e-5); + } + + #[test] + fn test_calculated_flow_zero_density() { + // When D = 0, Fc = 0 + let result = calculated_flow(0.266, 0.0, 1.40, 1.2); + assert!((result - 0.0).abs() < 1e-6); + } + + #[test] + fn test_calculated_flow_zero_width() { + // When We = 0, Fc = 0 + let result = calculated_flow(0.266, 0.5, 1.40, 0.0); + assert!((result - 0.0).abs() < 1e-6); } }