pivtools 0.1.3__cp311-cp311-win_amd64.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 (127) hide show
  1. pivtools-0.1.3.dist-info/METADATA +222 -0
  2. pivtools-0.1.3.dist-info/RECORD +127 -0
  3. pivtools-0.1.3.dist-info/WHEEL +5 -0
  4. pivtools-0.1.3.dist-info/entry_points.txt +3 -0
  5. pivtools-0.1.3.dist-info/top_level.txt +3 -0
  6. pivtools_cli/__init__.py +5 -0
  7. pivtools_cli/_build_marker.c +25 -0
  8. pivtools_cli/_build_marker.cp311-win_amd64.pyd +0 -0
  9. pivtools_cli/cli.py +225 -0
  10. pivtools_cli/example.py +139 -0
  11. pivtools_cli/lib/PIV_2d_cross_correlate.c +334 -0
  12. pivtools_cli/lib/PIV_2d_cross_correlate.h +22 -0
  13. pivtools_cli/lib/common.h +36 -0
  14. pivtools_cli/lib/interp2custom.c +146 -0
  15. pivtools_cli/lib/interp2custom.h +48 -0
  16. pivtools_cli/lib/peak_locate_gsl.c +711 -0
  17. pivtools_cli/lib/peak_locate_gsl.h +40 -0
  18. pivtools_cli/lib/peak_locate_gsl_print.c +736 -0
  19. pivtools_cli/lib/peak_locate_lm.c +751 -0
  20. pivtools_cli/lib/peak_locate_lm.h +27 -0
  21. pivtools_cli/lib/xcorr.c +342 -0
  22. pivtools_cli/lib/xcorr.h +31 -0
  23. pivtools_cli/lib/xcorr_cache.c +78 -0
  24. pivtools_cli/lib/xcorr_cache.h +26 -0
  25. pivtools_cli/piv/interp2custom/interp2custom.py +69 -0
  26. pivtools_cli/piv/piv.py +240 -0
  27. pivtools_cli/piv/piv_backend/base.py +825 -0
  28. pivtools_cli/piv/piv_backend/cpu_instantaneous.py +1005 -0
  29. pivtools_cli/piv/piv_backend/factory.py +28 -0
  30. pivtools_cli/piv/piv_backend/gpu_instantaneous.py +15 -0
  31. pivtools_cli/piv/piv_backend/infilling.py +445 -0
  32. pivtools_cli/piv/piv_backend/outlier_detection.py +306 -0
  33. pivtools_cli/piv/piv_backend/profile_cpu_instantaneous.py +230 -0
  34. pivtools_cli/piv/piv_result.py +40 -0
  35. pivtools_cli/piv/save_results.py +342 -0
  36. pivtools_cli/piv_cluster/cluster.py +108 -0
  37. pivtools_cli/preprocessing/filters.py +399 -0
  38. pivtools_cli/preprocessing/preprocess.py +79 -0
  39. pivtools_cli/tests/helpers.py +107 -0
  40. pivtools_cli/tests/instantaneous_piv/test_piv_integration.py +167 -0
  41. pivtools_cli/tests/instantaneous_piv/test_piv_integration_multi.py +553 -0
  42. pivtools_cli/tests/preprocessing/test_filters.py +41 -0
  43. pivtools_core/__init__.py +5 -0
  44. pivtools_core/config.py +703 -0
  45. pivtools_core/config.yaml +135 -0
  46. pivtools_core/image_handling/__init__.py +0 -0
  47. pivtools_core/image_handling/load_images.py +464 -0
  48. pivtools_core/image_handling/readers/__init__.py +53 -0
  49. pivtools_core/image_handling/readers/generic_readers.py +50 -0
  50. pivtools_core/image_handling/readers/lavision_reader.py +190 -0
  51. pivtools_core/image_handling/readers/registry.py +24 -0
  52. pivtools_core/paths.py +49 -0
  53. pivtools_core/vector_loading.py +248 -0
  54. pivtools_gui/__init__.py +3 -0
  55. pivtools_gui/app.py +687 -0
  56. pivtools_gui/calibration/__init__.py +0 -0
  57. pivtools_gui/calibration/app/__init__.py +0 -0
  58. pivtools_gui/calibration/app/views.py +1186 -0
  59. pivtools_gui/calibration/calibration_planar/planar_calibration_production.py +570 -0
  60. pivtools_gui/calibration/vector_calibration_production.py +544 -0
  61. pivtools_gui/config.py +703 -0
  62. pivtools_gui/image_handling/__init__.py +0 -0
  63. pivtools_gui/image_handling/load_images.py +464 -0
  64. pivtools_gui/image_handling/readers/__init__.py +53 -0
  65. pivtools_gui/image_handling/readers/generic_readers.py +50 -0
  66. pivtools_gui/image_handling/readers/lavision_reader.py +190 -0
  67. pivtools_gui/image_handling/readers/registry.py +24 -0
  68. pivtools_gui/masking/__init__.py +0 -0
  69. pivtools_gui/masking/app/__init__.py +0 -0
  70. pivtools_gui/masking/app/views.py +123 -0
  71. pivtools_gui/paths.py +49 -0
  72. pivtools_gui/piv_runner.py +261 -0
  73. pivtools_gui/pivtools.py +58 -0
  74. pivtools_gui/plotting/__init__.py +0 -0
  75. pivtools_gui/plotting/app/__init__.py +0 -0
  76. pivtools_gui/plotting/app/views.py +1671 -0
  77. pivtools_gui/plotting/plot_maker.py +220 -0
  78. pivtools_gui/post_processing/POD/__init__.py +0 -0
  79. pivtools_gui/post_processing/POD/app/__init__.py +0 -0
  80. pivtools_gui/post_processing/POD/app/views.py +647 -0
  81. pivtools_gui/post_processing/POD/pod_decompose.py +979 -0
  82. pivtools_gui/post_processing/POD/views.py +1096 -0
  83. pivtools_gui/post_processing/__init__.py +0 -0
  84. pivtools_gui/static/404.html +1 -0
  85. pivtools_gui/static/_next/static/chunks/117-d5793c8e79de5511.js +2 -0
  86. pivtools_gui/static/_next/static/chunks/484-cfa8b9348ce4f00e.js +1 -0
  87. pivtools_gui/static/_next/static/chunks/869-320a6b9bdafbb6d3.js +1 -0
  88. pivtools_gui/static/_next/static/chunks/app/_not-found/page-12f067ceb7415e55.js +1 -0
  89. pivtools_gui/static/_next/static/chunks/app/layout-b907d5f31ac82e9d.js +1 -0
  90. pivtools_gui/static/_next/static/chunks/app/page-334cc4e8444cde2f.js +1 -0
  91. pivtools_gui/static/_next/static/chunks/fd9d1056-ad15f396ddf9b7e5.js +1 -0
  92. pivtools_gui/static/_next/static/chunks/framework-f66176bb897dc684.js +1 -0
  93. pivtools_gui/static/_next/static/chunks/main-a1b3ced4d5f6d998.js +1 -0
  94. pivtools_gui/static/_next/static/chunks/main-app-8a63c6f5e7baee11.js +1 -0
  95. pivtools_gui/static/_next/static/chunks/pages/_app-72b849fbd24ac258.js +1 -0
  96. pivtools_gui/static/_next/static/chunks/pages/_error-7ba65e1336b92748.js +1 -0
  97. pivtools_gui/static/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  98. pivtools_gui/static/_next/static/chunks/webpack-4a8ca7c99e9bb3d8.js +1 -0
  99. pivtools_gui/static/_next/static/css/7d3f2337d7ea12a5.css +3 -0
  100. pivtools_gui/static/_next/static/vQeR20OUdSSKlK4vukC4q/_buildManifest.js +1 -0
  101. pivtools_gui/static/_next/static/vQeR20OUdSSKlK4vukC4q/_ssgManifest.js +1 -0
  102. pivtools_gui/static/file.svg +1 -0
  103. pivtools_gui/static/globe.svg +1 -0
  104. pivtools_gui/static/grid.svg +8 -0
  105. pivtools_gui/static/index.html +1 -0
  106. pivtools_gui/static/index.txt +8 -0
  107. pivtools_gui/static/next.svg +1 -0
  108. pivtools_gui/static/vercel.svg +1 -0
  109. pivtools_gui/static/window.svg +1 -0
  110. pivtools_gui/stereo_reconstruction/__init__.py +0 -0
  111. pivtools_gui/stereo_reconstruction/app/__init__.py +0 -0
  112. pivtools_gui/stereo_reconstruction/app/views.py +1985 -0
  113. pivtools_gui/stereo_reconstruction/stereo_calibration_production.py +606 -0
  114. pivtools_gui/stereo_reconstruction/stereo_reconstruction_production.py +544 -0
  115. pivtools_gui/utils.py +63 -0
  116. pivtools_gui/vector_loading.py +248 -0
  117. pivtools_gui/vector_merging/__init__.py +1 -0
  118. pivtools_gui/vector_merging/app/__init__.py +1 -0
  119. pivtools_gui/vector_merging/app/views.py +759 -0
  120. pivtools_gui/vector_statistics/app/__init__.py +1 -0
  121. pivtools_gui/vector_statistics/app/views.py +710 -0
  122. pivtools_gui/vector_statistics/ensemble_statistics.py +49 -0
  123. pivtools_gui/vector_statistics/instantaneous_statistics.py +311 -0
  124. pivtools_gui/video_maker/__init__.py +0 -0
  125. pivtools_gui/video_maker/app/__init__.py +0 -0
  126. pivtools_gui/video_maker/app/views.py +436 -0
  127. pivtools_gui/video_maker/video_maker.py +662 -0
