14 (declaim (optimize (speed 2) (debug 3) (safety 3)))
17 (sb-alien:define-alien-routine j0
19 (x sb-alien
:double-float
))
21 (sb-alien:define-alien-routine j1
23 (x sb-alien
:double-float
))
25 (sb-alien:define-alien-routine jn
28 (x sb-alien
:double-float
))
30 (sb-alien:define-alien-routine j0f
32 (x sb-alien
:single-float
))
34 (sb-alien:define-alien-routine j1f
36 (x sb-alien
:single-float
))
38 (sb-alien:define-alien-routine jnf
41 (x sb-alien
:single-float
)))
43 (deftype my-float-helper
()
46 (deftype my-float
(&optional
(low '*) (high '*))
47 `(single-float ,(if (eq low
'*)
49 (coerce low
'my-float-helper
))
52 (coerce high
'my-float-helper
))))
55 (declare ((complex my-float
) z
)
56 (values my-float
&optional
))
57 (let* ((x (realpart z
))
62 (declaim (type fixnum n
)
63 (type my-float
/sin-alpha
/sin-alpha2 sin-alpha2
)
64 (type (my-float -
1 1) sin-alpha
)
65 (type (simple-array my-float
1) ac as as^
2 ac2
))
69 (defparameter ac
(make-array n
:element-type
'my-float
))
70 (defparameter as
(make-array n
:element-type
'my-float
))
71 (defparameter as^
2 (make-array n
:element-type
'my-float
))
72 (defparameter ac2
(make-array n
:element-type
'my-float
))
73 (defparameter sin-alpha
(coerce .4 'my-float
))
74 (defparameter sin-alpha2
(* sin-alpha sin-alpha
))
75 (defparameter /sin-alpha
(/ sin-alpha
))
76 (defparameter /sin-alpha2
(/ sin-alpha2
)))
78 (defun init (&key
(numerical-aperture (coerce 1.2 'my-float
))
79 (immersion-index (coerce 1.515 'my-float
))
80 (integrand-evaluations 31))
81 (declare (my-float numerical-aperture immersion-index
)
82 (fixnum integrand-evaluations
)
83 (values null
&optional
))
84 (setf n integrand-evaluations
85 ac
(make-array n
:element-type
'my-float
)
86 as
(make-array n
:element-type
'my-float
)
87 as^
2 (make-array n
:element-type
'my-float
)
88 ac2
(make-array n
:element-type
'my-float
)
89 sin-alpha
(/ numerical-aperture immersion-index
)
90 sin-alpha2
(* sin-alpha sin-alpha
)
91 /sin-alpha
(/ sin-alpha
)
92 /sin-alpha2
(/ sin-alpha2
))
93 (let* ((alpha (asin sin-alpha
))
97 (let* ((theta (the (my-float 0d0
2d0
) (* dalpha iter
)))
102 (declare ((my-float 0 1) ct
)) ;; for the sqrt
103 (setf (aref ac iter
) ct
105 (aref as^
2 iter
) st^
2
106 (aref ac2 iter
) ct2
)))))
110 ;; k = omega/c = 2 pi / lambda
111 ;; u = k z sin(alpha)^2
112 ;; v = k sqrt(x^2+y^2) sin(alpha)
114 ;; for small angular aperture alpha << 1
116 ;; v ~ k (a/R) sqrt(x^2+y^2)
117 ;; with a .. radius of the exit pupil and
118 ;; R .. distance between exit pupil and focal plane
120 (defun transform-xyz-to-uv (x y z
&key
(immersion-index (coerce 1.515 'my-float
))
121 (numerical-aperture (coerce 1.38 'my-float
))
122 (wavelength (coerce .480 'my-float
)))
123 "Return the cylindrical coordinates u and v of a given 3D point. All
124 lengths in micrometer."
125 (declare (my-float x y z immersion-index numerical-aperture wavelength
)
126 (values my-float my-float
&optional
))
127 (let* ((k (/ (* #.
(coerce 2 'my-float
) (coerce pi
'my-float
) immersion-index
)
129 (sina (/ numerical-aperture
131 (u (* k z sina sina
))
132 (v (* k
(sqrt (+ (* x x
) (* y y
))) sina
)))
136 (transform-xyz-to-uv 0.0 1.0 1.0)
138 (defun intermediate-integrals-point (u v
)
139 (declare (my-float u v
)
140 (values (complex my-float
) (complex my-float
)
141 (complex my-float
) &optional
))
142 (let* ((zero #.
(coerce 0 '(complex my-float
)))
148 (let* ((s (aref as iter
))
151 (vv (* v s
/sin-alpha
))
152 (uu (* u c
/sin-alpha2
))
153 (e (exp (complex 0 uu
)))
154 (cmul0 (* scale e
(* c2 s
(+ 1 c
) (j0 vv
))))
155 (cmul1 (* scale e
(* c2
(aref as^
2 iter
) (j1 vv
))))
156 (cmul2 (* scale e
(* c2 s
(- 1 c
) (jn 2 vv
)))))
160 (cond ((eq iter
0) (setf scale
2))
161 ((eq iter
(- n
2)) (setf scale
1))
162 ((eq scale
2) (setf scale
4))
163 ((eq scale
4) (setf scale
2))))))
164 (let* ((s (* n
3d0
)))
165 (values (* s i0
) (* s i1
) (* s i2
)))))
167 (defun energy-density (u v
)
168 (declare (my-float u v
)
169 (values my-float
&optional
))
170 (multiple-value-bind (i0 i1 i2
)
171 (intermediate-integrals-point u v
)
176 (defun energy-density-cyl (&optional
(nu 100) (nv 100) (du #.
(coerce .1 'my-float
))
178 (declare (fixnum nu nv
)
180 (values (simple-array my-float
2) &optional
))
181 (let* ((res (make-array (list nu nv
)
182 :element-type
'my-float
)))
187 (setf (aref res iu iv
) (energy-density u v
))))))
190 (defun intermediate-integrals-cyl (&optional
(nu 100) (nv 100)
191 (du (coerce .1 'my-float
)) (dv du
))
192 (declare (fixnum nu nv
)
194 (values (simple-array (complex my-float
) 2)
195 (simple-array (complex my-float
) 2)
196 (simple-array (complex my-float
) 2) &optional
))
197 (let* ((dims (list nu nv
))
198 (ii0 (make-array dims
:element-type
'(complex my-float
)))
199 (ii1 (make-array dims
:element-type
'(complex my-float
)))
200 (ii2 (make-array dims
:element-type
'(complex my-float
))))
205 (multiple-value-bind (i0 i1 i2
)
206 (intermediate-integrals-point u v
)
207 (setf (aref ii0 iu iv
) i0
209 (aref ii2 iu iv
) i2
))))))
210 (values ii0 ii1 ii2
)))
218 (nradius (1+ (ceiling (* (sqrt 2d0
) (max x y
)))))
219 (nz (1+ (ceiling z
2))))
220 (multiple-value-bind (u v
)
221 (transform-xyz-to-uv size-x
0 (* .5d0 size-z
))
222 (multiple-value-bind (i0 i1 i2
)
223 (intermediate-integrals-cyl nz nradius
(/ u nz
) (/ v nradius
))
224 (vol::interpolate2-cdf i0
2d0
2d0
))))
226 ;; size radius is either the extend in x or y (in um) depending on what is bigger
227 (defun electric-field-psf
228 (z y x size-z size-radius
&key
(numerical-aperture (coerce 1.38 'my-float
))
229 (immersion-index (coerce 1.515 'my-float
))
230 (wavelength (coerce .480 'my-float
))
231 (integrand-evaluations 31))
232 (declare (fixnum z y x integrand-evaluations
)
233 (my-float size-z size-radius numerical-aperture immersion-index
235 (values (simple-array (complex my-float
) 3)
236 (simple-array (complex my-float
) 3)
237 (simple-array (complex my-float
) 3) &optional
))
238 (init :numerical-aperture numerical-aperture
239 :immersion-index immersion-index
240 :integrand-evaluations integrand-evaluations
)
241 (let* ((nradius (1+ (ceiling (* (sqrt 2d0
) (max x y
)))))
244 (e0 (make-array dims
:element-type
'(complex my-float
)))
245 (e1 (make-array dims
:element-type
'(complex my-float
)))
246 (e2 (make-array dims
:element-type
'(complex my-float
))))
247 (multiple-value-bind (u v
)
248 (transform-xyz-to-uv 0 (* (sqrt #.
(coerce 2 'my-float
)) size-radius
)
249 (* #.
(coerce .5 'my-float
) size-z
)
250 :numerical-aperture numerical-aperture
251 :immersion-index immersion-index
252 :wavelength wavelength
)
253 (multiple-value-bind (i0 i1 i2
)
254 (intermediate-integrals-cyl nz nradius
255 (/ (* 1d0 u
) nz
) (/ (* 1d0 v
) nradius
))
256 (let ((rad-a (make-array (list y x
) :element-type
'my-float
))
257 (cphi-a (make-array (list y x
) :element-type
'my-float
))
258 (c2phi-a (make-array (list y x
) :element-type
'my-float
))
259 (s2phi-a (make-array (list y x
) :element-type
'my-float
)))
260 (do-region ((j i
) (y x
))
261 (let* ((ii (- i
(floor x
2)))
262 (jj (- j
(floor y
2)))
263 (radius (sqrt (+ (* 1d0 ii ii
) (* jj jj
))))
264 (phi (atan (* 1d0 jj
) ii
)))
265 (setf (aref rad-a j i
) radius
266 (aref cphi-a j i
) (cos phi
)
267 (aref c2phi-a j i
) (cos (* 2d0 phi
))
268 (aref s2phi-a j i
) (sin (* 2d0 phi
)))))
269 (let ((del (if (eq 1 (mod z
2))
270 #.
(coerce 0 'my-float
)
271 #.
(coerce .5 'my-float
)))) ;; add .5 if z is even
272 (do-region ((k j i
) (nz y x
))
273 (let* ((zi (- nz k
(- 1d0 del
)))
275 (v0 (interpolate2 i0 zi r
))
276 (v1 (interpolate2 i1 zi r
))
277 (v2 (interpolate2 i2 zi r
)))
278 (setf (aref e0 k j i
) (* (complex 0d0 -
1d0
)
279 (+ v0
(* v2
(aref c2phi-a j i
))))
280 (aref e1 k j i
) (* (complex 0d0 -
1d0
)
281 v2
(aref s2phi-a j i
))
282 (aref e2 k j i
) (* -
2d0 v1
(aref cphi-a j i
))))))
283 (do-box (k j i
0 nz
0 y
0 x
)
284 (setf (aref e0
(- z k
1) j i
) (- (conjugate (aref e0 k j i
)))
285 (aref e1
(- z k
1) j i
) (- (conjugate (aref e1 k j i
)))
286 (aref e2
(- z k
1) j i
) (conjugate (aref e2 k j i
)))))))
290 (defparameter *e0
* (electric-field 10 10 10 3d0
3d0
))
292 (declaim (ftype (function (my-float my-float
&key
293 (:numerical-aperture my-float
)
294 (:immersion-index my-float
)
297 (:wavelength my-float
)
298 (:integrand-evaluations fixnum
))
299 (values (simple-array my-float
2) &optional
))
301 (defun intensity-psf-cyl (z radius
&key
(numerical-aperture 1.38d0
)
302 (immersion-index 1.515d0
)
303 (nz 50) (nradius 50) (wavelength .480d0
)
304 (integrand-evaluations 31))
305 "Calculate 2D cylindrical PSF with axial extend Z micrometers and
306 transversal extend RADIUS micrometers."
307 (psf:init
:numerical-aperture numerical-aperture
308 :immersion-index immersion-index
309 :integrand-evaluations integrand-evaluations
)
310 (multiple-value-bind (u v
)
311 (transform-xyz-to-uv 0 radius z
312 :numerical-aperture numerical-aperture
313 :immersion-index immersion-index
314 :wavelength wavelength
)
315 (let* ((a (energy-density-cyl nz nradius
(/ u nz
) (/ v nradius
))))
319 (progn (cyl-psf 3d0
1.5d0
)
322 (declaim (ftype (function (fixnum fixnum fixnum my-float my-float
323 &key
(:numerical-aperture my-float
)
324 (:immersion-index my-float
)
325 (:integrand-evaluations fixnum
)
326 (:wavelength my-float
))
327 (values (simple-array (complex my-float
) 3) &optional
))
329 (defun intensity-psf (z y x size-z size-radius
&key
(numerical-aperture 1.38d0
)
330 (immersion-index 1.515d0
) (integrand-evaluations 31)
332 "Calculate an intensity point spread function for an aplanatic microobjective with the given NUMERICAL-APERTURE, IMMERSION-INDEX and WAVELENGTH. Distances in micrometer."
333 (let* ((psf (make-array (list z y x
)
334 :element-type
'(complex my-float
)))
335 (nz (1+ (ceiling z
2)))
336 (nradius (1+ (ceiling (* (sqrt 2d0
) (max x y
)))))
337 (cyl (intensity-psf-cyl
343 :numerical-aperture numerical-aperture
344 :immersion-index immersion-index
345 :integrand-evaluations integrand-evaluations
346 :wavelength wavelength
)))
347 (let ((rad-a (make-array (list y x
) :element-type
'my-float
)))
348 (do-rectangle (j i
0 y
0 x
)
349 (let* ((ii (- i
(floor x
2)))
350 (jj (- j
(floor y
2)))
351 (radius (sqrt (+ (* 1d0 ii ii
) (* jj jj
)))))
352 (setf (aref rad-a j i
) radius
)))
353 (let ((del (if (eq 1 (mod z
2)) ;; add .5 when z is even
356 (do-box (k j i
0 nz
0 y
0 x
)
357 (setf (aref psf k j i
)
358 (complex (vol::interpolate2-df cyl
359 (- nz k
(- 1d0 del
)) (aref rad-a j i
))))))
360 (do-box (k j i
0 nz
0 y
0 x
)
361 (setf (aref psf
(- z k
1) j i
) (aref psf k j i
))))
368 (time (progn (integ-all)
371 ;; cylindrical coordinates:
375 #+nil
;; print out a cross section of the psf transversal 1.5 um and
377 (let ((numerical-aperture 1.38d0
)
378 (immersion-index 1.515d0
))
379 (init :numerical-aperture numerical-aperture
380 :immersion-index immersion-index
)
381 (multiple-value-bind (u v
)
382 (transform-xyz-to-uv 0 1.5 3
383 :numerical-aperture numerical-aperture
384 :immersion-index immersion-index
)
387 (a (energy-density-cyl nu nv
(/ u nu
) (/ v nv
)))
390 (destructuring-bind (uu vv
)
395 (format t
"~2d" (truncate (* scale
(aref a u v
)))))