lisp Integration¶
This example demonstrates how to use fluids from lisp.
Source Code¶
1#!/usr/bin/sbcl --script
2
3;; Load quicklisp
4#-quicklisp
5(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
6 (user-homedir-pathname))))
7 (when (probe-file quicklisp-init)
8 (load quicklisp-init)))
9
10;; Load py4cl and ensure we're using Python 3
11(ql:quickload :py4cl :silent t)
12(setf py4cl:*python-command* "python3")
13
14;; Import required modules
15;; (py4cl:import-module "fluids" :as "fl")
16(py4cl:import-module "fluids" :as "fluids")
17
18;; Check Python environment
19(py4cl:python-exec "
20import sys
21print('Python path:', sys.executable)
22try:
23 import numpy
24 print('NumPy found at:', numpy.__file__)
25 import fluids
26 print('fluids found at:', fluids.__file__)
27except ImportError as e:
28 print('Error importing NumPy:', e)
29")
30
31
32
33(defun test-fluids ()
34 (handler-case
35 (progn
36 (format t "✓ Successfully imported fluids~%")
37 (format t "✓ Fluids version: ~A~%" (py4cl:python-eval "fluids.__version__"))
38 ;; Test Reynolds number calculation
39 (let ((re (py4cl:python-eval
40 (format nil "fluids.Reynolds(**{'V': ~F, 'D': ~F, 'rho': ~F, 'mu': ~F})"
41 2.5 0.1 1000 0.001))))
42 (format t "✓ Reynolds number calculation successful: ~A~%" re)
43 (assert (> re 0)))
44
45 ;; Test friction factor calculation
46 (let ((fd (py4cl:python-eval
47 (format nil "fluids.friction_factor(**{'Re': ~E, 'eD': ~F})"
48 1e5 0.0001))))
49 (format t "✓ Friction factor calculation successful: ~A~%" fd)
50 (assert (and (> fd 0) (< fd 1))))
51
52 (format t "~%All basic tests completed successfully!~%"))
53 (error (e)
54 (format t "Error occurred: ~A~%" e)
55 (error e))))
56
57
58
59(defun test-atmosphere ()
60 (handler-case
61 (progn
62 ;; Create and store the atmosphere object in Python's namespace
63 (py4cl:python-exec
64 (format nil "atm = fluids.ATMOSPHERE_1976(**{'Z': ~F})" 5000))
65
66 (format t "~%Testing atmosphere at 5000m elevation:~%")
67 ;; Access properties using attributes
68 (format t "✓ Temperature: ~,4F~%"
69 (py4cl:python-eval "atm.T"))
70 (format t "✓ Pressure: ~,4F~%"
71 (py4cl:python-eval "atm.P"))
72 (format t "✓ Density: ~,6F~%"
73 (py4cl:python-eval "atm.rho"))
74
75 ;; Test derived properties
76 (format t "✓ Gravity: ~,6F~%"
77 (py4cl:python-eval "atm.g"))
78 (format t "✓ Viscosity: ~,6E~%"
79 (py4cl:python-eval "atm.mu"))
80 (format t "✓ Thermal conductivity: ~,6F~%"
81 (py4cl:python-eval "atm.k"))
82 (format t "✓ Sonic velocity: ~,4F~%"
83 (py4cl:python-eval "atm.v_sonic"))
84
85 ;; Test static methods
86 (let ((g-high (py4cl:python-eval
87 (format nil "fluids.ATMOSPHERE_1976.gravity(**{'Z': ~E})" 1e5))))
88 (format t "✓ High altitude gravity: ~,6F~%" g-high))
89
90 (let ((v-sonic (py4cl:python-eval
91 (format nil "fluids.ATMOSPHERE_1976.sonic_velocity(**{'T': ~F})" 300))))
92 (format t "✓ Sonic velocity at 300K: ~,4F~%" v-sonic))
93
94 (let ((mu-400 (py4cl:python-eval
95 (format nil "fluids.ATMOSPHERE_1976.viscosity(**{'T': ~F})" 400))))
96 (format t "✓ Viscosity at 400K: ~,6E~%" mu-400))
97
98 (let ((k-400 (py4cl:python-eval
99 (format nil "fluids.ATMOSPHERE_1976.thermal_conductivity(**{'T': ~F})" 400))))
100 (format t "✓ Thermal conductivity at 400K: ~,6F~%" k-400)))
101 (error (e)
102 (format t "Error in atmosphere tests: ~A~%" e)
103 (error e))))
104
105
106(defun test-tank ()
107 (handler-case
108 (progn
109 ;; Test basic tank creation
110 (py4cl:python-exec
111 (format nil "t1 = fluids.TANK(**{'V': ~F, 'L_over_D': ~F, 'sideB': 'conical', 'horizontal': False})"
112 10 0.7))
113 (format t "~%Testing tank calculations:~%")
114 (format t "✓ Tank length: ~,6F~%"
115 (py4cl:python-eval "t1.L"))
116 (format t "✓ Tank diameter: ~,6F~%"
117 (py4cl:python-eval "t1.D"))
118
119 ;; Test ellipsoidal tank
120 (py4cl:python-exec
121 (format nil "tank_ellip = fluids.TANK(**{'D': ~F, 'V': ~F, 'horizontal': False,
122 'sideA': 'ellipsoidal', 'sideB': 'ellipsoidal',
123 'sideA_a': ~F, 'sideB_a': ~F})"
124 10 500 1 1))
125 (format t "✓ Ellipsoidal tank L: ~,6F~%"
126 (py4cl:python-eval "tank_ellip.L"))
127
128 ;; Test torispherical tank
129 (py4cl:python-exec
130 (format nil "din = fluids.TANK(**{'L': ~F, 'D': ~F, 'horizontal': False,
131 'sideA': 'torispherical', 'sideB': 'torispherical',
132 'sideA_f': ~F, 'sideA_k': ~F, 'sideB_f': ~F, 'sideB_k': ~F})"
133 3 5 1 0.1 1 0.1))
134
135 (format t "✓ Tank representation: ~A~%"
136 (py4cl:python-eval "str(din)"))
137 (format t "✓ Tank max height: ~,6F~%"
138 (py4cl:python-eval "din.h_max"))
139 (format t "✓ Height at V=40: ~,6F~%"
140 (py4cl:python-eval "din.h_from_V(40)"))
141 (format t "✓ Volume at h=4.1: ~,5F~%"
142 (py4cl:python-eval "din.V_from_h(4.1)"))
143 (format t "✓ Surface area at h=2.1: ~,5F~%"
144 (py4cl:python-eval "din.SA_from_h(2.1)")))
145 (error (e)
146 (format t "Error in tank tests: ~A~%" e)
147 (error e))))
148
149
150(defun test-psd ()
151 (handler-case
152 (progn
153 (format t "~%Testing particle size distribution functionality:~%")
154
155 ;; Create arrays in Python's namespace
156 (py4cl:python-exec "
157ds = [240, 360, 450, 562.5, 703, 878, 1097, 1371, 1713, 2141, 2676, 3345, 4181, 5226, 6532]
158numbers = [65, 119, 232, 410, 629, 849, 990, 981, 825, 579, 297, 111, 21, 1]")
159
160 ;; Create discrete PSD
161 (py4cl:python-exec "
162psd = fluids.particle_size_distribution.ParticleSizeDistribution(
163 ds=ds,
164 fractions=numbers,
165 order=0
166)")
167 (format t "✓ Created discrete PSD~%")
168
169 ;; Test mean sizes
170 (let ((d21 (py4cl:python-eval "psd.mean_size(2, 1)")))
171 (format t "✓ Size-weighted mean diameter: ~,4F~%" d21)
172 (assert (< (abs (- d21 1857.788)) 0.1)))
173
174 (let ((d10 (py4cl:python-eval "psd.mean_size(1, 0)")))
175 (format t "✓ Arithmetic mean diameter: ~,4F~%" d10)
176 (assert (< (abs (- d10 1459.372)) 0.1)))
177
178 ;; Test percentile calculations
179 (let ((d10-percentile (py4cl:python-eval "psd.dn(0.1)"))
180 (d90-percentile (py4cl:python-eval "psd.dn(0.9)")))
181 (format t "✓ D10: ~,4F~%" d10-percentile)
182 (format t "✓ D90: ~,4F~%" d90-percentile))
183
184 ;; Test probability functions
185 (let ((pdf-val (py4cl:python-eval "psd.pdf(1000)"))
186 (cdf-val (py4cl:python-eval "psd.cdf(5000)")))
187 (format t "✓ PDF at 1000: ~,4E~%" pdf-val)
188 (format t "✓ CDF at 5000: ~,6F~%" cdf-val))
189
190 ;; Test lognormal distribution
191 (py4cl:python-exec
192 (format nil "psd_log = fluids.particle_size_distribution.PSDLognormal(**{'s': ~F, 'd_characteristic': ~E})"
193 0.5 5e-6))
194 (format t "✓ Created lognormal PSD~%")
195
196 (let ((vssa (py4cl:python-eval "psd_log.vssa")))
197 (format t "✓ Volume specific surface area: ~,2F~%" vssa))
198
199 (let ((span (py4cl:python-eval "psd_log.dn(0.9) - psd_log.dn(0.1)")))
200 (format t "✓ Span: ~,4E~%" span))
201
202 (let ((ratio-7525 (py4cl:python-eval "psd_log.dn(0.75)/psd_log.dn(0.25)")))
203 (format t "✓ D75/D25 ratio: ~,6F~%" ratio-7525)))
204 (error (e)
205 (format t "Error in PSD tests: ~A~%" e)
206 (error e))))
207
208(defun benchmark-fluids ()
209 (format t "~%Running benchmarks:~%")
210
211 ;; Benchmark friction factor calculation
212 (format t "~%Benchmarking friction_factor:~%")
213 (let ((t1 (get-internal-real-time)))
214 (dotimes (i 10000)
215 (py4cl:python-eval
216 (format nil "fluids.friction_factor(**{'Re': ~E, 'eD': ~F})" 1e5 0.0001)))
217 (let ((elapsed (/ (- (get-internal-real-time) t1) internal-time-units-per-second)))
218 (format t "Time for 1e6 friction_factor calls: ~,6F seconds~%" elapsed)
219 (format t "Average time per call: ~,6F seconds~%" (/ elapsed 10000))))
220
221 ;; Benchmark tank creation
222 (format t "~%Benchmarking TANK creation:~%")
223 (let ((t2 (get-internal-real-time)))
224 (dotimes (i 10000)
225 (py4cl:python-eval
226 (format nil "fluids.TANK(**{'L': ~F, 'D': ~F, 'horizontal': False,
227 'sideA': 'torispherical', 'sideB': 'torispherical',
228 'sideA_f': ~F, 'sideA_k': ~F,
229 'sideB_f': ~F, 'sideB_k': ~F})"
230 3 5 1 0.1 1 0.1)))
231 (let ((elapsed (/ (- (get-internal-real-time) t2) internal-time-units-per-second)))
232 (format t "Average time per creation: ~,6F seconds~%" (/ elapsed 10000)))))
233
234
235 ;; Run all tests
236(format t "Running fluids tests from Common Lisp...~%")
237(test-fluids)
238(test-atmosphere)
239(test-tank)
240(test-psd)
241(benchmark-fluids)
242(format t "~%All tests completed!~%")
243
244;; Clean up
245(py4cl:python-stop)
Requirements¶
Python with fluids installed
Usage Notes¶
The example demonstrates basic integration with fluids
80 microsecond friction factor, 200 microsecond tank creation observed by author