pyvale 2025.7.1__cp311-cp311-macosx_14_0_arm64.whl → 2025.8.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 (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/dic/dic2dcpp.cpython-311-darwin.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/{cython → sensorsim/cython}/rastercyth.cpython-311-darwin.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 +262 -0
  162. pyvale/dataset.py +0 -415
  163. pyvale/dic2dcpp.cpython-311-darwin.so +0 -0
  164. pyvale/dicdataimport.py +0 -247
  165. pyvale/simtools.py +0 -67
  166. pyvale-2025.7.1.dist-info/RECORD +0 -213
  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
@@ -0,0 +1,356 @@
1
+ # ==============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+ import os
7
+ import json
8
+ from pathlib import Path
9
+ from multiprocessing.pool import Pool
10
+ from pyvale.mooseherder.directorymanager import DirectoryManager
11
+ import pyvale.mooseherder.directorymanager as dm
12
+ from pyvale.mooseherder.exodusreader import ExodusReader
13
+ from pyvale.mooseherder.simdata import SimData, SimReadConfig
14
+
15
+
16
+ class SweepReader:
17
+ """Used to read the output from one or more calls to mooseherd.run_para().
18
+ has configurable options for reading in the variable sweep in parallel.
19
+ """
20
+ def __init__(self,
21
+ dir_manager: DirectoryManager,
22
+ num_para_read: int = 1) -> None:
23
+ """Construct the sweep reader with a directory manager and
24
+ the number of simulations to read in parallel.
25
+
26
+ Parameters
27
+ ----------
28
+ dir_manager : DirectoryManager
29
+ The directory manager as used by the mooseherd that ran the
30
+ simulation sweep.
31
+ num_para_read : int, optional
32
+ Number of simulation to read in parallel. Defaults to 1.
33
+ """
34
+ self._dir_manager = dir_manager
35
+ self._output_files = list([])
36
+ self._n_para_read = num_para_read
37
+
38
+
39
+ def read_output_file_key(self, sweep_iter: int) -> list[list[Path | None]]:
40
+ """read_output_key: reads the output key json file produced by running
41
+ the variable sweep. The output key file maps which simulation were run
42
+ in a given sub directory.
43
+
44
+ Parameters
45
+ ----------
46
+ sweep_iter : int
47
+ sweep iteration to read. This is the number that
48
+ is appended to the output key file e.g. output-key-2.json for
49
+ the 2nd call to run_seq/para in the mooseherd.
50
+
51
+
52
+ Returns
53
+ -------
54
+ list[list[Path]]
55
+ paths to the outputs from the variable sweep the
56
+ outer list is the simulation iteration and the inner list is
57
+ the position in the simulation chain.
58
+
59
+ """
60
+ output_key = self._dir_manager.get_output_key_file(sweep_iter)
61
+ if not output_key.is_file():
62
+ raise FileNotFoundError(f'Output key file for sweep iteration {sweep_iter} not found at path: {output_key}')
63
+
64
+ with open(output_key, 'r', encoding='utf-8') as okf:
65
+ output_files = json.load(okf)
66
+
67
+ return dm.output_str_to_paths(output_files)
68
+
69
+
70
+ def read_all_output_file_keys(self) -> list[list[Path | None]]:
71
+ """read_all_output_keys: as read_output_keys() but finds all output key
72
+ files in the first sub-directory and reads them.
73
+
74
+ Parameters
75
+ ----------
76
+
77
+ Returns
78
+ -------
79
+ list[list[Path]]
80
+ paths to the outputs from the variable sweep the
81
+ outer list is the simulation iteration and the inner list is
82
+ the position in the simulation chain.
83
+
84
+ Raises
85
+ ------
86
+ FileNotFoundError
87
+ No output key files found in the first sub-
88
+ directory.
89
+
90
+ """
91
+ output_paths = self._find_files_by_str(self._dir_manager.get_output_key_tag(),
92
+ self._dir_manager.get_run_dir(0))
93
+
94
+ if len(output_paths) == 0:
95
+ raise FileNotFoundError("No output key json files found.")
96
+
97
+ output_files = list([])
98
+ for output_path in output_paths:
99
+ sweep_iter = output_path.name.split('.')[0].split('-')[-1]
100
+ output_files = output_files + self.read_output_file_key(int(sweep_iter))
101
+
102
+ self._output_files = output_files
103
+ return self._output_files
104
+
105
+
106
+ def read_sweep_var_file(self, sweep_iter: int = 1
107
+ ) -> list[list[dict | None]]:
108
+ """read_sweep_var_file: reads the file containing the sweep variable
109
+ dictionary for a given sweep iteration and returns it.
110
+
111
+ Parameters
112
+ ----------
113
+ sweep_iter : int
114
+ The sweep iteration (i.e. the call
115
+ number to mooseher.run_seq/para) Defaults to 1.
116
+
117
+ Returns
118
+ -------
119
+ list[list[dict | None]]
120
+ The sweep variables as passed to mooseherd
121
+ .run_seq/para.
122
+
123
+ Raises
124
+ ------
125
+ FileNotFoundError
126
+ Sweep file not found.
127
+
128
+ """
129
+ sweep_var_file = self._dir_manager.get_sweep_var_file(sweep_iter)
130
+ if not sweep_var_file.is_file():
131
+ raise FileNotFoundError(
132
+ f'Sweep variable file for sweep iteration {sweep_iter}'+
133
+ f'not found at path: {sweep_var_file}')
134
+
135
+ with open(sweep_var_file, 'r', encoding='utf-8') as svf:
136
+ sweep_vars = json.load(svf)
137
+
138
+ return sweep_vars
139
+
140
+
141
+ def read_all_sweep_var_files(self) -> list[list[dict | None]]:
142
+ """read_all_sweep_var_files: as read sweep variables but finds all
143
+ sweep variables in the first sub-directory and reads them.
144
+
145
+ Parameters
146
+ ----------
147
+
148
+ Returns
149
+ -------
150
+ list[list[dict | None]]
151
+ The sweep variables as passed to mooseherd
152
+ .run_seq/para. Additional sweep iterations are appended to the
153
+ end of the list.
154
+
155
+ Raises
156
+ ------
157
+ FileNotFoundError
158
+ No sweep variable files found.
159
+
160
+ """
161
+ sweep_var_paths = self._find_files_by_str(self._dir_manager.get_sweep_var_tag(),
162
+ self._dir_manager.get_run_dir(0))
163
+
164
+ if len(sweep_var_paths) == 0:
165
+ raise FileNotFoundError("No sweep variable json files found.")
166
+
167
+ sweep_vars = list([])
168
+ for ii,_ in enumerate(sweep_var_paths):
169
+ sweep_vars = sweep_vars + self.read_sweep_var_file(ii+1)
170
+
171
+ return sweep_vars
172
+
173
+
174
+ def _find_files_by_str(self, search_str: str, search_path: Path
175
+ ) -> list[Path]:
176
+ """_find_files_by_str: helper function for finding output key and sweep
177
+ variable files based on a specific string.
178
+
179
+ Parameters
180
+ ----------
181
+ search_str : str
182
+ the string to find in the file name.
183
+ search_path : Path
184
+ the path to the directory to search for files
185
+ containing the specified string.
186
+
187
+
188
+ Returns
189
+ -------
190
+ list[Path]
191
+ list of paths to the files found with the string.
192
+
193
+ """
194
+ found_files = list([])
195
+
196
+ all_files = os.listdir(search_path)
197
+
198
+ for ff in all_files:
199
+ if search_str in ff:
200
+ found_files.append(Path(ff))
201
+
202
+ found_files.sort()
203
+
204
+ return found_files
205
+
206
+
207
+ def get_output_files(self) -> list[list[Path | None]]:
208
+ """get_output_files
209
+
210
+ Parameters
211
+ ----------
212
+
213
+ Returns
214
+ -------
215
+ list[list[Path]]
216
+ returns the paths to the output files as read
217
+ from the output key files.
218
+
219
+ """
220
+ return self._output_files
221
+
222
+
223
+ def read_results_once(self,
224
+ output_files: list[Path | None],
225
+ read_config: SimReadConfig | None = None
226
+ ) -> list[SimData | None]:
227
+ """read_results_once: reads a specific simulation at the specified
228
+ path based on the specified read configuration. If the read
229
+ configuration is None then read everything.
230
+
231
+ Parameters
232
+ ----------
233
+ output_file : list[Path | None] :
234
+ Path to the file to read
235
+ read_config : SimReadConfig | None
236
+ class to specify the data to read
237
+
238
+ Returns
239
+ -------
240
+ list[SimData | None]
241
+ list of data classes holding the simulation
242
+ data for each simulation in the chain. Will be None for a pre-
243
+ processor like Gmsh that has not output.
244
+
245
+ """
246
+ data_list = list([])
247
+
248
+ for ff in output_files:
249
+ if ff is None:
250
+ data_list.append(None)
251
+ else:
252
+ #TODO: replace with output reader ABC
253
+ reader = ExodusReader(ff)
254
+ if read_config is None:
255
+ data_list.append(reader.read_all_sim_data())
256
+ else:
257
+ data_list.append(reader.read_sim_data(read_config))
258
+
259
+ return data_list
260
+
261
+
262
+ def read_sequential(self,
263
+ sweep_iter: int | None = None,
264
+ read_config: SimReadConfig | None = None
265
+ ) -> list[list[SimData]]:
266
+ """read_results_sequential: reads the variable sweep results
267
+ sequentially. Can read a specific iteration with a specific read config
268
+ but defaults to reading everything found in the simulation directories.
269
+
270
+ Parameters
271
+ ----------
272
+ sweep_iter : int | None
273
+ sweep iteration number to read.
274
+ Reads the output key file for this iteration. Defaults to None.
275
+ read_config : SimReadConfig | None
276
+ object for specifying
277
+ which variables are to be extracted from the output. Defaults
278
+ to None.
279
+
280
+ Returns
281
+ -------
282
+ list[list[SimData]]
283
+ list of lists of SimData objects containing the
284
+ simulation results corresponding to each combination of
285
+ variables.
286
+
287
+ """
288
+ self._start_read_output_keys(sweep_iter)
289
+
290
+ sweep_results = list([])
291
+ for ii,ff in enumerate(self._output_files):
292
+ sweep_results.append(self.read_results_once(ff,read_config))
293
+
294
+ return sweep_results
295
+
296
+
297
+ def read_results_para(self,
298
+ sweep_iter: int | None = None,
299
+ read_config: SimReadConfig | None = None
300
+ ) -> list[list[SimData]]:
301
+ """read_results_para: reads the variable sweep results in parallel
302
+ Can read a specific iteration with a specific read config but defaults
303
+ to reading everything found in the simulation directories.
304
+
305
+ Parameters
306
+ ----------
307
+ sweep_iter : int | None
308
+ sweep iteration number to read.
309
+ Reads the output key file for this iteration. Defaults to None.
310
+ read_config : SimReadConfig | None
311
+ object for specifying
312
+ which variables are to be extracted from the output. Defaults
313
+ to None.
314
+
315
+ Returns
316
+ -------
317
+ list[list[SimData]]
318
+ list of lists of SimData objects containing the
319
+ simulation results corresponding to each combination of
320
+ variables.
321
+
322
+ """
323
+ self._start_read_output_keys(sweep_iter)
324
+
325
+ with Pool(self._n_para_read) as pool:
326
+ processes = list([])
327
+ for ff in self._output_files:
328
+ processes.append(pool.apply_async(
329
+ self.read_results_once, args=(ff,read_config)))
330
+
331
+ sweep_results = [pp.get() for pp in processes]
332
+
333
+ return sweep_results
334
+
335
+
336
+ def _start_read_output_keys(self, sweep_iter: int | None):
337
+ """_start_read: helper function to read the output keys for a specific
338
+ simulation iteration prior to reading the simulation outputs.
339
+
340
+ Parameters
341
+ ----------
342
+ sweep_iter : int | None
343
+ sweep iteration number to read. If None
344
+ read all of the output keys.
345
+
346
+ Returns
347
+ -------
348
+
349
+ """
350
+ if self._output_files == '':
351
+ self._output_files = self.read_output_file_key(sweep_iter=1)
352
+
353
+ if sweep_iter is None:
354
+ self.read_all_output_file_keys()
355
+
356
+
@@ -0,0 +1,76 @@
1
+ # ==============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+ from typing import Any
7
+ import itertools
8
+
9
+
10
+ def _single_sim_param_grid(in_params: dict[str,list[Any]] | None
11
+ ) -> list[dict[str,Any]] | None:
12
+ """Private helper function that unpacks the list inside each dictionary key
13
+ to find every possible unique combination of variables within each list.
14
+ This gives a list of dictionaries where the dictionary values are single
15
+ values not lists.
16
+
17
+ Parameters
18
+ ----------
19
+ in_params : dict[str,list[Any]] | None
20
+ Dictionary of lists keyed by the simulation variable name with lists
21
+ containing the parameters the will form the grid of combinations.
22
+
23
+ Returns
24
+ -------
25
+ list[dict[str,Any]] | None
26
+ The list of unique dictionaries that have single values not lists.
27
+ """
28
+ if in_params is None:
29
+ return None
30
+
31
+ param_keys = in_params.keys()
32
+ param_vals = in_params.values()
33
+ param_combs = itertools.product(*param_vals)
34
+
35
+ params = []
36
+ for cc in param_combs:
37
+ this_params = dict(zip(param_keys,cc))
38
+ params.append(this_params)
39
+
40
+ return params
41
+
42
+
43
+ def sweep_param_grid(in_params: list[dict[str,list[Any]] | None]
44
+ ) -> list[list[dict[str,Any] | None]]:
45
+ """Helper function for generating grid parameter sweeps for all possible
46
+ combinations of modified variables in the simulation chain.
47
+
48
+ Parameters
49
+ ----------
50
+ in_params : list[dict[str,list[Any]] | None]
51
+ List of the same length as the simulation input modifier/runner list
52
+ where each dictionary corresponds to the variables that will be modified
53
+ for the corresponding simulation tool. The variables should be keyed by
54
+ their string identigfier in the simulation input file and the list
55
+ should contain all unique values of the variables to analyse.
56
+
57
+ Returns
58
+ -------
59
+ list[list[dict[str,Any] | None]]
60
+ The outer list is for each unique parameter combination. The inner list
61
+ position corresponds to the simulation input modifier/runner position in
62
+ the simulation chain. The dictionary is then keyed by the variable name
63
+ in the corresponding input file and the unique value the variable takes
64
+ for this combination of parameters.
65
+ """
66
+ param_grids = []
67
+ for pp in in_params:
68
+ this_params = _single_sim_param_grid(pp)
69
+
70
+ if this_params is None:
71
+ param_grids.append([None])
72
+ else:
73
+ param_grids.append(this_params)
74
+
75
+ sweep_params = [list(pp) for pp in itertools.product(*param_grids)]
76
+ return sweep_params
@@ -0,0 +1,82 @@
1
+ # ==============================================================================
2
+ # . the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ # ==============================================================================
6
+
7
+ """
8
+ The python validation engine (`.) is your virtual engineering laboratory:
9
+ An all-in-one package for sensor simulation, sensor uncertainty quantification,
10
+ sensor placement optimisation and simulation calibration/validation. Used to
11
+ simulate experimental data from an input multi-physics simulation by explicitly
12
+ modelling sensors with realistic uncertainties. Useful for experimental design,
13
+ sensor placement optimisation, testing simulation validation metrics and
14
+ virtually testing digital shadows/twins.
15
+ """
16
+
17
+ # NOTE: this simplifies and decouples how the user calls .from the
18
+ # underlying project structure: the user should be able to use '.'
19
+ # and access everything in one layer without multiple import dots
20
+
21
+ from .field import *
22
+ from .fieldscalar import *
23
+ from .fieldvector import *
24
+ from .fieldtensor import *
25
+ from .fieldconverter import *
26
+ from .fieldtransform import *
27
+ from .fieldinterp import *
28
+ from .fieldinterpmesh import *
29
+ from .fieldinterppoints import*
30
+
31
+ from .integratorspatial import *
32
+ from .integratorquadrature import *
33
+ from .integratorrectangle import *
34
+ from .integratorfactory import *
35
+
36
+ from .sensordescriptor import *
37
+ from .sensortools import *
38
+ from .sensorarray import *
39
+ from .sensorarrayfactory import *
40
+ from .sensorarraypoint import *
41
+ from .sensordata import *
42
+
43
+ from .camera import *
44
+ from .cameradata import *
45
+ from .cameradata2d import *
46
+ from .cameratools import *
47
+ from .camerastereo import *
48
+
49
+ from .rastercy import *
50
+
51
+ from .renderscene import *
52
+ from .rendermesh import *
53
+ from .rasternp import *
54
+
55
+ from .imagedef2d import *
56
+
57
+ from .errorintegrator import *
58
+ from .errorrand import *
59
+ from .errorsysindep import *
60
+ from .errorsysdep import *
61
+ from .errorsysfield import *
62
+ from .errorsyscalib import *
63
+ from .errordriftcalc import *
64
+
65
+ from .generatorsrandom import *
66
+
67
+ from .visualopts import *
68
+ from .visualtools import *
69
+ from .visualsimsensors import *
70
+ from .visualsimanimator import *
71
+ from .visualexpplotter import *
72
+ from .visualtraceplotter import *
73
+ from .visualimages import *
74
+ from .visualimagedef import *
75
+
76
+ from .simtools import *
77
+
78
+ from .experimentsimulator import *
79
+ from .output import *
80
+ from .exceptions import *
81
+
82
+
@@ -9,13 +9,13 @@ NOTE: This module is a feature under developement.
9
9
  """
10
10
 
11
11
  import numpy as np
12
- from pyvale.field import IField
13
- from pyvale.sensorarray import ISensorArray
14
- from pyvale.errorintegrator import ErrIntegrator
15
- from pyvale.sensordescriptor import SensorDescriptor
16
- from pyvale.fieldsampler import sample_field_with_sensor_data
17
- from pyvale.cameradata2d import CameraData2D
18
- from pyvale.cameratools import CameraTools
12
+ from pyvale.sensorsim.field import IField
13
+ from pyvale.sensorsim.sensorarray import ISensorArray
14
+ from pyvale.sensorsim.errorintegrator import ErrIntegrator
15
+ from pyvale.sensorsim.sensordescriptor import SensorDescriptor
16
+ from pyvale.sensorsim.fieldsampler import sample_field_with_sensor_data
17
+ from pyvale.sensorsim.cameradata2d import CameraData2D
18
+ from pyvale.sensorsim.cameratools import CameraTools
19
19
 
20
20
 
21
21
 
@@ -9,13 +9,13 @@ NOTE: This module is a feature under developement.
9
9
  """
10
10
 
11
11
  import numpy as np
12
- from pyvale.field import IField
13
- from pyvale.sensorarray import ISensorArray
14
- from pyvale.errorintegrator import ErrIntegrator
15
- from pyvale.sensordescriptor import SensorDescriptor
16
- from pyvale.fieldsampler import sample_field_with_sensor_data
17
- from pyvale.cameradata2d import CameraData2D
18
- from pyvale.cameratools import CameraTools
12
+ from pyavle.sensorsim.field import IField
13
+ from pyavle.sensorsim.sensorarray import ISensorArray
14
+ from pyavle.sensorsim.errorintegrator import ErrIntegrator
15
+ from pyavle.sensorsim.sensordescriptor import SensorDescriptor
16
+ from pyavle.sensorsim.fieldsampler import sample_field_with_sensor_data
17
+ from pyavle.sensorsim.cameradata2d import CameraData2D
18
+ from pyavle.sensorsim.cameratools import CameraTools
19
19
 
20
20
 
21
21
 
@@ -13,8 +13,8 @@ from pathlib import Path
13
13
  import numpy as np
14
14
  import yaml
15
15
  from scipy.spatial.transform import Rotation
16
- from pyvale.cameradata import CameraData
17
- from pyvale.pyvaleexceptions import BlenderError
16
+ from pyvale.sensorsim.cameradata import CameraData
17
+ from pyvale.blender.blenderexceptions import BlenderError
18
18
 
19
19
 
20
20
  class CameraStereo:
@@ -16,10 +16,10 @@ import copy
16
16
  from scipy.spatial.transform import Rotation
17
17
  import matplotlib.image as mplim
18
18
  from PIL import Image
19
- from pyvale.cameradata2d import CameraData2D
20
- from pyvale.sensordata import SensorData
21
- from pyvale.cameradata import CameraData
22
- from pyvale.camerastereo import CameraStereo
19
+ from pyvale.sensorsim.cameradata2d import CameraData2D
20
+ from pyvale.sensorsim.sensordata import SensorData
21
+ from pyvale.sensorsim.cameradata import CameraData
22
+ from pyvale.sensorsim.camerastereo import CameraStereo
23
23
 
24
24
 
25
25
  class CameraTools: