Repository: uncscode/particula

Issue:
Add/check for droplet properties
### $\tau_p$: Droplet Inertia Time

Adjusts droplet inertia:

$$
\tau_p = \frac{2}{9} \frac{\rho_w}{\rho} \frac{a^2}{\nu f(Re_p)}
$$

with:

$$
f(Re_p) = 1 + 0.15 Re_p^{0.687}
$$

### $v_p$: Droplet Settling Velocity

The settling velocity under gravity:

$$
v_p = \tau_p |g|
$$



Discussion:
sourcery-ai[bot]: <!-- Generated by sourcery-ai[bot]: start review_guide -->

🧙 Sourcery is reviewing your pull request!

---

<details>
<summary>Tips and commands</summary>

#### Interacting with Sourcery

- **Trigger a new review:** Comment `@sourcery-ai review` on the pull request.
- **Continue discussions:** Reply directly to Sourcery's review comments.
- **Generate a GitHub issue from a review comment:** Ask Sourcery to create an
  issue from a review comment by replying to it.
- **Generate a pull request title:** Write `@sourcery-ai` anywhere in the pull
  request title to generate a title at any time.
- **Generate a pull request summary:** Write `@sourcery-ai summary` anywhere in
  the pull request body to generate a PR summary at any time. You can also use
  this command to specify where the summary should be inserted.

#### Customizing Your Experience

