pyvale 2025.7.1__cp311-cp311-musllinux_1_2_aarch64.whl → 2025.8.1__cp311-cp311-musllinux_1_2_aarch64.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 (186) hide show
  1. pyvale/__init__.py +12 -92
  2. pyvale/blender/__init__.py +23 -0
  3. pyvale/{pyvaleexceptions.py → blender/blenderexceptions.py} +0 -3
  4. pyvale/{blenderlightdata.py → blender/blenderlightdata.py} +3 -3
  5. pyvale/{blendermaterialdata.py → blender/blendermaterialdata.py} +1 -1
  6. pyvale/{blenderrenderdata.py → blender/blenderrenderdata.py} +5 -3
  7. pyvale/{blenderscene.py → blender/blenderscene.py} +33 -30
  8. pyvale/{blendertools.py → blender/blendertools.py} +14 -10
  9. pyvale/dataset/__init__.py +7 -0
  10. pyvale/dataset/dataset.py +443 -0
  11. pyvale/dic/__init__.py +20 -0
  12. pyvale/dic/cpp/dicfourier.cpp +36 -4
  13. pyvale/dic/cpp/dicinterpolator.cpp +56 -1
  14. pyvale/dic/cpp/dicmain.cpp +24 -19
  15. pyvale/dic/cpp/dicoptimizer.cpp +6 -1
  16. pyvale/dic/cpp/dicscanmethod.cpp +32 -32
  17. pyvale/dic/cpp/dicsignalhandler.cpp +16 -0
  18. pyvale/dic/cpp/dicstrain.cpp +7 -3
  19. pyvale/dic/cpp/dicutil.cpp +79 -23
  20. pyvale/{dic2d.py → dic/dic2d.py} +51 -29
  21. pyvale/dic/dic2dconv.py +6 -0
  22. pyvale/{dic2dcpp.cpython-311-aarch64-linux-musl.so → dic/dic2dcpp.cpython-311-aarch64-linux-musl.so} +0 -0
  23. pyvale/{dicchecks.py → dic/dicchecks.py} +28 -16
  24. pyvale/dic/dicdataimport.py +370 -0
  25. pyvale/{dicregionofinterest.py → dic/dicregionofinterest.py} +169 -12
  26. pyvale/{dicresults.py → dic/dicresults.py} +4 -1
  27. pyvale/{dicstrain.py → dic/dicstrain.py} +9 -9
  28. pyvale/examples/basics/{ex1_1_basicscalars_therm2d.py → ex1a_basicscalars_therm2d.py} +12 -9
  29. pyvale/examples/basics/{ex1_2_sensormodel_therm2d.py → ex1b_sensormodel_therm2d.py} +17 -14
  30. pyvale/examples/basics/{ex1_3_customsens_therm3d.py → ex1c_customsens_therm3d.py} +27 -24
  31. pyvale/examples/basics/{ex1_4_basicerrors_therm3d.py → ex1d_basicerrors_therm3d.py} +32 -29
  32. pyvale/examples/basics/{ex1_5_fielderrs_therm3d.py → ex1e_fielderrs_therm3d.py} +19 -15
  33. pyvale/examples/basics/{ex1_6_caliberrs_therm2d.py → ex1f_caliberrs_therm2d.py} +20 -16
  34. pyvale/examples/basics/{ex1_7_spatavg_therm2d.py → ex1g_spatavg_therm2d.py} +19 -16
  35. pyvale/examples/basics/{ex2_1_basicvectors_disp2d.py → ex2a_basicvectors_disp2d.py} +13 -10
  36. pyvale/examples/basics/{ex2_2_vectorsens_disp2d.py → ex2b_vectorsens_disp2d.py} +19 -15
  37. pyvale/examples/basics/{ex2_3_sensangle_disp2d.py → ex2c_sensangle_disp2d.py} +21 -18
  38. pyvale/examples/basics/{ex2_4_chainfielderrs_disp2d.py → ex2d_chainfielderrs_disp2d.py} +31 -29
  39. pyvale/examples/basics/{ex2_5_vectorfields3d_disp3d.py → ex2e_vectorfields3d_disp3d.py} +21 -18
  40. pyvale/examples/basics/{ex3_1_basictensors_strain2d.py → ex3a_basictensors_strain2d.py} +16 -14
  41. pyvale/examples/basics/{ex3_2_tensorsens2d_strain2d.py → ex3b_tensorsens2d_strain2d.py} +17 -14
  42. pyvale/examples/basics/{ex3_3_tensorsens3d_strain3d.py → ex3c_tensorsens3d_strain3d.py} +25 -22
  43. pyvale/examples/basics/{ex4_1_expsim2d_thermmech2d.py → ex4a_expsim2d_thermmech2d.py} +17 -14
  44. pyvale/examples/basics/{ex4_2_expsim3d_thermmech3d.py → ex4b_expsim3d_thermmech3d.py} +37 -34
  45. pyvale/examples/basics/ex5_nomesh.py +24 -0
  46. pyvale/examples/dic/ex1_2_blenderdeformed.py +174 -0
  47. pyvale/examples/dic/ex1_region_of_interest.py +6 -3
  48. pyvale/examples/dic/ex2_plate_with_hole.py +21 -18
  49. pyvale/examples/dic/ex3_plate_with_hole_strain.py +8 -6
  50. pyvale/examples/dic/ex4_dic_blender.py +17 -15
  51. pyvale/examples/dic/ex5_dic_challenge.py +19 -14
  52. pyvale/examples/genanalyticdata/ex1_1_scalarvisualisation.py +16 -10
  53. pyvale/examples/genanalyticdata/ex1_2_scalarcasebuild.py +3 -3
  54. pyvale/examples/genanalyticdata/ex2_1_analyticsensors.py +29 -23
  55. pyvale/examples/genanalyticdata/ex2_2_analyticsensors_nomesh.py +67 -0
  56. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +12 -9
  57. pyvale/examples/mooseherder/ex0_create_moose_config.py +65 -0
  58. pyvale/examples/mooseherder/ex1a_modify_moose_input.py +71 -0
  59. pyvale/examples/mooseherder/ex1b_modify_gmsh_input.py +69 -0
  60. pyvale/examples/mooseherder/ex2a_run_moose_once.py +80 -0
  61. pyvale/examples/mooseherder/ex2b_run_gmsh_once.py +64 -0
  62. pyvale/examples/mooseherder/ex2c_run_both_once.py +114 -0
  63. pyvale/examples/mooseherder/ex3_run_moose_seq_para.py +157 -0
  64. pyvale/examples/mooseherder/ex4_run_gmsh-moose_seq_para.py +176 -0
  65. pyvale/examples/mooseherder/ex5_run_moose_paramulti.py +136 -0
  66. pyvale/examples/mooseherder/ex6_read_moose_exodus.py +163 -0
  67. pyvale/examples/mooseherder/ex7a_read_moose_herd_results.py +153 -0
  68. pyvale/examples/mooseherder/ex7b_read_multi_herd_results.py +116 -0
  69. pyvale/examples/mooseherder/ex7c_read_multi_gmshmoose_results.py +127 -0
  70. pyvale/examples/mooseherder/ex7d_readconfig_multi_gmshmoose_results.py +143 -0
  71. pyvale/examples/mooseherder/ex8_read_existing_sweep_output.py +72 -0
  72. pyvale/examples/renderblender/ex1_1_blenderscene.py +24 -20
  73. pyvale/examples/renderblender/ex1_2_blenderdeformed.py +22 -18
  74. pyvale/examples/renderblender/ex2_1_stereoscene.py +36 -29
  75. pyvale/examples/renderblender/ex2_2_stereodeformed.py +26 -20
  76. pyvale/examples/renderblender/ex3_1_blendercalibration.py +24 -17
  77. pyvale/examples/renderrasterisation/ex_rastenp.py +14 -12
  78. pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +14 -15
  79. pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +13 -11
  80. pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +13 -11
  81. pyvale/mooseherder/__init__.py +32 -0
  82. pyvale/mooseherder/directorymanager.py +416 -0
  83. pyvale/mooseherder/exodusreader.py +763 -0
  84. pyvale/mooseherder/gmshrunner.py +163 -0
  85. pyvale/mooseherder/inputmodifier.py +236 -0
  86. pyvale/mooseherder/mooseconfig.py +226 -0
  87. pyvale/mooseherder/mooseherd.py +527 -0
  88. pyvale/mooseherder/mooserunner.py +303 -0
  89. pyvale/mooseherder/outputreader.py +22 -0
  90. pyvale/mooseherder/simdata.py +92 -0
  91. pyvale/mooseherder/simrunner.py +31 -0
  92. pyvale/mooseherder/sweepreader.py +356 -0
  93. pyvale/mooseherder/sweeptools.py +76 -0
  94. pyvale/sensorsim/__init__.py +82 -0
  95. pyvale/{camera.py → sensorsim/camera.py} +7 -7
  96. pyvale/{camerasensor.py → sensorsim/camerasensor.py} +7 -7
  97. pyvale/{camerastereo.py → sensorsim/camerastereo.py} +2 -2
  98. pyvale/{cameratools.py → sensorsim/cameratools.py} +4 -4
  99. pyvale/{cython → sensorsim/cython}/rastercyth.c +596 -596
  100. pyvale/sensorsim/cython/rastercyth.cpython-311-aarch64-linux-musl.so +0 -0
  101. pyvale/{cython → sensorsim/cython}/rastercyth.py +16 -17
  102. pyvale/{errorcalculator.py → sensorsim/errorcalculator.py} +1 -1
  103. pyvale/{errorintegrator.py → sensorsim/errorintegrator.py} +2 -2
  104. pyvale/{errorrand.py → sensorsim/errorrand.py} +4 -4
  105. pyvale/{errorsyscalib.py → sensorsim/errorsyscalib.py} +2 -2
  106. pyvale/{errorsysdep.py → sensorsim/errorsysdep.py} +2 -2
  107. pyvale/{errorsysfield.py → sensorsim/errorsysfield.py} +8 -8
  108. pyvale/{errorsysindep.py → sensorsim/errorsysindep.py} +3 -3
  109. pyvale/sensorsim/exceptions.py +8 -0
  110. pyvale/{experimentsimulator.py → sensorsim/experimentsimulator.py} +23 -3
  111. pyvale/{field.py → sensorsim/field.py} +1 -1
  112. pyvale/{fieldconverter.py → sensorsim/fieldconverter.py} +72 -19
  113. pyvale/sensorsim/fieldinterp.py +37 -0
  114. pyvale/sensorsim/fieldinterpmesh.py +124 -0
  115. pyvale/sensorsim/fieldinterppoints.py +55 -0
  116. pyvale/{fieldsampler.py → sensorsim/fieldsampler.py} +4 -4
  117. pyvale/{fieldscalar.py → sensorsim/fieldscalar.py} +28 -24
  118. pyvale/{fieldtensor.py → sensorsim/fieldtensor.py} +33 -31
  119. pyvale/{fieldvector.py → sensorsim/fieldvector.py} +33 -31
  120. pyvale/{imagedef2d.py → sensorsim/imagedef2d.py} +9 -5
  121. pyvale/{integratorfactory.py → sensorsim/integratorfactory.py} +6 -6
  122. pyvale/{integratorquadrature.py → sensorsim/integratorquadrature.py} +3 -3
  123. pyvale/{integratorrectangle.py → sensorsim/integratorrectangle.py} +3 -3
  124. pyvale/{integratorspatial.py → sensorsim/integratorspatial.py} +1 -1
  125. pyvale/{rastercy.py → sensorsim/rastercy.py} +5 -5
  126. pyvale/{rasternp.py → sensorsim/rasternp.py} +9 -9
  127. pyvale/{rasteropts.py → sensorsim/rasteropts.py} +1 -1
  128. pyvale/{renderer.py → sensorsim/renderer.py} +1 -1
  129. pyvale/{rendermesh.py → sensorsim/rendermesh.py} +5 -5
  130. pyvale/{renderscene.py → sensorsim/renderscene.py} +2 -2
  131. pyvale/{sensorarray.py → sensorsim/sensorarray.py} +1 -1
  132. pyvale/{sensorarrayfactory.py → sensorsim/sensorarrayfactory.py} +12 -12
  133. pyvale/{sensorarraypoint.py → sensorsim/sensorarraypoint.py} +10 -8
  134. pyvale/{sensordata.py → sensorsim/sensordata.py} +1 -1
  135. pyvale/{sensortools.py → sensorsim/sensortools.py} +2 -20
  136. pyvale/sensorsim/simtools.py +174 -0
  137. pyvale/{visualexpplotter.py → sensorsim/visualexpplotter.py} +3 -3
  138. pyvale/{visualimages.py → sensorsim/visualimages.py} +2 -2
  139. pyvale/{visualsimanimator.py → sensorsim/visualsimanimator.py} +4 -4
  140. pyvale/{visualsimplotter.py → sensorsim/visualsimplotter.py} +5 -5
  141. pyvale/{visualsimsensors.py → sensorsim/visualsimsensors.py} +12 -12
  142. pyvale/{visualtools.py → sensorsim/visualtools.py} +1 -1
  143. pyvale/{visualtraceplotter.py → sensorsim/visualtraceplotter.py} +2 -2
  144. pyvale/simcases/case17.geo +3 -0
  145. pyvale/simcases/case17.i +4 -4
  146. pyvale/simcases/run_1case.py +1 -9
  147. pyvale/simcases/run_all_cases.py +1 -1
  148. pyvale/simcases/run_build_case.py +1 -1
  149. pyvale/simcases/run_example_cases.py +1 -1
  150. pyvale/verif/__init__.py +12 -0
  151. pyvale/{analyticsimdatafactory.py → verif/analyticsimdatafactory.py} +2 -2
  152. pyvale/{analyticsimdatagenerator.py → verif/analyticsimdatagenerator.py} +2 -2
  153. pyvale/verif/psens.py +125 -0
  154. pyvale/verif/psensconst.py +18 -0
  155. pyvale/verif/psensmech.py +227 -0
  156. pyvale/verif/psensmultiphys.py +187 -0
  157. pyvale/verif/psensscalar.py +347 -0
  158. pyvale/verif/psenstensor.py +123 -0
  159. pyvale/verif/psensvector.py +116 -0
  160. {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/METADATA +6 -7
  161. pyvale-2025.8.1.dist-info/RECORD +263 -0
  162. pyvale/cython/rastercyth.cpython-311-aarch64-linux-musl.so +0 -0
  163. pyvale/dataset.py +0 -415
  164. pyvale/dicdataimport.py +0 -247
  165. pyvale/simtools.py +0 -67
  166. pyvale-2025.7.1.dist-info/RECORD +0 -214
  167. /pyvale/{blendercalibrationdata.py → blender/blendercalibrationdata.py} +0 -0
  168. /pyvale/{dicspecklegenerator.py → dic/dicspecklegenerator.py} +0 -0
  169. /pyvale/{dicspecklequality.py → dic/dicspecklequality.py} +0 -0
  170. /pyvale/{dicstrainresults.py → dic/dicstrainresults.py} +0 -0
  171. /pyvale/{cameradata.py → sensorsim/cameradata.py} +0 -0
  172. /pyvale/{cameradata2d.py → sensorsim/cameradata2d.py} +0 -0
  173. /pyvale/{errordriftcalc.py → sensorsim/errordriftcalc.py} +0 -0
  174. /pyvale/{fieldtransform.py → sensorsim/fieldtransform.py} +0 -0
  175. /pyvale/{generatorsrandom.py → sensorsim/generatorsrandom.py} +0 -0
  176. /pyvale/{imagetools.py → sensorsim/imagetools.py} +0 -0
  177. /pyvale/{integratortype.py → sensorsim/integratortype.py} +0 -0
  178. /pyvale/{output.py → sensorsim/output.py} +0 -0
  179. /pyvale/{raster.py → sensorsim/raster.py} +0 -0
  180. /pyvale/{sensordescriptor.py → sensorsim/sensordescriptor.py} +0 -0
  181. /pyvale/{visualimagedef.py → sensorsim/visualimagedef.py} +0 -0
  182. /pyvale/{visualopts.py → sensorsim/visualopts.py} +0 -0
  183. /pyvale/{analyticmeshgen.py → verif/analyticmeshgen.py} +0 -0
  184. {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/WHEEL +0 -0
  185. {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/licenses/LICENSE +0 -0
  186. {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/top_level.txt +0 -0
@@ -16,6 +16,7 @@
16
16
  #include <pybind11/pybind11.h>
17
17
  #include <pybind11/numpy.h>
18
18
  #include <pybind11/stl.h>
19
+ #include <pybind11/iostream.h>
19
20
 
20
21
  // Program Header files
21
22
  #include "./dicinterpolator.hpp"
@@ -26,6 +27,7 @@
26
27
  #include "./dicutil.hpp"
27
28
  #include "./dicstrain.hpp"
28
29
  #include "./dicfourier.hpp"
30
+ #include "./dicsignalhandler.hpp"
29
31
 
30
32
  // cuda Header files
31
33
  #include "../cuda/malloc.hpp"
@@ -39,6 +41,10 @@ void DICengine(const py::array_t<double>& img_ref_arr,
39
41
  util::Config &conf,
40
42
  util::SaveConfig &saveconf){
41
43
 
44
+ // Register signal handler for Ctrl+C and set debug_level
45
+ signal(SIGINT, signalHandler);
46
+ g_debug_level = conf.debug_level;
47
+
42
48
  // ------------------------------------------------------------------------
43
49
  // Initialisation
44
50
  // ------------------------------------------------------------------------
@@ -59,28 +65,16 @@ void DICengine(const py::array_t<double>& img_ref_arr,
59
65
  INFO_OUT("Subset Size:", conf.ss_size << " [px]");
60
66
  INFO_OUT("Subset Step:", conf.ss_step << " [px]" );
61
67
  INFO_OUT("Number of OMP threads:", omp_get_max_threads());
68
+ INFO_OUT("Debug level: ", conf.debug_level);
62
69
  if (conf.scan_method=="RG") INFO_OUT("Reliability Guided Seed central px location: ", "("
63
70
  << conf.rg_seed.first+conf.ss_size/2 << ", " << conf.rg_seed.second+conf.ss_size/2 << ") [px] " )
64
71
 
65
- // Register signal handler for Ctrl+C
66
- signal(SIGINT, scanmethod::signalHandler);
67
72
 
68
- // get raw pointers
73
+ // get raw pointers
69
74
  bool* img_roi = static_cast<bool*>(img_roi_arr.request().ptr);
70
75
  double* img_ref = static_cast<double*>(img_ref_arr.request().ptr);
71
76
  double* img_def_stack = static_cast<double*>(img_def_stack_arr.request().ptr);
72
77
 
73
- // debugging
74
- //for (int y = 0; y < conf.px_vert; y++){
75
- // for (int x = 0; x < conf.px_hori; x++){
76
- // std::cout << x << " " << y << " ";
77
- // std::cout << img_ref[y*conf.px_hori + x] << " ";
78
- // std::cout << img_def_stack[y*conf.px_hori + x] << " ";
79
- // std::cout << img_roi[y*conf.px_hori+x] << std::endl;
80
- // }
81
- //}
82
- //exit(0);
83
-
84
78
  // ------------------------------------------------------------------------
85
79
  // get a list of ss coordinates within RIO;
86
80
  // ------------------------------------------------------------------------
@@ -108,8 +102,8 @@ void DICengine(const py::array_t<double>& img_ref_arr,
108
102
  optimizer::init(conf.corr_crit, conf.shape_func);
109
103
 
110
104
  // initialise the brute force scan
111
- std::string brute_method = "EXPANDING_WAVEFRONT";
112
- brute::init(conf.corr_crit, brute_method);
105
+ // std::string brute_method = "EXPANDING_WAVEFRONT";
106
+ // brute::init(conf.corr_crit, brute_method);
113
107
 
114
108
 
115
109
 
@@ -150,7 +144,6 @@ void DICengine(const py::array_t<double>& img_ref_arr,
150
144
 
151
145
  if (!saveconf.at_end)
152
146
  util::save_to_disk(img_num, saveconf, ssdata.back(), conf.num_def_img, conf.num_params, conf.filenames);
153
-
154
147
  }
155
148
 
156
149
  if (saveconf.at_end)
@@ -172,8 +165,16 @@ void build_info(){
172
165
  }
173
166
 
174
167
 
168
+ void set_num_threads(int n) {
169
+ omp_set_num_threads(n);
170
+ }
171
+
172
+
175
173
 
176
174
  PYBIND11_MODULE(dic2dcpp, m) {
175
+
176
+ py::add_ostream_redirect(m, "ostream_redirect");
177
+
177
178
  py::class_<util::Config>(m, "Config")
178
179
  .def(py::init<>())
179
180
  .def_readwrite("ss_step", &util::Config::ss_step)
@@ -194,7 +195,8 @@ PYBIND11_MODULE(dic2dcpp, m) {
194
195
  .def_readwrite("num_params", &util::Config::num_params)
195
196
  .def_readwrite("fft_mad", &util::Config::fft_mad)
196
197
  .def_readwrite("fft_mad_scale", &util::Config::fft_mad_scale)
197
- .def_readwrite("filenames", &util::Config::filenames);
198
+ .def_readwrite("filenames", &util::Config::filenames)
199
+ .def_readwrite("debug_level", &util::Config::debug_level);
198
200
 
199
201
  py::class_<util::SaveConfig>(m, "SaveConfig")
200
202
  .def(py::init<>())
@@ -202,12 +204,15 @@ PYBIND11_MODULE(dic2dcpp, m) {
202
204
  .def_readwrite("binary", &util::SaveConfig::binary)
203
205
  .def_readwrite("prefix", &util::SaveConfig::prefix)
204
206
  .def_readwrite("delimiter", &util::SaveConfig::delimiter)
205
- .def_readwrite("at_end", &util::SaveConfig::at_end);
207
+ .def_readwrite("at_end", &util::SaveConfig::at_end)
208
+ .def_readwrite("output_unconverged", &util::SaveConfig::output_unconverged)
209
+ .def_readwrite("shape_params", &util::SaveConfig::shape_params);
206
210
 
207
211
  // Bind the engine function
208
212
  m.def("build_info", &build_info, "build information");
209
213
  m.def("dic_engine", &DICengine, "Run 2D analysis on input images with config");
210
214
  m.def("strain_engine", &strain::engine, "Strain C++ calculations");
215
+ m.def("set_num_threads", &set_num_threads, "Set the number of OpenMP threads");
211
216
  }
212
217
 
213
218
 
@@ -52,7 +52,7 @@ namespace optimizer {
52
52
  double ftol = 0;
53
53
  double xtol = 0;
54
54
  opt.lambda = 0.001;
55
- bool converged = false;
55
+ uint8_t converged = false;
56
56
 
57
57
 
58
58
  // trying relative instead of global coordinates for the optimization
@@ -69,6 +69,9 @@ namespace optimizer {
69
69
  optimize_cost(ss_ref, ss_def, interp_def, opt, global_x, global_y);
70
70
  update_lambda(opt.costp, opt.costpdp, opt.p, opt.pdp, opt.lambda, opt.num_params);
71
71
 
72
+ // TODO: have a look at removing the two square roots in the below. Can we get away without
73
+ // it? cache is locally and perform the square root only once?
74
+
72
75
  // relative change of all parameters
73
76
  xtol = std::sqrt(std::inner_product(opt.dp.begin(), opt.dp.end(), opt.dp.begin(), 0.0)) /
74
77
  std::sqrt(std::inner_product( opt.p.begin(), opt.p.end(), opt.p.begin(), 0.0));
@@ -78,6 +81,8 @@ namespace optimizer {
78
81
  // variation on correlation coefficient
79
82
  ftol = std::abs(opt.costpdp - opt.costp);
80
83
 
84
+
85
+ // TODO: convert ssd if statement into func pointer.
81
86
  // convergence criteria
82
87
  // - rel change in parameters is less than user precision
83
88
  // - change in corr coeff is less than precision
@@ -23,19 +23,11 @@
23
23
  #include "./indicators.hpp"
24
24
  #include "./cursor_control.hpp"
25
25
  #include "./dicfourier.hpp"
26
+ #include "./dicsignalhandler.hpp"
26
27
 
27
28
  namespace scanmethod {
28
29
 
29
30
 
30
- // for graceful exit
31
- std::atomic<bool> stop_request(false);
32
-
33
- void signalHandler(int signal) {
34
- if (signal == SIGINT) {
35
- stop_request = true;
36
- }
37
- }
38
-
39
31
  void image(const double *img_ref,
40
32
  const Interpolator &interp_def,
41
33
  const util::SubsetData &ssdata,
@@ -47,11 +39,11 @@ namespace scanmethod {
47
39
 
48
40
  // progress bar
49
41
  indicators::ProgressBar bar;
50
- util::create_progress_bar(bar, conf.filenames, img_num, 100);
42
+ util::create_progress_bar(bar, conf.filenames[img_num], num_ss);
51
43
  std::atomic<int> current_progress = 0;
52
- std::atomic<int> prev_pct = 0;
44
+ int prev_pct = 0;
53
45
 
54
- // loop over subsets within the ROI
46
+ // loop over subsets within the ROI
55
47
  #pragma omp parallel shared(stop_request)
56
48
  {
57
49
 
@@ -103,10 +95,13 @@ namespace scanmethod {
103
95
 
104
96
  // update progress bar
105
97
  int progress = current_progress.fetch_add(1);
106
- util::update_progress_bar(bar, progress, num_ss, prev_pct);
98
+ if (omp_get_thread_num()==0) util::update_progress_bar(bar, progress, num_ss, prev_pct);
107
99
 
108
100
  }
109
101
  }
102
+
103
+ int progress = current_progress;
104
+ util::update_progress_bar(bar, progress-1, num_ss, prev_pct);
110
105
  bar.mark_as_completed();
111
106
  indicators::show_console_cursor(true);
112
107
 
@@ -126,9 +121,9 @@ namespace scanmethod {
126
121
 
127
122
  // progress bar
128
123
  indicators::ProgressBar bar;
129
- util::create_progress_bar(bar, conf.filenames, img_num, num_ss);
124
+ util::create_progress_bar(bar, conf.filenames[img_num], num_ss);
130
125
  std::atomic<int> current_progress = 0;
131
- std::atomic<int> prev_pct = 0;
126
+ int prev_pct = 0;
132
127
 
133
128
  // initialise subsets
134
129
  util::Subset ss_def(ss_size);
@@ -211,9 +206,11 @@ namespace scanmethod {
211
206
 
212
207
  // update progress bar
213
208
  int progress = current_progress.fetch_add(1);
214
- util::update_progress_bar(bar, progress, num_ss, prev_pct);
209
+ if (omp_get_thread_num()==0) util::update_progress_bar(bar, progress, num_ss, prev_pct);
215
210
 
216
211
  }
212
+ int progress = current_progress;
213
+ util::update_progress_bar(bar, progress-1, num_ss, prev_pct);
217
214
  bar.mark_as_completed();
218
215
  indicators::show_console_cursor(true);
219
216
  }
@@ -242,15 +239,16 @@ namespace scanmethod {
242
239
  const int ss_size = ssdata[last_size].size;
243
240
  const int ss_step = ssdata[last_size].step;
244
241
 
245
-
242
+ //TODO: sort this function name out
246
243
  fourier::mgwd(ssdata, img_ref, img_def, interp_def,
247
244
  conf.fft_mad, conf.fft_mad_scale);
248
245
 
249
246
  // progress bar
250
247
  indicators::ProgressBar bar;
251
- util::create_progress_bar(bar, conf.filenames, img_num, num_ss);
248
+ util::create_progress_bar(bar, conf.filenames[img_num], num_ss);
252
249
  std::atomic<int> current_progress(0);
253
- std::atomic<int> prev_pct(0);
250
+ //int prev_pct(0);
251
+ int prev_pct = 0;
254
252
 
255
253
  // quick check for the initial seed point
256
254
  if (!rg::is_valid_point(seed_x, seed_y, ssdata[last_size])) {
@@ -259,7 +257,7 @@ namespace scanmethod {
259
257
 
260
258
  // Initialize binary mask for computed points (initialized to 0)
261
259
  std::vector<std::atomic<int>> computed_mask(ssdata[last_size].mask.size());
262
- for (auto& val : computed_mask) val.store(0);
260
+ for (auto& val : computed_mask) val.store(0);
263
261
 
264
262
  // queue for each thread
265
263
  std::vector<std::priority_queue<rg::Point>> local_q(omp_get_max_threads());
@@ -287,7 +285,7 @@ namespace scanmethod {
287
285
  if (conf.corr_crit=="SSD")
288
286
  opt.opt_threshold = std::numeric_limits<double>::max();
289
287
 
290
- brute::Parameters brute(conf.bf_threshold, conf.max_disp);
288
+ // brute::Parameters brute(conf.bf_threshold, conf.max_disp);
291
289
 
292
290
  std::vector<std::unique_ptr<fourier::FFT>> fft_windows;
293
291
 
@@ -299,6 +297,8 @@ namespace scanmethod {
299
297
  // number of iterations to make sure we get a good convergence.
300
298
  // this is hardcoded for now. Could do with updating so that
301
299
  // the seed location is checked ahead of the main correlation run.
300
+
301
+ // TODO: opt.seed_iter exposed to user.
302
302
  opt.max_iter = 200;
303
303
 
304
304
  // ---------------------------------------------------------------------------------------------------------------------------
@@ -336,9 +336,6 @@ namespace scanmethod {
336
336
 
337
337
  computed_mask[idx].store(1);
338
338
 
339
- // int progress = current_progress.fetch_add(1);
340
- // util::update_progress_bar(bar, progress, num_ss, prev_pct);
341
-
342
339
  // loop over the neighbours for the initial seed point
343
340
  for (size_t n = 0; n < ssdata[last_size].neigh[idx].size(); n++) {
344
341
 
@@ -369,7 +366,7 @@ namespace scanmethod {
369
366
  util::append_results(img_num, nidx, nres, num_ss);
370
367
 
371
368
  // update mask
372
- computed_mask[idx].store(1);
369
+ computed_mask[nidx].store(1);
373
370
 
374
371
  // add this point to queue
375
372
  // Protect push with mutex
@@ -390,6 +387,7 @@ namespace scanmethod {
390
387
  // ---------------------------------------------------------------------------------------------------------------------------
391
388
  #pragma omp barrier
392
389
 
390
+ // TODO: reset seed location using the last computed point
393
391
  opt.max_iter = conf.max_iter;
394
392
 
395
393
  std::vector<rg::Point> temp_neigh;
@@ -494,7 +492,7 @@ namespace scanmethod {
494
492
 
495
493
  // update progress bar
496
494
  int progress = current_progress.fetch_add(1);
497
- util::update_progress_bar(bar, progress, num_ss, prev_pct);
495
+ if (omp_get_thread_num()==0) util::update_progress_bar(bar, progress, num_ss, prev_pct);
498
496
 
499
497
  }
500
498
  }
@@ -505,6 +503,8 @@ namespace scanmethod {
505
503
  }
506
504
  }
507
505
  }
506
+ int progress = current_progress;
507
+ util::update_progress_bar(bar, progress-1, num_ss, prev_pct);
508
508
  bar.mark_as_completed();
509
509
  indicators::show_console_cursor(true);
510
510
 
@@ -532,9 +532,9 @@ namespace scanmethod {
532
532
 
533
533
  // progress bar
534
534
  indicators::ProgressBar bar;
535
- util::create_progress_bar(bar, conf.filenames, img_num, num_ss);
535
+ util::create_progress_bar(bar, conf.filenames[img_num], num_ss);
536
536
  std::atomic<int> current_progress = 0;
537
- std::atomic<int> prev_pct = 0;
537
+ int prev_pct = 0;
538
538
 
539
539
  // loop over subsets within the ROI
540
540
  #pragma omp parallel shared(stop_request)
@@ -587,7 +587,7 @@ namespace scanmethod {
587
587
 
588
588
  // update progress bar
589
589
  int progress = current_progress.fetch_add(1);
590
- util::update_progress_bar(bar, progress, num_ss, prev_pct);
590
+ if (omp_get_thread_num()==0) util::update_progress_bar(bar, progress, num_ss, prev_pct);
591
591
 
592
592
  }
593
593
  }
@@ -613,9 +613,9 @@ namespace scanmethod {
613
613
 
614
614
  // progress bar
615
615
  indicators::ProgressBar bar;
616
- util::create_progress_bar(bar, conf.filenames, img_num, num_ss);
616
+ util::create_progress_bar(bar, conf.filenames[img_num], num_ss);
617
617
  std::atomic<int> current_progress = 0;
618
- std::atomic<int> prev_pct = 0;
618
+ int prev_pct = 0;
619
619
 
620
620
  // loop over subsets within the ROI
621
621
  #pragma omp parallel shared(stop_request)
@@ -666,7 +666,7 @@ namespace scanmethod {
666
666
 
667
667
  // update progress bar
668
668
  int progress = current_progress.fetch_add(1);
669
- util::update_progress_bar(bar, progress, num_ss, prev_pct);
669
+ if (omp_get_thread_num()==0) util::update_progress_bar(bar, progress, num_ss, prev_pct);
670
670
 
671
671
  }
672
672
  }
@@ -0,0 +1,16 @@
1
+ // ================================================================================
2
+ // pyvale: the python validation engine
3
+ // License: MIT
4
+ // Copyright (C) 2025 The Computer Aided Validation Team
5
+ // ================================================================================
6
+
7
+ #include "./dicsignalhandler.hpp"
8
+ #include <csignal>
9
+
10
+ std::atomic<bool> stop_request = false;
11
+
12
+ void signalHandler(int signal) {
13
+ if (signal == SIGINT) {
14
+ stop_request = true;
15
+ }
16
+ }
@@ -6,6 +6,7 @@
6
6
 
7
7
  // STD library Header files
8
8
  #include <cmath>
9
+ #include <omp.h>
9
10
  #include <vector>
10
11
  #include <iostream>
11
12
  #include <iomanip>
@@ -70,8 +71,8 @@ namespace strain {
70
71
  for (int img_num = 0; img_num < nimg; img_num++) {
71
72
 
72
73
  indicators::ProgressBar bar;
73
- util::create_progress_bar(bar, filenames, img_num, nwindows);
74
- std::atomic<int> prev_pct = 0;
74
+ util::create_progress_bar(bar, filenames[img_num], nwindows);
75
+ int prev_pct = 0;
75
76
 
76
77
  // loop over strain windows within the image
77
78
  for (int sw = 0; sw < nwindows; sw++){
@@ -81,6 +82,9 @@ namespace strain {
81
82
  results.x[sw] = x0;
82
83
  results.y[sw] = y0;
83
84
 
85
+ // TODO: through a warning. NAN out the entire window.
86
+ // it should be up to the user whether they correct with
87
+ // outlier removal / smoothing.
84
88
  results.valid_window[sw] = fill_window(ss_x, ss_y, u, v, img_num,
85
89
  sw, window, nss_x,
86
90
  nss_y, sw_size);
@@ -102,7 +106,7 @@ namespace strain {
102
106
  deform_grad, eps, nwindows, img_num);
103
107
  }
104
108
 
105
- util::update_progress_bar(bar, sw, nwindows, prev_pct);
109
+ if (omp_get_thread_num() == 0) util::update_progress_bar(bar, sw, nwindows, prev_pct);
106
110
 
107
111
  }
108
112
 
@@ -30,7 +30,7 @@ namespace util {
30
30
  std::vector<double> ftol_arr;
31
31
  std::vector<double> xtol_arr;
32
32
  std::vector<double> cost_arr;
33
- std::vector<bool> conv_arr;
33
+ std::vector<uint8_t> conv_arr;
34
34
  bool at_end;
35
35
 
36
36
 
@@ -189,12 +189,16 @@ namespace util {
189
189
  }
190
190
  }
191
191
 
192
- // When partial count num of px in roi
192
+ // When partial count num of px in roi. if its outside
193
+ // the image its still not valid
193
194
  else {
194
- if (is_valid_in_dims(px_x, px_y, px_hori, px_vert) &&
195
- is_valid_in_roi(px_x, px_y, px_hori, px_vert, img_roi)) {
195
+ if (is_valid_in_roi(px_x, px_y, px_hori, px_vert, img_roi)) {
196
196
  valid_count++;
197
197
  }
198
+ if (!is_valid_in_dims(px_x, px_y, px_hori, px_vert)) {
199
+ valid = false;
200
+ break;
201
+ }
198
202
  }
199
203
  }
200
204
 
@@ -202,7 +206,7 @@ namespace util {
202
206
  }
203
207
 
204
208
  // TODO: this is hardcoded so that atleast 70% of pixels in subset must be in ROI
205
- if (partial) {
209
+ if (partial && valid) {
206
210
  if (valid_count >= (ss_size*ss_size) * (0.70)) {
207
211
  valid = true;
208
212
  } else {
@@ -394,23 +398,44 @@ namespace util {
394
398
  int idx = img * ssdata.num + i;
395
399
  //int idx_p = num_params*idx;
396
400
 
401
+ // if the subset has not converged, set values to nan
402
+ if (!saveconf.output_unconverged && !conv_arr[idx]) {
403
+ u_arr[idx] = NAN;
404
+ v_arr[idx] = NAN;
405
+ for (int p = 0; p < num_params; p++){
406
+ p_arr[num_params*idx+p] = NAN;
407
+ }
408
+ cost_arr[idx] = NAN;
409
+ ftol_arr[idx] = NAN;
410
+ xtol_arr[idx] = NAN;
411
+ }
412
+
413
+
397
414
  double mag = std::sqrt(u_arr[idx]*u_arr[idx]+
398
415
  v_arr[idx]*v_arr[idx]);
399
416
 
400
417
  // convert from corner to centre subset coords
401
418
  double ss_x = ssdata.coords[2*i ] + static_cast<double>(ssdata.size)/2.0 - 0.5;
402
419
  double ss_y = ssdata.coords[2*i+1] + static_cast<double>(ssdata.size)/2.0 - 0.5;
420
+
403
421
 
404
422
  write_int(outfile, ss_x);
405
423
  write_int(outfile, ss_y);
406
424
  write_dbl(outfile, u_arr[idx]);
407
425
  write_dbl(outfile, v_arr[idx]);
408
426
  write_dbl(outfile, mag);
409
- write_bool(outfile, conv_arr[idx]);
427
+ write_uint8t(outfile, conv_arr[idx]);
410
428
  write_dbl(outfile, cost_arr[idx]);
411
429
  write_dbl(outfile, ftol_arr[idx]);
412
430
  write_dbl(outfile, xtol_arr[idx]);
413
431
  write_int(outfile, niter_arr[idx]);
432
+
433
+ if (saveconf.shape_params) {
434
+ for (int p = 0; p < num_params; p++){
435
+ write_dbl(outfile, p_arr[num_params*idx+p]);
436
+ }
437
+ }
438
+
414
439
  }
415
440
 
416
441
  outfile.close();
@@ -429,7 +454,18 @@ namespace util {
429
454
  outfile << "cost" << delimiter;
430
455
  outfile << "ftol" << delimiter;
431
456
  outfile << "xtol" << delimiter;
432
- outfile << "num_iterations\n";
457
+ outfile << "num_iterations";
458
+
459
+ // column headers for shape parameters
460
+ if (saveconf.shape_params) {
461
+ for (int p = 0; p < num_params; p++){
462
+ outfile << delimiter;
463
+ outfile << "shape_p" << p;
464
+ }
465
+ }
466
+
467
+ // newline after headers
468
+ outfile << "\n";
433
469
 
434
470
  for (int i = 0; i < ssdata.num; i++) {
435
471
 
@@ -440,6 +476,18 @@ namespace util {
440
476
  double ss_x = ssdata.coords[2*i ] + static_cast<double>(ssdata.size)/2.0 - 0.5;
441
477
  double ss_y = ssdata.coords[2*i+1] + static_cast<double>(ssdata.size)/2.0 - 0.5;
442
478
 
479
+ // if the subset has not converged, set values to nan
480
+ if (!saveconf.output_unconverged && !conv_arr[idx]) {
481
+ u_arr[idx] = NAN;
482
+ v_arr[idx] = NAN;
483
+ for (int p = 0; p < num_params; p++){
484
+ p_arr[num_params*idx+p] = NAN;
485
+ }
486
+ cost_arr[idx] = NAN;
487
+ ftol_arr[idx] = NAN;
488
+ xtol_arr[idx] = NAN;
489
+ }
490
+
443
491
 
444
492
  outfile << ss_x << delimiter;
445
493
  outfile << ss_y << delimiter;
@@ -447,14 +495,24 @@ namespace util {
447
495
  outfile << v_arr[idx] << delimiter;
448
496
  outfile << sqrt(u_arr[idx]*u_arr[idx]+
449
497
  v_arr[idx]*v_arr[idx]) << delimiter;
450
- //for (int p = 0; p < num_params; p++){
451
- // outfile << p_arr[idx_p+p] << delimiter;
452
- //}
453
- outfile << conv_arr[idx] << delimiter;
498
+ outfile << static_cast<int>(conv_arr[idx]) << delimiter;
454
499
  outfile << cost_arr[idx] << delimiter;
455
500
  outfile << ftol_arr[idx] << delimiter;
456
501
  outfile << xtol_arr[idx] << delimiter;
457
- outfile << niter_arr[idx] << "\n";
502
+ outfile << niter_arr[idx];
503
+
504
+ // write shape parameters if requested
505
+ if (saveconf.shape_params) {
506
+ for (int p = 0; p < num_params; p++){
507
+ outfile << delimiter;
508
+ outfile << p_arr[num_params*idx+p];
509
+ }
510
+ }
511
+
512
+ // newline after each subset
513
+ outfile << "\n";
514
+
515
+
458
516
  }
459
517
  outfile.close();
460
518
  }
@@ -532,8 +590,8 @@ namespace util {
532
590
  }
533
591
 
534
592
  void create_progress_bar(indicators::ProgressBar &bar,
535
- const std::vector<std::string> &filenames,
536
- const int img_num, const int num_ss){
593
+ const std::string &bar_title,
594
+ const int num_ss){
537
595
  //Hide cursor
538
596
  indicators::show_console_cursor(false);
539
597
  bar.set_option(indicators::option::BarWidth{50});
@@ -542,22 +600,20 @@ namespace util {
542
600
  bar.set_option(indicators::option::Lead{"#"});
543
601
  bar.set_option(indicators::option::Remainder{"-"});
544
602
  bar.set_option(indicators::option::End{"]"});
545
- bar.set_option(indicators::option::PrefixText{filenames[img_num]});
603
+ bar.set_option(indicators::option::PrefixText{bar_title});
546
604
  bar.set_option(indicators::option::ShowPercentage{true});
547
605
  bar.set_option(indicators::option::ShowElapsedTime{true});
548
606
  }
549
607
 
550
- void update_progress_bar(indicators::ProgressBar &bar, int i, int num_ss, std::atomic<int> &prev_pct) {
551
- int curr_pct = static_cast<float>(i) / static_cast<float>(num_ss) * 100;
552
- int expected = prev_pct.load();
608
+ void update_progress_bar(indicators::ProgressBar &bar, int i, int num_ss, int &prev_pct) {
609
+ int curr_pct = static_cast<int>((static_cast<float>(i) / num_ss) * 100.0f);
553
610
 
554
- // Only update bar if we've passed the previous percentage
555
- if (curr_pct > expected && prev_pct.compare_exchange_strong(expected, curr_pct)) {
556
- #pragma omp critical
557
- bar.set_progress(curr_pct);
611
+ // Only update if we've passed a new percentage
612
+ if (curr_pct > prev_pct) {
613
+ prev_pct = curr_pct;
614
+ bar.set_progress(curr_pct);
558
615
  }
559
616
  }
560
617
 
561
618
 
562
-
563
619
  }