microeye 2.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. microEye/__init__.py +47 -0
  2. microEye/_version.py +2 -0
  3. microEye/analysis/__init__.py +1 -0
  4. microEye/analysis/checklist_dialog.py +143 -0
  5. microEye/analysis/cmosMaps.py +228 -0
  6. microEye/analysis/filters/__init__.py +9 -0
  7. microEye/analysis/filters/base.py +21 -0
  8. microEye/analysis/filters/spatial.py +338 -0
  9. microEye/analysis/filters/temporal.py +76 -0
  10. microEye/analysis/fitting/__init__.py +0 -0
  11. microEye/analysis/fitting/fit.py +680 -0
  12. microEye/analysis/fitting/nena.py +375 -0
  13. microEye/analysis/fitting/phasor_fit.py +90 -0
  14. microEye/analysis/fitting/processing.py +317 -0
  15. microEye/analysis/fitting/psf/__init__.py +6 -0
  16. microEye/analysis/fitting/psf/extract.py +1129 -0
  17. microEye/analysis/fitting/psf/rubost_mean.py +150 -0
  18. microEye/analysis/fitting/psf/spline.py +167 -0
  19. microEye/analysis/fitting/psf/stats/__init__.py +12 -0
  20. microEye/analysis/fitting/psf/stats/core.py +295 -0
  21. microEye/analysis/fitting/psf/stats/curve_fit.py +708 -0
  22. microEye/analysis/fitting/psf/stats/io.py +104 -0
  23. microEye/analysis/fitting/psf/stats/slope_fit.py +171 -0
  24. microEye/analysis/fitting/psf/temp.py +147 -0
  25. microEye/analysis/fitting/psf/test.py +47 -0
  26. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUfunctions.py +657 -0
  27. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUmleFit_LM.py +1336 -0
  28. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUsplineLib.py +270 -0
  29. microEye/analysis/fitting/pyfit3Dcspline/CPU/__init__.py +1 -0
  30. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUfunctions.py +609 -0
  31. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_EMCCD.py +1396 -0
  32. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_sCMOS.py +1426 -0
  33. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUsplineLib.py +231 -0
  34. microEye/analysis/fitting/pyfit3Dcspline/GPU/__init__.py +2 -0
  35. microEye/analysis/fitting/pyfit3Dcspline/__init__.py +10 -0
  36. microEye/analysis/fitting/pyfit3Dcspline/constants.py +27 -0
  37. microEye/analysis/fitting/pyfit3Dcspline/mainfunctions.py +903 -0
  38. microEye/analysis/fitting/results.py +917 -0
  39. microEye/analysis/fitting/results_stats.py +251 -0
  40. microEye/analysis/fitting/tardis.py +209 -0
  41. microEye/analysis/multi_viewer.py +568 -0
  42. microEye/analysis/processing/__init__.py +1 -0
  43. microEye/analysis/processing/frc.py +120 -0
  44. microEye/analysis/rendering/__init__.py +3 -0
  45. microEye/analysis/rendering/base.py +452 -0
  46. microEye/analysis/rendering/cloud.py +215 -0
  47. microEye/analysis/rendering/core.py +47 -0
  48. microEye/analysis/rendering/volumetric.py +198 -0
  49. microEye/analysis/tools/__init__.py +0 -0
  50. microEye/analysis/tools/kymograms.py +1079 -0
  51. microEye/analysis/tools/roi_selectors.py +556 -0
  52. microEye/analysis/utils/__init__.py +3 -0
  53. microEye/analysis/utils/coordinates.py +18 -0
  54. microEye/analysis/utils/images.py +68 -0
  55. microEye/analysis/utils/windows.py +19 -0
  56. microEye/analysis/viewer/__init__.py +3 -0
  57. microEye/analysis/viewer/image_options_widget.py +615 -0
  58. microEye/analysis/viewer/images.py +1225 -0
  59. microEye/analysis/viewer/layers_widget.py +415 -0
  60. microEye/analysis/viewer/localizations.py +1304 -0
  61. microEye/analysis/viewer/psf.py +1003 -0
  62. microEye/analysis/viewer/volume.py +456 -0
  63. microEye/hardware/__init__.py +3 -0
  64. microEye/hardware/cams/__init__.py +29 -0
  65. microEye/hardware/cams/camera_calibration.py +99 -0
  66. microEye/hardware/cams/camera_list.py +528 -0
  67. microEye/hardware/cams/camera_options.py +694 -0
  68. microEye/hardware/cams/camera_panel.py +941 -0
  69. microEye/hardware/cams/dummy/__init__.py +1 -0
  70. microEye/hardware/cams/dummy/dummy_panel.py +759 -0
  71. microEye/hardware/cams/jobs.py +497 -0
  72. microEye/hardware/cams/line_profiler.py +99 -0
  73. microEye/hardware/cams/linescan/IR_Cam.py +474 -0
  74. microEye/hardware/cams/linescan/__init__.py +1 -0
  75. microEye/hardware/cams/micam.py +524 -0
  76. microEye/hardware/cams/pco/__init__.py +58 -0
  77. microEye/hardware/cams/pco/enums.py +382 -0
  78. microEye/hardware/cams/pco/pco_cam.py +761 -0
  79. microEye/hardware/cams/pco/pco_panel.py +477 -0
  80. microEye/hardware/cams/shortcuts.py +312 -0
  81. microEye/hardware/cams/thorlabs/__init__.py +1 -0
  82. microEye/hardware/cams/thorlabs/thorlabs.py +1508 -0
  83. microEye/hardware/cams/thorlabs/thorlabs_panel.py +850 -0
  84. microEye/hardware/cams/ueye/__init__.py +1 -0
  85. microEye/hardware/cams/ueye/ueye_camera.py +1023 -0
  86. microEye/hardware/cams/ueye/ueye_panel.py +861 -0
  87. microEye/hardware/cams/vimba/__init__.py +1 -0
  88. microEye/hardware/cams/vimba/vimba_cam.py +1000 -0
  89. microEye/hardware/cams/vimba/vimba_panel.py +813 -0
  90. microEye/hardware/device.py +60 -0
  91. microEye/hardware/lasers/__init__.py +13 -0
  92. microEye/hardware/lasers/io_matchbox.py +791 -0
  93. microEye/hardware/lasers/io_params.py +85 -0
  94. microEye/hardware/lasers/io_single_laser.py +742 -0
  95. microEye/hardware/lasers/laser_relay.py +594 -0
  96. microEye/hardware/mieye/__init__.py +1 -0
  97. microEye/hardware/mieye/acquisition_manager.py +467 -0
  98. microEye/hardware/mieye/devices_manager.py +533 -0
  99. microEye/hardware/mieye/miEye.py +659 -0
  100. microEye/hardware/misc/__init__.py +0 -0
  101. microEye/hardware/misc/acquisition_view.py +71 -0
  102. microEye/hardware/misc/reglo.py +761 -0
  103. microEye/hardware/misc/temp.py +188 -0
  104. microEye/hardware/port_config.py +59 -0
  105. microEye/hardware/protocols/__init__.py +2 -0
  106. microEye/hardware/protocols/actions.py +402 -0
  107. microEye/hardware/protocols/actions_items.py +703 -0
  108. microEye/hardware/protocols/designer.py +244 -0
  109. microEye/hardware/protocols/scene_manager.py +191 -0
  110. microEye/hardware/protocols/serialization.py +97 -0
  111. microEye/hardware/pycromanager/__init__.py +16 -0
  112. microEye/hardware/pycromanager/core.py +1433 -0
  113. microEye/hardware/pycromanager/devices.py +461 -0
  114. microEye/hardware/pycromanager/enums.py +107 -0
  115. microEye/hardware/pycromanager/headless.py +153 -0
  116. microEye/hardware/pycromanager/utils.py +34 -0
  117. microEye/hardware/pycromanager/widgets/__init__.py +5 -0
  118. microEye/hardware/pycromanager/widgets/bridges.py +407 -0
  119. microEye/hardware/pycromanager/widgets/headless_manager.py +258 -0
  120. microEye/hardware/pycromanager/widgets/headless_options.py +224 -0
  121. microEye/hardware/pycromanager/widgets/pycro_panel.py +455 -0
  122. microEye/hardware/stages/__init__.py +18 -0
  123. microEye/hardware/stages/elliptec/__init__.py +5 -0
  124. microEye/hardware/stages/elliptec/baseDevice.py +314 -0
  125. microEye/hardware/stages/elliptec/device.py +384 -0
  126. microEye/hardware/stages/elliptec/deviceID.py +212 -0
  127. microEye/hardware/stages/elliptec/devicePort.py +379 -0
  128. microEye/hardware/stages/elliptec/deviceStatus.py +65 -0
  129. microEye/hardware/stages/elliptec/devicesView.py +706 -0
  130. microEye/hardware/stages/elliptec/ellDevices.py +134 -0
  131. microEye/hardware/stages/elliptec/messageUpdater.py +34 -0
  132. microEye/hardware/stages/elliptec/motorInfo.py +153 -0
  133. microEye/hardware/stages/elliptec/stage.py +62 -0
  134. microEye/hardware/stages/elliptec/test.py +139 -0
  135. microEye/hardware/stages/kinesis/__init__.py +1 -0
  136. microEye/hardware/stages/kinesis/kdc101/__init__.py +1 -0
  137. microEye/hardware/stages/kinesis/kdc101/enums.py +1002 -0
  138. microEye/hardware/stages/kinesis/kdc101/factory.py +171 -0
  139. microEye/hardware/stages/kinesis/kdc101/kdc101.py +718 -0
  140. microEye/hardware/stages/kinesis/kinesis.py +776 -0
  141. microEye/hardware/stages/piezo_concept.py +607 -0
  142. microEye/hardware/stages/stabilizer.py +785 -0
  143. microEye/hardware/stages/stage.py +89 -0
  144. microEye/hardware/widgets/__init__.py +10 -0
  145. microEye/hardware/widgets/controller.py +246 -0
  146. microEye/hardware/widgets/devices.py +133 -0
  147. microEye/hardware/widgets/focusWidget.py +264 -0
  148. microEye/hardware/widgets/qlist_slider.py +113 -0
  149. microEye/hardware/widgets/scan_acquisition.py +424 -0
  150. microEye/icons/1024.png +0 -0
  151. microEye/icons/128.png +0 -0
  152. microEye/icons/16.png +0 -0
  153. microEye/icons/24.png +0 -0
  154. microEye/icons/256.png +0 -0
  155. microEye/icons/32.png +0 -0
  156. microEye/icons/48.png +0 -0
  157. microEye/icons/512.png +0 -0
  158. microEye/icons/64.png +0 -0
  159. microEye/icons/__init__.py +0 -0
  160. microEye/icons/close.svg +88 -0
  161. microEye/icons/mieye.png +0 -0
  162. microEye/icons/min.svg +83 -0
  163. microEye/icons/viewer.png +0 -0
  164. microEye/launcher.py +42 -0
  165. microEye/qt.py +181 -0
  166. microEye/utils/__init__.py +2 -0
  167. microEye/utils/enum_encoder.py +10 -0
  168. microEye/utils/expandable_groupbox.py +93 -0
  169. microEye/utils/gui_helper.py +457 -0
  170. microEye/utils/hid/__init__.py +8 -0
  171. microEye/utils/hid/controller.py +153 -0
  172. microEye/utils/hid/device.py +63 -0
  173. microEye/utils/hid/enums.py +140 -0
  174. microEye/utils/hid/utils.py +58 -0
  175. microEye/utils/labelled_slider.py +134 -0
  176. microEye/utils/metadata.py +599 -0
  177. microEye/utils/metadata_tree.py +718 -0
  178. microEye/utils/micro_launcher.py +245 -0
  179. microEye/utils/parameter_tree.py +325 -0
  180. microEye/utils/pyscripting.py +444 -0
  181. microEye/utils/retry_exec.py +35 -0
  182. microEye/utils/start_gui.py +112 -0
  183. microEye/utils/thread_worker.py +115 -0
  184. microEye/utils/uImage.py +1512 -0
  185. microeye-2.3.2.dist-info/METADATA +401 -0
  186. microeye-2.3.2.dist-info/RECORD +190 -0
  187. microeye-2.3.2.dist-info/WHEEL +5 -0
  188. microeye-2.3.2.dist-info/entry_points.txt +2 -0
  189. microeye-2.3.2.dist-info/licenses/LICENSE +674 -0
  190. microeye-2.3.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1336 @@
