11 (declaim (optimize (speed 2) (debug 3) (safety 3)))
13 (sb-alien:define-alien-routine j0
15 (x sb-alien
:double-float
))
17 (sb-alien:define-alien-routine j1
19 (x sb-alien
:double-float
))
21 (sb-alien:define-alien-routine jn
24 (x sb-alien
:double-float
))
26 (declaim (ftype (function ((complex double-float
))
27 (values double-float
&optional
)) abs2
)
30 (declare (type (complex double-float
) z
))
31 (let* ((x (realpart z
))
35 (declaim (type fixnum n
)
36 (type double-float
/sin-alpha
/sin-alpha2 sin-alpha2
)
37 (type (double-float -
1d0
1d0
) sin-alpha
)
38 (type (simple-array double-float
1) ac as as^
2 ac2
))
41 (defparameter ac
(make-array n
:element-type
'double-float
))
42 (defparameter as
(make-array n
:element-type
'double-float
))
43 (defparameter as^
2 (make-array n
:element-type
'double-float
))
44 (defparameter ac2
(make-array n
:element-type
'double-float
))
45 (defparameter sin-alpha
.4d0
)
46 (defparameter sin-alpha2
(* sin-alpha sin-alpha
))
47 (defparameter /sin-alpha
(/ sin-alpha
))
48 (defparameter /sin-alpha2
(/ sin-alpha2
))
50 (declaim (ftype (function (&key
(:numerical-aperture double-float
)
51 (:immersion-index double-float
)
52 (:integrand-evaluations fixnum
))
53 (values null
&optional
))
56 (defun init (&key
(numerical-aperture 1.2d0
) (immersion-index 1.515d0
) (integrand-evaluations 31))
57 (setf n integrand-evaluations
58 ac
(make-array n
:element-type
'double-float
)
59 as
(make-array n
:element-type
'double-float
)
60 as^
2 (make-array n
:element-type
'double-float
)
61 ac2
(make-array n
:element-type
'double-float
)
62 sin-alpha
(/ numerical-aperture immersion-index
)
63 sin-alpha2
(* sin-alpha sin-alpha
)
64 /sin-alpha
(/ sin-alpha
)
65 /sin-alpha2
(/ sin-alpha2
))
66 (let* ((alpha (asin sin-alpha
))
70 (let* ((theta (the (double-float 0d0
2d0
) (* dalpha iter
)))
75 (declare ((double-float 0d0
1d0
) ct
)) ;; for the sqrt
76 (setf (aref ac iter
) ct
79 (aref ac2 iter
) ct2
)))))
83 ;; k = omega/c = 2 pi / lambda
84 ;; u = k z sin(alpha)^2
85 ;; v = k sqrt(x^2+y^2) sin(alpha)
87 ;; for small angular aperture alpha << 1
89 ;; v ~ k (a/R) sqrt(x^2+y^2)
90 ;; with a .. radius of the exit pupil and
91 ;; R .. distance between exit pupil and focal plane
93 (declaim (ftype (function (double-float double-float double-float
94 &key
(:immersion-index double-float
)
95 (:numerical-aperture double-float
)
96 (:wavelength double-float
))
97 (values double-float double-float
&optional
))))
98 (defun transform-xyz-to-uv (x y z
&key
(immersion-index 1.515d0
)
99 (numerical-aperture 1.38d0
) (wavelength .480d0
))
100 "Return the cylindrical coordinates u and v of a given 3D point. All
101 lengths in micrometer."
102 (let* ((k (/ (* 2d0 pi immersion-index
)
104 (sina (/ numerical-aperture
106 (u (* k z sina sina
))
107 (v (* k
(sqrt (+ (* x x
) (* y y
))) sina
)))
111 (tranform-xyz-to-uv 0 1 1)
113 (declaim (ftype (function (double-float double-float
)
114 (values (complex double-float
)
115 (complex double-float
)
116 (complex double-float
) &optional
))
117 intermediate-integrals-point
)
118 (inline intermediate-integrals-point
))
119 (defun intermediate-integrals-point (u v
)
120 (let* ((i0 (complex 0d0
0d0
))
121 (i1 (complex 0d0
0d0
))
122 (i2 (complex 0d0
0d0
)))
123 (declare (type (complex double-float
) i0 i1 i2
))
126 (let* ((s (aref as iter
))
129 (vv (* v s
/sin-alpha
))
130 (uu (* u c
/sin-alpha2
))
131 (e (exp (complex 0 uu
)))
132 (cmul0 (* scale e
(* c2 s
(+ 1 c
) (j0 vv
))))
133 (cmul1 (* scale e
(* c2
(aref as^
2 iter
) (j1 vv
))))
134 (cmul2 (* scale e
(* c2 s
(- 1 c
) (jn 2 vv
)))))
138 (cond ((eq iter
0) (setf scale
2))
139 ((eq iter
(- n
2)) (setf scale
1))
140 ((eq scale
2) (setf scale
4))
141 ((eq scale
4) (setf scale
2))))))
142 (let* ((s (* n
3d0
)))
143 (values (* s i0
) (* s i1
) (* s i2
)))))
145 (declaim (ftype (function (double-float double-float
)
146 (values double-float
&optional
))
148 (inline energy-density
))
149 (defun energy-density (u v
)
150 (multiple-value-bind (i0 i1 i2
)
151 (intermediate-integrals-point u v
)
156 (declaim (ftype (function
157 (&optional fixnum fixnum double-float double-float
)
158 (values (simple-array double-float
(* *)) &optional
))
160 (defun energy-density-cyl (&optional
(nu 100) (nv 100) (du .1d0
) (dv .1d0
))
161 (let* ((res (make-array (list nu nv
)
162 :element-type
'double-float
)))
167 (setf (aref res iu iv
) (energy-density u v
))))))
170 (declaim (ftype (function
171 (&optional fixnum fixnum double-float double-float
)
172 (values (simple-array (complex double-float
) (* *))
173 (simple-array (complex double-float
) (* *))
174 (simple-array (complex double-float
) (* *))
176 intermediate-integrals-cyl
))
178 (defun intermediate-integrals-cyl (&optional
(nu 100) (nv 100)
180 (let* ((dims (list nu nv
))
181 (ii0 (make-array dims
:element-type
'(complex double-float
)))
182 (ii1 (make-array dims
:element-type
'(complex double-float
)))
183 (ii2 (make-array dims
:element-type
'(complex double-float
))))
188 (multiple-value-bind (i0 i1 i2
)
189 (intermediate-integrals-point u v
)
190 (setf (aref ii0 iu iv
) i0
192 (aref ii2 iu iv
) i2
))))))
193 (values ii0 ii1 ii2
)))
196 (declaim (ftype (function (fixnum fixnum fixnum double-float double-float
198 (:numerical-aperture double-float
)
199 (:immersion-index double-float
)
200 (:wavelength double-float
)
201 (:integrand-evaluations fixnum
))
202 (values (simple-array (complex double-float
) 3)
203 (simple-array (complex double-float
) 3)
204 (simple-array (complex double-float
) 3)
214 (nradius (1+ (ceiling (* (sqrt 2d0
) (max x y
)))))
215 (nz (1+ (ceiling z
2))))
216 (multiple-value-bind (u v
)
217 (transform-xyz-to-uv size-x
0 (* .5d0 size-z
))
218 (multiple-value-bind (i0 i1 i2
)
219 (intermediate-integrals-cyl nz nradius
(/ u nz
) (/ v nradius
))
220 (vol::interpolate2-cdf i0
2d0
2d0
))))
222 ;; size radius is either the extend in x or y (in um) depending on what is bigger
223 (defun electric-field-psf
224 (z y x size-z size-radius
&key
(numerical-aperture 1.38d0
)
225 (immersion-index 1.515d0
) (wavelength .480d0
)
226 (integrand-evaluations 31))
227 (init :numerical-aperture numerical-aperture
228 :immersion-index immersion-index
229 :integrand-evaluations integrand-evaluations
)
230 (let* ((nradius (1+ (ceiling (* (sqrt 2d0
) (max x y
)))))
233 (e0 (make-array dims
:element-type
'(complex double-float
)))
234 (e1 (make-array dims
:element-type
'(complex double-float
)))
235 (e2 (make-array dims
:element-type
'(complex double-float
))))
236 (multiple-value-bind (u v
)
237 (transform-xyz-to-uv 0 (* (sqrt 2d0
) size-radius
) (* .5d0 size-z
)
238 :numerical-aperture numerical-aperture
239 :immersion-index immersion-index
240 :wavelength wavelength
)
241 (multiple-value-bind (i0 i1 i2
)
242 (intermediate-integrals-cyl nz nradius
243 (/ (* 1d0 u
) nz
) (/ (* 1d0 v
) nradius
))
244 (let ((rad-a (make-array (list y x
) :element-type
'double-float
))
245 (cphi-a (make-array (list y x
) :element-type
'double-float
))
246 (c2phi-a (make-array (list y x
) :element-type
'double-float
))
247 (s2phi-a (make-array (list y x
) :element-type
'double-float
)))
248 (do-rectangle (j i
0 y
0 x
)
249 (let* ((ii (- i
(floor x
2)))
250 (jj (- j
(floor y
2)))
251 (radius (sqrt (+ (* 1d0 ii ii
) (* jj jj
))))
252 (phi (atan (* 1d0 jj
) ii
)))
253 (setf (aref rad-a j i
) radius
254 (aref cphi-a j i
) (cos phi
)
255 (aref c2phi-a j i
) (cos (* 2d0 phi
))
256 (aref s2phi-a j i
) (sin (* 2d0 phi
)))))
257 (let ((del (if (eq 1 (mod z
2))
259 .5d0
))) ;; add .5 if z is even
260 (do-box (k j i
0 nz
0 y
0 x
)
261 (let* ((zi (- nz k
(- 1d0 del
)))
263 (v0 (interpolate2 i0 zi r
))
264 (v1 (interpolate2 i1 zi r
))
265 (v2 (interpolate2 i2 zi r
)))
266 (setf (aref e0 k j i
) (* (complex 0d0 -
1d0
)
267 (+ v0
(* v2
(aref c2phi-a j i
))))
268 (aref e1 k j i
) (* (complex 0d0 -
1d0
)
269 v2
(aref s2phi-a j i
))
270 (aref e2 k j i
) (* -
2d0 v1
(aref cphi-a j i
))))))
271 (do-box (k j i
0 nz
0 y
0 x
)
272 (setf (aref e0
(- z k
1) j i
) (- (conjugate (aref e0 k j i
)))
273 (aref e1
(- z k
1) j i
) (- (conjugate (aref e1 k j i
)))
274 (aref e2
(- z k
1) j i
) (conjugate (aref e2 k j i
)))))))
278 (defparameter *e0
* (electric-field 10 10 10 3d0
3d0
))
280 (declaim (ftype (function (double-float double-float
&key
281 (:numerical-aperture double-float
)
282 (:immersion-index double-float
)
285 (:wavelength double-float
)
286 (:integrand-evaluations fixnum
))
287 (values (simple-array double-float
2) &optional
))
289 (defun intensity-psf-cyl (z radius
&key
(numerical-aperture 1.38d0
)
290 (immersion-index 1.515d0
)
291 (nz 50) (nradius 50) (wavelength .480d0
)
292 (integrand-evaluations 31))
293 "Calculate 2D cylindrical PSF with axial extend Z micrometers and
294 transversal extend RADIUS micrometers."
295 (psf:init
:numerical-aperture numerical-aperture
296 :immersion-index immersion-index
297 :integrand-evaluations integrand-evaluations
)
298 (multiple-value-bind (u v
)
299 (transform-xyz-to-uv 0 radius z
300 :numerical-aperture numerical-aperture
301 :immersion-index immersion-index
302 :wavelength wavelength
)
303 (let* ((a (energy-density-cyl nz nradius
(/ u nz
) (/ v nradius
))))
307 (progn (cyl-psf 3d0
1.5d0
)
310 (declaim (ftype (function (fixnum fixnum fixnum double-float double-float
311 &key
(:numerical-aperture double-float
)
312 (:immersion-index double-float
)
313 (:integrand-evaluations fixnum
)
314 (:wavelength double-float
))
315 (values (simple-array (complex double-float
) 3) &optional
))
317 (defun intensity-psf (z y x size-z size-radius
&key
(numerical-aperture 1.38d0
)
318 (immersion-index 1.515d0
) (integrand-evaluations 31)
320 "Calculate an intensity point spread function for an aplanatic microobjective with the given NUMERICAL-APERTURE, IMMERSION-INDEX and WAVELENGTH. Distances in micrometer."
321 (let* ((psf (make-array (list z y x
)
322 :element-type
'(complex double-float
)))
323 (nz (1+ (ceiling z
2)))
324 (nradius (1+ (ceiling (* (sqrt 2d0
) (max x y
)))))
325 (cyl (intensity-psf-cyl
331 :numerical-aperture numerical-aperture
332 :immersion-index immersion-index
333 :integrand-evaluations integrand-evaluations
334 :wavelength wavelength
)))
335 (let ((rad-a (make-array (list y x
) :element-type
'double-float
)))
336 (do-rectangle (j i
0 y
0 x
)
337 (let* ((ii (- i
(floor x
2)))
338 (jj (- j
(floor y
2)))
339 (radius (sqrt (+ (* 1d0 ii ii
) (* jj jj
)))))
340 (setf (aref rad-a j i
) radius
)))
341 (let ((del (if (eq 1 (mod z
2)) ;; add .5 when z is even
344 (do-box (k j i
0 nz
0 y
0 x
)
345 (setf (aref psf k j i
)
346 (complex (vol::interpolate2-df cyl
347 (- nz k
(- 1d0 del
)) (aref rad-a j i
))))))
348 (do-box (k j i
0 nz
0 y
0 x
)
349 (setf (aref psf
(- z k
1) j i
) (aref psf k j i
))))
356 (time (progn (integ-all)
359 ;; cylindrical coordinates:
363 #+nil
;; print out a cross section of the psf transversal 1.5 um and
365 (let ((numerical-aperture 1.38d0
)
366 (immersion-index 1.515d0
))
367 (init :numerical-aperture numerical-aperture
368 :immersion-index immersion-index
)
369 (multiple-value-bind (u v
)
370 (transform-xyz-to-uv 0 1.5 3
371 :numerical-aperture numerical-aperture
372 :immersion-index immersion-index
)
375 (a (energy-density-cyl nu nv
(/ u nu
) (/ v nv
)))
378 (destructuring-bind (uu vv
)
383 (format t
"~2d" (truncate (* scale
(aref a u v
)))))