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

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