@@ -0,0 +1,736 @@
1
+ #include "peak_locate_gsl.h"
2
+ #include "common.h"
3
+ #include <stdlib.h>
4
+ #include <string.h>
5
+ #include <math.h>
6
+ #include <float.h>
7
+
8
+ /******************************************************************************
9
+ * Function: lsqpeaklocate
10
+ * ---------------------------------------------------------------------------
11
+ * Description:
12
+ * This function locates the peaks in a cross-correlation matrix using a
13
+ * least-squares fitting approach. The function finds the specified number
14
+ * of peak locations (`nPeaks`) and estimates the peak's position using
15
+ * different fitting types, depending on the specified `iFitType`. The function
16
+ * returns the locations of the peaks in the `peak_loc` array and optionally
17
+ * provides the estimated standard deviation of the peak using `std_dev`.
18
+ *
19
+ * The function performs a 2D search to locate the maximum points in the
20
+ * cross-correlation matrix (`xcorr`). For each peak, the function applies
21
+ * least-squares fitting to refine the location estimate.
22
+ *
23
+ * The method of fitting is determined by the `iFitType` parameter, which
24
+ * specifies different fitting models based on the number of degrees of freedom
25
+ * (DOF).
26
+ *
27
+ * ---------------------------------------------------------------------------
28
+ * Inputs:
29
+ * float *xcorr : Pointer to the 2D array representing the cross-correlation
30
+ * matrix. The matrix should be of size [N[0], N[1]] where
31
+ * N[0] is the number of rows and N[1] is the number of columns.
32
+ *
33
+ * int *N : Pointer to an array of size 2 where:
34
+ * - N[0] : The number of rows in the xcorr matrix.
35
+ * - N[1] : The number of columns in the xcorr matrix.
36
+ *
37
+ * int nPeaks : The number of peaks to locate in the cross-correlation matrix.
38
+ * Should be a positive integer (e.g., 1 for a single peak).
39
+ *
40
+ * int iFitType : Specifies the type of least-squares fit to use for peak
41
+ * localization. Valid options include:
42
+ * - 3 : Use a 3-point least-squares estimator.
43
+ * - 4 : Use a 4-DOF Gaussian fit.
44
+ * - 5 : Use a 5-DOF Gaussian fit.
45
+ * - 6 : Use a 6-DOF Gaussian fit.
46
+ *
47
+ * ---------------------------------------------------------------------------
48
+ * Outputs:
49
+ * float *peak_loc : Pointer to an array where the locations of the peaks
50
+ * will be stored. It must be able to hold `nPeaks * 2` elements
51
+ * (x, y coordinates for each peak).
52
+ *
53
+ * float *std_dev : Pointer to a variable where the standard deviation of
54
+ * the peak location will be stored (optional, can be NULL).
55
+ *
56
+ * ---------------------------------------------------------------------------
57
+ * Procedures:
58
+ * 1. Parse the cross-correlation matrix and search for the highest values (peaks).
59
+ * 2. For each identified peak, refine the location using the least-squares
60
+ * fitting method based on the `iFitType` parameter.
61
+ * 3. Store the estimated peak locations in the `peak_loc` array.
62
+ * 4. Optionally, compute the standard deviation of the peak location and
63
+ * store it in `std_dev`.
64
+ *
65
+ * ---------------------------------------------------------------------------
66
+ * Example Usage:
67
+ * float xcorr[10][10]; // Cross-correlation matrix of size 10x10
68
+ * int N[2] = {10, 10}; // N[0] = 10 (rows), N[1] = 10 (columns)
69
+ * float peak_loc[2]; // Array to store peak locations (x, y)
70
+ * int nPeaks = 1; // Looking for 1 peak
71
+ * int iFitType = 4; // Use 4-point Gaussian fitting
72
+ * float std_dev; // Variable to store the peak standard deviation
73
+ *
74
+ * lsqpeaklocate(&xcorr[0][0], N, peak_loc, nPeaks, iFitType, &std_dev);
75
+ * printf("Peak at location: (%f, %f)\n", peak_loc[0], peak_loc[1]);
76
+ * printf("Peak standard deviation: %f\n", std_dev);
77
+ *
78
+ *****************************************************************************/
79
+
80
+ void lsqpeaklocate(const float *xcorr, const int *N, float *peak_loc, int nPeaks, int iFitType, float *std_dev)
81
+ {
82
+ int i, j, iPeak, idx;
83
+ int i0, j0;
84
+ float *xcorr_copy;
85
+ float fPeakHeight;
86
+ float subxcorr[PKSIZE_X][PKSIZE_Y];
87
+ float fitval[PKSIZE_X][PKSIZE_Y];
88
+ int Nsub[2];
89
+ float peak[2];
90
+ float sig[3];
91
+ if (!xcorr) {
92
+ return;
93
+ }
94
+ if (!N) {
95
+ return;
96
+ }
97
+ if (!peak_loc) {
98
+ return;
99
+ }
100
+ if (!std_dev) {
101
+ }
102
+
103
+ // Validate N array
104
+ if (N[0] <= 0 || N[1] <= 0) {
105
+ return;
106
+ }
107
+
108
+ // Validate number of peaks
109
+ if (nPeaks <= 0) {
110
+ return;
111
+ }
112
+
113
+ // Validate fit type
114
+ if (iFitType < 3 || iFitType > 6) {
115
+ return;
116
+ }
117
+ /* make a copy of xcorr that we can manipulate */
118
+ xcorr_copy = (float*)malloc(sizeof(float) * N[0]*N[1]);
119
+ memcpy(xcorr_copy, xcorr, N[0]*N[1]*sizeof(float));
120
+ Nsub[0] = PKSIZE_X;
121
+ Nsub[1] = PKSIZE_Y;
122
+
123
+ /* iterate over peaks */
124
+ for(iPeak = 0; iPeak < nPeaks; ++iPeak)
125
+ {
126
+ /* find maximum value in array
127
+ * only search for peaks in range
128
+ * N[0]/8 <= i < N[0]*7/8
129
+ * N[1]/8 <= j < N[1]*7/8
130
+ */
131
+ i0 = j0 = 0;
132
+ fPeakHeight = 0;
133
+ for(i = N[0]/8; i < N[0]*7/8; ++i)
134
+ {
135
+ for(j = N[1]/8; j < N[1]*7/8; ++j)
136
+ {
137
+ if(xcorr_copy[SUB2IND_2D(i, j, N[0])] > fPeakHeight)
138
+ {
139
+ fPeakHeight = xcorr_copy[SUB2IND_2D(i, j, N[0])];
140
+ i0 = i;
141
+ j0 = j;
142
+ }
143
+ }
144
+ }
145
+
146
+ /* error out if peak height is not positive */
147
+ if(fPeakHeight <= 0)
148
+ {
149
+ peak_loc[SUB2IND_2D(0, iPeak, 3)] = NAN;
150
+ peak_loc[SUB2IND_2D(1, iPeak, 3)] = NAN;
151
+ peak_loc[SUB2IND_2D(2, iPeak, 3)] = 0;
152
+ continue;
153
+ }
154
+
155
+ /* error out if too close to the edges, or is not a local maximum */
156
+ if( i0 < (PKSIZE_X-1)/2 || i0 >= N[0]-(PKSIZE_X-1)/2
157
+ || j0 < (PKSIZE_Y-1)/2 || j0 >= N[1]-(PKSIZE_Y-1)/2
158
+ || fPeakHeight <= xcorr_copy[SUB2IND_2D(i0-1, j0 , N[0])]
159
+ || fPeakHeight <= xcorr_copy[SUB2IND_2D(i0+1, j0 , N[0])]
160
+ || fPeakHeight <= xcorr_copy[SUB2IND_2D(i0 , j0-1, N[0])]
161
+ || fPeakHeight <= xcorr_copy[SUB2IND_2D(i0 , j0+1, N[0])] )
162
+ {
163
+ peak_loc[SUB2IND_2D(0, iPeak, 3)] = NAN;
164
+ peak_loc[SUB2IND_2D(1, iPeak, 3)] = NAN;
165
+ peak_loc[SUB2IND_2D(2, iPeak, 3)] = 0;
166
+ continue;
167
+ }
168
+
169
+ /* copy into C-style matrix */
170
+ for(i = 0; i < PKSIZE_X; ++i)
171
+ {
172
+ for(j = 0; j < PKSIZE_Y; ++j)
173
+ {
174
+ subxcorr[i][j] = xcorr_copy[SUB2IND_2D(i0 + i - (PKSIZE_X-1)/2, j0 + j - (PKSIZE_Y-1)/2, N[0])];
175
+ }
176
+ }
177
+
178
+ /* perform least-squares fit to get peak location
179
+ * only bother using high-order scheme for first peak
180
+ */
181
+ peakfit(&subxcorr[0][0], Nsub, peak, &fitval[0][0], iPeak ? 3 : iFitType, sig);
182
+
183
+ /* save peak location and subtract fit from correlation plane
184
+ * note this could mean that the correlation plane is not strictly positive-valued everywhere
185
+ */
186
+
187
+ peak_loc[SUB2IND_2D(0, iPeak, 3)] = peak[0] + i0;
188
+ peak_loc[SUB2IND_2D(1, iPeak, 3)] = peak[1] + j0;
189
+ peak_loc[SUB2IND_2D(2, iPeak, 3)] = fPeakHeight;
190
+ std_dev[SUB2IND_2D(0, iPeak, 3)] = sig[0];
191
+ std_dev[SUB2IND_2D(1, iPeak, 3)] = sig[1];
192
+ std_dev[SUB2IND_2D(2, iPeak, 3)] = sig[2];
193
+ for(i = 0; i < PKSIZE_X; ++i)
194
+ {
195
+ for(j = 0; j < PKSIZE_Y; ++j)
196
+ {
197
+ idx = SUB2IND_2D( i0 + i - (PKSIZE_X-1)/2, j0 + j - (PKSIZE_Y-1)/2, N[0]);
198
+ xcorr_copy[idx] = MAX(0, xcorr_copy[idx] - fitval[i][j]);
199
+ }
200
+ }
201
+ }
202
+
203
+ /* clean up and exit */
204
+ free(xcorr_copy);
205
+ return;
206
+ }
207
+
208
+ /****************************************************
209
+ * void peakfit(const float *xcorr, const int *N, float *peak_loc, float *fitval, int iFitType)
210
+ *
211
+ * finds the sub-grid location of the nPeaks largest correlation-peaks in
212
+ * the two-dimensional array xcorr
213
+ *
214
+ * xcorr is a two-dimensional array with an odd number of elements along each dimension
215
+ * typically five
216
+ * such that the element at the centre is at i = j = 0
217
+ *
218
+ * the sub-grid location is returned in peak_loc in this coordinate system
219
+ * the best fit function is returned in fitval for the fit parameters which best match the correlation peak
220
+ *
221
+ * the fit type to be used (3, 4, 5 or 6 degree of freedom) is specified by iFitType
222
+ *
223
+ */
224
+
225
+ void peakfit(const float *xcorr, const int *N, float *peak_loc, float *fitval, int iFitType, float *sig)
226
+ {
227
+ float x_fit[3];
228
+ float y_fit[3];
229
+ int i;
230
+ int info, status;
231
+ float A, sx, sy, sx_lb, sy_lb, sx_ub, sy_ub, A_lb, A_ub;
232
+
233
+ size_t n_data;
234
+ double X[6];
235
+ pkdata pd;
236
+ gsl_vector *gsl_F, *gsl_X;
237
+ gsl_vector_view gsl_X0;
238
+
239
+ /* make initial guess of sub-pixel location and gaussian peak size
240
+ * using three-point estimator
241
+ */
242
+ for(i = 0; i < 3; ++i)
243
+ {
244
+ x_fit[i] = xcorr[ (i - 1 + (N[0]-1)/2) *N[1]
245
+ + (N[1]-1)/2 ];
246
+ y_fit[i] = xcorr[ (N[0]-1)/2 *N[1]
247
+ + (i - 1 + (N[1]-1)/2) ];
248
+ x_fit[i] = (float)log((x_fit[i] < FLT_EPSILON) ? FLT_EPSILON : x_fit[i]);
249
+ y_fit[i] = (float)log((y_fit[i] < FLT_EPSILON) ? FLT_EPSILON : y_fit[i]);
250
+ }
251
+
252
+ /* peak location in i direction is at i0 = numer/denom
253
+ * numer = ln(R(i-1), j) - ln(R(i+1), j)
254
+ * ~= -4 (i0 - i) / sigma_x^2
255
+ * denom = 2ln(R(i-1, j)) - 4ln(R(i,j)) + 2ln(R(i+1,j))
256
+ * ~= -4 / sigma_x^2
257
+ * when R is modelled as a gaussian R ~ exp(-(i-i0)/sigma_x^2)
258
+ */
259
+ peak_loc[0] = (x_fit[0] - x_fit[2]) / (2*x_fit[0] - 4*x_fit[1] + 2*x_fit[2]);
260
+ peak_loc[1] = (y_fit[0] - y_fit[2]) / (2*y_fit[0] - 4*y_fit[1] + 2*y_fit[2]);
261
+ A = xcorr[(N[0]-1)/2*N[1] + (N[1]-1)/2];
262
+ sx = (float)sqrt(-4 / (2*x_fit[0] - 4*x_fit[1] + 2*x_fit[2]));
263
+ sy = (float)sqrt(-4 / (2*y_fit[0] - 4*y_fit[1] + 2*y_fit[2]));
264
+ sx_lb = 0.25; sy_lb = 0.25;
265
+ sx_ub = 2*sx; sy_ub = 2*sy;
266
+ A_lb = A / 2;
267
+ A_ub = A * 2;
268
+
269
+ /***** allocate default result for 3-point fit *****/
270
+ X[0] = A;
271
+ X[1] = peak_loc[0];
272
+ X[2] = peak_loc[1];
273
+ X[3] = sqrt(sx*sx+sy*sy);
274
+ n_data = N[0] * N[1];
275
+
276
+ // evaluate fit function and copy
277
+ memset(fitval, 0, sizeof(float)*n_data);
278
+ pd.xcorr = fitval; // hand gauss4_f a zero array to evaluate fit function only
279
+ pd.N = N;
280
+ gsl_F = gsl_vector_alloc(n_data);
281
+ gsl_X0 = gsl_vector_view_array(X, 4);
282
+ gauss4_f(&(gsl_X0.vector), (void*)&pd, gsl_F);
283
+ for(i = 0; i < n_data; ++i)
284
+ fitval[i] = (float) gsl_vector_get(gsl_F, i);
285
+ gsl_vector_free(gsl_F);
286
+
287
+ /* if using three point estimator fit, stop here */
288
+ if(iFitType == 3)
289
+ return;
290
+
291
+ /***** set-up for non-linear least squares fitting *****/
292
+ const gsl_multifit_nlinear_type *gsl_fittype = gsl_multifit_nlinear_trust;
293
+ gsl_multifit_nlinear_workspace *gsl_ws;
294
+ gsl_multifit_nlinear_fdf gsl_fdf;
295
+ gsl_multifit_nlinear_parameters gsl_fdf_params = gsl_multifit_nlinear_default_parameters();
296
+
297
+ const double xtol = 1e-6;
298
+ const double gtol = 1e-6;
299
+ const double ftol = 0.0;
300
+
301
+ /* set common parameters for all types of fit */
302
+ pd.N = N;
303
+ pd.xcorr = xcorr;
304
+ gsl_fdf.fvv = NULL; // not using geodesic acceleration
305
+ gsl_fdf.n = N[0]*N[1]; // number of data
306
+ gsl_fdf.params =&pd; // data for optimisation
307
+ gsl_fdf_params.trs= gsl_multifit_nlinear_trs_lm;
308
+
309
+ /* specific settings for different fit types */
310
+ switch(iFitType)
311
+ {
312
+ case 4:
313
+ /* four DOF fit */
314
+ /* initial guess */
315
+ X[0] = A;
316
+ X[1] = peak_loc[0];
317
+ X[2] = peak_loc[1];
318
+ X[3] = sqrt(sx*sx+sy*sy);
319
+ gsl_X0 = gsl_vector_view_array(X, 4);
320
+
321
+ /* define the function to be minimized */
322
+ gsl_fdf.f = gauss4_f; // objective function to minimise
323
+ gsl_fdf.df = gauss4_jac; // jacobian
324
+ gsl_fdf.p = 4; // number of parameters
325
+ break;
326
+ case 5:
327
+ /* five DOF fit */
328
+ /* initial guess */
329
+ X[0] = A;
330
+ X[1] = peak_loc[0];
331
+ X[2] = peak_loc[1];
332
+ X[3] = sx;
333
+ X[4] = sy;
334
+ gsl_X0 = gsl_vector_view_array(X, 5);
335
+
336
+ /* define the function to be minimized */
337
+ gsl_fdf.f = gauss5_f; // objective function to minimise
338
+ gsl_fdf.df = gauss5_jac; // jacobian
339
+ gsl_fdf.p = 5; // number of parameters
340
+ break;
341
+ default:
342
+ case 6:
343
+ /* six DOF fit */
344
+ /* initial guess */
345
+
346
+ X[0] = A;
347
+ X[1] = peak_loc[0];
348
+ X[2] = peak_loc[1];
349
+ X[3] = sx*sx;
350
+ X[4] = sy*sy;
351
+ X[5] = 0;
352
+ gsl_X0 = gsl_vector_view_array(X, 6);
353
+
354
+ /* define the function to be minimized */
355
+ gsl_fdf.f = gauss6_f; // objective function to minimise
356
+ gsl_fdf.df = gauss6_jac; // jacobian
357
+ gsl_fdf.p = 6; // number of parameters
358
+ break;
359
+ }
360
+
361
+ /**** run solver ****/
362
+ // allocate workspace with default parameters
363
+ gsl_ws = gsl_multifit_nlinear_alloc(gsl_fittype, &gsl_fdf_params, gsl_fdf.n, gsl_fdf.p);
364
+ // initialize solver with starting point and weights
365
+ gsl_multifit_nlinear_init(&(gsl_X0.vector), &gsl_fdf, gsl_ws);
366
+ // solve the system with a maximum of MAXITER iterations
367
+ gsl_X = gsl_multifit_nlinear_position(gsl_ws);
368
+
369
+ // note: fitting can crash with a memory access error if nan or bad values are returned by any of the fitting functions!
370
+ status = gsl_multifit_nlinear_driver(MAXITER, xtol, gtol, ftol, NULL, NULL, &info, gsl_ws);
371
+
372
+ /**** allocate result if successful ****/
373
+ if(status == GSL_SUCCESS)
374
+ //extract std 210224a
375
+
376
+ {
377
+ gsl_X = gsl_multifit_nlinear_position(gsl_ws);
378
+ if (gsl_fdf.p == 6) {
379
+ sig[0] = (float)gsl_vector_get(gsl_X,4);
380
+ sig[1] = (float)gsl_vector_get(gsl_X,3);
381
+ sig[2] = -(float)gsl_vector_get(gsl_X, 5)*(sig[0]*sig[1]-((float)gsl_vector_get(gsl_X, 5)*(float)gsl_vector_get(gsl_X, 5)));
382
+ } else {
383
+ sig[0] = 0.0;
384
+ sig[1] = 0.0;
385
+ sig[2] = 0.0;
386
+ }
387
+
388
+ peak_loc[0] = (float)gsl_vector_get(gsl_X, 1);
389
+ peak_loc[1] = (float)gsl_vector_get(gsl_X, 2);
390
+ // evaluate fit function and copy
391
+ memset(fitval, 0, sizeof(float)*n_data);
392
+ pd.xcorr = fitval; // necessary
393
+ pd.N = N;
394
+ gsl_F = gsl_vector_alloc(n_data);
395
+ (*gsl_fdf.f)(gsl_X, (void*)&pd, gsl_F);
396
+ for(i = 0; i < n_data; ++i)
397
+ fitval[i] = (float) gsl_vector_get(gsl_F, i);
398
+ gsl_vector_free(gsl_F);
399
+ }
400
+
401
+ /**** free ****/
402
+ gsl_multifit_nlinear_free(gsl_ws);
403
+
404
+ return;
405
+ }
406
+
407
+ /****************************************************
408
+ * fitting functions
409
+ *
410
+ * we provide the function which predicts
411
+ * the measurement vector x of dimension n x 1 that
412
+ * x = F(i, j; p)
413
+ * where p is the vector to be predicted with dimension m x 1
414
+ *
415
+ * the jacobian jac = \partial x / \partial p is organised in a C-style
416
+ * n x m matrix, such that
417
+ * jac[0] corresponds to \partial x_0 / \partial p_0
418
+ * jac[1] " " \partial x_0 / \partial p_1
419
+ * jac[i*m + j] " " \partial x_i / \partial p_j
420
+ *
421
+ * x represents a flattened C-style N[0] x N[1] array indexed by
422
+ * x[i][j], i = -(N[0]-1)/2 .. (N[0]-1)/2, j = -(N[1]-1)/2 ...
423
+ * and should contain F(i, j; p) evaluated at each i, j
424
+ *
425
+ * data is a pointer to an int array (int*) which contains the
426
+ * dimensions that the flattened array x corresponds to
427
+ */
428
+
429
+ /********
430
+ * gauss4 and gauss4jac
431
+ * four-DOF gaussian fit
432
+ *
433
+ * F(i, j) = A * exp( -((i - i0)^2 + (j - j0)^2) / sigma^2)
434
+ *
435
+ * p = [A i0 j0 sigma]
436
+ */
437
+ int gauss4_f(const gsl_vector *p, void *data, gsl_vector *res)
438
+ {
439
+ const int *N;
440
+ int ii, jj, xidx;
441
+ float i0, j0, A, s, i, j, ihat, jhat, F;
442
+ const float *f;
443
+
444
+ /* extract parameters */
445
+ N = ((pkdata*)data)->N;
446
+ f = ((pkdata*)data)->xcorr;
447
+ A = (float)gsl_vector_get(p, 0);
448
+ i0 = (float)gsl_vector_get(p, 1);
449
+ j0 = (float)gsl_vector_get(p, 2);
450
+ s = (float)gsl_vector_get(p, 3);
451
+
452
+ /* F(i, j) = A * exp( -((i - i0)^2 + (j - j0)^2) / s^2 ) */
453
+ for(ii = 0; ii < N[0]; ++ii)
454
+ {
455
+ i = (float)(ii - (N[0]-1)/2);
456
+ for(jj = 0; jj < N[1]; ++jj)
457
+ {
458
+ j = (float)(jj - (N[1]-1)/2);
459
+ xidx = ii*N[1] + jj;
460
+ ihat = (i-i0)/s;
461
+ jhat = (j-j0)/s;
462
+ F = A * expf( -ihat*ihat - jhat*jhat );
463
+ gsl_vector_set(res, xidx, F - f[xidx]);
464
+ }
465
+ }
466
+
467
+ return GSL_SUCCESS;
468
+ }
469
+
470
+ int gauss4_jac(const gsl_vector *p, void *data, gsl_matrix *jac)
471
+ {
472
+ const int *N;
473
+ int ii, jj, xidx;
474
+ float i0, j0, A, s, i, j, ihat, jhat, F;
475
+
476
+ /* extract parameters */
477
+ N = ((pkdata*)data)->N;
478
+ A = (float)gsl_vector_get(p, 0);
479
+ i0 = (float)gsl_vector_get(p, 1);
480
+ j0 = (float)gsl_vector_get(p, 2);
481
+ s = (float)gsl_vector_get(p, 3);
482
+
483
+ /* F(i, j) = A * exp( -((i - i0)^2 + (j - j0)^2) / (s*s))
484
+ * dF / dA = F / A
485
+ * dF / di0 = 2*F*(i - i0)/s^2
486
+ * dF / dj0 = 2*F*(j - j0)/s^2
487
+ * dF / ds = 2*((i - i0)^2 + (j - j0)^2)/s^3
488
+ */
489
+ for(ii = 0; ii < N[0]; ++ii)
490
+ {
491
+ i = (float)(ii - (N[0]-1)/2);
492
+ for(jj = 0; jj < N[1]; ++jj)
493
+ {
494
+ j = (float)(jj - (N[1]-1)/2);
495
+ xidx = ii*N[1] + jj;
496
+ ihat = (i-i0)/s;
497
+ jhat = (j-j0)/s;
498
+ F = A * expf( -ihat*ihat - jhat*jhat );
499
+
500
+ gsl_matrix_set(jac, xidx, 0, F / A); /* dF / dA */
501
+ gsl_matrix_set(jac, xidx, 1, 2*F*ihat/s); /* dF / di0 */
502
+ gsl_matrix_set(jac, xidx, 2, 2*F*jhat/s); /* dF / dj0 */
503
+ gsl_matrix_set(jac, xidx, 3, 2*F*(ihat*ihat+jhat*jhat)/s); /* dF / ds */
504
+ }
505
+ }
506
+
507
+ return GSL_SUCCESS;
508
+ }
509
+
510
+ int gauss4_fvv(const gsl_vector *p, const gsl_vector *v, void *data, gsl_vector *fvv)
511
+ {
512
+ const int *N;
513
+ int ii, jj, xidx;
514
+ float i0, j0, A, s, i, j, F, ss, ihat, jhat;
515
+ float vA, vi, vj, vs;
516
+ float DAi, DAj, DAs, Dii, Dij, Dis, Djj, Djs, Dss, D2v;
517
+ const float *f;
518
+
519
+ /* extract parameters */
520
+ N = ((pkdata*)data)->N;
521
+ A = (float)gsl_vector_get(p, 0);
522
+ i0 = (float)gsl_vector_get(p, 1);
523
+ j0 = (float)gsl_vector_get(p, 2);
524
+ s = (float)gsl_vector_get(p, 3);
525
+ /* velocity */
526
+ vA = (float)gsl_vector_get(v, 0);
527
+ vi = (float)gsl_vector_get(v, 1);
528
+ vj = (float)gsl_vector_get(v, 2);
529
+ vs = (float)gsl_vector_get(v, 3);
530
+
531
+ /* F(i, j) = A * exp( -((i - i0)^2 + (j - j0)^2) / s^2 ) */
532
+ for(ii = 0; ii < N[0]; ++ii)
533
+ {
534
+ i = (float)(ii - (N[0]-1)/2);
535
+ for(jj = 0; jj < N[1]; ++jj)
536
+ {
537
+ j = (float)(jj - (N[1]-1)/2);
538
+ xidx = ii*N[1] + jj;
539
+
540
+ /* calculate second derivatives */
541
+ ihat = (i - i0)/s;
542
+ jhat = (j - j0)/s;
543
+
544
+
545
+ DAi = 2.0*ihat/(s*A);
546
+ DAj = 2.0*jhat/(s*A);
547
+ DAs = 2.0*(ihat*ihat + jhat*jhat)/(s*A);
548
+ Dii = 2.0*(ihat*ihat - 1.0)/(s*s);
549
+ Dij = 4.0*ihat*jhat/(s*s);
550
+ Dis = 4.0*ihat*(ihat*ihat + jhat*jhat - 1.0)/(s*s);
551
+ Djj = 2.0*(jhat*jhat - 1.0);
552
+ Djs = 4.0*jhat*(ihat*ihat + jhat*jhat - 1.0)/(s*s);
553
+ Dss = 4.0*(ihat*ihat + jhat*jhat)*(ihat*ihat + jhat*jhat - 1.5)/(s*s);
554
+
555
+ F = A * expf(-ihat*ihat - jhat*jhat);
556
+ D2v = F*(0 + 2*DAi*vA*vi + 2*DAj*vA*vj + 2*DAs*vA*vs
557
+ + Dii*vi*vi + 2*Dij*vi*vj + 2*Dis*vi*vs
558
+ + Djj*vj*vj + 2*Djs*vj*vs + Dss*vs*vs);
559
+
560
+ gsl_vector_set(fvv, xidx, D2v);
561
+ }
562
+ }
563
+
564
+ return GSL_SUCCESS;
565
+ }
566
+
567
+ /********
568
+ * gauss5 and gauss5jac
569
+ * five-DOF gaussian fit
570
+ *
571
+ * F(i, j) = A * exp( -(i - i0)^2*sxx - (j - j0)^2*syy)
572
+ *
573
+ * p = [A i0 j0 sxx syy]
574
+ * (sxx = 1/sigma_x^2)
575
+ */
576
+ int gauss5_f(const gsl_vector *p, void *data, gsl_vector *res)
577
+ {
578
+ const int *N;
579
+ int ii, jj, xidx;
580
+ float i0, j0, A, sx, sy, i, j, ihat, jhat, F;
581
+ const float *f;
582
+
583
+ /* extract parameters */
584
+ N = ((pkdata*)data)->N;
585
+ f = ((pkdata*)data)->xcorr;
586
+ A = (float)gsl_vector_get(p, 0);
587
+ i0 = (float)gsl_vector_get(p, 1);
588
+ j0 = (float)gsl_vector_get(p, 2);
589
+ sx = (float)gsl_vector_get(p, 3);
590
+ sy = (float)gsl_vector_get(p, 4);
591
+
592
+ /* F(i, j) = A * exp( -(i - i0)^2/sx^2 - (j - j0)^2/sy^2) */
593
+ for(ii = 0; ii < N[0]; ++ii)
594
+ {
595
+ i = (float)(ii - (N[0]-1)/2);
596
+ for(jj = 0; jj < N[1]; ++jj)
597
+ {
598
+ j = (float)(jj - (N[1]-1)/2);
599
+ xidx = ii*N[1] + jj;
600
+ ihat = (i-i0)/sx;
601
+ jhat = (j-j0)/sy;
602
+ F = A * expf( -ihat*ihat - jhat*jhat );
603
+ gsl_vector_set(res, xidx, F - f[xidx]);
604
+ }
605
+ }
606
+
607
+ return GSL_SUCCESS;
608
+ }
609
+
610
+ int gauss5_jac(const gsl_vector *p, void *data, gsl_matrix *jac)
611
+ {
612
+ const int *N;
613
+ int ii, jj, xidx;
614
+ float i0, j0, A, sx, sy, i, j, ihat, jhat, F;
615
+
616
+ /* extract parameters */
617
+ N = ((pkdata*)data)->N;
618
+ A = (float)gsl_vector_get(p, 0);
619
+ i0 = (float)gsl_vector_get(p, 1);
620
+ j0 = (float)gsl_vector_get(p, 2);
621
+ sx = (float)gsl_vector_get(p, 3);
622
+ sy = (float)gsl_vector_get(p, 4);
623
+
624
+ /* F(i, j) = A * exp( -(i - i0)^2*sxx - (j - j0)^2*syy)
625
+ * dF / dA = F / A
626
+ * dF / di0 = 2*F*(i - i0)/sx^2
627
+ * dF / dj0 = 2*F*(j - j0)/sy^2
628
+ * dF / dsx = 2*F*(i - i0)^2/sx^3
629
+ * dF / dsy = 2*F*(j - j0)^2/sy^3
630
+ */
631
+ for(ii = 0; ii < N[0]; ++ii)
632
+ {
633
+ i = (float)(ii - (N[0]-1)/2);
634
+ for(jj = 0; jj < N[1]; ++jj)
635
+ {
636
+ j = (float)(jj - (N[1]-1)/2);
637
+ xidx = ii*N[1] + jj;
638
+ ihat = (i-i0)/sx;
639
+ jhat = (j-j0)/sy;
640
+ F = A * expf( -ihat*ihat - jhat*jhat );
641
+
642
+ gsl_matrix_set(jac, xidx, 0, F / A); /* dF / dA */
643
+ gsl_matrix_set(jac, xidx, 1, 2*F*ihat/sx); /* dF / di0 */
644
+ gsl_matrix_set(jac, xidx, 2, 2*F*jhat/sy); /* dF / dj0 */
645
+ gsl_matrix_set(jac, xidx, 3, 2*F*ihat*ihat/sx); /* dF / dsx */
646
+ gsl_matrix_set(jac, xidx, 4, 2*F*jhat*jhat/sy); /* dF / dsy */
647
+ }
648
+ }
649
+
650
+ return GSL_SUCCESS;
651
+ }
652
+
653
+
654
+ /********
655
+ * gauss6 and gauss6jac
656
+ * six-DOF gaussian fit
657
+ *
658
+ * F(i, j) = A * exp( -(i - i0)*(i - i0)/sx^2 -(j - j0)*(j - j0)/sy^2
659
+ * -(i - i0)*(j - j0)*sxy)
660
+ *
661
+ * p = [A i0 j0 sxx syy sxy]
662
+ * (sxx = 1/sigma_x^2 etc.)
663
+ */
664
+ int gauss6_f(const gsl_vector *p, void *data, gsl_vector *res)
665
+ {
666
+ const int *N;
667
+ int ii, jj, xidx;
668
+ float i0, j0, A, sx, sy, sxy, i, j, F;
669
+ const float *f;
670
+
671
+ /* extract parameters */
672
+ N = ((pkdata*)data)->N;
673
+ f = ((pkdata*)data)->xcorr;
674
+ A = (float)gsl_vector_get(p, 0);
675
+ i0 = (float)gsl_vector_get(p, 1);
676
+ j0 = (float)gsl_vector_get(p, 2);
677
+ sx = (float)gsl_vector_get(p, 3);
678
+ sy = (float)gsl_vector_get(p, 4);
679
+ sxy = (float)gsl_vector_get(p, 5);
680
+
681
+ /* F(i, j) =A*exp(-0.5*((((j-xbar)^2*sy)-(2*(j-xbar)*(i-ybar)*sxy)+(i-ybar)^2*sx))/(sx*sy-sxy^2));
682
+ */
683
+ for(ii = 0; ii < N[0]; ++ii)
684
+ {
685
+ i = (float)(ii - (N[0]-1)/2); /* goes from -N/2 to N/2 */
686
+ for(jj = 0; jj < N[1]; ++jj)
687
+ {
688
+ j = (float)(jj - (N[1]-1)/2);
689
+ xidx = ii*N[1] + jj;
690
+ F = A * expf(0.5*( -(i-i0)*(i-i0)/(sx)
691
+ -(j-j0)*(j-j0)/(sy)
692
+ -2*(i-i0)*(j-j0)* sxy));
693
+ gsl_vector_set(res, xidx, F - f[xidx]);
694
+ }
695
+ }
696
+
697
+ return GSL_SUCCESS;
698
+ }
699
+
700
+ int gauss6_jac(const gsl_vector *p, void *data, gsl_matrix *jac)
701
+ {
702
+ const int *N;
703
+ int ii, jj, xidx;
704
+ float i0, j0, A, sx, sy, sxy, i, j, F, ihat, jhat;
705
+
706
+ /* extract parameters */
707
+ N = ((pkdata*)data)->N;
708
+ A = (float)gsl_vector_get(p, 0);
709
+ i0 = (float)gsl_vector_get(p, 1);
710
+ j0 = (float)gsl_vector_get(p, 2);
711
+ sx = (float)gsl_vector_get(p, 3);
712
+ sy = (float)gsl_vector_get(p, 4);
713
+ sxy = (float)gsl_vector_get(p, 5);
714
+
715
+ for(ii = 0; ii < N[0]; ++ii)
716
+ {
717
+ i = (float)(ii - (N[0]-1)/2);
718
+ for(jj = 0; jj < N[1]; ++jj)
719
+ {
720
+ j = (float)(jj - (N[1]-1)/2);
721
+ xidx = ii*N[1] + jj;
722
+ F = A * expf(0.5*( -(i-i0)*(i-i0)/(sx)
723
+ -(j-j0)*(j-j0)/(sy)
724
+ -2*(i-i0)*(j-j0)* sxy));
725
+
726
+ gsl_matrix_set(jac, xidx, 0, F / A); /* dF / dA */
727
+ gsl_matrix_set(jac, xidx, 1, -(F*(i0 + (j0 - j) * sx * sxy - i))/(sx)); /* dF / di0 */
728
+ gsl_matrix_set(jac, xidx, 2, -(F*(j0 + (i0 - i) * sy * sxy - j))/(sy)); /* dF / dj0 */
729
+ gsl_matrix_set(jac, xidx, 3, (F*(i-i0)*(i-i0))/(2*sx*sx)); /* dF / dsx */
730
+ gsl_matrix_set(jac, xidx, 4, (F*(j-j0)*(j-j0))/(2*sy*sy)); /* dF / dsy */
731
+ gsl_matrix_set(jac, xidx, 5, -(i-i0)*(j-j0)*F); /* dF / dsxy */
732
+ }
733
+ }
734
+
735
+ return GSL_SUCCESS;
736
+ }