pyvale 2025.5.3__cp311-cp311-macosx_14_0_arm64.whl → 2025.7.0__cp311-cp311-macosx_14_0_arm64.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.

Potentially problematic release.


This version of pyvale might be problematic. Click here for more details.

Files changed (95) hide show
  1. pyvale/.dylibs/libomp.dylib +0 -0
  2. pyvale/.dylibs/libunwind.1.0.dylib +0 -0
  3. pyvale/__init__.py +12 -0
  4. pyvale/blendercalibrationdata.py +3 -1
  5. pyvale/blenderscene.py +7 -5
  6. pyvale/blendertools.py +27 -5
  7. pyvale/camera.py +1 -0
  8. pyvale/cameradata.py +3 -0
  9. pyvale/camerasensor.py +147 -0
  10. pyvale/camerastereo.py +4 -4
  11. pyvale/cameratools.py +23 -61
  12. pyvale/cython/rastercyth.c +1657 -1352
  13. pyvale/cython/rastercyth.cpython-311-darwin.so +0 -0
  14. pyvale/cython/rastercyth.py +71 -26
  15. pyvale/data/plate_hole_def0000.tiff +0 -0
  16. pyvale/data/plate_hole_def0001.tiff +0 -0
  17. pyvale/data/plate_hole_ref0000.tiff +0 -0
  18. pyvale/data/plate_rigid_def0000.tiff +0 -0
  19. pyvale/data/plate_rigid_def0001.tiff +0 -0
  20. pyvale/data/plate_rigid_ref0000.tiff +0 -0
  21. pyvale/dataset.py +96 -6
  22. pyvale/dic/cpp/dicbruteforce.cpp +370 -0
  23. pyvale/dic/cpp/dicfourier.cpp +648 -0
  24. pyvale/dic/cpp/dicinterpolator.cpp +559 -0
  25. pyvale/dic/cpp/dicmain.cpp +215 -0
  26. pyvale/dic/cpp/dicoptimizer.cpp +675 -0
  27. pyvale/dic/cpp/dicrg.cpp +137 -0
  28. pyvale/dic/cpp/dicscanmethod.cpp +677 -0
  29. pyvale/dic/cpp/dicsmooth.cpp +138 -0
  30. pyvale/dic/cpp/dicstrain.cpp +383 -0
  31. pyvale/dic/cpp/dicutil.cpp +563 -0
  32. pyvale/dic2d.py +164 -0
  33. pyvale/dic2dcpp.cpython-311-darwin.so +0 -0
  34. pyvale/dicchecks.py +476 -0
  35. pyvale/dicdataimport.py +247 -0
  36. pyvale/dicregionofinterest.py +887 -0
  37. pyvale/dicresults.py +55 -0
  38. pyvale/dicspecklegenerator.py +238 -0
  39. pyvale/dicspecklequality.py +305 -0
  40. pyvale/dicstrain.py +387 -0
  41. pyvale/dicstrainresults.py +37 -0
  42. pyvale/errorintegrator.py +10 -8
  43. pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +124 -113
  44. pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +124 -132
  45. pyvale/examples/basics/ex1_3_customsens_therm3d.py +199 -195
  46. pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +125 -121
  47. pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +145 -141
  48. pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +96 -101
  49. pyvale/examples/basics/ex1_7_spatavg_therm2d.py +109 -105
  50. pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +92 -91
  51. pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +96 -90
  52. pyvale/examples/basics/ex2_3_sensangle_disp2d.py +88 -89
  53. pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +172 -171
  54. pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +88 -86
  55. pyvale/examples/basics/ex3_1_basictensors_strain2d.py +90 -90
  56. pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +93 -91
  57. pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +172 -160
  58. pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +154 -148
  59. pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +249 -231
  60. pyvale/examples/dic/ex1_region_of_interest.py +98 -0
  61. pyvale/examples/dic/ex2_plate_with_hole.py +149 -0
  62. pyvale/examples/dic/ex3_plate_with_hole_strain.py +93 -0
  63. pyvale/examples/dic/ex4_dic_blender.py +95 -0
  64. pyvale/examples/dic/ex5_dic_challenge.py +102 -0
  65. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +4 -2
  66. pyvale/examples/renderblender/ex1_1_blenderscene.py +152 -105
  67. pyvale/examples/renderblender/ex1_2_blenderdeformed.py +151 -100
  68. pyvale/examples/renderblender/ex2_1_stereoscene.py +183 -116
  69. pyvale/examples/renderblender/ex2_2_stereodeformed.py +185 -112
  70. pyvale/examples/renderblender/ex3_1_blendercalibration.py +164 -109
  71. pyvale/examples/renderrasterisation/ex_rastenp.py +74 -35
  72. pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +6 -13
  73. pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +2 -2
  74. pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +2 -4
  75. pyvale/imagedef2d.py +3 -2
  76. pyvale/imagetools.py +137 -0
  77. pyvale/rastercy.py +34 -4
  78. pyvale/rasternp.py +300 -276
  79. pyvale/rasteropts.py +58 -0
  80. pyvale/renderer.py +47 -0
  81. pyvale/rendermesh.py +52 -62
  82. pyvale/renderscene.py +51 -0
  83. pyvale/sensorarrayfactory.py +2 -2
  84. pyvale/sensortools.py +19 -35
  85. pyvale/simcases/case21.i +1 -1
  86. pyvale/simcases/run_1case.py +8 -0
  87. pyvale/simtools.py +2 -2
  88. pyvale/visualsimplotter.py +180 -0
  89. {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/METADATA +11 -57
  90. {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/RECORD +93 -57
  91. {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/WHEEL +1 -1
  92. pyvale/examples/visualisation/ex1_1_plot_traces.py +0 -102
  93. pyvale/examples/visualisation/ex2_1_animate_sim.py +0 -89
  94. {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/licenses/LICENSE +0 -0
  95. {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,138 @@
1
+ // ================================================================================
2
+ // pyvale: the python validation engine
3
+ // License: MIT
4
+ // Copyright (C) 2025 The Computer Aided Validation Team
5
+ // ================================================================================
6
+
7
+ // STD library Header files
8
+ #include <vector>
9
+
10
+ // Program Header files
11
+ #include "./dicsmooth.hpp"
12
+ #include "./defines.hpp"
13
+ #include "./Eigen/Dense"
14
+
15
+ namespace smooth {
16
+
17
+ // bilinear lagrange polynomials
18
+ Eigen::VectorXd q4(std::vector<int> &x, std::vector<int> &y,
19
+ std::vector<double>& disp_vals){
20
+
21
+ Eigen::MatrixXd A(disp_vals.size(), 4);
22
+ Eigen::VectorXd b(disp_vals.size());
23
+
24
+ for (size_t i = 0; i < x.size(); ++i) {
25
+ double ss_x = x[i];
26
+ double ss_y = y[i];
27
+ A(i, 0) = 1.0;
28
+ A(i, 1) = ss_x;
29
+ A(i, 2) = ss_y;
30
+ A(i, 3) = ss_x * ss_y;
31
+ b(i) = disp_vals[i];
32
+ }
33
+
34
+ // solve linear system A * coeffs = b
35
+ Eigen::VectorXd coeffs = (A.transpose() * A).ldlt().solve(A.transpose() * b);
36
+ return coeffs;
37
+ }
38
+
39
+ // biquadratic lagrange polynomials
40
+ Eigen::VectorXd q9(std::vector<int>& x, std::vector<int>& y,
41
+ std::vector<double>& disp_vals) {
42
+
43
+ Eigen::MatrixXd A(disp_vals.size(), 9);
44
+ Eigen::VectorXd b(disp_vals.size());
45
+
46
+ for (size_t i = 0; i < x.size(); ++i) {
47
+ double ss_x = x[i];
48
+ double ss_y = y[i];
49
+ A(i, 0) = 1.0;
50
+ A(i, 1) = ss_x;
51
+ A(i, 2) = ss_y;
52
+ A(i, 3) = ss_x * ss_y;
53
+ A(i, 4) = ss_x * ss_x;
54
+ A(i, 5) = ss_y * ss_y;
55
+ A(i, 6) = ss_x * ss_x * ss_y;
56
+ A(i, 7) = ss_x * ss_y * ss_y;
57
+ A(i, 8) = ss_x * ss_x * ss_y * ss_y;
58
+
59
+ b(i) = disp_vals[i];
60
+ }
61
+
62
+ Eigen::VectorXd coeffs = (A.transpose() * A).ldlt().solve(A.transpose() * b);
63
+ return coeffs;
64
+ }
65
+
66
+
67
+ // 2D Gaussian kernel with a given radius and sigma
68
+ std::vector<std::vector<double>> make_gaussian_kernel(int radius, double sigma) {
69
+ std::vector<std::vector<double>> kernel(2 * radius + 1, std::vector<double>(2 * radius + 1));
70
+ double sum = 0.0;
71
+
72
+ for (int y = -radius; y <= radius; ++y) {
73
+ for (int x = -radius; x <= radius; ++x) {
74
+ double value = std::exp(-(x * x + y * y) / (2.0 * sigma * sigma));
75
+ kernel[y + radius][x + radius] = value;
76
+ sum += value;
77
+ }
78
+ }
79
+
80
+ // Normalize the kernel
81
+ for (int y = 0; y < 2 * radius + 1; ++y) {
82
+ for (int x = 0; x < 2 * radius + 1; ++x) {
83
+ kernel[y][x] /= sum;
84
+ }
85
+ }
86
+
87
+ return kernel;
88
+ }
89
+
90
+ // Reflect index at boundaries (mirrored edges)
91
+ int mirror_index(int idx, int max) {
92
+ if (idx < 0) return -idx;
93
+ if (idx >= max) return 2 * max - idx - 2;
94
+ return idx;
95
+ }
96
+
97
+ void gaussian_2d(std::vector<double>& data,
98
+ const std::vector<int>& mask,
99
+ int width, int height, double sigma) {
100
+
101
+ int radius = static_cast<int>(std::ceil(3.0 * sigma));
102
+ std::vector<std::vector<double>> kernel = make_gaussian_kernel(radius, sigma);
103
+
104
+ std::vector<double> result(data.size(), 0.0);
105
+
106
+ for (int y = 0; y < height; ++y) {
107
+ for (int x = 0; x < width; ++x) {
108
+
109
+ int idx = y * width + x;
110
+ if (mask[idx]==-1) continue;
111
+
112
+ double weighted_sum = 0.0;
113
+ double weight_total = 0.0;
114
+
115
+ for (int ky = -radius; ky <= radius; ++ky) {
116
+ for (int kx = -radius; kx <= radius; ++kx) {
117
+ int nx = mirror_index(x + kx, width);
118
+ int ny = mirror_index(y + ky, height);
119
+ int nidx = ny * width + nx;
120
+
121
+ if (mask[nidx]!=-1) {
122
+ double weight = kernel[ky + radius][kx + radius];
123
+ weighted_sum += data[nidx] * weight;
124
+ weight_total += weight;
125
+ }
126
+ }
127
+ }
128
+
129
+ if (weight_total > 0.0) {
130
+ result[idx] = weighted_sum / weight_total;
131
+ }
132
+ }
133
+ }
134
+
135
+ data = result;
136
+ }
137
+
138
+ }
@@ -0,0 +1,383 @@
1
+ // ================================================================================
2
+ // pyvale: the python validation engine
3
+ // License: MIT
4
+ // Copyright (C) 2025 The Computer Aided Validation Team
5
+ // ================================================================================
6
+
7
+ // STD library Header files
8
+ #include <cmath>
9
+ #include <vector>
10
+ #include <iostream>
11
+ #include <iomanip>
12
+ #include <fstream>
13
+
14
+ // Program Header files
15
+ #include "./dicsmooth.hpp"
16
+ #include "./dicstrain.hpp"
17
+ #include "./defines.hpp"
18
+ #include "./Eigen/Dense"
19
+ #include "./dicutil.hpp"
20
+
21
+ // pybind header files
22
+ #include <pybind11/pybind11.h>
23
+ #include <pybind11/numpy.h>
24
+
25
+ namespace py = pybind11;
26
+
27
+ namespace strain {
28
+
29
+ Eigen::Matrix2d I = Eigen::Matrix2d::Identity();
30
+
31
+ void engine(const py::array_t<int> &ss_x_arr,
32
+ const py::array_t<int> &ss_y_arr,
33
+ const py::array_t<double> &u_arr,
34
+ const py::array_t<double> &v_arr,
35
+ const int nss_x, const int nss_y,
36
+ const int nimg, const int sw_size,
37
+ const int q, const std::string &form,
38
+ const std::vector<std::string> &filenames,
39
+ const util::SaveConfig &strain_save_conf){
40
+
41
+ TITLE("Strain Config");
42
+ INFO_OUT("Number of Images:", nimg)
43
+ INFO_OUT("Strain window size:", sw_size)
44
+ INFO_OUT("Strain element (4 = bilinear, 9 is biquadratic):", q);
45
+ INFO_OUT("Strain formulation:", form);
46
+ INFO_OUT("Saving data to folder:", strain_save_conf.basepath)
47
+ INFO_OUT("Saving data as binary ", strain_save_conf.binary)
48
+
49
+
50
+ const bool save_at_end = strain_save_conf.at_end;
51
+ const int nwindows = nss_x*nss_y;
52
+
53
+ // get raw pointers for numpy arrays
54
+ int* ss_x = static_cast<int*>(ss_x_arr.request().ptr);
55
+ int* ss_y = static_cast<int*>(ss_y_arr.request().ptr);
56
+ double* u = static_cast<double*>(u_arr.request().ptr);
57
+ double* v = static_cast<double*>(v_arr.request().ptr);
58
+
59
+ // function wrapper for bilinear or biquadratic element
60
+ std::function<Eigen::VectorXd(std::vector<int>&, std::vector<int>&, std::vector<double>&)> smooth_window = (q == 4) ? smooth::q4 : smooth::q9;
61
+
62
+
63
+ strain::Window window(sw_size);
64
+ strain::Results results(save_at_end ? nimg * nwindows : nwindows);
65
+
66
+
67
+ TITLE("Deformation Gradient and Strain Calculation")
68
+
69
+ // loop over the displacement images
70
+ for (int img_num = 0; img_num < nimg; img_num++) {
71
+
72
+ indicators::ProgressBar bar;
73
+ util::create_progress_bar(bar, filenames, img_num, nwindows);
74
+ std::atomic<int> prev_pct = 0;
75
+
76
+ // loop over strain windows within the image
77
+ for (int sw = 0; sw < nwindows; sw++){
78
+
79
+ int x0 = ss_x[sw];
80
+ int y0 = ss_y[sw];
81
+ results.x[sw] = x0;
82
+ results.y[sw] = y0;
83
+
84
+ results.valid_window[sw] = fill_window(ss_x, ss_y, u, v, img_num,
85
+ sw, window, nss_x,
86
+ nss_y, sw_size);
87
+
88
+ // element coefficients
89
+ Eigen::VectorXd uc;
90
+ Eigen::VectorXd vc;
91
+
92
+ // 2D deformation gradient matrix and identity matrix
93
+ Eigen::Matrix2d deform_grad = Eigen::Matrix2d::Zero();
94
+ Eigen::Matrix2d eps = Eigen::Matrix2d::Zero();
95
+
96
+ if (results.valid_window[sw]){
97
+ uc = smooth_window(window.x, window.y, window.u);
98
+ vc = smooth_window(window.x, window.y, window.v);
99
+ deform_grad = compute_def_grad(q, uc, vc, x0, y0);
100
+ eps = compute_strain(form, deform_grad);
101
+ append_results(sw, results, save_at_end, x0, y0,
102
+ deform_grad, eps, nwindows, img_num);
103
+ }
104
+
105
+ util::update_progress_bar(bar, sw, nwindows, prev_pct);
106
+
107
+ }
108
+
109
+
110
+ // finish up progress bar
111
+ bar.mark_as_completed();
112
+ indicators::show_console_cursor(true);
113
+
114
+ if (!save_at_end){
115
+ strain::save_to_disk(img_num, results, strain_save_conf,
116
+ nwindows, nimg, filenames);
117
+ }
118
+ }
119
+
120
+ if (save_at_end){
121
+ for (int img_num = 0; img_num < nimg; img_num++)
122
+ strain::save_to_disk(img_num, results, strain_save_conf,
123
+ nwindows, nimg, filenames);
124
+ }
125
+ }
126
+
127
+
128
+
129
+ bool fill_window(int *ss_x, int *ss_y, double *u, double *v,
130
+ int img, int sw, Window &window,
131
+ int nss_x, int nss_y, int sw_size){
132
+
133
+ const int swr = sw_size / 2;
134
+ const int x0_idx = sw % nss_x;
135
+ const int y0_idx = sw / nss_x;
136
+ const int xmin = x0_idx - swr;
137
+ const int xmax = x0_idx + swr;
138
+ const int ymin = y0_idx - swr;
139
+ const int ymax = y0_idx + swr;
140
+
141
+ // check centre of strain window is within mask bounds
142
+ if ((xmin < 0) || (xmax >= nss_x) || (ymin < 0) || (ymax >= nss_y)) return false;
143
+
144
+ int widx = 0;
145
+ for (int j = ymin; j <= ymax; j++){
146
+ for (int i = xmin; i <= xmax; i++){
147
+
148
+ // index in 3d results array
149
+ int idx_2d = nss_x*j + i;
150
+ int idx_3d = nss_x*nss_y*img + idx_2d;
151
+
152
+ // check if all subsets in the strain window are not nan
153
+ if (std::isnan(u[idx_3d]) || std::isnan(v[idx_3d])) return false;
154
+
155
+ // populate subset window
156
+ window.x[widx] = ss_x[idx_2d];
157
+ window.y[widx] = ss_y[idx_2d];
158
+ window.u[widx] = u[idx_3d];
159
+ window.v[widx] = v[idx_3d];
160
+
161
+ //std::cout << window.x[idx] << " " << window.y[idx] << " ";
162
+ //std::cout << window.u[idx] << " " << window.v[idx] << std::endl;
163
+ widx++;
164
+ }
165
+ }
166
+ return true;
167
+ }
168
+
169
+
170
+ Eigen::Matrix2d compute_def_grad(const int q, const Eigen::VectorXd &uc,
171
+ const Eigen::VectorXd& vc, const double x0,
172
+ const double y0) {
173
+
174
+ Eigen::Matrix2d grad;
175
+
176
+ if (q == 4) {
177
+ grad(0,0) = 1.0 + uc[1] + uc[3]*y0;
178
+ grad(0,1) = uc[2] + uc[3]*x0;
179
+ grad(1,0) = vc[1] + vc[3]*y0;
180
+ grad(1,1) = 1.0 + vc[2] + vc[3]*x0;
181
+ }
182
+ else if (q == 9) {
183
+ grad(0,0) = 1.0 + uc[1] + uc[3]*y0 + 2.0*uc[4]*x0 + 2.0*uc[6]*x0*y0 + uc[7]*y0*y0 + 2.0*uc[8]*x0*y0*y0;
184
+ grad(0,1) = uc[2] + uc[3]*x0 + 2.0*uc[5]*y0 + uc[6]*x0*x0 + 2.0*uc[7]*x0*y0 + 2.0*uc[8]*x0*x0*y0;
185
+ grad(1,0) = vc[1] + vc[3]*y0 + 2.0*vc[4]*x0 + 2.0*vc[6]*x0*y0 + vc[7]*y0*y0 + 2.0*vc[8]*x0*y0*y0;
186
+ grad(1,1) = 1.0 + vc[2] + vc[3]*x0 + 2.0*vc[5]*y0 + vc[6]*x0*x0 + 2.0*vc[7]*x0*y0 + 2.0*vc[8]*x0*x0*y0;
187
+ }
188
+
189
+ return grad;
190
+ }
191
+
192
+ Eigen::Matrix2d compute_strain(const std::string& form, const Eigen::Matrix2d& deform_grad) {
193
+ if (form == "GREEN") return green(deform_grad);
194
+ else if (form == "ALMANSI") return almansi(deform_grad);
195
+ else if (form == "HENCKY") return hencky(deform_grad);
196
+ else if (form == "BIOT_EULER") return biot_euler(deform_grad);
197
+ else if (form == "BIOT_LAGRANGE") return biot_lagrange(deform_grad);
198
+
199
+ std::cerr << "Unknown Strain formulation: '" << form << "'." << std::endl;
200
+ return Eigen::Matrix2d::Zero();
201
+ }
202
+
203
+
204
+ inline Eigen::Matrix2d green(Eigen::Matrix2d F){
205
+ return 0.5 * (F.transpose() * F - I);
206
+ }
207
+
208
+
209
+
210
+
211
+
212
+ inline Eigen::Matrix2d hencky(Eigen::Matrix2d F){
213
+ Eigen::Matrix2d C = F.transpose() * F;
214
+
215
+ Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> solver(C);
216
+ if (solver.info() != Eigen::Success)
217
+ throw std::runtime_error("Eigen decomposition failed.");
218
+
219
+ // Get eigenvectors and sqrt-eigenvalues
220
+ const Eigen::Matrix2d Q = solver.eigenvectors();
221
+ const Eigen::Vector2d eigvals = solver.eigenvalues();
222
+
223
+ return Q * (0.5 * eigvals.array().log().matrix().asDiagonal()) * Q.transpose();
224
+ }
225
+
226
+
227
+
228
+
229
+ inline Eigen::Matrix2d almansi(Eigen::Matrix2d F){
230
+ Eigen::Matrix2d B = F * F.transpose();
231
+ Eigen::Matrix2d B_inv = B.inverse();
232
+ return 0.5 * (I - B_inv);
233
+ }
234
+
235
+
236
+
237
+
238
+
239
+ inline Eigen::Matrix2d biot_euler(Eigen::Matrix2d F){
240
+
241
+ Eigen::Matrix2d C = F * F.transpose();
242
+
243
+ Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> solver(C);
244
+ if (solver.info() != Eigen::Success)
245
+ throw std::runtime_error("Eigen decomposition failed.");
246
+
247
+ // U = sqrt(C) = Q * sqrt(D) * Q^T
248
+ Eigen::Matrix2d D_sqrt = solver.eigenvalues().cwiseSqrt().asDiagonal();
249
+ Eigen::Matrix2d U = solver.eigenvectors() * D_sqrt * solver.eigenvectors().transpose();
250
+
251
+ return U - I;
252
+
253
+ }
254
+
255
+
256
+
257
+
258
+ inline Eigen::Matrix2d biot_lagrange(Eigen::Matrix2d F){
259
+
260
+ Eigen::Matrix2d C = F.transpose() * F;
261
+
262
+ Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> solver(C);
263
+ if (solver.info() != Eigen::Success)
264
+ throw std::runtime_error("Eigen decomposition failed.");
265
+
266
+ // U = sqrt(C) = Q * sqrt(D) * Q^T
267
+ Eigen::Matrix2d D_sqrt = solver.eigenvalues().cwiseSqrt().asDiagonal();
268
+ Eigen::Matrix2d U = solver.eigenvectors() * D_sqrt * solver.eigenvectors().transpose();
269
+
270
+ return U - I;
271
+
272
+ }
273
+
274
+
275
+ void append_results(int sw, strain::Results &results,
276
+ const bool save_at_end, const int x0, const int y0,
277
+ const Eigen::Matrix2d &deform_grad,
278
+ const Eigen::Matrix2d &eps,
279
+ const int nwindows, const int img){
280
+
281
+ // index in results arrays depending on whether saving at end or on a per image basis
282
+ int idx;
283
+ if (save_at_end) idx = nwindows * img + sw;
284
+ else idx = sw;
285
+
286
+ results.def_grad[4*idx+0] = deform_grad(0,0);
287
+ results.def_grad[4*idx+1] = deform_grad(0,1);
288
+ results.def_grad[4*idx+2] = deform_grad(1,0);
289
+ results.def_grad[4*idx+3] = deform_grad(1,1);
290
+ results.strain[4*idx+0] = eps(0,0);
291
+ results.strain[4*idx+1] = eps(0,1);
292
+ results.strain[4*idx+2] = eps(1,0);
293
+ results.strain[4*idx+3] = eps(1,1);
294
+ }
295
+
296
+ void save_to_disk(int img_num, const strain::Results &results,
297
+ const util::SaveConfig &strain_save_conf,
298
+ const int nwindows, const int nimg,
299
+ const std::vector<std::string> filenames){
300
+
301
+ const std::string delimiter = strain_save_conf.delimiter;
302
+
303
+ // open the file
304
+ std::stringstream outfile_str;
305
+ std::ofstream outfile;
306
+
307
+
308
+ // file extension
309
+ std::string file_ext;
310
+ if (strain_save_conf.binary) file_ext=".dic2d";
311
+ else file_ext=".csv";
312
+
313
+ // Extract the base filename without extension
314
+ std::string full_filename = filenames[img_num];
315
+ size_t dot_pos = full_filename.find(".");
316
+ if (dot_pos != std::string::npos) {
317
+ full_filename = full_filename.substr(0, dot_pos);
318
+ }
319
+
320
+ // output filename
321
+ outfile_str << strain_save_conf.basepath << "/" <<
322
+ strain_save_conf.prefix << full_filename << file_ext;
323
+
324
+ // set the img var to 0 after opening file if not saving at end
325
+ if (!strain_save_conf.at_end) img_num = 0;
326
+
327
+ // save in binary format
328
+ if (strain_save_conf.binary){
329
+ outfile.open(outfile_str.str(), std::ios::binary);
330
+
331
+ for (int i = 0; i < nwindows; ++i) {
332
+ int idx = img_num * nwindows + i;
333
+ util::write_int(outfile, results.x[idx]);
334
+ util::write_int(outfile, results.y[idx]);
335
+ util::write_dbl(outfile, results.def_grad[4*idx+0]);
336
+ util::write_dbl(outfile, results.def_grad[4*idx+1]);
337
+ util::write_dbl(outfile, results.def_grad[4*idx+2]);
338
+ util::write_dbl(outfile, results.def_grad[4*idx+3]);
339
+ util::write_dbl(outfile, results.strain[4*idx+0]);
340
+ util::write_dbl(outfile, results.strain[4*idx+1]);
341
+ util::write_dbl(outfile, results.strain[4*idx+2]);
342
+ util::write_dbl(outfile, results.strain[4*idx+3]);
343
+ }
344
+
345
+ outfile.close();
346
+ }
347
+ else {
348
+ outfile.open(outfile_str.str());
349
+
350
+ // column headers
351
+ outfile << "window_x" << delimiter;
352
+ outfile << "window_y" << delimiter;
353
+ outfile << "def_grad_00" << delimiter;
354
+ outfile << "def_grad_01" << delimiter;
355
+ outfile << "def_grad_10" << delimiter;
356
+ outfile << "def_grad_11" << delimiter;
357
+ outfile << "eps_00" << delimiter;
358
+ outfile << "eps_01" << delimiter;
359
+ outfile << "eps_10" << delimiter;
360
+ outfile << "eps_11\n";
361
+
362
+ for (int i = 0; i < nwindows; i++) {
363
+ int idx = img_num * nwindows + i;
364
+ if (results.valid_window[idx]) {
365
+ outfile << results.x[idx] << delimiter;
366
+ outfile << results.y[idx] << delimiter;
367
+ outfile << results.def_grad[4*idx+0] << delimiter;
368
+ outfile << results.def_grad[4*idx+1] << delimiter;
369
+ outfile << results.def_grad[4*idx+2] << delimiter;
370
+ outfile << results.def_grad[4*idx+3] << delimiter;
371
+ outfile << results.strain[4*idx+0] << delimiter;
372
+ outfile << results.strain[4*idx+1] << delimiter;
373
+ outfile << results.strain[4*idx+2] << delimiter;
374
+ outfile << results.strain[4*idx+3] << "\n";
375
+ }
376
+ }
377
+ outfile.close();
378
+ }
379
+ }
380
+
381
+
382
+
383
+ } // namespace strain