pyvale 2025.5.3__cp311-cp311-win_amd64.whl → 2025.7.0__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.
Potentially problematic release.
This version of pyvale might be problematic. Click here for more details.
- pyvale/__init__.py +12 -0
- pyvale/blendercalibrationdata.py +3 -1
- pyvale/blenderscene.py +7 -5
- pyvale/blendertools.py +27 -5
- pyvale/camera.py +1 -0
- pyvale/cameradata.py +3 -0
- pyvale/camerasensor.py +147 -0
- pyvale/camerastereo.py +4 -4
- pyvale/cameratools.py +23 -61
- pyvale/cython/rastercyth.c +1657 -1352
- pyvale/cython/rastercyth.cp311-win_amd64.pyd +0 -0
- pyvale/cython/rastercyth.py +71 -26
- pyvale/data/plate_hole_def0000.tiff +0 -0
- pyvale/data/plate_hole_def0001.tiff +0 -0
- pyvale/data/plate_hole_ref0000.tiff +0 -0
- pyvale/data/plate_rigid_def0000.tiff +0 -0
- pyvale/data/plate_rigid_def0001.tiff +0 -0
- pyvale/data/plate_rigid_ref0000.tiff +0 -0
- pyvale/dataset.py +96 -6
- pyvale/dic/cpp/dicbruteforce.cpp +370 -0
- pyvale/dic/cpp/dicfourier.cpp +648 -0
- pyvale/dic/cpp/dicinterpolator.cpp +559 -0
- pyvale/dic/cpp/dicmain.cpp +215 -0
- pyvale/dic/cpp/dicoptimizer.cpp +675 -0
- pyvale/dic/cpp/dicrg.cpp +137 -0
- pyvale/dic/cpp/dicscanmethod.cpp +677 -0
- pyvale/dic/cpp/dicsmooth.cpp +138 -0
- pyvale/dic/cpp/dicstrain.cpp +383 -0
- pyvale/dic/cpp/dicutil.cpp +563 -0
- pyvale/dic2d.py +164 -0
- pyvale/dic2dcpp.cp311-win_amd64.pyd +0 -0
- pyvale/dicchecks.py +476 -0
- pyvale/dicdataimport.py +247 -0
- pyvale/dicregionofinterest.py +887 -0
- pyvale/dicresults.py +55 -0
- pyvale/dicspecklegenerator.py +238 -0
- pyvale/dicspecklequality.py +305 -0
- pyvale/dicstrain.py +387 -0
- pyvale/dicstrainresults.py +37 -0
- pyvale/errorintegrator.py +10 -8
- pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +124 -113
- pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +124 -132
- pyvale/examples/basics/ex1_3_customsens_therm3d.py +199 -195
- pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +125 -121
- pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +145 -141
- pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +96 -101
- pyvale/examples/basics/ex1_7_spatavg_therm2d.py +109 -105
- pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +92 -91
- pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +96 -90
- pyvale/examples/basics/ex2_3_sensangle_disp2d.py +88 -89
- pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +172 -171
- pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +88 -86
- pyvale/examples/basics/ex3_1_basictensors_strain2d.py +90 -90
- pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +93 -91
- pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +172 -160
- pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +154 -148
- pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +249 -231
- pyvale/examples/dic/ex1_region_of_interest.py +98 -0
- pyvale/examples/dic/ex2_plate_with_hole.py +149 -0
- pyvale/examples/dic/ex3_plate_with_hole_strain.py +93 -0
- pyvale/examples/dic/ex4_dic_blender.py +95 -0
- pyvale/examples/dic/ex5_dic_challenge.py +102 -0
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +4 -2
- pyvale/examples/renderblender/ex1_1_blenderscene.py +152 -105
- pyvale/examples/renderblender/ex1_2_blenderdeformed.py +151 -100
- pyvale/examples/renderblender/ex2_1_stereoscene.py +183 -116
- pyvale/examples/renderblender/ex2_2_stereodeformed.py +185 -112
- pyvale/examples/renderblender/ex3_1_blendercalibration.py +164 -109
- pyvale/examples/renderrasterisation/ex_rastenp.py +74 -35
- pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +6 -13
- pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +2 -2
- pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +2 -4
- pyvale/imagedef2d.py +3 -2
- pyvale/imagetools.py +137 -0
- pyvale/rastercy.py +34 -4
- pyvale/rasternp.py +300 -276
- pyvale/rasteropts.py +58 -0
- pyvale/renderer.py +47 -0
- pyvale/rendermesh.py +52 -62
- pyvale/renderscene.py +51 -0
- pyvale/sensorarrayfactory.py +2 -2
- pyvale/sensortools.py +19 -35
- pyvale/simcases/case21.i +1 -1
- pyvale/simcases/run_1case.py +8 -0
- pyvale/simtools.py +2 -2
- pyvale/visualsimplotter.py +180 -0
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/METADATA +11 -57
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/RECORD +91 -56
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/WHEEL +1 -1
- pyvale/examples/visualisation/ex1_1_plot_traces.py +0 -102
- pyvale/examples/visualisation/ex2_1_animate_sim.py +0 -89
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/licenses/LICENSE +0 -0
- {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
|