pyvale 2025.7.1__cp311-cp311-musllinux_1_2_i686.whl → 2025.8.1__cp311-cp311-musllinux_1_2_i686.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 (185) 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-i386-linux-musl.so → dic/dic2dcpp.cpython-311-i386-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/{cython → sensorsim/cython}/rastercyth.cpython-311-i386-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/dataset.py +0 -415
  163. pyvale/dicdataimport.py +0 -247
  164. pyvale/simtools.py +0 -67
  165. pyvale-2025.7.1.dist-info/RECORD +0 -214
  166. /pyvale/{blendercalibrationdata.py → blender/blendercalibrationdata.py} +0 -0
  167. /pyvale/{dicspecklegenerator.py → dic/dicspecklegenerator.py} +0 -0
  168. /pyvale/{dicspecklequality.py → dic/dicspecklequality.py} +0 -0
  169. /pyvale/{dicstrainresults.py → dic/dicstrainresults.py} +0 -0
  170. /pyvale/{cameradata.py → sensorsim/cameradata.py} +0 -0
  171. /pyvale/{cameradata2d.py → sensorsim/cameradata2d.py} +0 -0
  172. /pyvale/{errordriftcalc.py → sensorsim/errordriftcalc.py} +0 -0
  173. /pyvale/{fieldtransform.py → sensorsim/fieldtransform.py} +0 -0
  174. /pyvale/{generatorsrandom.py → sensorsim/generatorsrandom.py} +0 -0
  175. /pyvale/{imagetools.py → sensorsim/imagetools.py} +0 -0
  176. /pyvale/{integratortype.py → sensorsim/integratortype.py} +0 -0
  177. /pyvale/{output.py → sensorsim/output.py} +0 -0
  178. /pyvale/{raster.py → sensorsim/raster.py} +0 -0
  179. /pyvale/{sensordescriptor.py → sensorsim/sensordescriptor.py} +0 -0
  180. /pyvale/{visualimagedef.py → sensorsim/visualimagedef.py} +0 -0
  181. /pyvale/{visualopts.py → sensorsim/visualopts.py} +0 -0
  182. /pyvale/{analyticmeshgen.py → verif/analyticmeshgen.py} +0 -0
  183. {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/WHEEL +0 -0
  184. {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/licenses/LICENSE +0 -0
  185. {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,227 @@
1
+ #===============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ #===============================================================================
6
+ import numpy as np
7
+ import pyvale.mooseherder as mh
8
+ import pyvale.sensorsim as sens
9
+ import pyvale.verif.psens as psens
10
+ import pyvale.verif.psensconst as psensconst
11
+ import pyvale.dataset as dataset
12
+
13
+ """
14
+ DEVELOPER VERIFICATION MODULE
15
+ --------------------------------------------------------------------------------
16
+ This module contains developer utility functions used for verification testing
17
+ of the point sensor simulation toolbox in pyvale.
18
+
19
+ Specifically, this module contains functions used for testing point sensors
20
+ applied to mechanical fields (displacement/strain) for testing vector and tensor
21
+ field point sensors.
22
+ """
23
+
24
+ def simdata_mech_2d() -> mh.SimData:
25
+ data_path = dataset.mechanical_2d_path()
26
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
27
+ sim_data = sens.scale_length_units(scale=1000.0,
28
+ sim_data=sim_data,
29
+ disp_comps=("disp_x","disp_y"))
30
+ return sim_data
31
+
32
+
33
+ def simdata_mech_3d() -> mh.SimData:
34
+ data_path = dataset.element_case_output_path(dataset.EElemTest.HEX20)
35
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
36
+ field_comps = ("disp_x","disp_y","disp_z")
37
+ sim_data = sens.scale_length_units(scale=1000.0,
38
+ sim_data=sim_data,
39
+ disp_comps=field_comps)
40
+ return sim_data
41
+
42
+ def sens_pos_2d() -> dict[str,np.ndarray]:
43
+ sim_dims = sens.SimTools.get_sim_dims(simdata_mech_2d())
44
+ sens_pos = {}
45
+
46
+ x_lims = sim_dims["x"]
47
+ y_lims = sim_dims["y"]
48
+ z_lims = (0,0)
49
+
50
+ n_sens = (1,4,1)
51
+ sens_pos["line-4"] = sens.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
52
+
53
+ n_sens = (2,3,1)
54
+ sens_pos["grid-23"] = sens.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
55
+
56
+ return sens_pos
57
+
58
+
59
+ def sens_pos_3d() -> dict[str,np.ndarray]:
60
+ sens_pos = {}
61
+ sens_pos["cent-cube"] = np.array(((5.0,0.0,5.0), # xz
62
+ (5.0,10.0,5.0), # xz
63
+ (5.0,5.0,0.0), # xy
64
+ (5.0,5.0,10.0), # xy
65
+ (0.0,5.0,5.0), # yz
66
+ (10.0,5.0,5.0),)) # yz
67
+ return sens_pos
68
+
69
+ def sens_pos_2d_lock(sens_pos: np.ndarray) -> dict[str,np.ndarray]:
70
+ pos_lock = {}
71
+ (xx,yy,zz) = (0,1,2)
72
+
73
+ lock = np.full_like(sens_pos,False,dtype=bool)
74
+ lock[:,zz] = True # lock z
75
+ pos_lock["line-4"] = None
76
+
77
+ lock = np.full_like(sens_pos,False,dtype=bool)
78
+ lock[:,zz] = True # lock z
79
+ pos_lock["grid-23"] = None
80
+
81
+ return pos_lock
82
+
83
+
84
+ def sens_pos_3d_lock(sens_pos: np.ndarray) -> dict[str,np.ndarray]:
85
+ pos_lock = {}
86
+ (xx,yy,zz) = (0,1,2)
87
+
88
+ lock = np.full_like(sens_pos,False,dtype=bool)
89
+ lock[0,yy] = True
90
+ lock[1,yy] = True
91
+ lock[2,zz] = True
92
+ lock[3,zz] = True
93
+ lock[4,xx] = True
94
+ lock[5,xx] = True
95
+ pos_lock["cent-cube"] = lock
96
+
97
+ return pos_lock
98
+
99
+
100
+ def sens_data_2d_dict() -> dict[str,sens.SensorData]:
101
+ return psens.sens_data_dict(simdata_mech_2d(),sens_pos_2d())
102
+
103
+
104
+ def sens_data_3d_dict() -> dict[str,sens.SensorData]:
105
+ return psens.sens_data_dict(simdata_mech_3d(),sens_pos_3d())
106
+
107
+
108
+ def err_chain_field(field: sens.IField,
109
+ sens_pos: np.ndarray,
110
+ samp_times: np.ndarray | None,
111
+ pos_lock: np.ndarray | None,
112
+ ) -> list[sens.IErrCalculator]:
113
+
114
+ if samp_times is None:
115
+ samp_times = field.get_time_steps()
116
+
117
+ pos_offset_xyz = np.array((1.0,1.0,-1.0),dtype=np.float64)
118
+ pos_offset_xyz = np.tile(pos_offset_xyz,(sens_pos.shape[0],1))
119
+
120
+ time_offset = np.full((samp_times.shape[0],),0.1)
121
+
122
+ pos_rand = sens.GenNormal(std=1.0,
123
+ mean=0.0,
124
+ seed=psensconst.GOLD_SEED) # units = mm
125
+ time_rand = sens.GenNormal(std=0.1,
126
+ mean=0.0,
127
+ seed=psensconst.GOLD_SEED) # units = s
128
+ ang_rand = sens.GenUniform(low=-1.0,
129
+ high=1.0,
130
+ seed=psensconst.GOLD_SEED)
131
+
132
+ field_err_data = sens.ErrFieldData(
133
+ pos_offset_xyz=pos_offset_xyz,
134
+ time_offset=time_offset,
135
+ pos_rand_xyz=(pos_rand,pos_rand,pos_rand),
136
+ ang_rand_zyx=(ang_rand,ang_rand,ang_rand),
137
+ time_rand=time_rand,
138
+ pos_lock_xyz=pos_lock,
139
+ )
140
+
141
+ err_chain = []
142
+ err_chain.append(sens.ErrSysField(field,
143
+ field_err_data))
144
+ return err_chain
145
+
146
+
147
+ def err_chain_field_dep(field: sens.IField,
148
+ sens_pos: np.ndarray,
149
+ samp_times: np.ndarray | None,
150
+ pos_lock: np.ndarray | None,
151
+ ) -> list[sens.IErrCalculator]:
152
+
153
+ if samp_times is None:
154
+ samp_times = field.get_time_steps()
155
+
156
+ time_offset = 2.0*np.ones_like(samp_times)
157
+ time_error_data = sens.ErrFieldData(time_offset=time_offset)
158
+
159
+ pos_offset = -1.0*np.ones_like(sens_pos)
160
+ pos_error_data = sens.ErrFieldData(pos_offset_xyz=pos_offset,
161
+ pos_lock_xyz=pos_lock)
162
+
163
+ angle_offset = np.ones_like(sens_pos)
164
+ angle_error_data = sens.ErrFieldData(ang_offset_zyx=angle_offset)
165
+
166
+ err_chain = []
167
+ err_chain.append(sens.ErrSysField(field,
168
+ time_error_data,
169
+ sens.EErrDep.DEPENDENT))
170
+ err_chain.append(sens.ErrSysField(field,
171
+ time_error_data,
172
+ sens.EErrDep.DEPENDENT))
173
+ err_chain.append(sens.ErrSysField(field,
174
+ pos_error_data,
175
+ sens.EErrDep.DEPENDENT))
176
+ err_chain.append(sens.ErrSysField(field,
177
+ pos_error_data,
178
+ sens.EErrDep.DEPENDENT))
179
+ err_chain.append(sens.ErrSysField(field,
180
+ angle_error_data,
181
+ sens.EErrDep.DEPENDENT))
182
+ err_chain.append(sens.ErrSysField(field,
183
+ angle_error_data,
184
+ sens.EErrDep.DEPENDENT))
185
+ return err_chain
186
+
187
+
188
+ def err_chain_2d_dict(field: sens.IField,
189
+ sens_pos: np.ndarray,
190
+ samp_times: np.ndarray | None,
191
+ pos_lock: np.ndarray | None
192
+ ) -> dict[str,list[sens.IErrCalculator]]:
193
+ err_cases = {}
194
+ err_cases["none"] = None
195
+ err_cases["basic"] = psens.err_chain_basic()
196
+ err_cases["basic-gen"] = psens.err_chain_gen()
197
+ err_cases["field"] = err_chain_field(field,sens_pos,samp_times,pos_lock)
198
+ err_cases["field-dep"] = err_chain_field_dep(field,sens_pos,samp_times,pos_lock)
199
+
200
+ # This has to be last so when we chain all errors together the saturation
201
+ # error is the last thing that happens
202
+ err_cases["basic-dep"] = psens.err_chain_dep()
203
+
204
+ err_cases["all"] = psens.err_chain_all(err_cases)
205
+
206
+ return err_cases
207
+
208
+
209
+ def err_chain_3d_dict(field: sens.IField,
210
+ sens_pos: np.ndarray,
211
+ samp_times: np.ndarray | None,
212
+ pos_lock: np.ndarray | None
213
+ ) -> dict[str,list[sens.IErrCalculator]]:
214
+ err_cases = {}
215
+ err_cases["none"] = None
216
+ err_cases["basic"] = psens.err_chain_basic()
217
+ err_cases["basic-gen"] = psens.err_chain_gen()
218
+ err_cases["field"] = err_chain_field(field,sens_pos,samp_times,pos_lock)
219
+ err_cases["field-dep"] = err_chain_field_dep(field,sens_pos,samp_times,pos_lock)
220
+
221
+ # This has to be last so when we chain all errors together the saturation
222
+ # error is the last thing that happens
223
+ err_cases["basic-dep"] = psens.err_chain_dep()
224
+
225
+ err_cases["all"] = psens.err_chain_all(err_cases)
226
+
227
+ return err_cases
@@ -0,0 +1,187 @@
1
+ #===============================================================================
2
+ # pyvale: the python validation engine
3
+ # License: MIT
4
+ # Copyright (C) 2025 The Computer Aided Validation Team
5
+ #===============================================================================
6
+ from pathlib import Path
7
+ import copy
8
+ import numpy as np
9
+ import pyvale.mooseherder as mh
10
+ import pyvale.sensorsim as sens
11
+ import pyvale.verif.psens as psens
12
+ import pyvale.verif.psensscalar as psensscalar
13
+ import pyvale.verif.psensvector as psensvector
14
+ import pyvale.verif.psenstensor as psenstensor
15
+ import pyvale.verif.psensmech as psensmech
16
+ import pyvale.dataset as dataset
17
+
18
+
19
+ def load_simdata_list(data_paths: list[Path],
20
+ disp_comps: tuple[str,...]) -> list[mh.SimData]:
21
+ sim_list = []
22
+ for pp in data_paths:
23
+ sim_data = mh.ExodusReader(pp).read_all_sim_data()
24
+ sim_data = sens.scale_length_units(scale=1000.0,
25
+ sim_data=sim_data,
26
+ disp_comps=disp_comps)
27
+ sim_list.append(sim_data)
28
+
29
+ return sim_list
30
+
31
+
32
+ def simdata_list_2d() -> list[mh.SimData]:
33
+ data_paths = dataset.thermomechanical_2d_experiment_paths()
34
+ disp_comps = ("disp_x","disp_y")
35
+ return load_simdata_list(data_paths,disp_comps)
36
+
37
+
38
+ def simdata_list_3d() -> list[mh.SimData]:
39
+ data_paths = [dataset.element_case_output_path(dataset.EElemTest.TET4),
40
+ dataset.element_case_output_path(dataset.EElemTest.TET10),
41
+ dataset.element_case_output_path(dataset.EElemTest.HEX8),
42
+ dataset.element_case_output_path(dataset.EElemTest.HEX20)]
43
+ disp_comps = ("disp_x","disp_y","disp_z")
44
+ return load_simdata_list(data_paths,disp_comps)
45
+
46
+
47
+ def sens_pos_2d() -> dict[str,np.ndarray]:
48
+ # Geometry does not change
49
+ sim_dims = sens.SimTools.get_sim_dims(simdata_list_2d()[0])
50
+ sens_pos = {}
51
+
52
+ x_lims = sim_dims["x"]
53
+ y_lims = sim_dims["y"]
54
+ z_lims = (0,0)
55
+
56
+ n_sens = (2,2,1)
57
+ sens_pos["grid-22"] = sens.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
58
+
59
+ return sens_pos
60
+
61
+ def sens_pos_2d_lock(sens_pos: np.ndarray) -> dict[str,np.ndarray]:
62
+ pos_lock = {}
63
+ (xx,yy,zz) = (0,1,2)
64
+
65
+ lock = np.full_like(sens_pos,False,dtype=bool)
66
+ lock[:,zz] = True # lock z
67
+ pos_lock["grid-22"] = None
68
+
69
+ return pos_lock
70
+
71
+
72
+ def sens_pos_3d_lock(sens_pos: np.ndarray) -> dict[str,np.ndarray]:
73
+ pos_lock = {}
74
+ (xx,yy,zz) = (0,1,2)
75
+
76
+ lock = np.full_like(sens_pos,False,dtype=bool)
77
+ lock[0,yy] = True
78
+ lock[1,yy] = True
79
+ lock[2,zz] = True
80
+ lock[3,zz] = True
81
+ lock[4,xx] = True
82
+ lock[5,xx] = True
83
+ pos_lock["cent-cube"] = lock
84
+
85
+ return pos_lock
86
+
87
+
88
+ def sens_pos_3d() -> dict[str,np.ndarray]:
89
+ sens_pos = {}
90
+ sens_pos["cent-cube"] = np.array(((5.0,0.0,5.0), # xz
91
+ (5.0,10.0,5.0), # xz
92
+ (5.0,5.0,0.0), # xy
93
+ (5.0,5.0,10.0), # xy
94
+ (0.0,5.0,5.0), # yz
95
+ (10.0,5.0,5.0),)) # yz
96
+ return sens_pos
97
+
98
+ def sens_data_2d_dict() -> dict[str,sens.SensorData]:
99
+ # Time steps don't change so can take first sim here
100
+ return psens.sens_data_dict(simdata_list_2d()[0],sens_pos_2d())
101
+
102
+ def sens_data_3d_dict() -> dict[str,sens.SensorData]:
103
+ # Time steps don't change so can take first sim here
104
+ return psens.sens_data_dict(simdata_list_3d()[0],sens_pos_3d())
105
+
106
+ def exp_sim_2d() -> dict[str,sens.ExperimentSimulator]:
107
+ sens_data_dict = sens_data_2d_dict()
108
+ sim_list = simdata_list_2d()
109
+
110
+ fields = ("scal","vect","tens")
111
+ exp_sims = {}
112
+ for ss in sens_data_dict:
113
+
114
+ sens_noerrs = {}
115
+ sens_noerrs["scal"] = psensscalar.sens_noerrs(sim_list[0],
116
+ sens_data_dict[ss],
117
+ elem_dims=2)
118
+ sens_noerrs["vect"] = psensvector.sens_2d_noerrs(sim_list[0],
119
+ sens_data_dict[ss])
120
+ sens_noerrs["tens"] = psenstensor.sens_2d_noerrs(sim_list[0],
121
+ sens_data_dict[ss])
122
+
123
+ pos_lock = sens_pos_2d_lock(sens_data_dict[ss].positions)
124
+ for kk in pos_lock:
125
+ if kk in ss:
126
+ pos_lock_key = kk
127
+ break
128
+
129
+ err_chain_dict={}
130
+ err_chain_dict["scal"] = psensscalar.err_chain_2d_dict(
131
+ sens_noerrs["scal"].get_field(),
132
+ sens_data_dict[ss].positions,
133
+ sens_data_dict[ss].sample_times,
134
+ pos_lock[pos_lock_key]
135
+ )
136
+
137
+ err_chain_dict["vect"] = psensmech.err_chain_2d_dict(
138
+ sens_noerrs["vect"].get_field(),
139
+ sens_data_dict[ss].positions,
140
+ sens_data_dict[ss].sample_times,
141
+ pos_lock[pos_lock_key]
142
+ )
143
+
144
+ err_chain_dict["tens"] = psensmech.err_chain_2d_dict(
145
+ sens_noerrs["tens"].get_field(),
146
+ sens_data_dict[ss].positions,
147
+ sens_data_dict[ss].sample_times,
148
+ pos_lock[pos_lock_key]
149
+ )
150
+
151
+ common_keys = (err_chain_dict["scal"].keys() &
152
+ err_chain_dict["vect"].keys() &
153
+ err_chain_dict["tens"].keys())
154
+ # print(80*"=")
155
+ # print(common_keys)
156
+ # print(80*"=")
157
+
158
+ for ee in common_keys:
159
+ tag = f"exp2d_{ss}_err-{ee}"
160
+
161
+ sensor_arrays = []
162
+ for ff in fields:
163
+ this_sens = copy.deepcopy(sens_noerrs[ff])
164
+ # print(80*"-")
165
+ # print(f"{ff=}")
166
+ # print(f"{ee=}")
167
+ # print(80*"-")
168
+ if err_chain_dict[ff][ee] is not None:
169
+ err_int_opts = sens.ErrIntOpts
170
+ err_int = sens.ErrIntegrator(err_chain_dict[ff][ee],
171
+ sens_data_dict[ss],
172
+ this_sens.get_measurement_shape(),
173
+ err_int_opts=err_int_opts)
174
+ this_sens.set_error_integrator(err_int)
175
+
176
+ sensor_arrays.append(this_sens)
177
+
178
+ sim_list = simdata_list_2d()
179
+ sensor_arrays = [sens_noerrs["scal"],sens_noerrs["vect"],sens_noerrs["tens"]]
180
+ exp_sim = sens.ExperimentSimulator(sim_list,
181
+ sensor_arrays,
182
+ num_exp_per_sim=10)
183
+ exp_sims[tag] = exp_sim
184
+
185
+ return exp_sims
186
+
187
+