the mosaic scan seems to work now. however 30x30
[woropt.git] / frontend / merit.lisp
blob3a740a51c8af5d8f374647055efe1b8e4967a39c
1 (in-package :frontend)
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
6 ;; integral
7 ;;
8 ;; ---------
9 ;; ---/ \--- xy-cross section through a
10 ;; / \ nucleus in the sample plane
11 ;; -/ \-
12 ;; / \ choose s points along a line
13 ;; | | .
14 ;; / \ .
15 ;; 0 1 2 ...
16 ;; \ /
17 ;; | |
18 ;; \ /
19 ;; -\ /-
20 ;; \ /
21 ;; ---\ /-- -----------
22 ;; --------- ---/ \---
23 ;; -/ \-
24 ;; -/ back focal \-
25 ;; / plane \
26 ;; / \
27 ;; | |
28 ;; choose / \
29 ;; b points .... a b c d e f
30 ;; along a lin \ /
31 ;; with the same | |
32 ;; inclination theta \ /
33 ;; \ /
34 ;; -\ /-
35 ;; -\ /-
36 ;; ---\ /---
37 ;; -----------
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
47 ;; in the nucleus.
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
55 theta."
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))))
61 (result nil))
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))))
66 (nreverse result)))
68 #+nil
69 (sample-line 2 2)
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))
78 (result nil))
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)
83 (* rotator b))
84 result))))
85 (when (and (oddp nr-ffp) (oddp nr-bfp)) ;; central ray was omitted above
86 (push (list (complex 0d0) (complex 0d0)) result))
87 (nreverse result)))
89 #+nil
90 (sample-circles 2 2 1)
92 ;; ------+------
93 ;; ---/ | \---
94 ;; --/ |---+--- \--
95 ;; -/ -| | \- \-
96 ;; / / | z | \ \
97 ;; -/ / | | r \ \-
98 ;; / |y +---+------+ \
99 ;; / \ | | / \
100 ;; | \ | | / |
101 ;; / -| | /- \
102 ;; | |---+--- |
103 ;; -+--------------------+---+----------------+--
104 ;; | | x rr |
105 ;; \ | /
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)
114 (double-float rr)
115 (values (complex double-float) &optional))
116 (+ (complex (* x/rr rr) (* y/rr rr))
117 (* r/rr rr z)))
119 #+nil
120 (move-complex-circle (complex 1d0 0d0) 2d0 .9d0 0d0 .1d0)
122 #+nil
123 (move-complex-circle (complex 1d0 0d0) 1d0 .9d0 0d0 .1d0)
125 #+nil
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)
140 (cons positions)
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))
148 (result nil))
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)
156 radius)))
157 (handler-case
158 (multiple-value-bind (exit enter)
159 (lens:get-ray-behind-objective
160 objective
161 (realpart fr) (imagpart fr)
162 (realpart br) (imagpart br))
163 (push (list exit enter) result))
164 (ray-lost () nil))))
165 (nreverse result)))))
167 #+nil
168 (defparameter *look*
169 (loop for (exit enter) in (make-rays (lens:make-objective :center (v 0 0 1))
170 *model* 0
171 (sample-circles 2 2 1)
172 .0d0 0d0 .1d0)
173 collect
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)
181 (cons params)
182 (values double-float &optional))
183 (destructuring-bind (objective model nucleus-index
184 window-radius positions)
185 params
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
189 ;; border of the bfp
190 ;; enforce bad merit
191 ;; function
192 (sum 0d0)
193 (radius (norm2 vec2)))
194 (if (< radius (- .99d0 border-width))
195 ;; inside
196 (loop for (exit enter) in (make-rays objective model nucleus-index
197 positions (vec2-x vec2)
198 (vec2-y vec2) window-radius) do
199 (incf sum
200 (raytrace:ray-spheres-intersection
201 exit model nucleus-index)))
202 ;; in the border-width or outside of bfp
203 (incf sum border-value))
204 sum)))
206 #+nil ;; call merit function for one window center position
207 (let* ((obj (lens:make-objective :center (v) :normal (v 0 0 1)))
208 (window-radius .2d0)
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
216 *model*
218 window-radius
219 positions)))
220 (merit-function (make-vec2 :x -.2d0 :y 0d0)
221 params))))
223 #+nil ;; store the scan for each nucleus in the bfp
224 (time
225 (let* ((n 30)
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)))
233 (dotimes (nuc 1 nn)
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)
247 params))))))))
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)
254 (cons params)
255 (values vec2 &optional))
256 (setf (elt params 2) nucleus)
257 (loop
258 (multiple-value-bind (min point)
259 (simplex-anneal:anneal (simplex-anneal:make-simplex
260 (make-vec2 :x -1d0 :y -1d0) 1d0)
261 #'merit-function
262 ;; set temperature bigger than the
263 ;; maxima in the bfp but smaller
264 ;; than border-value
265 :start-temperature 2.4d0
266 :eps/m .02d0
267 :itmax 1000
268 :ftol 1d-3
269 :params params)
270 (when (< min 100d0)
271 (return-from find-optimal-bfp-window-center point)))))
273 #+nil
274 (find-optimal-bfp-window-center 0)