# nim Integration

This example demonstrates how to use fluids from nim.

## Source Code

      1import nimpy
      2import times
      3import strformat
      4import math
      5
      6# Initialize Python and import fluids
      7let fluids = pyImport("fluids")
      8
      9proc test_fluids() =
     10  try:
     11    # Test basic module import
     12    echo "Running fluids tests from Nim..."
     13    echo "✓ Successfully imported fluids"
     14    echo &"✓ Fluids version: {fluids.getAttr(\"__version__\").to(string)}"
     15
     16    # Test basic Reynolds number calculation
     17    let Re = fluids.Reynolds(V=2.5, D=0.1, rho=1000, mu=0.001).to(float)
     18    echo &"✓ Reynolds number calculation successful: {Re}"
     19    assert Re > 0
     20
     21    # Test friction factor calculation
     22    let fd = fluids.friction_factor(Re=1e5, eD=0.0001).to(float)
     23    echo &"✓ Friction factor calculation successful: {fd}"
     24    assert 0 < fd and fd < 1
     25
     26    echo "\nAll basic tests completed successfully!"
     27
     28  except:
     29    echo "Error in fluids tests: ", getCurrentExceptionMsg()
     30    raise
     31
     32proc test_atmosphere() =
     33  try:
     34    # Test ATMOSPHERE_1976 class
     35    let atm = fluids.ATMOSPHERE_1976(Z=5000)
     36
     37    echo "\nTesting atmosphere at 5000m elevation:"
     38    echo &"✓ Temperature: {atm.T.to(float):.4f}"
     39    echo &"✓ Pressure: {atm.P.to(float):.4f}"
     40    echo &"✓ Density: {atm.rho.to(float):.6f}"
     41
     42    # Test derived properties
     43    echo &"✓ Gravity: {atm.g.to(float):.6f}"
     44    echo &"✓ Viscosity: {atm.mu.to(float):.6e}"
     45    echo &"✓ Thermal conductivity: {atm.k.to(float):.6f}"
     46    echo &"✓ Sonic velocity: {atm.v_sonic.to(float):.4f}"
     47
     48    # Test static methods
     49    let g_high = fluids.ATMOSPHERE_1976.gravity(Z=1E5).to(float)
     50    echo &"✓ High altitude gravity: {g_high:.6f}"
     51
     52    let v_sonic = fluids.ATMOSPHERE_1976.sonic_velocity(T=300).to(float)
     53    echo &"✓ Sonic velocity at 300K: {v_sonic:.4f}"
     54
     55    let mu_400 = fluids.ATMOSPHERE_1976.viscosity(T=400).to(float)
     56    echo &"✓ Viscosity at 400K: {mu_400:.6e}"
     57
     58    let k_400 = fluids.ATMOSPHERE_1976.thermal_conductivity(T=400).to(float)
     59    echo &"✓ Thermal conductivity at 400K: {k_400:.6f}"
     60
     61  except:
     62    echo "Error in atmosphere tests: ", getCurrentExceptionMsg()
     63    raise
     64
     65proc test_tank() =
     66  try:
     67    # Test basic tank creation
     68    let T1 = fluids.TANK(V=10, L_over_D=0.7, sideB="conical", horizontal=false)
     69    echo "\nTesting tank calculations:"
     70    echo &"✓ Tank length: {T1.L.to(float):.6f}"
     71    echo &"✓ Tank diameter: {T1.D.to(float):.6f}"
     72
     73    # Test ellipsoidal tank
     74    let tank_ellip = fluids.TANK(
     75      D=10, V=500, horizontal=false,
     76      sideA="ellipsoidal", sideB="ellipsoidal",
     77      sideA_a=1, sideB_a=1
     78    )
     79    echo &"✓ Ellipsoidal tank L: {tank_ellip.L.to(float):.6f}"
     80
     81    # Test torispherical tank
     82    let DIN = fluids.TANK(
     83      L=3, D=5, horizontal=false,
     84      sideA="torispherical", sideB="torispherical",
     85      sideA_f=1, sideA_k=0.1, sideB_f=1, sideB_k=0.1
     86    )
     87
     88    echo &"✓ Tank representation: {$DIN}"
     89    echo &"✓ Tank max height: {DIN.h_max.to(float):.6f}"
     90    echo &"✓ Height at V=40: {DIN.h_from_V(40).to(float):.6f}"
     91    echo &"✓ Volume at h=4.1: {DIN.V_from_h(4.1).to(float):.5f}"
     92    echo &"✓ Surface area at h=2.1: {DIN.SA_from_h(2.1).to(float):.5f}"
     93
     94  except:
     95    echo "Error in tank tests: ", getCurrentExceptionMsg()
     96    raise
     97
     98proc test_reynolds() =
     99  try:
    100    echo "\nTesting Reynolds number calculations:"
    101
    102    # Test with density and viscosity
    103    let Re1 = fluids.Reynolds(V=2.5, D=0.25, rho=1.1613, mu=1.9E-5).to(float)
    104    echo &"✓ Re (with rho, mu): {Re1:.4f}"
    105    assert abs(Re1 - 38200.6579) < 0.1
    106
    107    # Test with kinematic viscosity
    108    let Re2 = fluids.Reynolds(V=2.5, D=0.25, nu=1.636e-05).to(float)
    109    echo &"✓ Re (with nu): {Re2:.4f}"
    110    assert abs(Re2 - 38202.934) < 0.1
    111
    112  except:
    113    echo "Error in Reynolds tests: ", getCurrentExceptionMsg()
    114    raise
    115
    116proc test_psd() =
    117  try:
    118    echo "\nTesting particle size distribution functionality:"
    119
    120    # Create a discrete PSD
    121    let ds = @[240.0, 360.0, 450.0, 562.5, 703.0, 878.0, 1097.0, 1371.0,
    122               1713.0, 2141.0, 2676.0, 3345.0, 4181.0, 5226.0, 6532.0]
    123    let numbers = @[65.0, 119.0, 232.0, 410.0, 629.0, 849.0, 990.0, 981.0,
    124                   825.0, 579.0, 297.0, 111.0, 21.0, 1.0]
    125
    126    let psd = fluids.particle_size_distribution.ParticleSizeDistribution(
    127      ds=ds,
    128      fractions=numbers,
    129      order=0
    130    )
    131    echo "✓ Created discrete PSD"
    132
    133    # Test mean sizes
    134    let d21 = psd.mean_size(2, 1).to(float)
    135    echo &"✓ Size-weighted mean diameter: {d21:.4f}"
    136    assert abs(d21 - 1857.788) < 0.1
    137
    138    let d10 = psd.mean_size(1, 0).to(float)
    139    echo &"✓ Arithmetic mean diameter: {d10:.4f}"
    140    assert abs(d10 - 1459.372) < 0.1
    141
    142    # Test percentile calculations
    143    let d10_percentile = psd.dn(0.1).to(float)
    144    let d90_percentile = psd.dn(0.9).to(float)
    145    echo &"✓ D10: {d10_percentile:.4f}"
    146    echo &"✓ D90: {d90_percentile:.4f}"
    147
    148    # Test probability functions
    149    let pdf_val = psd.pdf(1000).to(float)
    150    let cdf_val = psd.cdf(5000).to(float)
    151    echo &"✓ PDF at 1000: {pdf_val:.4e}"
    152    echo &"✓ CDF at 5000: {cdf_val:.6f}"
    153
    154    # Test lognormal distribution
    155    let psd_log = fluids.particle_size_distribution.PSDLognormal(s=0.5, d_characteristic=5E-6)
    156    echo "✓ Created lognormal PSD"
    157
    158    let vssa = psd_log.vssa.to(float)
    159    echo &"✓ Volume specific surface area: {vssa:.2f}"
    160
    161    let span = psd_log.dn(0.9).to(float) - psd_log.dn(0.1).to(float)
    162    echo &"✓ Span: {span:.4e}"
    163
    164    let ratio_7525 = psd_log.dn(0.75).to(float) / psd_log.dn(0.25).to(float)
    165    echo &"✓ D75/D25 ratio: {ratio_7525:.6f}"
    166
    167  except:
    168    echo "Error in PSD tests: ", getCurrentExceptionMsg()
    169    raise
    170
    171proc benchmark_fluids() =
    172  echo "\nRunning benchmarks:"
    173
    174  # Benchmark friction factor calculation
    175  echo "\nBenchmarking friction_factor:"
    176  let start = epochTime()
    177
    178  for i in 1..1_000_000:
    179    discard fluids.friction_factor(Re=1e5, eD=0.0001)
    180
    181  let duration = (epochTime() - start) * 1_000_000  # Convert to microseconds
    182  echo &"Time for 1e6 friction_factor calls: {duration.int} microseconds"
    183  echo &"Average time per call: {duration / 1_000_000:.6f} microseconds"
    184
    185  # Benchmark tank creation
    186  echo "\nBenchmarking TANK creation:"
    187  let tank_start = epochTime()
    188
    189  for i in 1..1000:
    190    discard fluids.TANK(
    191      L=3, D=5, horizontal=false,
    192      sideA="torispherical", sideB="torispherical",
    193      sideA_f=1, sideA_k=0.1,
    194      sideB_f=1, sideB_k=0.1
    195    )
    196
    197  let tank_duration = (epochTime() - tank_start) * 1_000_000  # Convert to microseconds
    198  echo &"Average time per tank creation: {tank_duration / 1000:.6f} microseconds"
    199
    200when isMainModule:
    201  try:
    202    test_fluids()
    203    test_atmosphere()
    204    test_tank()
    205    test_reynolds()
    206    test_psd()
    207    benchmark_fluids()
    208    echo "\nAll tests completed!"
    209  except:
    210    echo "Fatal error: ", getCurrentExceptionMsg()
    211    quit(1)

## Requirements

- Python with fluids installed

- Nimpy: https://github.com/yglukhov/nimpy

## Usage Notes

- Nim has a great package manager and is easy to read/write. This example took 10 minutes to develop.

- 1.5 microsecond friction factor, 9 microsecond tank creation observed by author; very comparable to pybind11