Access your [dashboard](https://app.sourcery.ai) to:
- Enable or disable review features such as the Sourcery-generated pull request
  summary, the reviewer's guide, and others.
- Change the review language.
- Add, remove or edit custom review instructions.
- Adjust other review settings.

#### Getting Help

- [Contact our support team](mailto:support@sourcery.ai) for questions or feedback.
- Visit our [documentation](https://docs.sourcery.ai) for detailed guides and information.
- Keep in touch with the Sourcery team by following us on [X/Twitter](https://x.com/SourceryAI), [LinkedIn](https://www.linkedin.com/company/sourcery-ai/) or [GitHub](https://github.com/sourcery-ai).

</details>

<!-- Generated by sourcery-ai[bot]: end review_guide -->
github-actions[bot]: [PR Preview Action](https://github.com/rossjrw/pr-preview-action) v1.6.0
:---:
| <p></p> :rocket: View preview at <br> https://uncscode.github.io/particula/pr-preview/pr-585/ <br><br>
| <h6>Built to branch [`gh-pages`](https://github.com/uncscode/particula/tree/gh-pages) at 2025-01-19 15:09 UTC. <br> Preview will be ready when the [GitHub Pages deployment](https://github.com/uncscode/particula/deployments) is complete. <br><br> </h6>
<!-- Sticky Pull Request Commentpr-preview -->

Patch:
diff --git a/particula/particles/properties/__init__.py b/particula/particles/properties/__init__.py
index 4628992bb..8a7a060a8 100644
--- a/particula/particles/properties/__init__.py
+++ b/particula/particles/properties/__init__.py
@@ -49,6 +49,7 @@ from particula.particles.properties.special_functions import (
 )
 from particula.particles.properties.settling_velocity import (
     particle_settling_velocity,
+    get_particle_settling_velocity_via_inertia,
     particle_settling_velocity_via_system_state,
 )
 from particula.particles.properties.diffusion_coefficient import (
@@ -67,3 +68,6 @@ from particula.particles.properties.activity_module import (
     kappa_activity,
     calculate_partial_pressure,
 )
+from particula.particles.properties.inertia_time import (
+    get_particle_inertia_time,
+)
diff --git a/particula/particles/properties/inertia_time.py b/particula/particles/properties/inertia_time.py
new file mode 100644
index 000000000..b1b30f7b4
--- /dev/null
+++ b/particula/particles/properties/inertia_time.py
@@ -0,0 +1,81 @@
+"""
+Particle inertia time calculation.
+"""
+from typing import Union
+from numpy.typing import NDArray
+import numpy as np
+
+from particula.util.validate_inputs import validate_inputs
+
+
+@validate_inputs(
+    {
+        "particle_radius": "positive",
+        "particle_density": "positive",
+        "fluid_density": "positive",
+        "kinematic_viscosity": "positive",
+        "relative_velocity": "positive",
+    }
+)
+def get_particle_inertia_time(
+    particle_radius: Union[float, NDArray[np.float64]],
+    particle_density: Union[float, NDArray[np.float64]],
+    fluid_density: Union[float, NDArray[np.float64]],
+    kinematic_viscosity: Union[float, NDArray[np.float64]],
+    relative_velocity: Union[float, NDArray[np.float64]],
+) -> Union[float, NDArray[np.float64]]:
+    """
+    Calculate the particle inertia time.
+
+    The particle inertia time (τ_p) represents the response time of a particle
+    to velocity changes in the surrounding fluid and is given by:
+
+        τ_p = (2 / 9) * (ρ_p / ρ_f) * (r² / (ν f(Re_p)))
+
+    - τ_p : Particle inertia time [s]
+    - r (particle_radius) : Particle radius [m]
+    - ρ_p (particle_density) : Particle (e.g., droplet, dust) density [kg/m³]
+    - ρ_f (fluid_density) : Density of the surrounding fluid (e.g., air, water)
+        [kg/m³]
+    - ν (kinematic_viscosity) : Kinematic viscosity of the fluid [m²/s]
+    - f(Re_p) : Drag correction factor based on the particle Reynolds number
+        [-]
+
+    The drag correction factor f(Re_p) is given by:
+
+        f(Re_p) = 1 + 0.15 Re_p^(0.687)
+
+    where the particle Reynolds number is:
+
+        Re_p = (2 r v) / v
+
+    - v (relative_velocity) : Relative velocity between particle and fluid
+        [m/s]
+
+    Arguments:
+    ----------
+        - particle_radius : Radius of the particle [m]
+        - particle_density : Density of the particle [kg/m³]
+        - fluid_density : Density of the surrounding fluid [kg/m³]
+        - kinematic_viscosity : Kinematic viscosity of the fluid [m²/s]
+        - relative_velocity : Relative velocity between particle and fluid
+            [m/s]
+
+    Returns:
+    --------
+        - Particle inertia time [s]
+
+    References:
+    ----------
+        - Ayala, O., Rosa, B., & Wang, L. P. (2008). Effects of turbulence on
+        the geometric collision rate of sedimenting droplets. Part 2. Theory
+        and parameterization. New Journal of Physics, 10.
+        https://doi.org/10.1088/1367-2630/10/7/075016
+    """
+    re_p = (2 * particle_radius * relative_velocity) / kinematic_viscosity
+    drag_correction = 1 + 0.15 * re_p**0.687
+    return (
+        (2 / 9)
+        * (particle_density / fluid_density)
+        * (particle_radius**2 / (kinematic_viscosity * drag_correction))
+    )
diff --git a/particula/particles/properties/settling_velocity.py b/particula/particles/properties/settling_velocity.py
index cb2120174..c52fe7d99 100644
--- a/particula/particles/properties/settling_velocity.py
+++ b/particula/particles/properties/settling_velocity.py
@@ -5,6 +5,7 @@ import numpy as np
 from numpy.typing import NDArray
 
 from particula.util.constants import STANDARD_GRAVITY
+from particula.util.validate_inputs import validate_inputs
 from particula.gas.properties.dynamic_viscosity import (
     get_dynamic_viscosity,
 )
@@ -55,6 +56,48 @@ def particle_settling_velocity(
     return settling_velocity
 
 
+@validate_inputs(
+    {
+        "particle_inertia_time": "positive",
+        "gravitational_acceleration": "positive",
+        "slip_correction_factor": "positive",
+    }
+)
+def get_particle_settling_velocity_via_inertia(
+    particle_inertia_time: Union[float, NDArray[np.float64]],
+    gravitational_acceleration: float,
+    slip_correction_factor: Union[float, NDArray[np.float64]],
+) -> Union[float, NDArray[np.float64]]:
+    """
+    Calculate the gravitational settling velocity from the particle inertia
+    time.
+
+    The settling velocity (v_s) is given by:
+
+        v_s = g * τ_p * C_c
+
+    - v_s : Settling velocity [m/s]
+    - g (gravitational_acceleration) : Gravitational acceleration [m/s²]
+    - τ_p (particle_inertia_time) : Particle inertia time [s]
+    - C_c (slip_correction_factor) : Cunningham slip correction factor [-]
+
+    Arguments:
+    ----------
+        - particle_inertia_time : Particle inertia time [s]
+        - gravitational_acceleration : Gravitational acceleration [m/s²]
+        - slip_correction_factor : Cunningham slip correction factor [-]
+
+    Returns:
+    --------
+        - Particle settling velocity [m/s]
+    """
+    return (
+        gravitational_acceleration
+        * particle_inertia_time
+        * slip_correction_factor
+    )
+
+
 def particle_settling_velocity_via_system_state(
     particle_radius: Union[float, NDArray[np.float64]],
     particle_density: Union[float, NDArray[np.float64]],


Test patch:
diff --git a/particula/particles/properties/tests/inertia_time_test.py b/particula/particles/properties/tests/inertia_time_test.py
new file mode 100644
index 000000000..0b20a5675
--- /dev/null
+++ b/particula/particles/properties/tests/inertia_time_test.py
@@ -0,0 +1,96 @@
+"""
+Tests for the get_particle_inertia_time function.
+"""
+import pytest
+import numpy as np
+from particula.particles.properties.inertia_time import (
+    get_particle_inertia_time
+)
+
+
+def test_get_particle_inertia_time_scalar():
+    """
+    Test get_particle_inertia_time with scalar inputs.
+    """
+    particle_radius = 50e-6  # 50 microns
+    particle_density = 1000  # kg/m³ (e.g., water, dust)
+    fluid_density = 1.2  # kg/m³ (air)
+    kinematic_viscosity = 1.5e-5  # m²/s
+    relative_velocity = 0.1  # m/s
+
+    re_p = (2 * particle_radius * relative_velocity) / kinematic_viscosity
+    drag_correction = 1 + 0.15 * re_p**0.687
+    expected = (
+        (2 / 9)
+        * (particle_density / fluid_density)
+        * (particle_radius**2 / (kinematic_viscosity * drag_correction))
+    )
+
+    result = get_particle_inertia_time(
+        particle_radius,
+        particle_density,
+        fluid_density,
+        kinematic_viscosity,
+        relative_velocity,
+    )
+
+    assert np.isclose(result, expected, atol=1e-10)
+
+
+def test_get_particle_inertia_time_array():
+    """
+    Test get_particle_inertia_time with NumPy array inputs.
+    """
+    particle_radius = np.array([50e-6, 80e-6])
+    particle_density = np.array([1000, 1200])
+    fluid_density = np.array([1.2, 1.2])
+    kinematic_viscosity = np.array([1.5e-5, 1.5e-5])
+    relative_velocity = np.array([0.1, 0.2])
+
+    re_p = (2 * particle_radius * relative_velocity) / kinematic_viscosity
+    drag_correction = 1 + 0.15 * re_p**0.687
+    expected = (
+        (2 / 9)
+        * (particle_density / fluid_density)
+        * (particle_radius**2 / (kinematic_viscosity * drag_correction))
+    )
+
+    result = get_particle_inertia_time(
+        particle_radius,
+        particle_density,
+        fluid_density,
+        kinematic_viscosity,
+        relative_velocity,
+    )
+
+    assert np.allclose(result, expected, atol=1e-10)
+
+
+def test_get_particle_inertia_time_invalid():
+    """
+    Test that get_particle_inertia_time raises errors for invalid inputs.
+    """
+    with pytest.raises(ValueError):
+        get_particle_inertia_time(
+            -50e-6, 1000, 1.2, 1.5e-5, 0.1
+        )  # Negative radius
+
+    with pytest.raises(ValueError):
+        get_particle_inertia_time(
+            50e-6, -1000, 1.2, 1.5e-5, 0.1
+        )  # Negative particle density
+
+    with pytest.raises(ValueError):
+        get_particle_inertia_time(
+            50e-6, 1000, -1.2, 1.5e-5, 0.1
+        )  # Negative fluid density
+
+    with pytest.raises(ValueError):
+        get_particle_inertia_time(
+            50e-6, 1000, 1.2, -1.5e-5, 0.1
+        )  # Negative viscosity
+
+    with pytest.raises(ValueError):
+        get_particle_inertia_time(
+            50e-6, 1000, 1.2, 1.5e-5, -0.1
+        )  # Negative velocity
diff --git a/particula/particles/properties/tests/settling_velocity_test.py b/particula/particles/properties/tests/settling_velocity_test.py
index 6bbc991ca..3bb186279 100644
--- a/particula/particles/properties/tests/settling_velocity_test.py
+++ b/particula/particles/properties/tests/settling_velocity_test.py
@@ -1,9 +1,13 @@
-"""Tests for the settling velocity property calculation."""
+"""
+Tests for the settling velocity property calculation.
+"""
 
 import numpy as np
 import pytest
+
 from particula.particles.properties.settling_velocity import (
     particle_settling_velocity,
+    get_particle_settling_velocity_via_inertia,
 )
 
 
@@ -76,3 +80,70 @@ def test_calculate_settling_velocity_with_invalid_inputs():
             dynamic_viscosity,
             gravitational_acceleration,
         )
+
+
+def test_get_particle_settling_velocity_via_inertia_scalar():
+    """
+    Test get_particle_settling_velocity_via_inertia with scalar inputs.
+    """
+    particle_inertia_time = 0.02  # s
+    gravitational_acceleration = 9.81  # m/s²
+    slip_correction_factor = 1.0  # Default (no slip correction)
+
+    expected = (
+        gravitational_acceleration
+        * particle_inertia_time
+        * slip_correction_factor
+    )
+    result = get_particle_settling_velocity_via_inertia(
+        particle_inertia_time,
+        gravitational_acceleration,
+        slip_correction_factor,
+    )
+
+    assert np.isclose(result, expected, atol=1e-10)
+
+
+def test_get_particle_settling_velocity_via_inertia_array():
+    """
+    Test get_particle_settling_velocity_via_inertia with NumPy array inputs.
+    """
+    particle_inertia_time = np.array([0.02, 0.03])
+    gravitational_acceleration = 9.81  # m/s²
+    slip_correction_factor = np.array(
+        [1.0, 1.1]
+    )  # Some slip correction for small particles
+
+    expected = (
+        gravitational_acceleration
+        * particle_inertia_time
+        * slip_correction_factor
+    )
+    result = get_particle_settling_velocity_via_inertia(
+        particle_inertia_time,
+        gravitational_acceleration,
+        slip_correction_factor,
+    )
+
+    assert np.allclose(result, expected, atol=1e-10)
+
+
+def test_get_particle_settling_velocity_via_inertia_invalid():
+    """
+    Test that get_particle_settling_velocity_via_inertia raises errors for
+    invalid inputs.
+    """
+    with pytest.raises(ValueError):
+        get_particle_settling_velocity_via_inertia(
+            -0.02, 9.81, 1.0
+        )  # Negative inertia time
+
+    with pytest.raises(ValueError):
+        get_particle_settling_velocity_via_inertia(
+            0.02, -9.81, 1.0
+        )  # Negative gravity
+
+    with pytest.raises(ValueError):
+        get_particle_settling_velocity_via_inertia(
+            0.02, 9.81, -1.0
+        )  # Negative slip correction