pyvale 2025.5.3__cp311-cp311-macosx_14_0_arm64.whl → 2025.7.1__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 (97) 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/DIC_Challenge_Star_Noise_Def.tiff +0 -0
  16. pyvale/data/DIC_Challenge_Star_Noise_Ref.tiff +0 -0
  17. pyvale/data/plate_hole_def0000.tiff +0 -0
  18. pyvale/data/plate_hole_def0001.tiff +0 -0
  19. pyvale/data/plate_hole_ref0000.tiff +0 -0
  20. pyvale/data/plate_rigid_def0000.tiff +0 -0
  21. pyvale/data/plate_rigid_def0001.tiff +0 -0
  22. pyvale/data/plate_rigid_ref0000.tiff +0 -0
  23. pyvale/dataset.py +96 -6
  24. pyvale/dic/cpp/dicbruteforce.cpp +370 -0
  25. pyvale/dic/cpp/dicfourier.cpp +648 -0
  26. pyvale/dic/cpp/dicinterpolator.cpp +559 -0
  27. pyvale/dic/cpp/dicmain.cpp +215 -0
  28. pyvale/dic/cpp/dicoptimizer.cpp +675 -0
  29. pyvale/dic/cpp/dicrg.cpp +137 -0
  30. pyvale/dic/cpp/dicscanmethod.cpp +677 -0
  31. pyvale/dic/cpp/dicsmooth.cpp +138 -0
  32. pyvale/dic/cpp/dicstrain.cpp +383 -0
  33. pyvale/dic/cpp/dicutil.cpp +563 -0
  34. pyvale/dic2d.py +164 -0
  35. pyvale/dic2dcpp.cpython-311-darwin.so +0 -0
  36. pyvale/dicchecks.py +476 -0
  37. pyvale/dicdataimport.py +247 -0
  38. pyvale/dicregionofinterest.py +887 -0
  39. pyvale/dicresults.py +55 -0
  40. pyvale/dicspecklegenerator.py +238 -0
  41. pyvale/dicspecklequality.py +305 -0
  42. pyvale/dicstrain.py +387 -0
  43. pyvale/dicstrainresults.py +37 -0
  44. pyvale/errorintegrator.py +10 -8
  45. pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +124 -113
  46. pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +124 -132
  47. pyvale/examples/basics/ex1_3_customsens_therm3d.py +199 -195
  48. pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +125 -121
  49. pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +145 -141
  50. pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +96 -101
  51. pyvale/examples/basics/ex1_7_spatavg_therm2d.py +109 -105
  52. pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +92 -91
  53. pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +96 -90
  54. pyvale/examples/basics/ex2_3_sensangle_disp2d.py +88 -89
  55. pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +172 -171
  56. pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +88 -86
  57. pyvale/examples/basics/ex3_1_basictensors_strain2d.py +90 -90
  58. pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +93 -91
  59. pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +172 -160
  60. pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +154 -148
  61. pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +249 -231
  62. pyvale/examples/dic/ex1_region_of_interest.py +98 -0
  63. pyvale/examples/dic/ex2_plate_with_hole.py +149 -0
  64. pyvale/examples/dic/ex3_plate_with_hole_strain.py +93 -0
  65. pyvale/examples/dic/ex4_dic_blender.py +95 -0
  66. pyvale/examples/dic/ex5_dic_challenge.py +102 -0
  67. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +4 -2
  68. pyvale/examples/renderblender/ex1_1_blenderscene.py +152 -105
  69. pyvale/examples/renderblender/ex1_2_blenderdeformed.py +151 -100
  70. pyvale/examples/renderblender/ex2_1_stereoscene.py +183 -116
  71. pyvale/examples/renderblender/ex2_2_stereodeformed.py +185 -112
  72. pyvale/examples/renderblender/ex3_1_blendercalibration.py +164 -109
  73. pyvale/examples/renderrasterisation/ex_rastenp.py +74 -35
  74. pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +6 -13
  75. pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +2 -2
  76. pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +2 -4
  77. pyvale/imagedef2d.py +3 -2
  78. pyvale/imagetools.py +137 -0
  79. pyvale/rastercy.py +34 -4
  80. pyvale/rasternp.py +300 -276
  81. pyvale/rasteropts.py +58 -0
  82. pyvale/renderer.py +47 -0
  83. pyvale/rendermesh.py +52 -62
  84. pyvale/renderscene.py +51 -0
  85. pyvale/sensorarrayfactory.py +2 -2
  86. pyvale/sensortools.py +19 -35
  87. pyvale/simcases/case21.i +1 -1
  88. pyvale/simcases/run_1case.py +8 -0
  89. pyvale/simtools.py +2 -2
  90. pyvale/visualsimplotter.py +180 -0
  91. {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/METADATA +11 -57
  92. {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/RECORD +95 -57
  93. {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/WHEEL +1 -1
  94. pyvale/examples/visualisation/ex1_1_plot_traces.py +0 -102
  95. pyvale/examples/visualisation/ex2_1_animate_sim.py +0 -89
  96. {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/licenses/LICENSE +0 -0
  97. {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,559 @@
1
+ // ================================================================================
2
+ // pyvale: the python validation engine
3
+ // License: MIT
4
+ // Copyright (C) 2025 The Computer Aided Validation Team
5
+ // ================================================================================
6
+
7
+
8
+ // STD library Header files
9
+ #include <vector>
10
+ #include <iostream>
11
+
12
+ // Program Header files
13
+ #include "./dicinterpolator.hpp"
14
+
15
+
16
+
17
+ inline int idx_from_2d(const int x, const int y, const int length){
18
+ return y*length+x;
19
+ }
20
+
21
+
22
+
23
+ Interpolator::Interpolator(double*img, int px_hori, int px_vert){
24
+
25
+ //util::Timer timer("interpolator initialisation");
26
+
27
+ // intitialise vars used globally within Interpolator.
28
+ this->image = img;
29
+ this->px_vert = px_vert;
30
+ this->px_hori = px_hori;
31
+
32
+ // allocate memory for pixel coordinate arrays
33
+ px_y.resize(px_vert);
34
+ px_x.resize(px_hori);
35
+
36
+ // allocate memory for image derivatives
37
+ dx.resize(px_vert*px_hori);
38
+ dy.resize(px_vert*px_hori);
39
+ dxy.resize(px_vert*px_hori);
40
+
41
+ // setting pixel values for internal vectors
42
+ for (int i = 0; i < px_hori; i++) {
43
+ px_x[i] = i;
44
+ }
45
+ for (int j = 0; j < px_vert; j++) {
46
+ px_y[j] = j;
47
+
48
+ }
49
+
50
+ //interpolator data
51
+ std::vector<double> data(px_hori,0);
52
+
53
+ //#pragma omp parallel for
54
+ for (int j = 0; j < px_vert; j++){
55
+
56
+ // get 1D data
57
+ for (int i = 0; i < px_hori; i++) {
58
+ data[i] = image[j*px_hori + i];
59
+ }
60
+
61
+ cspline_init(px_x, data);
62
+ for (int i = 0; i < px_hori; i++){
63
+ dx[j*px_hori + i] = cspline_eval_deriv(px_x, data, px_x[i], px_hori);
64
+ }
65
+ }
66
+
67
+ data.resize(px_vert,0);
68
+
69
+ //#pragma omp parallel for
70
+ for (int i = 0; i < px_hori; ++i) {
71
+
72
+ // get 1D data
73
+ for (int j = 0; j < px_vert; j++){
74
+ data[j] = image[j*px_hori + i];
75
+ }
76
+
77
+ cspline_init(px_y, data);
78
+ for (int j = 0; j < px_vert; j++){
79
+ dy[j*px_hori + i] = cspline_eval_deriv(px_y, data, px_y[j], px_vert);
80
+ }
81
+ }
82
+
83
+
84
+ data.resize(px_hori,0);
85
+
86
+ //#pragma omp parallel for
87
+ for (int j = 0; j < px_vert; j++){
88
+
89
+ // get 1D data
90
+ for (int i = 0; i < px_hori; i++) {
91
+ data[i] = dy[j*px_hori + i];
92
+ }
93
+
94
+ cspline_init(px_x, data);
95
+ for (int i = 0; i < px_hori; i++){
96
+ dxy[j*px_hori + i] = cspline_eval_deriv(px_x, data, px_x[i], px_hori);
97
+ }
98
+ }
99
+ }
100
+
101
+ double Interpolator::eval_bicubic(const int ss_x, const int ss_y, const double subpx_x, const double subpx_y) const {
102
+
103
+ // get indices
104
+ size_t xi,yi;
105
+ index_lookup_xy(ss_x, ss_y, xi, yi, subpx_x, subpx_y);
106
+
107
+ // 4 neighbouring grid points
108
+ int idx00 = idx_from_2d(xi, yi, px_hori);
109
+ int idx01 = idx_from_2d(xi, yi + 1, px_hori);
110
+ int idx10 = idx_from_2d(xi + 1, yi, px_hori);
111
+ int idx11 = idx_from_2d(xi + 1, yi + 1, px_hori);
112
+
113
+ double d00 = image[idx00];
114
+ double d01 = image[idx01];
115
+ double d10 = image[idx10];
116
+ double d11 = image[idx11];
117
+
118
+ double dx00 = dx[idx00];
119
+ double dx01 = dx[idx01];
120
+ double dx10 = dx[idx10];
121
+ double dx11 = dx[idx11];
122
+
123
+ double dy00 = dy[idx00];
124
+ double dy01 = dy[idx01];
125
+ double dy10 = dy[idx10];
126
+ double dy11 = dy[idx11];
127
+
128
+ double dxy00 = dxy[idx00];
129
+ double dxy01 = dxy[idx01];
130
+ double dxy10 = dxy[idx10];
131
+ double dxy11 = dxy[idx11];
132
+
133
+ // polynomial terms
134
+ double t0 = 1;
135
+ double u0 = 1;
136
+ double t1 = (subpx_x - px_x[xi]);
137
+ double u1 = (subpx_y - px_y[yi]);
138
+ double t2 = t1*t1;
139
+ double u2 = u1*u1;
140
+ double t3 = t1*t2;
141
+ double u3 = u1*u2;
142
+
143
+ /* Perform bicubic interpolation */
144
+ double result = 0.0;
145
+ result += d00*t0*u0;
146
+ result += dy00*t0*u1;
147
+ result += (-3*d00 + 3*d01 - 2*dy00 - dy01)*t0*u2;
148
+ result += (2*d00 - 2*d01 + dy00 + dy01)*t0*u3;
149
+
150
+ result += dx00*t1*u0;
151
+ result += dxy00*t1*u1;
152
+ result += (-3*dx00 + 3*dx01 - 2*dxy00 - dxy01)*t1*u2;
153
+ result += (2*dx00 - 2*dx01 + dxy00 + dxy01)*t1*u3;
154
+
155
+ result += (-3*d00 + 3*d10 - 2*dx00 - dx10)*t2*u0;
156
+ result += (-3*dy00 + 3*dy10 - 2*dxy00 - dxy10)*t2*u1;
157
+ result += (9*d00 - 9*d10 + 9*d11 - 9*d01 + 6*dx00 + 3*dx10 - 3*dx11 - 6*dx01 + 6*dy00 - 6*dy10 - 3*dy11 + 3*dy01 + 4*dxy00 + 2*dxy10 + dxy11 + 2*dxy01)*t2*u2;
158
+ result += (-6*d00 + 6*d10 - 6*d11 + 6*d01 - 4*dx00 - 2*dx10 + 2*dx11 + 4*dx01 - 3*dy00 + 3*dy10 + 3*dy11 - 3*dy01 - 2*dxy00 - dxy10 - dxy11 - 2*dxy01)*t2*u3;
159
+
160
+ result += (2*d00 - 2*d10 + dx00 + dx10)*t3*u0;
161
+ result += (2*dy00 - 2*dy10 + dxy00 + dxy10)*t3*u1;
162
+ result += (-6*d00 + 6*d10 - 6*d11 + 6*d01 - 3*dx00 - 3*dx10 + 3*dx11 + 3*dx01 - 4*dy00 + 4*dy10 + 2*dy11 - 2*dy01 - 2*dxy00 - 2*dxy10 - dxy11 - dxy01)*t3*u2;
163
+ result += (4*d00 - 4*d10 + 4*d11 - 4*d01 + 2*dx00 + 2*dx10 - 2*dx11 - 2*dx01 + 2*dy00 - 2*dy10 - 2*dy11 + 2*dy01 + dxy00 + dxy10 + dxy11 + dxy01)*t3*u3;
164
+
165
+ return result;
166
+ }
167
+
168
+
169
+
170
+
171
+ double Interpolator::eval_bicubic_dx(const int ss_x, const int ss_y, const double subpx_x, const double subpx_y) const{
172
+
173
+ /* first compute the indices into the data arrays where we are interpolating */
174
+ size_t xi,yi;
175
+ index_lookup_xy(ss_x, ss_y, xi, yi, subpx_x, subpx_y);
176
+
177
+ int idx00 = idx_from_2d(xi, yi, px_hori);
178
+ int idx01 = idx_from_2d(xi, yi + 1, px_hori);
179
+ int idx10 = idx_from_2d(xi + 1, yi, px_hori);
180
+ int idx11 = idx_from_2d(xi + 1, yi + 1, px_hori);
181
+
182
+ double d00 = image[idx00];
183
+ double d01 = image[idx01];
184
+ double d10 = image[idx10];
185
+ double d11 = image[idx11];
186
+
187
+ double dx00 = dx[idx00];
188
+ double dx01 = dx[idx01];
189
+ double dx10 = dx[idx10];
190
+ double dx11 = dx[idx11];
191
+ double dy00 = dy[idx00];
192
+ double dy01 = dy[idx01];
193
+ double dy10 = dy[idx10];
194
+ double dy11 = dy[idx11];
195
+ double dxy00 = dxy[idx00];
196
+ double dxy01 = dxy[idx01];
197
+ double dxy10 = dxy[idx10];
198
+ double dxy11 = dxy[idx11];
199
+
200
+ // polynomial terms
201
+ double t0 = 1;
202
+ double u0 = 1;
203
+ double t1 = (subpx_x - px_x[xi]);
204
+ double u1 = (subpx_y - px_y[yi]);
205
+ double t2 = t1*t1;
206
+ double u2 = u1*u1;
207
+ double u3 = u1*u2;
208
+
209
+ double result = 0.0;
210
+ result += dx00 *t0*u0;
211
+ result += dxy00*t0*u1;
212
+ result += (-3*dx00 + 3*dx01 - 2*dxy00 - dxy01) *t0*u2;
213
+ result += (2*dx00 - 2*dx01 + dxy00 + dxy01)*t0*u3;
214
+ result += 2*(-3*d00 + 3*d10 - 2*dx00 - dx10)*t1*u0;
215
+ result += 2*(-3*dy00 + 3*dy10 - 2*dxy00 - dxy10)*t1*u1;
216
+ result += 2*(9*d00 - 9*d10 + 9*d11 - 9*d01 + 6*dx00 + 3*dx10 - 3*dx11 - 6*dx01 + 6*dy00 - 6*dy10 - 3*dy11 + 3*dy01 + 4*dxy00 + 2*dxy10 + dxy11 + 2*dxy01)*t1*u2;
217
+ result += 2*(-6*d00 + 6*d10 - 6*d11 + 6*d01 - 4*dx00 - 2*dx10 + 2*dx11 + 4*dx01 - 3*dy00 + 3*dy10 + 3*dy11 - 3*dy01 - 2*dxy00 - dxy10 - dxy11 - 2*dxy01)*t1*u3;
218
+ result += 3*(2*d00 - 2*d10 + dx00 + dx10)*t2 *u0;
219
+ result += 3*(2*dy00 - 2*dy10 + dxy00 + dxy10)*t2*u1;
220
+ result += 3*(-6*d00 + 6*d10 - 6*d11 + 6*d01 - 3*dx00 - 3*dx10 + 3*dx11 + 3*dx01 - 4*dy00 + 4*dy10 + 2*dy11 - 2*dy01 - 2*dxy00 - 2*dxy10 - dxy11 - dxy01)*t2*u2;
221
+ result += 3*(4*d00 - 4*d10 + 4*d11 - 4*d01 + 2*dx00 + 2*dx10 - 2*dx11 - 2*dx01 + 2*dy00 - 2*dy10 - 2*dy11 + 2*dy01 + dxy00 + dxy10 + dxy11 + dxy01)*t2*u3;
222
+ return result;
223
+
224
+ }
225
+
226
+
227
+ double Interpolator::eval_bicubic_dy(const int ss_x, const int ss_y, const double subpx_x, const double subpx_y) const{
228
+
229
+ size_t xi,yi;
230
+ index_lookup_xy(ss_x, ss_y, xi, yi, subpx_x, subpx_y);
231
+
232
+ // precompute indices of surrounding pixel values
233
+ size_t idx00 = idx_from_2d(xi, yi, px_hori);
234
+ size_t idx01 = idx_from_2d(xi, yi + 1, px_hori);
235
+ size_t idx10 = idx_from_2d(xi + 1, yi, px_hori);
236
+ size_t idx11 = idx_from_2d(xi + 1, yi + 1, px_hori);
237
+
238
+ double d00 = image[idx00];
239
+ double d01 = image[idx01];
240
+ double d10 = image[idx10];
241
+ double d11 = image[idx11];
242
+
243
+ double dx00 = dx[idx00];
244
+ double dx01 = dx[idx01];
245
+ double dx10 = dx[idx10];
246
+ double dx11 = dx[idx11];
247
+ double dy00 = dy[idx00];
248
+ double dy01 = dy[idx01];
249
+ double dy10 = dy[idx10];
250
+ double dy11 = dy[idx11];
251
+ double dxy00 = dxy[idx00];
252
+ double dxy01 = dxy[idx01];
253
+ double dxy10 = dxy[idx10];
254
+ double dxy11 = dxy[idx11];
255
+
256
+ // polynomial terms
257
+ double t0 = 1;
258
+ double u0 = 1;
259
+ double t1 = (subpx_x - px_x[xi]);
260
+ double u1 = (subpx_y - px_y[yi]);
261
+ double t2 = t1*t1;
262
+ double u2 = u1*u1;
263
+ double t3 = t1*t2;
264
+
265
+ double result = 0.0;
266
+ result += dy00*t0*u0;
267
+ result += 2*(-3*d00 + 3*d01 - 2*dy00 - dy01)*t0*u1;
268
+ result += 3*(2*d00-2*d01 + dy00 + dy01)*t0*u2;
269
+ result += dxy00*t1*u0;
270
+ result += 2*(-3*dx00 + 3*dx01 - 2*dxy00 - dxy01)*t1*u1;
271
+ result += 3*(2*dx00 - 2*dx01 + dxy00 + dxy01)*t1*u2;
272
+ result += (-3*dy00 + 3*dy10 - 2*dxy00 - dxy10)*t2*u0;
273
+ result += 2*(9*d00 - 9*d10 + 9*d11 - 9*d01 + 6*dx00 + 3*dx10 - 3*dx11 - 6*dx01 + 6*dy00 - 6*dy10 - 3*dy11 + 3*dy01 + 4*dxy00 + 2*dxy10 + dxy11 + 2*dxy01)*t2*u1;
274
+ result += 3*(-6*d00 + 6*d10 - 6*d11 + 6*d01 - 4*dx00 - 2*dx10 + 2*dx11 + 4*dx01 - 3*dy00 + 3*dy10 + 3*dy11 - 3*dy01 - 2*dxy00 - dxy10 - dxy11 - 2*dxy01)*t2*u2;
275
+ result += (2*dy00 - 2*dy10 + dxy00 + dxy10)*t3*u0;
276
+ result += 2*(-6*d00 + 6*d10 - 6*d11 + 6*d01 - 3*dx00 - 3*dx10 + 3*dx11 + 3*dx01 - 4*dy00 + 4*dy10 + 2*dy11 - 2*dy01 - 2*dxy00 - 2*dxy10 - dxy11 - dxy01)*t3*u1;
277
+ result += 3*(4*d00 - 4*d10 + 4*d11 - 4*d01 + 2*dx00 + 2*dx10 - 2*dx11 - 2*dx01 + 2*dy00 - 2*dy10 - 2*dy11 + 2*dy01 + dxy00 + dxy10 + dxy11 + dxy01)*t3*u2;
278
+
279
+ return result;
280
+ }
281
+
282
+
283
+ InterpVals Interpolator::eval_bicubic_and_derivs(const int ss_x, const int ss_y, const double subpx_x, const double subpx_y) const{
284
+
285
+ // pixel floor of x and y
286
+ size_t xi,yi;
287
+ index_lookup_xy(ss_x, ss_y, xi, yi, subpx_x, subpx_y);
288
+
289
+ // precompute indices of surrounding pixel values
290
+ size_t idx00 = idx_from_2d(xi, yi, px_hori);
291
+ size_t idx01 = idx_from_2d(xi, yi + 1, px_hori);
292
+ size_t idx10 = idx_from_2d(xi + 1, yi, px_hori);
293
+ size_t idx11 = idx_from_2d(xi + 1, yi + 1, px_hori);
294
+
295
+ double d00 = image[idx00];
296
+ double d01 = image[idx01];
297
+ double d10 = image[idx10];
298
+ double d11 = image[idx11];
299
+
300
+ double dx00 = dx[idx00];
301
+ double dx01 = dx[idx01];
302
+ double dx10 = dx[idx10];
303
+ double dx11 = dx[idx11];
304
+ double dy00 = dy[idx00];
305
+ double dy01 = dy[idx01];
306
+ double dy10 = dy[idx10];
307
+ double dy11 = dy[idx11];
308
+ double dxy00 = dxy[idx00];
309
+ double dxy01 = dxy[idx01];
310
+ double dxy10 = dxy[idx10];
311
+ double dxy11 = dxy[idx11];
312
+
313
+ // polynomial terms
314
+ double t0 = 1;
315
+ double u0 = 1;
316
+ double t1 = (subpx_x - px_x[xi]);
317
+ double u1 = (subpx_y - px_y[yi]);
318
+ double t2 = t1*t1;
319
+ double u2 = u1*u1;
320
+ double t3 = t1*t2;
321
+ double u3 = u1*u2;
322
+
323
+ double result = 0.0;
324
+ double result_dx = 0.0;
325
+ double result_dy = 0.0;
326
+
327
+ result += d00*t0*u0;
328
+ result += dy00*t0*u1;
329
+ result += (-3*d00 + 3*d01 - 2*dy00 - dy01)*t0*u2;
330
+ result += (2*d00 - 2*d01 + dy00 + dy01)*t0*u3;
331
+ result += dx00*t1*u0;
332
+ result += dxy00*t1*u1;
333
+ result += (-3*dx00 + 3*dx01 - 2*dxy00 - dxy01)*t1*u2;
334
+ result += (2*dx00 - 2*dx01 + dxy00 + dxy01)*t1*u3;
335
+ result += (-3*d00 + 3*d10 - 2*dx00 - dx10)*t2*u0;
336
+ result += (-3*dy00 + 3*dy10 - 2*dxy00 - dxy10)*t2*u1;
337
+ result += (9*d00 - 9*d10 + 9*d11 - 9*d01 + 6*dx00 + 3*dx10 - 3*dx11 - 6*dx01 + 6*dy00 - 6*dy10 - 3*dy11 + 3*dy01 + 4*dxy00 + 2*dxy10 + dxy11 + 2*dxy01)*t2*u2;
338
+ result += (-6*d00 + 6*d10 - 6*d11 + 6*d01 - 4*dx00 - 2*dx10 + 2*dx11 + 4*dx01 - 3*dy00 + 3*dy10 + 3*dy11 - 3*dy01 - 2*dxy00 - dxy10 - dxy11 - 2*dxy01)*t2*u3;
339
+ result += (2*d00 - 2*d10 + dx00 + dx10)*t3*u0;
340
+ result += (2*dy00 - 2*dy10 + dxy00 + dxy10)*t3*u1;
341
+ result += (-6*d00 + 6*d10 - 6*d11 + 6*d01 - 3*dx00 - 3*dx10 + 3*dx11 + 3*dx01 - 4*dy00 + 4*dy10 + 2*dy11 - 2*dy01 - 2*dxy00 - 2*dxy10 - dxy11 - dxy01)*t3*u2;
342
+ result += (4*d00 - 4*d10 + 4*d11 - 4*d01 + 2*dx00 + 2*dx10 - 2*dx11 - 2*dx01 + 2*dy00 - 2*dy10 - 2*dy11 + 2*dy01 + dxy00 + dxy10 + dxy11 + dxy01)*t3*u3;
343
+
344
+ result_dx += dx00 *t0*u0;
345
+ result_dx += dxy00*t0*u1;
346
+ result_dx += (-3*dx00 + 3*dx01 - 2*dxy00 - dxy01) *t0*u2;
347
+ result_dx += (2*dx00 - 2*dx01 + dxy00 + dxy01)*t0*u3;
348
+ result_dx += 2*(-3*d00 + 3*d10 - 2*dx00 - dx10)*t1*u0;
349
+ result_dx += 2*(-3*dy00 + 3*dy10 - 2*dxy00 - dxy10)*t1*u1;
350
+ result_dx += 2*(9*d00 - 9*d10 + 9*d11 - 9*d01 + 6*dx00 + 3*dx10 - 3*dx11 - 6*dx01 + 6*dy00 - 6*dy10 - 3*dy11 + 3*dy01 + 4*dxy00 + 2*dxy10 + dxy11 + 2*dxy01)*t1*u2;
351
+ result_dx += 2*(-6*d00 + 6*d10 - 6*d11 + 6*d01 - 4*dx00 - 2*dx10 + 2*dx11 + 4*dx01 - 3*dy00 + 3*dy10 + 3*dy11 - 3*dy01 - 2*dxy00 - dxy10 - dxy11 - 2*dxy01)*t1*u3;
352
+ result_dx += 3*(2*d00 - 2*d10 + dx00 + dx10)*t2 *u0;
353
+ result_dx += 3*(2*dy00 - 2*dy10 + dxy00 + dxy10)*t2*u1;
354
+ result_dx += 3*(-6*d00 + 6*d10 - 6*d11 + 6*d01 - 3*dx00 - 3*dx10 + 3*dx11 + 3*dx01 - 4*dy00 + 4*dy10 + 2*dy11 - 2*dy01 - 2*dxy00 - 2*dxy10 - dxy11 - dxy01)*t2*u2;
355
+ result_dx += 3*(4*d00 - 4*d10 + 4*d11 - 4*d01 + 2*dx00 + 2*dx10 - 2*dx11 - 2*dx01 + 2*dy00 - 2*dy10 - 2*dy11 + 2*dy01 + dxy00 + dxy10 + dxy11 + dxy01)*t2*u3;
356
+
357
+ result_dy += dy00*t0*u0;
358
+ result_dy += 2*(-3*d00 + 3*d01 - 2*dy00 - dy01)*t0*u1;
359
+ result_dy += 3*(2*d00-2*d01 + dy00 + dy01)*t0*u2;
360
+ result_dy += dxy00*t1*u0;
361
+ result_dy += 2*(-3*dx00 + 3*dx01 - 2*dxy00 - dxy01)*t1*u1;
362
+ result_dy += 3*(2*dx00 - 2*dx01 + dxy00 + dxy01)*t1*u2;
363
+ result_dy += (-3*dy00 + 3*dy10 - 2*dxy00 - dxy10)*t2*u0;
364
+ result_dy += 2*(9*d00 - 9*d10 + 9*d11 - 9*d01 + 6*dx00 + 3*dx10 - 3*dx11 - 6*dx01 + 6*dy00 - 6*dy10 - 3*dy11 + 3*dy01 + 4*dxy00 + 2*dxy10 + dxy11 + 2*dxy01)*t2*u1;
365
+ result_dy += 3*(-6*d00 + 6*d10 - 6*d11 + 6*d01 - 4*dx00 - 2*dx10 + 2*dx11 + 4*dx01 - 3*dy00 + 3*dy10 + 3*dy11 - 3*dy01 - 2*dxy00 - dxy10 - dxy11 - 2*dxy01)*t2*u2;
366
+ result_dy += (2*dy00 - 2*dy10 + dxy00 + dxy10)*t3*u0;
367
+ result_dy += 2*(-6*d00 + 6*d10 - 6*d11 + 6*d01 - 3*dx00 - 3*dx10 + 3*dx11 + 3*dx01 - 4*dy00 + 4*dy10 + 2*dy11 - 2*dy01 - 2*dxy00 - 2*dxy10 - dxy11 - dxy01)*t3*u1;
368
+ result_dy += 3*(4*d00 - 4*d10 + 4*d11 - 4*d01 + 2*dx00 + 2*dx10 - 2*dx11 - 2*dx01 + 2*dy00 - 2*dy10 - 2*dy11 + 2*dy01 + dxy00 + dxy10 + dxy11 + dxy01)*t3*u2;
369
+
370
+ return {result, result_dx, result_dy};
371
+ }
372
+
373
+
374
+
375
+
376
+ inline void Interpolator::coeff_calc(std::vector<double> &tridiag_solution, double dy, double dx, size_t i, double *b, double *c, double *d) {
377
+
378
+ const double s_i = tridiag_solution[i];
379
+ const double s_ip1 = tridiag_solution[i + 1];
380
+ const double dx_inv = 1.0 / dx;
381
+
382
+ *b = (dy*dx_inv) - dx*(s_ip1 + 2.0*s_i) / 3.0;
383
+ *c = s_i;
384
+ *d = (s_ip1 - s_i) / (3.0*dx);
385
+ }
386
+
387
+
388
+ inline void Interpolator::index_lookup_xy(const int ss_x, const int ss_y, size_t &xi, size_t &yi, const double subpx_x, const double subpx_y) const {
389
+
390
+ if (subpx_x < px_x[0])
391
+ xi = 0;
392
+ else if (subpx_x > px_x[px_hori - 2])
393
+ xi = px_hori - 2;
394
+ else
395
+ xi = static_cast<size_t>(subpx_x);
396
+
397
+ if (subpx_y < px_y[0])
398
+ yi = 0;
399
+ else if (subpx_y > px_y[px_vert - 2])
400
+ yi = px_vert - 2;
401
+ else
402
+ yi = static_cast<size_t>(subpx_y);
403
+
404
+ //if (subpx_x >= px_x[0] && subpx_x <= px_x[px_hori-1]) {
405
+ // xi = static_cast<size_t>(subpx_x); // Return x as the index
406
+ //}
407
+ //else {
408
+ // std::cerr << "ERROR in \'" << __FILE__ << "\' at line \'" << __LINE__ << "\' \n";
409
+ // std::cerr << "Interpolator went out of bounds for subset (" << ss_x << ", " << ss_y << ")" << std::endl;
410
+ // std::cerr << "value is out of bounds: (" << subpx_x << ", " << subpx_y << ")" << std::endl;
411
+ // std::cerr << "Image bounds: (0,0) to (" << px_hori-1 << ", " << px_vert-1 << ")" << std::endl;
412
+ // exit(EXIT_FAILURE);
413
+ //}
414
+
415
+ //if (subpx_y >= px_y[0] && subpx_y <= px_y[px_vert-1]) {
416
+ // yi = static_cast<size_t>(subpx_y); // Return x as the index
417
+ //}
418
+ //else {
419
+ // std::cerr << "ERROR in \'" << __FILE__ << "\' at line \'" << __LINE__ << "\' \n";
420
+ // std::cerr << "Interpolator went out of bounds for subset (" << ss_x << ", " << ss_y << ")" << std::endl;
421
+ // std::cerr << "value is out of bounds: (" << subpx_x << ", " << subpx_y << ")" << std::endl;
422
+ // std::cerr << "Image bounds: (0,0) to (" << px_hori-1 << ", " << px_vert-1 << ")" << std::endl;
423
+ // exit(EXIT_FAILURE);
424
+ //}
425
+ }
426
+
427
+
428
+ inline int Interpolator::index_lookup(const std::vector<double> &px, double x) const {
429
+
430
+ // Clamp coordinates to valid range
431
+ // double clamped_x = std::max(static_cast<double>(index_lo), std::min(static_cast<double>(index_hi), x));
432
+
433
+ // if (x >= px[index_lo] && x <= px[index_hi]) {
434
+ // // return static_cast<int>(x); // Return x as the index
435
+ // }
436
+ // else {
437
+ // // std::cout << "ERROR in \'" << __FILE__ << "\' at line \'" << __LINE__ << "\' \n";
438
+ // // std::cout << "value is out of bounds. value = " << x << std::endl;
439
+ // // exit(EXIT_FAILURE);
440
+ // }
441
+ // return static_cast<int>(clamped_x);
442
+
443
+ if (x >= px.front() && x <= px.back()) {
444
+ return static_cast<int>(x); // Return x as the index
445
+ }
446
+ else {
447
+ std::cerr << "ERROR in \'" << __FILE__ << "\' at line \'" << __LINE__ << "\' \n";
448
+ std::cerr << "value is out of bounds. value = " << x << std::endl;
449
+ exit(EXIT_FAILURE);
450
+ }
451
+
452
+ }
453
+
454
+
455
+
456
+ void Interpolator::cspline_init(std::vector<double> &px, std::vector<double> &data){
457
+
458
+
459
+ int num_points = px.size();
460
+ int max_index = num_points - 1;
461
+ int sys_size = max_index - 1;
462
+
463
+ std::vector<double> diagonal(num_points);
464
+ std::vector<double> off_diagonal(num_points);
465
+ std::vector<double> rhs(num_points);
466
+ tridiag_solution.resize(num_points,0.0);
467
+
468
+ for (int i = 0; i < sys_size; i++)
469
+ {
470
+ const double h_i = px[i + 1] - px[i];
471
+ const double h_ip1 = px[i + 2] - px[i + 1];
472
+ const double ydiff_i = data[i + 1] - data[i];
473
+ const double ydiff_ip1 = data[i + 2] - data[i + 1];
474
+ const double g_i = (h_i != 0.0) ? 1.0 / h_i : 0.0;
475
+ const double g_ip1 = (h_ip1 != 0.0) ? 1.0 / h_ip1 : 0.0;
476
+ off_diagonal[i] = h_ip1;
477
+ diagonal[i] = 2.0*(h_ip1 + h_i);
478
+ rhs[i] = 3.0*(ydiff_ip1*g_ip1 - ydiff_i*g_i);
479
+
480
+ }
481
+
482
+ std::vector<double> gamma(sys_size);
483
+ std::vector<double> alpha(sys_size);
484
+ std::vector<double> c(sys_size);
485
+ std::vector<double> z(sys_size);
486
+ alpha[0] = diagonal[0];
487
+ gamma[0] = off_diagonal[0] / alpha[0];
488
+
489
+ if (alpha[0] == 0) {
490
+ std::cerr << __FILE__ << " " << __LINE__ << "ERROR: div by zero" << std::endl;
491
+ exit(1);
492
+ }
493
+
494
+ for (int i = 1; i < sys_size - 1; i++) {
495
+
496
+ alpha[i] = diagonal[i] - off_diagonal[i - 1]*gamma[i - 1];
497
+ gamma[i] = off_diagonal[i] / alpha[i];
498
+ if (alpha[i] == 0) {
499
+ std::cerr << __FILE__ << " " << __LINE__ << "ERROR: div by zero" << std::endl;
500
+ exit(1);
501
+ }
502
+
503
+ }
504
+
505
+ if (sys_size > 1) {
506
+ alpha[sys_size - 1] = diagonal[(sys_size - 1)] - off_diagonal[(sys_size - 2)]*gamma[sys_size - 2];
507
+ }
508
+
509
+ // RHS of equation
510
+ z[0] = rhs[0];
511
+ for (int i = 1; i < sys_size; i++) {
512
+ z[i] = rhs[i] - gamma[i - 1]*z[i - 1];
513
+ }
514
+
515
+ for (int i = 0; i < sys_size; i++){
516
+ c[i] = z[i] / alpha[i];
517
+ }
518
+
519
+ // back substitution
520
+ tridiag_solution[sys_size] = c[sys_size - 1];
521
+ if (sys_size >= 2) {
522
+ for (int i = sys_size - 2; i >= 0; i--) {
523
+ tridiag_solution[i+1] = c[i] - gamma[i]*tridiag_solution[i + 2];
524
+ }
525
+ }
526
+ }
527
+
528
+ double Interpolator::cspline_eval_deriv(std::vector<double> &px, std::vector<double> &data, double value, int length) {
529
+
530
+ // Find the interval containing the evaluation point
531
+ int index = index_lookup(px, value);
532
+
533
+ // Get interval boundaries
534
+ double px_min = px[index];
535
+ double px_max = px[index + 1];
536
+ double dx = px_max - px_min;
537
+
538
+ // Handle degenerate case where interval has zero width
539
+ if (dx <= 0.0) {
540
+ return 0.0;
541
+ }
542
+
543
+ // Get y-values at interval endpoints
544
+ double y_lo = data[index];
545
+ double y_hi = data[index + 1];
546
+ double dy = y_hi - y_lo;
547
+
548
+ // Calculate distance from left endpoint
549
+ double delx = value - px_min;
550
+
551
+ // Calculate cubic spline coefficients for this interval
552
+ double b_i, c_i, d_i;
553
+ coeff_calc(tridiag_solution, dy, dx, index, &b_i, &c_i, &d_i);
554
+
555
+ // Evaluate derivative: dy/dx = b + 2c*delx + 3d*delx^2
556
+ double dydx = b_i + delx*(2.0*c_i + 3.0*d_i*delx);
557
+
558
+ return dydx;
559
+ }