1
+ import numba as nb
2
+ import numpy as np
3
+
4
+ from microEye.analysis.fitting.pyfit3Dcspline.CPU.CPUfunctions import *
5
+ from microEye.analysis.fitting.pyfit3Dcspline.CPU.CPUsplineLib import *
6
+
7
+
8
+ @nb.njit(cache=True)
9
+ def kernel_MLEFit_LM(d_data, PSFSigma, sz, iterations, d_varim=None):
10
+ '''
11
+ brief basic MLE fitting kernel. No additional parameters are computed.
12
+
13
+ Parameters
14
+ ----------
15
+ d_data : ndarray
16
+ d_data array of subregions to fit copied to GPU
17
+ PSFSigma : float
18
+ PSFSigma sigma of the point spread function
19
+ sz : int
20
+ sz nxn size of the subregion to fit
21
+ iterations : int
22
+ iterations number of iterations for solution to converge
23
+ d_varim : ndarray
24
+ variance map of CMOS if None then EMCCD
25
+ '''
26
+ NV = NV_P
27
+ M = np.zeros(NV**2, np.float32)
28
+ Diag = np.zeros(NV, np.float32)
29
+ Minv = np.zeros(NV**2, np.float32)
30
+
31
+ model = 0
32
+ data = 0
33
+ d_LogLikelihood = Div = 0
34
+
35
+ d_Parameters = np.zeros(NV + 1, np.float32)
36
+ d_CRLBs = np.zeros(NV, np.float32)
37
+
38
+ newTheta = np.zeros(NV, np.float32)
39
+ oldTheta = np.zeros(NV, np.float32)
40
+ newLambda = INIT_LAMBDA
41
+ oldLambda = INIT_LAMBDA
42
+ mu = 0
43
+
44
+ newUpdate = np.zeros(NV, np.float32)
45
+ oldUpdate = np.zeros(NV, np.float32)
46
+ newUpdate[:] = 1e13
47
+ oldUpdate[:] = 1e13
48
+
49
+ newDudt = np.zeros(NV, np.float32)
50
+ maxJump = np.array([1.0, 1.0, 100.0, 20.0], np.float32)
51
+
52
+ newErr = 1e12
53
+ oldErr = 1e13
54
+
55
+ jacobian = np.zeros(NV, np.float32)
56
+ hessian = np.zeros(NV**2, np.float32)
57
+ t1 = 0
58
+ t2 = 0
59
+
60
+ Nmax = 0
61
+ errFlag = 0
62
+ L = np.zeros(NV**2, np.float32)
63
+ U = np.zeros(NV**2, np.float32)
64
+
65
+ # Requires Checking
66
+ s_data = d_data
67
+ s_varim = d_varim
68
+
69
+ # initial values
70
+ newTheta[0], newTheta[1] = kernel_CenterofMass2D(sz, s_data)
71
+ Nmax, newTheta[3] = kernel_GaussFMaxMin2D(sz, PSFSigma, s_data)
72
+ newTheta[2] = max(0.0, (Nmax - newTheta[3]) * 2 * pi * PSFSigma * PSFSigma)
73
+ newTheta[3] = max(newTheta[3], 0.01)
74
+
75
+ maxJump[2] = max(newTheta[2], maxJump[2])
76
+
77
+ maxJump[3] = max(newTheta[3], maxJump[3])
78
+
79
+ for ii in range(NV):
80
+ oldTheta[ii] = newTheta[ii]
81
+
82
+ # updateFitValues
83
+ newErr = 0
84
+ for ii in range(sz):
85
+ for jj in range(sz):
86
+ newDudt, model = kernel_DerivativeGauss2D(
87
+ ii, jj, PSFSigma, newTheta, newDudt
88
+ )
89
+ if s_varim is not None:
90
+ model += s_varim[sz * jj + ii]
91
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
92
+ else:
93
+ data = s_data[sz * jj + ii]
94
+
95
+ if data > 0:
96
+ newErr = newErr + 2 * ((model - data) - data * math.log(model / data))
97
+ else:
98
+ newErr = newErr + 2 * model
99
+ data = 0
100
+
101
+ t1 = 1 - data / model
102
+ for ll in range(NV):
103
+ jacobian[ll] += t1 * newDudt[ll]
104
+
105
+ t2 = data / math.pow(model, 2)
106
+ for ll in range(NV):
107
+ for mm in range(ll, NV, 1):
108
+ hessian[ll * NV + mm] += t2 * newDudt[ll] * newDudt[mm]
109
+ hessian[mm * NV + ll] = hessian[ll * NV + mm]
110
+
111
+ for kk in range(iterations): # main iterative loop # noqa: B007
112
+ if abs((newErr - oldErr) / newErr) < TOLERANCE:
113
+ break # CONVERGED
114
+ else:
115
+ if newErr > ACCEPTANCE * oldErr:
116
+ # copy Fitdata
117
+
118
+ for i in range(NV):
119
+ newTheta[i] = oldTheta[i]
120
+ newUpdate[i] = oldUpdate[i]
121
+ newLambda = oldLambda
122
+ newErr = oldErr
123
+ mu = max((1 + newLambda * SCALE_UP) / (1 + newLambda), 1.3)
124
+ newLambda = SCALE_UP * newLambda
125
+ elif newErr < oldErr and errFlag == 0:
126
+ newLambda = SCALE_DOWN * newLambda
127
+ mu = 1 + newLambda
128
+
129
+ for i in range(NV):
130
+ hessian[i * NV + i] = hessian[i * NV + i] * mu
131
+
132
+ L[:] = 0
133
+ U[:] = 0
134
+
135
+ errFlag = kernel_cholesky(hessian, NV, L, U)
136
+ if errFlag == 0:
137
+ for i in range(NV):
138
+ oldTheta[i] = newTheta[i]
139
+ oldUpdate[i] = newUpdate[i]
140
+ oldLambda = newLambda
141
+ oldErr = newErr
142
+
143
+ newUpdate = kernel_luEvaluate(L, U, jacobian, NV, newUpdate)
144
+
145
+ # updateFitParameters
146
+ for ll in range(NV):
147
+ if newUpdate[ll] / oldUpdate[ll] < -0.5:
148
+ maxJump[ll] = maxJump[ll] * 0.5
149
+
150
+ newUpdate[ll] = newUpdate[ll] / (
151
+ 1 + math.fabs(newUpdate[ll] / maxJump[ll])
152
+ )
153
+ newTheta[ll] = newTheta[ll] - newUpdate[ll]
154
+
155
+ # restrict range
156
+ newTheta[0] = max(newTheta[0], (float(sz) - 1) / 2 - sz / 4.0)
157
+ newTheta[0] = min(newTheta[0], (float(sz) - 1) / 2 + sz / 4.0)
158
+ newTheta[1] = max(newTheta[1], (float(sz) - 1) / 2 - sz / 4.0)
159
+ newTheta[1] = min(newTheta[1], (float(sz) - 1) / 2 + sz / 4.0)
160
+ newTheta[2] = max(newTheta[2], 1.0)
161
+ newTheta[3] = max(newTheta[3], 0.01)
162
+
163
+ newErr = 0
164
+ jacobian[:] = 0
165
+ hessian[:] = 0
166
+ for ii in range(sz):
167
+ for jj in range(sz):
168
+ # calculating derivatives
169
+ newDudt, model = kernel_DerivativeGauss2D(
170
+ ii, jj, PSFSigma, newTheta, newDudt
171
+ )
172
+ if s_varim is not None:
173
+ model += s_varim[sz * jj + ii]
174
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
175
+ else:
176
+ data = s_data[sz * jj + ii]
177
+
178
+ if data > 0:
179
+ newErr = newErr + 2 * (
180
+ (model - data) - data * math.log(model / data)
181
+ )
182
+ else:
183
+ newErr = newErr + 2 * model
184
+ data = 0
185
+
186
+ t1 = 1 - data / model
187
+ for ll in range(NV):
188
+ jacobian[ll] += t1 * newDudt[ll]
189
+
190
+ t2 = data / math.pow(model, 2)
191
+ for ll in range(NV):
192
+ for mm in range(ll, NV, 1):
193
+ hessian[ll * NV + mm] += t2 * newDudt[ll] * newDudt[mm]
194
+ hessian[mm * NV + ll] = hessian[ll * NV + mm]
195
+ else:
196
+ mu = max((1 + newLambda * SCALE_UP) / (1 + newLambda), 1.3)
197
+ newLambda = SCALE_UP * newLambda
198
+
199
+ # output iteration
200
+
201
+ d_Parameters[NV] = kk
202
+ # Calculating the CRLB and LogLikelihood
203
+ Div = 0.0
204
+ for ii in range(sz):
205
+ for jj in range(sz):
206
+ newDudt, model = kernel_DerivativeGauss2D(
207
+ ii, jj, PSFSigma, newTheta, newDudt
208
+ )
209
+ if s_varim is not None:
210
+ model += s_varim[sz * jj + ii]
211
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
212
+ else:
213
+ data = s_data[sz * jj + ii]
214
+
215
+ # Building the Fisher Information Matrix
216
+ for kk in range(NV):
217
+ for ll in range(kk, NV, 1):
218
+ M[kk * NV + ll] += newDudt[ll] * newDudt[kk] / model
219
+ M[ll * NV + kk] = M[kk * NV + ll]
220
+
221
+ # LogLikelyhood
222
+ if model > 0:
223
+ if data > 0:
224
+ Div += data * math.log(model) - model - data * math.log(data) + data
225
+ else:
226
+ Div += -model
227
+
228
+ # Matrix inverse (CRLB=F^-1) and output assigments
229
+ kernel_MatInvN(M, Minv, Diag, NV)
230
+ # Write to global arrays
231
+ for kk in range(NV):
232
+ d_Parameters[kk] = newTheta[kk]
233
+ d_CRLBs[kk] = Diag[kk]
234
+ d_LogLikelihood = Div
235
+
236
+ return d_Parameters, d_CRLBs, d_LogLikelihood
237
+
238
+
239
+ @nb.njit(cache=True)
240
+ def kernel_MLEFit_LM_Sigma(d_data, PSFSigma, sz, iterations, d_varim=None):
241
+ '''
242
+ basic MLE fitting kernel. No additional parameters are computed.
243
+
244
+ Parameters
245
+ ----------
246
+ d_data : float[]
247
+ d_data array of subregions to fit copied to GPU
248
+ PSFSigma : float
249
+ PSFSigma sigma of the point spread function
250
+ sz : int
251
+ sz nxn size of the subregion to fit
252
+ iterations : int
253
+ iterations number of iterations for solution to converge
254
+ d_varim : float[]
255
+ variance map of CMOS if None then EMCCD
256
+ '''
257
+ NV = NV_PS
258
+
259
+ M = np.zeros(NV**2, np.float32)
260
+ Diag = np.zeros(NV, np.float32)
261
+ Minv = np.zeros(NV**2, np.float32)
262
+
263
+ model = 0
264
+ data = 0
265
+ d_LogLikelihood = Div = 0
266
+
267
+ d_Parameters = np.zeros(NV + 1, np.float32)
268
+ d_CRLBs = np.zeros(NV, np.float32)
269
+
270
+ newTheta = np.zeros(NV, np.float32)
271
+ oldTheta = np.zeros(NV, np.float32)
272
+ newLambda = INIT_LAMBDA
273
+ oldLambda = INIT_LAMBDA
274
+ mu = 0
275
+
276
+ newUpdate = np.zeros(NV, np.float32)
277
+ oldUpdate = np.zeros(NV, np.float32)
278
+ newUpdate[:] = 1e13
279
+ oldUpdate[:] = 1e13
280
+ newDudt = np.zeros(NV, np.float32)
281
+ maxJump = np.array([1.0, 1.0, 100.0, 20.0, 0.5], np.float32)
282
+
283
+ newErr = 1e12
284
+ oldErr = 1e13
285
+
286
+ jacobian = np.zeros(NV, np.float32)
287
+ hessian = np.zeros(NV**2, np.float32)
288
+ t1 = 0
289
+ t2 = 0
290
+
291
+ Nmax = 0
292
+ errFlag = 0
293
+ L = np.zeros(NV**2, np.float32)
294
+ U = np.zeros(NV**2, np.float32)
295
+
296
+ # Requires Checking
297
+ s_data = d_data
298
+ s_varim = d_varim
299
+
300
+ # initial values
301
+ newTheta[0], newTheta[1] = kernel_CenterofMass2D(sz, s_data)
302
+ Nmax, newTheta[3] = kernel_GaussFMaxMin2D(sz, PSFSigma, s_data)
303
+ newTheta[2] = max(0.0, (Nmax - newTheta[3]) * 2 * pi * PSFSigma * PSFSigma)
304
+ newTheta[3] = max(newTheta[3], 0.01)
305
+ newTheta[4] = PSFSigma
306
+
307
+ maxJump[2] = max(newTheta[2], maxJump[2])
308
+
309
+ maxJump[3] = max(newTheta[3], maxJump[3])
310
+
311
+ for ii in range(NV):
312
+ oldTheta[ii] = newTheta[ii]
313
+
314
+ # updateFitValues
315
+ newErr = 0
316
+ for ii in range(sz):
317
+ for jj in range(sz):
318
+ newDudt, model = kernel_DerivativeGauss2D_sigma(ii, jj, newTheta, newDudt)
319
+ if s_varim is not None:
320
+ model += s_varim[sz * jj + ii]
321
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
322
+ else:
323
+ data = s_data[sz * jj + ii]
324
+
325
+ if data > 0:
326
+ newErr = newErr + 2 * ((model - data) - data * math.log(model / data))
327
+ else:
328
+ newErr = newErr + 2 * model
329
+ data = 0
330
+
331
+ t1 = 1 - data / model
332
+ for ll in range(NV):
333
+ jacobian[ll] += t1 * newDudt[ll]
334
+
335
+ t2 = data / math.pow(model, 2)
336
+ for ll in range(NV):
337
+ for mm in range(ll, NV, 1):
338
+ hessian[ll * NV + mm] += t2 * newDudt[ll] * newDudt[mm]
339
+ hessian[mm * NV + ll] = hessian[ll * NV + mm]
340
+
341
+ for kk in range(iterations): # main iterative loop # noqa: B007
342
+ if abs((newErr - oldErr) / newErr) < TOLERANCE:
343
+ break # CONVERGED
344
+ else:
345
+ if newErr > ACCEPTANCE * oldErr:
346
+ # copy Fitdata
347
+
348
+ for i in range(NV):
349
+ newTheta[i] = oldTheta[i]
350
+ newUpdate[i] = oldUpdate[i]
351
+ newLambda = oldLambda
352
+ newErr = oldErr
353
+ mu = max((1 + newLambda * SCALE_UP) / (1 + newLambda), 1.3)
354
+ newLambda = SCALE_UP * newLambda
355
+ elif newErr < oldErr and errFlag == 0:
356
+ newLambda = SCALE_DOWN * newLambda
357
+ mu = 1 + newLambda
358
+
359
+ for i in range(NV):
360
+ hessian[i * NV + i] = hessian[i * NV + i] * mu
361
+
362
+ L[:] = 0
363
+ U[:] = 0
364
+
365
+ errFlag = kernel_cholesky(hessian, NV, L, U)
366
+ if errFlag == 0:
367
+ for i in range(NV):
368
+ oldTheta[i] = newTheta[i]
369
+ oldUpdate[i] = newUpdate[i]
370
+ oldLambda = newLambda
371
+ oldErr = newErr
372
+
373
+ newUpdate = kernel_luEvaluate(L, U, jacobian, NV, newUpdate)
374
+
375
+ # updateFitParameters
376
+ for ll in range(NV):
377
+ if newUpdate[ll] / oldUpdate[ll] < -0.5:
378
+ maxJump[ll] = maxJump[ll] * 0.5
379
+
380
+ newUpdate[ll] = newUpdate[ll] / (
381
+ 1 + math.fabs(newUpdate[ll] / maxJump[ll])
382
+ )
383
+ newTheta[ll] = newTheta[ll] - newUpdate[ll]
384
+ # restrict range
385
+ newTheta[0] = max(newTheta[0], (float(sz) - 1) / 2 - sz / 4.0)
386
+ newTheta[0] = min(newTheta[0], (float(sz) - 1) / 2 + sz / 4.0)
387
+ newTheta[1] = max(newTheta[1], (float(sz) - 1) / 2 - sz / 4.0)
388
+ newTheta[1] = min(newTheta[1], (float(sz) - 1) / 2 + sz / 4.0)
389
+ newTheta[2] = max(newTheta[2], 1.0)
390
+ newTheta[3] = max(newTheta[3], 0.01)
391
+ newTheta[4] = max(newTheta[4], 0.0)
392
+ newTheta[4] = min(newTheta[4], sz / 2.0)
393
+
394
+ newErr = 0
395
+ jacobian[:] = 0
396
+ hessian[:] = 0
397
+ for ii in range(sz):
398
+ for jj in range(sz):
399
+ # calculating derivatives
400
+ newDudt, model = kernel_DerivativeGauss2D_sigma(
401
+ ii, jj, newTheta, newDudt
402
+ )
403
+ if s_varim is not None:
404
+ model += s_varim[sz * jj + ii]
405
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
406
+ else:
407
+ data = s_data[sz * jj + ii]
408
+
409
+ if data > 0:
410
+ newErr = newErr + 2 * (
411
+ (model - data) - data * math.log(model / data)
412
+ )
413
+ else:
414
+ newErr = newErr + 2 * model
415
+ data = 0
416
+
417
+ t1 = 1 - data / model
418
+ for ll in range(NV):
419
+ jacobian[ll] += t1 * newDudt[ll]
420
+
421
+ t2 = data / math.pow(model, 2)
422
+ for ll in range(NV):
423
+ for mm in range(ll, NV, 1):
424
+ hessian[ll * NV + mm] += t2 * newDudt[ll] * newDudt[mm]
425
+ hessian[mm * NV + ll] = hessian[ll * NV + mm]
426
+ else:
427
+ mu = max((1 + newLambda * SCALE_UP) / (1 + newLambda), 1.3)
428
+ newLambda = SCALE_UP * newLambda
429
+
430
+ # output iteration
431
+
432
+ d_Parameters[NV] = kk
433
+
434
+ # Calculating the CRLB and LogLikelihood
435
+ Div = 0.0
436
+ for ii in range(sz):
437
+ for jj in range(sz):
438
+ newDudt, model = kernel_DerivativeGauss2D_sigma(ii, jj, newTheta, newDudt)
439
+ if s_varim is not None:
440
+ model += s_varim[sz * jj + ii]
441
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
442
+ else:
443
+ data = s_data[sz * jj + ii]
444
+
445
+ # Building the Fisher Information Matrix
446
+ for kk in range(NV):
447
+ for ll in range(kk, NV, 1):
448
+ M[kk * NV + ll] += newDudt[ll] * newDudt[kk] / model
449
+ M[ll * NV + kk] = M[kk * NV + ll]
450
+
451
+ # LogLikelyhood
452
+ if model > 0:
453
+ if data > 0:
454
+ Div += data * math.log(model) - model - data * math.log(data) + data
455
+ else:
456
+ Div += -model
457
+
458
+ # Matrix inverse (CRLB=F^-1) and output assigments
459
+ kernel_MatInvN(M, Minv, Diag, NV)
460
+ # Write to global arrays
461
+ for kk in range(NV):
462
+ d_Parameters[kk] = newTheta[kk]
463
+ d_CRLBs[kk] = Diag[kk]
464
+ d_LogLikelihood = Div
465
+
466
+ return d_Parameters, d_CRLBs, d_LogLikelihood
467
+
468
+
469
+ @nb.njit(cache=True)
470
+ def kernel_MLEFit_LM_z(
471
+ d_data,
472
+ PSFSigma_x,
473
+ Ax,
474
+ Ay,
475
+ Bx,
476
+ By,
477
+ gamma,
478
+ d,
479
+ PSFSigma_y,
480
+ sz,
481
+ iterations,
482
+ d_varim=None,
483
+ ):
484
+ '''
485
+ basic MLE fitting kernel. No additional parameters are computed.
486
+
487
+ Parameters
488
+ ----------
489
+ d_data : float[]
490
+ array of subregions to fit copied to GPU
491
+ PSFSigma_x : float
492
+ sigma of the point spread function on the x axis
493
+ Ax : float
494
+ ???
495
+ Ay : float
496
+ ???
497
+ Bx : float
498
+ ???
499
+ By : float
500
+ ???
501
+ gamma : float
502
+ ???
503
+ d : float
504
+ ???
505
+ PSFSigma_y : float
506
+ sigma of the point spread function on the y axis
507
+ sz : int
508
+ nxn size of the subregion to fit
509
+ iterations : int
510
+ number of iterations for solution to converge
511
+ d_varim : float[]
512
+ variance map of CMOS if None then EMCCD
513
+ '''
514
+ NV = NV_PS
515
+
516
+ M = np.zeros(NV**2, np.float32)
517
+ Diag = np.zeros(NV, np.float32)
518
+ Minv = np.zeros(NV**2, np.float32)
519
+
520
+ model = 0
521
+ data = 0
522
+ d_LogLikelihood = Div = 0
523
+
524
+ d_Parameters = np.zeros(NV + 1, np.float32)
525
+ d_CRLBs = np.zeros(NV, np.float32)
526
+
527
+ # PSFy = PSFx = 0
528
+
529
+ newTheta = np.zeros(NV, np.float32)
530
+ oldTheta = np.zeros(NV, np.float32)
531
+ newLambda = INIT_LAMBDA
532
+ oldLambda = INIT_LAMBDA
533
+ mu = 0
534
+
535
+ newUpdate = np.zeros(NV, np.float32)
536
+ oldUpdate = np.zeros(NV, np.float32)
537
+ newUpdate[:] = 1e13
538
+ oldUpdate[:] = 1e13
539
+ newDudt = np.zeros(NV, np.float32)
540
+ maxJump = np.array([1.0, 1.0, 100.0, 20.0, 2], np.float32)
541
+
542
+ newErr = 1e12
543
+ oldErr = 1e13
544
+
545
+ jacobian = np.zeros(NV, np.float32)
546
+ hessian = np.zeros(NV**2, np.float32)
547
+ t1 = 0
548
+ t2 = 0
549
+
550
+ Nmax = 0
551
+ errFlag = 0
552
+ L = np.zeros(NV**2, np.float32)
553
+ U = np.zeros(NV**2, np.float32)
554
+
555
+ # Requires Checking
556
+ s_data = d_data
557
+ s_varim = d_varim
558
+
559
+ # initial values
560
+ newTheta[0], newTheta[1] = kernel_CenterofMass2D(sz, s_data)
561
+ Nmax, newTheta[3] = kernel_GaussFMaxMin2D(sz, PSFSigma_x, s_data)
562
+ newTheta[2] = max(
563
+ 0.0, (Nmax - newTheta[3]) * 2 * pi * PSFSigma_x * PSFSigma_y * math.sqrt(2.0)
564
+ )
565
+ newTheta[3] = max(newTheta[3], 0.01)
566
+ newTheta[4] = 0
567
+
568
+ maxJump[2] = max(newTheta[2], maxJump[2])
569
+
570
+ maxJump[3] = max(newTheta[3], maxJump[3])
571
+
572
+ for ii in range(NV):
573
+ oldTheta[ii] = newTheta[ii]
574
+
575
+ # updateFitValues
576
+ newErr = 0
577
+ for ii in range(sz):
578
+ for jj in range(sz):
579
+ PSFx, PSFy, newDudt, _, model = kernel_DerivativeIntGauss2Dz(
580
+ ii,
581
+ jj,
582
+ newTheta,
583
+ PSFSigma_x,
584
+ PSFSigma_y,
585
+ Ax,
586
+ Ay,
587
+ Bx,
588
+ By,
589
+ gamma,
590
+ d,
591
+ newDudt,
592
+ None,
593
+ False,
594
+ )
595
+ if s_varim is not None:
596
+ model += s_varim[sz * jj + ii]
597
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
598
+ else:
599
+ data = s_data[sz * jj + ii]
600
+
601
+ if data > 0:
602
+ newErr = newErr + 2 * ((model - data) - data * math.log(model / data))
603
+ else:
604
+ newErr = newErr + 2 * model
605
+ data = 0
606
+
607
+ t1 = 1 - data / model
608
+ for ll in range(NV):
609
+ jacobian[ll] += t1 * newDudt[ll]
610
+
611
+ t2 = data / math.pow(model, 2)
612
+ for ll in range(NV):
613
+ for mm in range(ll, NV, 1):
614
+ hessian[ll * NV + mm] += t2 * newDudt[ll] * newDudt[mm]
615
+ hessian[mm * NV + ll] = hessian[ll * NV + mm]
616
+
617
+ for kk in range(iterations): # main iterative loop # noqa: B007
618
+ if abs((newErr - oldErr) / newErr) < TOLERANCE:
619
+ break # CONVERGED
620
+ else:
621
+ if newErr > ACCEPTANCE * oldErr:
622
+ # copy Fitdata
623
+
624
+ for i in range(NV):
625
+ newTheta[i] = oldTheta[i]
626
+ newUpdate[i] = oldUpdate[i]
627
+ newLambda = oldLambda
628
+ newErr = oldErr
629
+ mu = max((1 + newLambda * SCALE_UP) / (1 + newLambda), 1.3)
630
+ newLambda = SCALE_UP * newLambda
631
+ elif newErr < oldErr and errFlag == 0:
632
+ newLambda = SCALE_DOWN * newLambda
633
+ mu = 1 + newLambda
634
+
635
+ for i in range(NV):
636
+ hessian[i * NV + i] = hessian[i * NV + i] * mu
637
+
638
+ L[:] = 0
639
+ U[:] = 0
640
+
641
+ errFlag = kernel_cholesky(hessian, NV, L, U)
642
+ if errFlag == 0:
643
+ for i in range(NV):
644
+ oldTheta[i] = newTheta[i]
645
+ oldUpdate[i] = newUpdate[i]
646
+ oldLambda = newLambda
647
+ oldErr = newErr
648
+
649
+ newUpdate = kernel_luEvaluate(L, U, jacobian, NV, newUpdate)
650
+
651
+ # updateFitParameters
652
+ for ll in range(NV):
653
+ if newUpdate[ll] / oldUpdate[ll] < -0.5:
654
+ maxJump[ll] = maxJump[ll] * 0.5
655
+
656
+ newUpdate[ll] = newUpdate[ll] / (
657
+ 1 + math.fabs(newUpdate[ll] / maxJump[ll])
658
+ )
659
+ newTheta[ll] = newTheta[ll] - newUpdate[ll]
660
+ # restrict range
661
+ newTheta[0] = max(newTheta[0], (float(sz) - 1) / 2 - sz / 4.0)
662
+ newTheta[0] = min(newTheta[0], (float(sz) - 1) / 2 + sz / 4.0)
663
+ newTheta[1] = max(newTheta[1], (float(sz) - 1) / 2 - sz / 4.0)
664
+ newTheta[1] = min(newTheta[1], (float(sz) - 1) / 2 + sz / 4.0)
665
+ newTheta[2] = max(newTheta[2], 1.0)
666
+ newTheta[3] = max(newTheta[3], 0.01)
667
+
668
+ newErr = 0
669
+ jacobian[:] = 0
670
+ hessian[:] = 0
671
+ for ii in range(sz):
672
+ for jj in range(sz):
673
+ # calculating derivatives
674
+ PSFx, PSFy, newDudt, _, model = kernel_DerivativeIntGauss2Dz(
675
+ ii,
676
+ jj,
677
+ newTheta,
678
+ PSFSigma_x,
679
+ PSFSigma_y,
680
+ Ax,
681
+ Ay,
682
+ Bx,
683
+ By,
684
+ gamma,
685
+ d,
686
+ newDudt,
687
+ None,
688
+ False,
689
+ )
690
+ if s_varim is not None:
691
+ model += s_varim[sz * jj + ii]
692
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
693
+ else:
694
+ data = s_data[sz * jj + ii]
695
+
696
+ if data > 0:
697
+ newErr = newErr + 2 * (
698
+ (model - data) - data * math.log(model / data)
699
+ )
700
+ else:
701
+ newErr = newErr + 2 * model
702
+ data = 0
703
+
704
+ t1 = 1 - data / model
705
+ for ll in range(NV):
706
+ jacobian[ll] += t1 * newDudt[ll]
707
+
708
+ t2 = data / math.pow(model, 2)
709
+ for ll in range(NV):
710
+ for mm in range(ll, NV, 1):
711
+ hessian[ll * NV + mm] += t2 * newDudt[ll] * newDudt[mm]
712
+ hessian[mm * NV + ll] = hessian[ll * NV + mm]
713
+ else:
714
+ mu = max((1 + newLambda * SCALE_UP) / (1 + newLambda), 1.3)
715
+ newLambda = SCALE_UP * newLambda
716
+
717
+ # output iteration
718
+
719
+ d_Parameters[NV] = kk
720
+
721
+ # Calculating the CRLB and LogLikelihood
722
+ Div = 0.0
723
+ for ii in range(sz):
724
+ for jj in range(sz):
725
+ PSFx, PSFy, newDudt, _, model = kernel_DerivativeIntGauss2Dz(
726
+ ii,
727
+ jj,
728
+ newTheta,
729
+ PSFSigma_x,
730
+ PSFSigma_y,
731
+ Ax,
732
+ Ay,
733
+ Bx,
734
+ By,
735
+ gamma,
736
+ d,
737
+ newDudt,
738
+ None,
739
+ False,
740
+ )
741
+ if s_varim is not None:
742
+ model += s_varim[sz * jj + ii]
743
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
744
+ else:
745
+ data = s_data[sz * jj + ii]
746
+
747
+ # Building the Fisher Information Matrix
748
+ for kk in range(NV):
749
+ for ll in range(kk, NV, 1):
750
+ M[kk * NV + ll] += newDudt[ll] * newDudt[kk] / model
751
+ M[ll * NV + kk] = M[kk * NV + ll]
752
+
753
+ # LogLikelyhood
754
+ if model > 0:
755
+ if data > 0:
756
+ Div += data * math.log(model) - model - data * math.log(data) + data
757
+ else:
758
+ Div += -model
759
+
760
+ # Matrix inverse (CRLB=F^-1) and output assigments
761
+ kernel_MatInvN(M, Minv, Diag, NV)
762
+ # Write to global arrays
763
+ for kk in range(NV):
764
+ d_Parameters[kk] = newTheta[kk]
765
+ d_CRLBs[kk] = Diag[kk]
766
+ d_LogLikelihood = Div
767
+
768
+ return d_Parameters, d_CRLBs, d_LogLikelihood
769
+
770
+
771
+ @nb.njit(cache=True)
772
+ def kernel_MLEFit_LM_sigmaxy(d_data, PSFSigma, sz, iterations, d_varim=None):
773
+ '''
774
+ basic MLE fitting kernel. No additional parameters are computed.
775
+
776
+ Parameters
777
+ ----------
778
+ d_data : float[]
779
+ array of subregions to fit copied to GPU
780
+ PSFSigma : float
781
+ sigma of the point spread function
782
+ sz : int
783
+ nxn size of the subregion to fit
784
+ iterations : int
785
+ number of iterations for solution to converge
786
+ d_varim : float[]
787
+ variance map of CMOS if None then EMCCD
788
+ '''
789
+ NV = NV_PS2
790
+
791
+ M = np.zeros(NV**2, np.float32)
792
+ Diag = np.zeros(NV, np.float32)
793
+ Minv = np.zeros(NV**2, np.float32)
794
+
795
+ model = 0
796
+ data = 0
797
+ d_LogLikelihood = Div = 0
798
+
799
+ d_Parameters = np.zeros(NV + 1, np.float32)
800
+ d_CRLBs = np.zeros(NV, np.float32)
801
+
802
+ newTheta = np.zeros(NV, np.float32)
803
+ oldTheta = np.zeros(NV, np.float32)
804
+ newLambda = INIT_LAMBDA
805
+ oldLambda = INIT_LAMBDA
806
+ mu = 0
807
+
808
+ newUpdate = np.zeros(NV, np.float32)
809
+ oldUpdate = np.zeros(NV, np.float32)
810
+ newUpdate[:] = 1e13
811
+ oldUpdate[:] = 1e13
812
+ newDudt = np.zeros(NV, np.float32)
813
+ maxJump = np.zeros(NV, np.float32)
814
+ maxJump = np.array([1.0, 1.0, 100.0, 20.0, 0.5, 0.5], np.float32)
815
+
816
+ newErr = 1e12
817
+ oldErr = 1e13
818
+
819
+ jacobian = np.zeros(NV, np.float32)
820
+ hessian = np.zeros(NV**2, np.float32)
821
+ t1 = 0.0
822
+ t2 = 0.0
823
+
824
+ Nmax = 0
825
+ errFlag = 0
826
+ L = np.zeros(NV**2, np.float32)
827
+ U = np.zeros(NV**2, np.float32)
828
+
829
+ # Requires Checking
830
+ s_data = d_data
831
+ s_varim = d_varim
832
+
833
+ # initial values
834
+ newTheta[0], newTheta[1] = kernel_CenterofMass2D(sz, s_data)
835
+ Nmax, newTheta[3] = kernel_GaussFMaxMin2D(sz, PSFSigma, s_data)
836
+ newTheta[2] = max(0.0, (Nmax - newTheta[3]) * 2 * pi * PSFSigma * PSFSigma)
837
+ newTheta[3] = max(newTheta[3], 0.01)
838
+ newTheta[4] = PSFSigma
839
+ newTheta[5] = PSFSigma
840
+
841
+ maxJump[2] = max(newTheta[2], maxJump[2])
842
+
843
+ maxJump[3] = max(newTheta[3], maxJump[3])
844
+
845
+ oldTheta[:] = newTheta[:]
846
+
847
+ for kk in range(iterations): # noqa: B007
848
+ # Compute Jacobian and Hessian
849
+ newErr = 0
850
+ jacobian.fill(0)
851
+ hessian.fill(0)
852
+ for ii in range(sz):
853
+ for jj in range(sz):
854
+ # Compute Jacobian
855
+ newDudt, model = kernel_DerivativeGauss2D_sigmaxy(
856
+ ii, jj, newTheta, newDudt
857
+ )
858
+ if s_varim is not None:
859
+ model += s_varim[sz * jj + ii]
860
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
861
+ else:
862
+ data = s_data[sz * jj + ii]
863
+
864
+ if data > 0:
865
+ newErr += 2 * ((model - data) - data * math.log(model / data))
866
+ else:
867
+ newErr += 2 * model
868
+ data = 0
869
+
870
+ t1 = 1 - data / model
871
+ for ll in range(NV):
872
+ jacobian[ll] += t1 * newDudt[ll]
873
+
874
+ # Compute Hessian
875
+ t2 = data / math.pow(model, 2)
876
+ for ll in range(NV):
877
+ for mm in range(ll, NV, 1):
878
+ hessian[ll * NV + mm] += t2 * newDudt[ll] * newDudt[mm]
879
+ hessian[mm * NV + ll] = hessian[ll * NV + mm]
880
+
881
+ # Levenberg-Marquardt algorithm
882
+ if abs((newErr - oldErr) / newErr) < TOLERANCE:
883
+ break
884
+ elif newErr > ACCEPTANCE * oldErr:
885
+ newTheta[:] = oldTheta[:]
886
+ newUpdate[:] = oldUpdate[:]
887
+ newLambda = oldLambda
888
+ newErr = oldErr
889
+ mu = max((1 + newLambda * SCALE_UP) / (1 + newLambda), 1.3)
890
+ newLambda = SCALE_UP * newLambda
891
+ elif newErr < oldErr and errFlag == 0:
892
+ newLambda = SCALE_DOWN * newLambda
893
+ mu = 1 + newLambda
894
+
895
+ for i in range(NV):
896
+ hessian[i * NV + i] *= mu
897
+
898
+ L[:] = 0
899
+ U[:] = 0
900
+
901
+ errFlag = kernel_cholesky(hessian, NV, L, U)
902
+ if errFlag == 0:
903
+ oldTheta[:] = newTheta[:]
904
+ oldUpdate[:] = newUpdate[:]
905
+ oldLambda = newLambda
906
+ oldErr = newErr
907
+
908
+ newUpdate = kernel_luEvaluate(L, U, jacobian, NV, newUpdate)
909
+
910
+ # parameter update
911
+ for ll in range(NV):
912
+ if newUpdate[ll] / oldUpdate[ll] < -0.5:
913
+ maxJump[ll] *= 0.5
914
+
915
+ newUpdate[ll] = newUpdate[ll] / (
916
+ 1 + math.fabs(newUpdate[ll] / maxJump[ll])
917
+ )
918
+ newTheta[ll] -= newUpdate[ll]
919
+
920
+ # restrict range
921
+ newTheta[0] = max(newTheta[0], (float(sz) - 1) / 2 - sz / 4.0)
922
+ newTheta[0] = min(newTheta[0], (float(sz) - 1) / 2 + sz / 4.0)
923
+ newTheta[1] = max(newTheta[1], (float(sz) - 1) / 2 - sz / 4.0)
924
+ newTheta[1] = min(newTheta[1], (float(sz) - 1) / 2 + sz / 4.0)
925
+ newTheta[2] = max(newTheta[2], 1.0)
926
+ newTheta[3] = max(newTheta[3], 0.01)
927
+ newTheta[4] = max(newTheta[4], PSFSigma / 10.0)
928
+ newTheta[5] = max(newTheta[5], PSFSigma / 10.0)
929
+
930
+ else:
931
+ mu = max((1 + newLambda * SCALE_UP) / (1 + newLambda), 1.3)
932
+ newLambda = SCALE_UP * newLambda
933
+
934
+ # Output iteration count
935
+ d_Parameters[NV] = kk
936
+
937
+ # Calculate CRLB and LogLikelihood
938
+ Div = 0.0
939
+ for ii in range(sz):
940
+ for jj in range(sz):
941
+ newDudt, model = kernel_DerivativeGauss2D_sigmaxy(ii, jj, newTheta, newDudt)
942
+ if s_varim is not None:
943
+ model += s_varim[sz * jj + ii]
944
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
945
+ else:
946
+ data = s_data[sz * jj + ii]
947
+
948
+ # Building the Fisher Information Matrix
949
+ for kk in range(NV):
950
+ for ll in range(kk, NV, 1):
951
+ M[kk * NV + ll] += newDudt[ll] * newDudt[kk] / model
952
+ M[ll * NV + kk] = M[kk * NV + ll]
953
+
954
+ # LogLikelihood
955
+ if model > 0:
956
+ if data > 0:
957
+ Div += data * math.log(model) - model - data * math.log(data) + data
958
+ else:
959
+ Div += -model
960
+
961
+ # Matrix inverse (CRLB=F^-1) and output assigments
962
+ kernel_MatInvN(M, Minv, Diag, NV)
963
+ # Write to global arrays
964
+ for kk in range(NV):
965
+ d_Parameters[kk] = newTheta[kk]
966
+ d_CRLBs[kk] = Diag[kk]
967
+ d_LogLikelihood = Div
968
+
969
+ return d_Parameters, d_CRLBs, d_LogLikelihood
970
+
971
+
972
+ @nb.njit(cache=True)
973
+ def kernel_splineMLEFit_z(
974
+ d_data,
975
+ d_coeff,
976
+ spline_xsize,
977
+ spline_ysize,
978
+ spline_zsize,
979
+ sz,
980
+ iterations,
981
+ initZ,
982
+ d_varim=None,
983
+ ):
984
+ '''
985
+ basic MLE fitting kernel. No additional parameters are computed.
986
+
987
+ Parameters
988
+ ----------
989
+ d_data : float[]
990
+ array of subregions to fit copied to GPU
991
+ d_coeff : float[]
992
+ array of spline coefficients of the PSF model
993
+ spline_xsize : int
994
+ x size of spline coefficients
995
+ spline_ysize : int
996
+ y size of spline coefficients
997
+ spline_zsize : int
998
+ z size of spline coefficients
999
+ sz : int
1000
+ nxn size of the subregion to fit
1001
+ iterations : int
1002
+ number of iterations for solution to converge
1003
+ initZ : float
1004
+ intial z position used for fitting
1005
+ d_varim : float[]
1006
+ variance map of CMOS if None then EMCCD
1007
+ '''
1008
+ NV = NV_PSP
1009
+
1010
+ M = np.zeros(NV**2, np.float32)
1011
+ Diag = np.zeros(NV, np.float32)
1012
+ Minv = np.zeros(NV**2, np.float32)
1013
+
1014
+ xstart = ystart = zstart = 0
1015
+
1016
+ s_coeff = d_coeff
1017
+
1018
+ model = 0
1019
+ data = 0
1020
+ d_LogLikelihood = Div = 0
1021
+
1022
+ d_Parameters = np.zeros(NV + 1, np.float32)
1023
+ d_CRLBs = np.zeros(NV, np.float32)
1024
+
1025
+ newTheta = np.zeros(NV, np.float32)
1026
+ oldTheta = np.zeros(NV, np.float32)
1027
+ newLambda = INIT_LAMBDA
1028
+ oldLambda = INIT_LAMBDA
1029
+ mu = 0
1030
+
1031
+ newUpdate = np.zeros(NV, np.float32)
1032
+ oldUpdate = np.zeros(NV, np.float32)
1033
+ newDudt = np.zeros(NV, np.float32)
1034
+ newUpdate[:] = 1e13
1035
+ oldUpdate[:] = 1e13
1036
+ maxJump = np.array([1.0, 1.0, 100.0, 20.0, 2], np.float32)
1037
+
1038
+ newErr = 1e12
1039
+ oldErr = 1e13
1040
+
1041
+ off = 0.0
1042
+ jacobian = np.zeros(NV, np.float32)
1043
+ hessian = np.zeros(NV**2, np.float32)
1044
+ t1 = 0.0
1045
+ t2 = 0.0
1046
+
1047
+ Nmax = 0
1048
+ errFlag = 0
1049
+ L = np.zeros(NV**2, np.float32)
1050
+ U = np.zeros(NV**2, np.float32)
1051
+
1052
+ xc = yc = zc = 0.0
1053
+ delta_f = np.zeros(64, np.float32)
1054
+ delta_dxf = np.zeros(64, np.float32)
1055
+ delta_dyf = np.zeros(64, np.float32)
1056
+ delta_dzf = np.zeros(64, np.float32)
1057
+
1058
+ # Requires Checking
1059
+ s_data = d_data
1060
+ s_varim = d_varim
1061
+
1062
+ # initial values
1063
+ newTheta[0], newTheta[1] = kernel_CenterofMass2D(sz, s_data)
1064
+ Nmax, newTheta[3] = kernel_GaussFMaxMin2D(sz, 1.5, s_data)
1065
+
1066
+ # central pixel of spline model
1067
+ newTheta[3] = max(newTheta[3], 0.01)
1068
+ newTheta[2] = (
1069
+ (Nmax - newTheta[3])
1070
+ / d_coeff[
1071
+ int(spline_zsize / 2) * (spline_xsize * spline_ysize)
1072
+ + int(spline_ysize / 2) * spline_xsize
1073
+ + int(spline_xsize / 2)
1074
+ ]
1075
+ * 4
1076
+ )
1077
+
1078
+ # newTheta[4]=float(spline_zsize)/2;
1079
+ newTheta[4] = initZ
1080
+
1081
+ maxJump[2] = max(newTheta[2], maxJump[2])
1082
+ maxJump[3] = max(newTheta[3], maxJump[3])
1083
+ maxJump[4] = max(spline_zsize / 3.0, maxJump[4])
1084
+
1085
+ for ii in range(NV):
1086
+ oldTheta[ii] = newTheta[ii]
1087
+
1088
+ # updateFitValues
1089
+ xc = -1.0 * ((newTheta[0] - float(sz) / 2) + 0.5)
1090
+ yc = -1.0 * ((newTheta[1] - float(sz) / 2) + 0.5)
1091
+
1092
+ off = math.floor((float(spline_xsize) + 1.0 - float(sz)) / 2)
1093
+
1094
+ xstart = math.floor(xc)
1095
+ xc = xc - xstart
1096
+
1097
+ ystart = math.floor(yc)
1098
+ yc = yc - ystart
1099
+
1100
+ # zstart = floor(newTheta[4]);
1101
+ zstart = math.floor(newTheta[4])
1102
+ zc = newTheta[4] - zstart
1103
+
1104
+ # updateFitValues
1105
+ newErr = 0
1106
+ delta_f, delta_dxf, delta_dyf, delta_dzf = kernel_computeDelta3D(
1107
+ xc, yc, zc, delta_f, delta_dxf, delta_dyf, delta_dzf
1108
+ )
1109
+
1110
+ for ii in range(sz):
1111
+ for jj in range(sz):
1112
+ newDudt, model = kernel_DerivativeSpline(
1113
+ ii + xstart + off,
1114
+ jj + ystart + off,
1115
+ zstart,
1116
+ spline_xsize,
1117
+ spline_ysize,
1118
+ spline_zsize,
1119
+ delta_f,
1120
+ delta_dxf,
1121
+ delta_dyf,
1122
+ delta_dzf,
1123
+ s_coeff,
1124
+ newTheta,
1125
+ newDudt,
1126
+ )
1127
+ if s_varim is not None:
1128
+ model += s_varim[sz * jj + ii]
1129
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
1130
+ else:
1131
+ data = s_data[sz * jj + ii]
1132
+
1133
+ if data > 0:
1134
+ newErr = newErr + 2 * ((model - data) - data * math.log(model / data))
1135
+ else:
1136
+ newErr = newErr + 2 * model
1137
+ data = 0
1138
+
1139
+ t1 = 1 - data / model
1140
+ for ll in range(NV):
1141
+ jacobian[ll] += t1 * newDudt[ll]
1142
+
1143
+ t2 = data / math.pow(model, 2)
1144
+ for ll in range(NV):
1145
+ for mm in range(ll, NV, 1):
1146
+ hessian[ll * NV + mm] += t2 * newDudt[ll] * newDudt[mm]
1147
+ hessian[mm * NV + ll] = hessian[ll * NV + mm]
1148
+
1149
+ for kk in range(iterations): # main iterative loop # noqa: B007
1150
+ if abs((newErr - oldErr) / newErr) < TOLERANCE:
1151
+ break # CONVERGED
1152
+ else:
1153
+ if newErr > ACCEPTANCE * oldErr:
1154
+ # copy Fitdata
1155
+ for i in range(NV):
1156
+ newTheta[i] = oldTheta[i]
1157
+ newUpdate[i] = oldUpdate[i]
1158
+ newLambda = oldLambda
1159
+ newErr = oldErr
1160
+ mu = max((1 + newLambda * SCALE_UP) / (1 + newLambda), 1.3)
1161
+ newLambda = SCALE_UP * newLambda
1162
+ elif newErr < oldErr and errFlag == 0:
1163
+ newLambda = SCALE_DOWN * newLambda
1164
+ mu = 1 + newLambda
1165
+
1166
+ for i in range(NV):
1167
+ hessian[i * NV + i] = hessian[i * NV + i] * mu
1168
+
1169
+ L[:] = 0
1170
+ U[:] = 0
1171
+
1172
+ errFlag = kernel_cholesky(hessian, NV, L, U)
1173
+
1174
+ if errFlag == 0:
1175
+ for i in range(NV):
1176
+ oldTheta[i] = newTheta[i]
1177
+ oldUpdate[i] = newUpdate[i]
1178
+ oldLambda = newLambda
1179
+ oldErr = newErr
1180
+
1181
+ newUpdate = kernel_luEvaluate(L, U, jacobian, NV, newUpdate)
1182
+
1183
+ # updateFitParameters
1184
+ for ll in range(NV):
1185
+ if newUpdate[ll] / oldUpdate[ll] < -0.5:
1186
+ maxJump[ll] = maxJump[ll] * 0.5
1187
+
1188
+ newUpdate[ll] = newUpdate[ll] / (
1189
+ 1 + math.fabs(newUpdate[ll] / maxJump[ll])
1190
+ )
1191
+ newTheta[ll] = newTheta[ll] - newUpdate[ll]
1192
+ # restrict range
1193
+ newTheta[0] = max(newTheta[0], (float(sz) - 1) / 2 - sz / 4.0)
1194
+ newTheta[0] = min(newTheta[0], (float(sz) - 1) / 2 + sz / 4.0)
1195
+ newTheta[1] = max(newTheta[1], (float(sz) - 1) / 2 - sz / 4.0)
1196
+ newTheta[1] = min(newTheta[1], (float(sz) - 1) / 2 + sz / 4.0)
1197
+ newTheta[2] = max(newTheta[2], 1.0)
1198
+ newTheta[3] = max(newTheta[3], 0.01)
1199
+ newTheta[4] = max(newTheta[4], 0.0)
1200
+ newTheta[4] = min(newTheta[4], float(spline_zsize))
1201
+
1202
+ # updateFitValues
1203
+ xc = -1.0 * ((newTheta[0] - float(sz) / 2) + 0.5)
1204
+ yc = -1.0 * ((newTheta[1] - float(sz) / 2) + 0.5)
1205
+
1206
+ xstart = math.floor(xc)
1207
+ xc = xc - xstart
1208
+
1209
+ ystart = math.floor(yc)
1210
+ yc = yc - ystart
1211
+
1212
+ zstart = math.floor(newTheta[4])
1213
+ zc = newTheta[4] - zstart
1214
+
1215
+ newErr = 0
1216
+ jacobian[:] = 0
1217
+ hessian[:] = 0
1218
+ delta_f, delta_dxf, delta_dyf, delta_dzf = kernel_computeDelta3D(
1219
+ xc, yc, zc, delta_f, delta_dxf, delta_dyf, delta_dzf
1220
+ )
1221
+
1222
+ for ii in range(sz):
1223
+ for jj in range(sz):
1224
+ # calculating derivatives
1225
+ newDudt, model = kernel_DerivativeSpline(
1226
+ ii + xstart + off,
1227
+ jj + ystart + off,
1228
+ zstart,
1229
+ spline_xsize,
1230
+ spline_ysize,
1231
+ spline_zsize,
1232
+ delta_f,
1233
+ delta_dxf,
1234
+ delta_dyf,
1235
+ delta_dzf,
1236
+ s_coeff,
1237
+ newTheta,
1238
+ newDudt,
1239
+ )
1240
+ if s_varim is not None:
1241
+ model += s_varim[sz * jj + ii]
1242
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
1243
+ else:
1244
+ data = s_data[sz * jj + ii]
1245
+
1246
+ if data > 0:
1247
+ newErr = newErr + 2 * (
1248
+ (model - data) - data * math.log(model / data)
1249
+ )
1250
+ else:
1251
+ newErr = newErr + 2 * model
1252
+ data = 0
1253
+
1254
+ t1 = 1 - data / model
1255
+ for ll in range(NV):
1256
+ jacobian[ll] += t1 * newDudt[ll]
1257
+
1258
+ t2 = data / math.pow(model, 2)
1259
+ for ll in range(NV):
1260
+ for mm in range(ll, NV, 1):
1261
+ hessian[ll * NV + mm] += t2 * newDudt[ll] * newDudt[mm]
1262
+ hessian[mm * NV + ll] = hessian[ll * NV + mm]
1263
+ else:
1264
+ mu = max((1 + newLambda * SCALE_UP) / (1 + newLambda), 1.3)
1265
+ newLambda = SCALE_UP * newLambda
1266
+
1267
+ # output iteration
1268
+
1269
+ d_Parameters[NV] = kk
1270
+
1271
+ # Calculating the CRLB and LogLikelihood
1272
+ Div = 0.0
1273
+
1274
+ xc = -1.0 * ((newTheta[0] - float(sz) / 2) + 0.5)
1275
+ yc = -1.0 * ((newTheta[1] - float(sz) / 2) + 0.5)
1276
+
1277
+ # off = (float(spline_xsize)+1.0-2*float(sz))/2;
1278
+
1279
+ xstart = math.floor(xc)
1280
+ xc = xc - xstart
1281
+
1282
+ ystart = math.floor(yc)
1283
+ yc = yc - ystart
1284
+
1285
+ zstart = math.floor(newTheta[4])
1286
+ zc = newTheta[4] - zstart
1287
+
1288
+ delta_f, delta_dxf, delta_dyf, delta_dzf = kernel_computeDelta3D(
1289
+ xc, yc, zc, delta_f, delta_dxf, delta_dyf, delta_dzf
1290
+ )
1291
+
1292
+ for ii in range(sz):
1293
+ for jj in range(sz):
1294
+ newDudt, model = kernel_DerivativeSpline(
1295
+ ii + xstart + off,
1296
+ jj + ystart + off,
1297
+ zstart,
1298
+ spline_xsize,
1299
+ spline_ysize,
1300
+ spline_zsize,
1301
+ delta_f,
1302
+ delta_dxf,
1303
+ delta_dyf,
1304
+ delta_dzf,
1305
+ s_coeff,
1306
+ newTheta,
1307
+ newDudt,
1308
+ )
1309
+ if s_varim is not None:
1310
+ model += s_varim[sz * jj + ii]
1311
+ data = s_data[sz * jj + ii] + s_varim[sz * jj + ii]
1312
+ else:
1313
+ data = s_data[sz * jj + ii]
1314
+
1315
+ # Building the Fisher Information Matrix
1316
+ for kk in range(NV):
1317
+ for ll in range(kk, NV, 1):
1318
+ M[kk * NV + ll] += newDudt[ll] * newDudt[kk] / model
1319
+ M[ll * NV + kk] = M[kk * NV + ll]
1320
+
1321
+ # LogLikelyhood
1322
+ if model > 0:
1323
+ if data > 0:
1324
+ Div += data * math.log(model) - model - data * math.log(data) + data
1325
+ else:
1326
+ Div += -model
1327
+
1328
+ # Matrix inverse (CRLB=F^-1) and output assigments
1329
+ kernel_MatInvN(M, Minv, Diag, NV)
1330
+ # Write to global arrays
1331
+ for kk in range(NV):
1332
+ d_Parameters[kk] = newTheta[kk]
1333
+ d_CRLBs[kk] = Diag[kk]
1334
+ d_LogLikelihood = Div
1335
+
1336
+ return d_Parameters, d_CRLBs, d_LogLikelihood