3 ;; it turns out that using a few points on the border of the circles
4 ;; is too sparse. the following scheme should sample the space a bit
5 ;; better and therefore give a better approximation of the exposure
9 ;; ---/ \--- xy-cross section through a
10 ;; / \ nucleus in the sample plane
12 ;; / \ choose s points along a line
21 ;; ---\ /-- -----------
22 ;; --------- ---/ \---
29 ;; b points .... a b c d e f
32 ;; inclination theta \ /
39 ;; now shoot rays from each o the points in the bfp to each of the
40 ;; points in the sample plane. we have to make sure that a nucleus
41 ;; inside the illumination cone convolved with the cross section of
42 ;; the illuminated nucleus is hit by at least one ray. the necessary
43 ;; number of points s and b depends on the size of the nuclei as well
44 ;; as the furthest distance to the border of the stack. for now i
45 ;; don't want to think too hard about that. i guess it will be
46 ;; sufficient to sample with .01 in the back focal plane and 3 points
48 ;; two dimensional coordinates will be represented as complex numbers.
50 (defun sample-line (nr-ffp nr-bfp
)
51 "Create two lists like -1 0 1 and -1 -.5 0 .5 1. Here nr-ffp would
52 be 3 and nr-bfp would be 5. The result is the outer product -1 -1, -1
53 -.5, -1, 0, ..., a list with all interconnections. Note that the pair
54 0,0 isn't emitted as it would result in duplications when turned by
56 (declare ((integer 2) nr-ffp nr-bfp
))
57 (let ((ffps (loop for i below nr-ffp collect
58 (complex (- (/ (* 2d0 i
) (1- nr-ffp
)) 1))))
59 (bfps (loop for i below nr-bfp collect
60 (complex (- (/ (* 2d0 i
) (1- nr-bfp
)) 1))))
62 (loop for f in ffps do
63 (loop for b in bfps do
64 (unless (= (complex 0d0
) f b
) ;; prevent duplication of central ray
65 (push (list f b
) result
))))
71 (defun sample-circles (nr-ffp nr-bfp nr-theta
)
72 "Create coordinates in front and backfocal plane that sample circles
73 in a regular pattern."
74 (declare ((integer 2) nr-ffp nr-bfp
)
75 ((integer 1) nr-theta
)
76 (values cons
&optional
))
77 (let ((line (sample-line nr-ffp nr-bfp
))
79 (loop for theta below nr-theta do
80 (let ((rotator (exp (complex 0d0
(/ (* pi theta
) nr-theta
)))))
81 (loop for
(f b
) in line do
82 (push (list (* rotator f
)
85 (when (and (oddp nr-ffp
) (oddp nr-bfp
)) ;; central ray was omitted above
86 (push (list (complex 0d0
) (complex 0d0
)) result
))
90 (sample-circles 2 2 1)
98 ;; / |y +---+------+ \
103 ;; -+--------------------+---+----------------+--
107 (defun move-complex-circle (z rr x
/rr y
/rr r
/rr
)
108 "Given a complex number Z inside the unit circle, move the unit
109 circle to position X,Y inside the BFP with radius RR. Scale the unit
110 circle to the window-radius R."
111 (declare ((complex double-float
) z
)
112 ((double-float -
1d0
1d0
) x
/rr y
/rr
)
113 ((double-float 0d0
1d0
) r
/rr
)
115 (values (complex double-float
) &optional
))
116 (+ (complex (* x
/rr rr
) (* y
/rr rr
))
120 (move-complex-circle (complex 1d0
0d0
) 2d0
.9d0
0d0
.1d0
)
123 (move-complex-circle (complex 1d0
0d0
) 1d0
.9d0
0d0
.1d0
)
126 (move-complex-circle (complex 1d0
) 3.601d0
0d0
0d0
.1d0
)
128 (defmethod make-rays ((objective lens
::objective
) (model sphere-model
)
129 nucleus positions win-x
/r win-y
/r win-r
/r
)
130 "Given an objective and a nucleus in a model generate rays from a
131 circle on the back focal plane into the front focal plane. The pattern
132 of the rays is given as a list of 2-lists of complex numbers. The
133 first complex number gives the relative position inside the central
134 cross section of the nucleus and the second number gives the relative
135 position in the bfp. The coordinates and size of the window in the
136 back focal plane are given relative to the radius of the bfp. The
137 return value is a list of 2-lists of rays, where the first ray starts
138 from the principal sphere and the second ray from the bfp."
139 (declare (fixnum nucleus
)
141 (double-float win-x
/r win-y
/r win-r
/r
)
142 (values cons
&optional
))
143 (assert (subtypep (type-of (first (first positions
))) '(complex double-float
)))
144 (assert (subtypep (type-of (second (first positions
))) '(complex double-float
)))
145 (with-slots (centers-mm radii-mm
) model
146 (let ((center (elt centers-mm nucleus
))
147 (radius (elt radii-mm nucleus
))
149 (with-slots ((bfp-radius lens
::bfp-radius
)
150 (ri lens
::immersion-index
)
151 (f lens
::focal-length
)) objective
152 (loop for
(f b
) in positions do
153 (let ((br (move-complex-circle b
1d0
154 win-x
/r win-y
/r win-r
/r
))
155 (fr (move-complex-circle f
1d0
(vec-x center
) (vec-y center
)
158 (multiple-value-bind (exit enter
)
159 (lens:get-ray-behind-objective
161 (realpart fr
) (imagpart fr
)
162 (realpart br
) (imagpart br
))
163 (push (list exit enter
) result
))
165 (nreverse result
)))))
169 (loop for
(exit enter
) in
(make-rays (lens:make-objective
:center
(v 0 0 1))
171 (sample-circles 2 2 1)
174 (vector::start enter
)))
176 (defun merit-function (vec2 params
)
177 "Vec2 contains the center of the window in th bfp. Params must be a
178 list containing objective model nucleus-index window-radius
179 positions (positions is a list of 2-lists of complex numbers)."
180 (declare ((simple-array double-float
(2)) vec2
)
182 (values double-float
&optional
))
183 (destructuring-bind (objective model nucleus-index
184 window-radius positions
)
186 (let* ((border-value 0d0
) ;; value to return when outside of bfp
187 ;; this has to be considerably bigger than the maxima on the bfp
188 (border-width window-radius
) ;; in this range to the
193 (radius (norm2 vec2
)))
194 (if (< radius
(- .99d0 border-width
))
196 (loop for
(exit enter
) in
(make-rays objective model nucleus-index
197 positions
(vec2-x vec2
)
198 (vec2-y vec2
) window-radius
) do
200 (raytrace:ray-spheres-intersection
201 exit model nucleus-index
)))
202 ;; in the border-width or outside of bfp
203 (incf sum border-value
))
206 #+nil
;; call merit function for one window center position
207 (let* ((obj (lens:make-objective
:center
(v) :normal
(v 0 0 1)))
209 (positions (sample-circles 3 12 12))
210 (z-plane-mm (vec-z (elt (raytrace::centers-mm
*model
*) 0))))
211 (with-slots ((c lens
::center
)
212 (ri lens
::immersion-index
)
213 (f lens
::focal-length
)) obj
214 (setf c
(make-vec 0d0
0d0
(+ (- (* ri f
)) z-plane-mm
)))
215 (let* ((params (list obj
220 (merit-function (make-vec2 :x -
.2d0
:y
0d0
)
223 #+nil
;; store the scan for each nucleus in the bfp
226 (nn (length (centers *model
*)))
227 (mosaicx (ceiling (sqrt nn
)))
228 (mosaic (make-array (list (* n mosaicx
) (* n mosaicx
))
229 :element-type
'double-float
))
230 (obj (lens:make-objective
:center
(v) :normal
(v 0 0 1)))
231 (window-radius .01d0
)
232 (positions (sample-circles 3 7 8)))
234 (with-slots ((c lens
::center
)
235 (ri lens
::immersion-index
)
236 (f lens
::focal-length
)) obj
237 (let* ((z-plane-mm (vec-z (elt (raytrace::centers-mm
*model
*) nuc
))))
238 (setf c
(make-vec 0d0
0d0
(+ (- (* ri f
)) z-plane-mm
)))
239 (let* ((params (list obj
*model
* nuc window-radius positions
))
240 (px (* n
(mod nuc mosaicx
)))
241 (py (* n
(floor nuc mosaicx
))))
242 (do-region ((j i
) (n n
))
243 (let ((x (- (* 2d0
(/ i n
)) 1d0
))
244 (y (- (* 2d0
(/ j n
)) 1d0
)))
245 (setf (aref mosaic
(+ py j
) (+ px i
))
246 (merit-function (make-vec2 :x x
:y y
)
248 (write-pgm "/home/martin/tmp/scan-mosaic.pgm" (normalize-2-df/ub8 mosaic
))))
252 (defun find-optimal-bfp-window-center (nucleus params
)
253 (declare (fixnum nucleus
)
255 (values vec2
&optional
))
256 (setf (elt params
2) nucleus
)
258 (multiple-value-bind (min point
)
259 (simplex-anneal:anneal
(simplex-anneal:make-simplex
260 (make-vec2 :x -
1d0
:y -
1d0
) 1d0
)
262 ;; set temperature bigger than the
263 ;; maxima in the bfp but smaller
265 :start-temperature
2.4d0
271 (return-from find-optimal-bfp-window-center point
)))))
274 (find-optimal-bfp-window-center 0)