pyvale 2025.4.0__py3-none-any.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 (157) hide show
  1. pyvale/__init__.py +75 -0
  2. pyvale/core/__init__.py +7 -0
  3. pyvale/core/analyticmeshgen.py +59 -0
  4. pyvale/core/analyticsimdatafactory.py +63 -0
  5. pyvale/core/analyticsimdatagenerator.py +160 -0
  6. pyvale/core/camera.py +146 -0
  7. pyvale/core/cameradata.py +64 -0
  8. pyvale/core/cameradata2d.py +82 -0
  9. pyvale/core/cameratools.py +328 -0
  10. pyvale/core/cython/rastercyth.c +32267 -0
  11. pyvale/core/cython/rastercyth.py +636 -0
  12. pyvale/core/dataset.py +250 -0
  13. pyvale/core/errorcalculator.py +112 -0
  14. pyvale/core/errordriftcalc.py +146 -0
  15. pyvale/core/errorintegrator.py +339 -0
  16. pyvale/core/errorrand.py +614 -0
  17. pyvale/core/errorsysdep.py +331 -0
  18. pyvale/core/errorsysfield.py +407 -0
  19. pyvale/core/errorsysindep.py +905 -0
  20. pyvale/core/experimentsimulator.py +99 -0
  21. pyvale/core/field.py +136 -0
  22. pyvale/core/fieldconverter.py +154 -0
  23. pyvale/core/fieldsampler.py +112 -0
  24. pyvale/core/fieldscalar.py +167 -0
  25. pyvale/core/fieldtensor.py +221 -0
  26. pyvale/core/fieldtransform.py +384 -0
  27. pyvale/core/fieldvector.py +215 -0
  28. pyvale/core/generatorsrandom.py +528 -0
  29. pyvale/core/imagedef2d.py +566 -0
  30. pyvale/core/integratorfactory.py +241 -0
  31. pyvale/core/integratorquadrature.py +192 -0
  32. pyvale/core/integratorrectangle.py +88 -0
  33. pyvale/core/integratorspatial.py +90 -0
  34. pyvale/core/integratortype.py +44 -0
  35. pyvale/core/optimcheckfuncs.py +153 -0
  36. pyvale/core/raster.py +31 -0
  37. pyvale/core/rastercy.py +76 -0
  38. pyvale/core/rasternp.py +604 -0
  39. pyvale/core/rendermesh.py +156 -0
  40. pyvale/core/sensorarray.py +179 -0
  41. pyvale/core/sensorarrayfactory.py +210 -0
  42. pyvale/core/sensorarraypoint.py +280 -0
  43. pyvale/core/sensordata.py +72 -0
  44. pyvale/core/sensordescriptor.py +101 -0
  45. pyvale/core/sensortools.py +143 -0
  46. pyvale/core/visualexpplotter.py +151 -0
  47. pyvale/core/visualimagedef.py +71 -0
  48. pyvale/core/visualimages.py +75 -0
  49. pyvale/core/visualopts.py +180 -0
  50. pyvale/core/visualsimanimator.py +83 -0
  51. pyvale/core/visualsimplotter.py +182 -0
  52. pyvale/core/visualtools.py +81 -0
  53. pyvale/core/visualtraceplotter.py +256 -0
  54. pyvale/data/__init__.py +7 -0
  55. pyvale/data/case13_out.e +0 -0
  56. pyvale/data/case16_out.e +0 -0
  57. pyvale/data/case17_out.e +0 -0
  58. pyvale/data/case18_1_out.e +0 -0
  59. pyvale/data/case18_2_out.e +0 -0
  60. pyvale/data/case18_3_out.e +0 -0
  61. pyvale/data/case25_out.e +0 -0
  62. pyvale/data/case26_out.e +0 -0
  63. pyvale/data/optspeckle_2464x2056px_spec5px_8bit_gblur1px.tiff +0 -0
  64. pyvale/examples/__init__.py +7 -0
  65. pyvale/examples/analyticdatagen/__init__.py +7 -0
  66. pyvale/examples/analyticdatagen/ex1_1_scalarvisualisation.py +38 -0
  67. pyvale/examples/analyticdatagen/ex1_2_scalarcasebuild.py +46 -0
  68. pyvale/examples/analyticdatagen/ex2_1_analyticsensors.py +83 -0
  69. pyvale/examples/ex1_1_thermal2d.py +89 -0
  70. pyvale/examples/ex1_2_thermal2d.py +111 -0
  71. pyvale/examples/ex1_3_thermal2d.py +113 -0
  72. pyvale/examples/ex1_4_thermal2d.py +89 -0
  73. pyvale/examples/ex1_5_thermal2d.py +105 -0
  74. pyvale/examples/ex2_1_thermal3d .py +87 -0
  75. pyvale/examples/ex2_2_thermal3d.py +51 -0
  76. pyvale/examples/ex2_3_thermal3d.py +109 -0
  77. pyvale/examples/ex3_1_displacement2d.py +47 -0
  78. pyvale/examples/ex3_2_displacement2d.py +79 -0
  79. pyvale/examples/ex3_3_displacement2d.py +104 -0
  80. pyvale/examples/ex3_4_displacement2d.py +105 -0
  81. pyvale/examples/ex4_1_strain2d.py +57 -0
  82. pyvale/examples/ex4_2_strain2d.py +79 -0
  83. pyvale/examples/ex4_3_strain2d.py +100 -0
  84. pyvale/examples/ex5_1_multiphysics2d.py +78 -0
  85. pyvale/examples/ex6_1_multiphysics2d_expsim.py +118 -0
  86. pyvale/examples/ex6_2_multiphysics3d_expsim.py +158 -0
  87. pyvale/examples/features/__init__.py +7 -0
  88. pyvale/examples/features/ex_animation_tools_3dmonoblock.py +83 -0
  89. pyvale/examples/features/ex_area_avg.py +89 -0
  90. pyvale/examples/features/ex_calibration_error.py +108 -0
  91. pyvale/examples/features/ex_chain_field_errs.py +141 -0
  92. pyvale/examples/features/ex_field_errs.py +78 -0
  93. pyvale/examples/features/ex_sensor_single_angle_batch.py +110 -0
  94. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +86 -0
  95. pyvale/examples/rasterisation/ex_rastenp.py +154 -0
  96. pyvale/examples/rasterisation/ex_rastercyth_oneframe.py +220 -0
  97. pyvale/examples/rasterisation/ex_rastercyth_static_cypara.py +194 -0
  98. pyvale/examples/rasterisation/ex_rastercyth_static_pypara.py +193 -0
  99. pyvale/simcases/case00_HEX20.i +242 -0
  100. pyvale/simcases/case00_HEX27.i +242 -0
  101. pyvale/simcases/case00_TET10.i +242 -0
  102. pyvale/simcases/case00_TET14.i +242 -0
  103. pyvale/simcases/case01.i +101 -0
  104. pyvale/simcases/case02.i +156 -0
  105. pyvale/simcases/case03.i +136 -0
  106. pyvale/simcases/case04.i +181 -0
  107. pyvale/simcases/case05.i +234 -0
  108. pyvale/simcases/case06.i +305 -0
  109. pyvale/simcases/case07.geo +135 -0
  110. pyvale/simcases/case07.i +87 -0
  111. pyvale/simcases/case08.geo +144 -0
  112. pyvale/simcases/case08.i +153 -0
  113. pyvale/simcases/case09.geo +204 -0
  114. pyvale/simcases/case09.i +87 -0
  115. pyvale/simcases/case10.geo +204 -0
  116. pyvale/simcases/case10.i +257 -0
  117. pyvale/simcases/case11.geo +337 -0
  118. pyvale/simcases/case11.i +147 -0
  119. pyvale/simcases/case12.geo +388 -0
  120. pyvale/simcases/case12.i +329 -0
  121. pyvale/simcases/case13.i +140 -0
  122. pyvale/simcases/case14.i +159 -0
  123. pyvale/simcases/case15.geo +337 -0
  124. pyvale/simcases/case15.i +150 -0
  125. pyvale/simcases/case16.geo +391 -0
  126. pyvale/simcases/case16.i +357 -0
  127. pyvale/simcases/case17.geo +135 -0
  128. pyvale/simcases/case17.i +144 -0
  129. pyvale/simcases/case18.i +254 -0
  130. pyvale/simcases/case18_1.i +254 -0
  131. pyvale/simcases/case18_2.i +254 -0
  132. pyvale/simcases/case18_3.i +254 -0
  133. pyvale/simcases/case19.geo +252 -0
  134. pyvale/simcases/case19.i +99 -0
  135. pyvale/simcases/case20.geo +252 -0
  136. pyvale/simcases/case20.i +250 -0
  137. pyvale/simcases/case21.geo +74 -0
  138. pyvale/simcases/case21.i +155 -0
  139. pyvale/simcases/case22.geo +82 -0
  140. pyvale/simcases/case22.i +140 -0
  141. pyvale/simcases/case23.geo +164 -0
  142. pyvale/simcases/case23.i +140 -0
  143. pyvale/simcases/case24.geo +79 -0
  144. pyvale/simcases/case24.i +123 -0
  145. pyvale/simcases/case25.geo +82 -0
  146. pyvale/simcases/case25.i +140 -0
  147. pyvale/simcases/case26.geo +166 -0
  148. pyvale/simcases/case26.i +140 -0
  149. pyvale/simcases/run_1case.py +61 -0
  150. pyvale/simcases/run_all_cases.py +69 -0
  151. pyvale/simcases/run_build_case.py +64 -0
  152. pyvale/simcases/run_example_cases.py +69 -0
  153. pyvale-2025.4.0.dist-info/METADATA +140 -0
  154. pyvale-2025.4.0.dist-info/RECORD +157 -0
  155. pyvale-2025.4.0.dist-info/WHEEL +5 -0
  156. pyvale-2025.4.0.dist-info/licenses/LICENSE +21 -0
  157. pyvale-2025.4.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,51 @@
1
+ '''
2
+ ================================================================================
3
+ Example: 3d thermocouples on a monoblock
4
+
5
+ pyvale: the python validation engine
6
+ License: MIT
7
+ Copyright (C) 2025 The Computer Aided Validation Team
8
+ ================================================================================
9
+ '''
10
+ import mooseherder as mh
11
+ import pyvale as pyv
12
+
13
+
14
+ def main() -> None:
15
+ """pyvale example: thermocouples on a 3D divertor monoblock heatsink
16
+ ----------------------------------------------------------------------------
17
+ """
18
+ data_path = pyv.DataSet.thermal_3d_path()
19
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
20
+ field_name = 'temperature'
21
+
22
+ # Scale to mm to make 3D visualisation scaling easier
23
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
24
+
25
+ n_sens = (1,4,1)
26
+ x_lims = (12.5,12.5)
27
+ y_lims = (0,31.0)
28
+ z_lims = (0.0,12.5)
29
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
30
+
31
+ sens_data = pyv.SensorData(positions=sens_pos)
32
+
33
+ tc_array = pyv.SensorArrayFactory() \
34
+ .thermocouples_basic_errs(sim_data,
35
+ sens_data,
36
+ field_name,
37
+ spat_dims=3)
38
+
39
+
40
+ measurements = tc_array.get_measurements()
41
+ print(f'\nMeasurements for sensor at top of block:\n{measurements[-1,0,:]}\n')
42
+
43
+ pv_plot = pyv.plot_point_sensors_on_sim(tc_array,field_name)
44
+ pv_plot.camera_position = [(59.354, 43.428, 69.946),
45
+ (-2.858, 13.189, 4.523),
46
+ (-0.215, 0.948, -0.233)]
47
+ pv_plot.show()
48
+
49
+
50
+ if __name__ == '__main__':
51
+ main()
@@ -0,0 +1,109 @@
1
+ """
2
+ ================================================================================
3
+ Example: 3d thermocouples on a monoblock
4
+
5
+ pyvale: the python validation engine
6
+ License: MIT
7
+ Copyright (C) 2025 The Computer Aided Validation Team
8
+ ================================================================================
9
+ """
10
+ from pathlib import Path
11
+ import numpy as np
12
+ import matplotlib.pyplot as plt
13
+ import mooseherder as mh
14
+ import pyvale as pyv
15
+
16
+
17
+ def main() -> None:
18
+ """pyvale example: thermocouples on a 3D divertor monoblock heatsink
19
+ ----------------------------------------------------------------------------
20
+ """
21
+ data_path = pyv.DataSet.thermal_3d_path()
22
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
23
+
24
+ # Scale to mm to make 3D visualisation scaling easier
25
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
26
+
27
+ use_auto_descriptor = "manual"
28
+ if use_auto_descriptor == "factory":
29
+ descriptor = pyv.SensorDescriptorFactory.temperature_descriptor()
30
+ elif use_auto_descriptor == "manual":
31
+ descriptor = pyv.SensorDescriptor()
32
+ descriptor.name = "Temperature"
33
+ descriptor.symbol = "T"
34
+ descriptor.units = r"^{\circ}C"
35
+ descriptor.tag = "TC"
36
+ else:
37
+ descriptor = pyv.SensorDescriptor()
38
+
39
+
40
+ field_key = "temperature"
41
+ t_field = pyv.FieldScalar(sim_data,
42
+ field_key=field_key,
43
+ spat_dims=3)
44
+
45
+ n_sens = (1,4,1)
46
+ x_lims = (12.5,12.5)
47
+ y_lims = (0.0,33.0)
48
+ z_lims = (0.0,12.0)
49
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
50
+
51
+ use_sim_time = False
52
+ if use_sim_time:
53
+ sample_times = None
54
+ else:
55
+ sample_times = np.linspace(0.0,np.max(sim_data.time),80)
56
+
57
+ sens_data = pyv.SensorData(positions=sens_pos,
58
+ sample_times=sample_times)
59
+
60
+ tc_array = pyv.SensorArrayPoint(sens_data,
61
+ t_field,
62
+ descriptor)
63
+
64
+ errors_on = {"indep_sys": True,
65
+ "rand": True,
66
+ "dep_sys": True}
67
+
68
+ error_chain = []
69
+ if errors_on["indep_sys"]:
70
+ error_chain.append(pyv.ErrSysOffset(offset=-5.0))
71
+ error_chain.append(pyv.ErrSysUniform(low=-10.0,
72
+ high=10.0))
73
+
74
+ if errors_on["rand"]:
75
+ error_chain.append(pyv.ErrRandNormPercent(std_percent=5.0))
76
+ error_chain.append(pyv.ErrRandUnifPercent(low_percent=-5.0,
77
+ high_percent=5.0))
78
+
79
+ if errors_on["dep_sys"]:
80
+ error_chain.append(pyv.ErrSysDigitisation(bits_per_unit=1/20))
81
+ error_chain.append(pyv.ErrSysSaturation(meas_min=0.0,meas_max=800.0))
82
+
83
+ if len(error_chain) > 0:
84
+ error_integrator = pyv.ErrIntegrator(
85
+ error_chain,
86
+ sens_data,
87
+ tc_array.get_measurement_shape(),
88
+ )
89
+ tc_array.set_error_integrator(error_integrator)
90
+
91
+ measurements = tc_array.get_measurements()
92
+ print(f"\nMeasurements for sensor at top of block:\n{measurements[-1,0,:]}\n")
93
+
94
+
95
+ (fig,_) = pyv.plot_time_traces(tc_array,field_key)
96
+ plt.show()
97
+
98
+ save_fig = True
99
+ if save_fig:
100
+ image_path = Path.cwd() / "example_output"
101
+ image_file = image_path / "monoblock_thermal_traces_syserrs.png"
102
+ if not image_path.is_dir():
103
+ image_path.mkdir()
104
+
105
+ fig.savefig(image_file, dpi=300, format="png", bbox_inches="tight")
106
+
107
+
108
+ if __name__ == "__main__":
109
+ main()
@@ -0,0 +1,47 @@
1
+ '''
2
+ ================================================================================
3
+ example: displacement sensors on a 2d plate
4
+
5
+ pyvale: the python validation engine
6
+ License: MIT
7
+ Copyright (C) 2025 The Computer Aided Validation Team
8
+ ================================================================================
9
+ '''
10
+ import matplotlib.pyplot as plt
11
+ import mooseherder as mh
12
+ import pyvale as pyv
13
+
14
+ def main() -> None:
15
+ """pyvale example: displacement sensors on a 2D plate with a hole
16
+ ----------------------------------------------------------------------------
17
+ """
18
+ data_path = pyv.DataSet.mechanical_2d_path()
19
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
20
+ # Scale to mm to make 3D visualisation scaling easier
21
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
22
+
23
+ n_sens = (2,3,1)
24
+ x_lims = (0.0,100.0)
25
+ y_lims = (0.0,150.0)
26
+ z_lims = (0.0,0.0)
27
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
28
+
29
+ sens_data = pyv.SensorData(positions=sens_pos)
30
+
31
+ disp_sens_array = pyv.SensorArrayFactory \
32
+ .disp_sensors_basic_errs(sim_data,
33
+ sens_data,
34
+ "displacement",
35
+ spat_dims=2)
36
+
37
+ plot_field = 'disp_x'
38
+ pv_plot = pyv.plot_point_sensors_on_sim(disp_sens_array,plot_field)
39
+ pv_plot.show(cpos="xy")
40
+
41
+ pyv.plot_time_traces(disp_sens_array,'disp_x')
42
+ pyv.plot_time_traces(disp_sens_array,'disp_y')
43
+ plt.show()
44
+
45
+
46
+ if __name__ == "__main__":
47
+ main()
@@ -0,0 +1,79 @@
1
+ '''
2
+ ================================================================================
3
+ example: displacement sensors on a 2d plate
4
+
5
+ pyvale: the python validation engine
6
+ License: MIT
7
+ Copyright (C) 2025 The Computer Aided Validation Team
8
+ ================================================================================
9
+ '''
10
+ from pathlib import Path
11
+ import numpy as np
12
+ import matplotlib.pyplot as plt
13
+ import mooseherder as mh
14
+ import pyvale as pyv
15
+
16
+ def main() -> None:
17
+ """pyvale example: displacement sensors on a 2D plate with a hole
18
+ ----------------------------------------------------------------------------
19
+ """
20
+ data_path = pyv.DataSet.mechanical_2d_path()
21
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
22
+ # Scale to mm to make 3D visualisation scaling easier
23
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
24
+
25
+ descriptor = pyv.SensorDescriptor()
26
+ descriptor.name = 'Disp.'
27
+ descriptor.symbol = r'u'
28
+ descriptor.units = r'm'
29
+ descriptor.tag = 'DS'
30
+ descriptor.components = ('x','y','z')
31
+
32
+ spat_dims = 2
33
+ field_key = 'disp'
34
+ components = ('disp_x','disp_y')
35
+ disp_field = pyv.FieldVector(sim_data,field_key,components,spat_dims)
36
+
37
+ n_sens = (2,3,1)
38
+ x_lims = (0.0,100.0)
39
+ y_lims = (0.0,150.0)
40
+ z_lims = (0.0,0.0)
41
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
42
+
43
+ use_sim_time = False
44
+ if use_sim_time:
45
+ sample_times = None
46
+ else:
47
+ sample_times = np.linspace(0.0,np.max(sim_data.time),50)
48
+
49
+ sens_data = pyv.SensorData(positions=sens_pos,
50
+ sample_times=sample_times)
51
+
52
+ disp_sens_array = pyv.SensorArrayPoint(sens_data,
53
+ disp_field,
54
+ descriptor)
55
+
56
+ error_chain = []
57
+ error_chain.append(pyv.ErrSysUniform(low=-0.01e-3,high=0.01e-3))
58
+ error_chain.append(pyv.ErrRandNormal(std=0.01e-3))
59
+ error_int = pyv.ErrIntegrator(error_chain,
60
+ sens_data,
61
+ disp_sens_array.get_measurement_shape())
62
+ disp_sens_array.set_error_integrator(error_int)
63
+
64
+
65
+ plot_field = 'disp_x'
66
+ if plot_field == 'disp_x':
67
+ pv_plot = pyv.plot_point_sensors_on_sim(disp_sens_array,'disp_x')
68
+ pv_plot.show(cpos="xy")
69
+ elif plot_field == 'disp_y':
70
+ pv_plot = pyv.plot_point_sensors_on_sim(disp_sens_array,'disp_y')
71
+ pv_plot.show(cpos="xy")
72
+
73
+ pyv.plot_time_traces(disp_sens_array,'disp_x')
74
+ pyv.plot_time_traces(disp_sens_array,'disp_y')
75
+ plt.show()
76
+
77
+
78
+ if __name__ == "__main__":
79
+ main()
@@ -0,0 +1,104 @@
1
+ '''
2
+ ================================================================================
3
+ Example: displacement sensors on a 2d plate
4
+
5
+ pyvale: the python validation engine
6
+ License: MIT
7
+ Copyright (C) 2025 The Computer Aided Validation Team
8
+ ================================================================================
9
+ '''
10
+ from pathlib import Path
11
+ import numpy as np
12
+ import matplotlib.pyplot as plt
13
+ from scipy.spatial.transform import Rotation
14
+ import mooseherder as mh
15
+ import pyvale as pyv
16
+
17
+ def main() -> None:
18
+ """pyvale example: displacement sensors on a 2D plate with a hole
19
+ ----------------------------------------------------------------------------
20
+ - Demonstrates sensor rotation for vector fields
21
+ """
22
+ data_path = pyv.DataSet.mechanical_2d_path()
23
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
24
+ # Scale to mm to make 3D visualisation scaling easier
25
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
26
+
27
+ descriptor = pyv.SensorDescriptorFactory.displacement_descriptor()
28
+
29
+ spat_dims = 2
30
+ field_key = 'disp'
31
+ components = ('disp_x','disp_y')
32
+ disp_field = pyv.FieldVector(sim_data,field_key,components,spat_dims)
33
+
34
+ n_sens = (2,2,1)
35
+ x_lims = (0.0,100.0)
36
+ y_lims = (0.0,150.0)
37
+ z_lims = (0.0,0.0)
38
+ sensor_positions = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
39
+
40
+ use_sim_time = False
41
+ if use_sim_time:
42
+ sample_times = None
43
+ else:
44
+ sample_times = np.linspace(0.0,np.max(sim_data.time),50)
45
+
46
+ sens_data_norot = pyv.SensorData(positions=sensor_positions,
47
+ sample_times=sample_times)
48
+
49
+ disp_sens_norot = pyv.SensorArrayPoint(sens_data_norot,
50
+ disp_field,
51
+ descriptor)
52
+
53
+ meas_norot = disp_sens_norot.get_measurements()
54
+
55
+ sens_angles = sensor_positions.shape[0] * \
56
+ (Rotation.from_euler("zyx", [45, 0, 0], degrees=True),)
57
+
58
+ sens_data_rot = pyv.SensorData(positions=sensor_positions,
59
+ sample_times=sample_times,
60
+ angles=sens_angles)
61
+
62
+ disp_sens_rot = pyv.SensorArrayPoint(sens_data_rot,
63
+ disp_field,
64
+ descriptor)
65
+
66
+
67
+ angle_offset = np.zeros_like(sensor_positions)
68
+ angle_offset[:,0] = 1.0 # only rotate about z in 2D
69
+ angle_error_data = pyv.ErrFieldData(ang_offset_zyx=angle_offset)
70
+
71
+ sys_err_rot = pyv.ErrSysField(disp_field,angle_error_data)
72
+
73
+ sys_err_int = pyv.ErrIntegrator([sys_err_rot],
74
+ sens_data_rot,
75
+ disp_sens_rot.get_measurement_shape())
76
+ disp_sens_rot.set_error_integrator(sys_err_int)
77
+
78
+ meas_rot = disp_sens_rot.get_measurements()
79
+
80
+
81
+ print(80*'-')
82
+ sens_num = 4
83
+ print('The last 5 time steps (measurements) of sensor {sens_num}:')
84
+ pyv.print_measurements(disp_sens_rot,
85
+ (sens_num-1,sens_num),
86
+ (0,1),
87
+ (meas_rot.shape[2]-5,meas_rot.shape[2]))
88
+ print(80*'-')
89
+
90
+ plot_field = 'disp_x'
91
+ if plot_field == 'disp_x':
92
+ pv_plot = pyv.plot_point_sensors_on_sim(disp_sens_rot,'disp_x')
93
+ pv_plot.show(cpos="xy")
94
+ elif plot_field == 'disp_y':
95
+ pv_plot = pyv.plot_point_sensors_on_sim(disp_sens_rot,'disp_y')
96
+ pv_plot.show(cpos="xy")
97
+
98
+ pyv.plot_time_traces(disp_sens_norot,plot_field)
99
+ pyv.plot_time_traces(disp_sens_rot,plot_field)
100
+ plt.show()
101
+
102
+
103
+ if __name__ == "__main__":
104
+ main()
@@ -0,0 +1,105 @@
1
+ """
2
+ ================================================================================
3
+ Example: displacement sensors on a 2d plate
4
+
5
+ pyvale: the python validation engine
6
+ License: MIT
7
+ Copyright (C) 2025 The Computer Aided Validation Team
8
+ ================================================================================
9
+ """
10
+ import numpy as np
11
+ import matplotlib.pyplot as plt
12
+ from scipy.spatial.transform import Rotation
13
+ import mooseherder as mh
14
+ import pyvale as pyv
15
+
16
+ def main() -> None:
17
+ """pyvale example: displacement sensors on a 2D plate with a hole
18
+ ----------------------------------------------------------------------------
19
+ """
20
+ data_path = pyv.DataSet.mechanical_2d_path()
21
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
22
+ # Scale to mm to make 3D visualisation scaling easier
23
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
24
+
25
+ descriptor = pyv.SensorDescriptorFactory.displacement_descriptor()
26
+
27
+ spat_dims = 2
28
+ field_key = "disp"
29
+ components = ("disp_x","disp_y")
30
+ disp_field = pyv.FieldVector(sim_data,field_key,components,spat_dims)
31
+
32
+ #---------------------------------------------------------------------------
33
+ n_sens = (2,2,1)
34
+ x_lims = (0.0,100.0)
35
+ y_lims = (0.0,150.0)
36
+ z_lims = (0.0,0.0)
37
+ sensor_positions = pyv.create_sensor_pos_array(n_sens,
38
+ x_lims,
39
+ y_lims,
40
+ z_lims)
41
+
42
+ use_sim_time = False
43
+ if use_sim_time:
44
+ sample_times = None
45
+ else:
46
+ sample_times = np.linspace(0.0,np.max(sim_data.time),50)
47
+
48
+ sensor_angles = sensor_positions.shape[0] * \
49
+ (Rotation.from_euler("zyx", [0, 0, 0], degrees=True),)
50
+
51
+ sensor_data = pyv.SensorData(positions=sensor_positions,
52
+ sample_times=sample_times,
53
+ angles=sensor_angles,
54
+ spatial_averager=pyv.EIntSpatialType.QUAD4PT,
55
+ spatial_dims=np.array([5.0,5.0,0.0]))
56
+
57
+ #---------------------------------------------------------------------------
58
+ disp_sensors = pyv.SensorArrayPoint(sensor_data,
59
+ disp_field,
60
+ descriptor)
61
+
62
+ pos_offset = -10.0*np.ones_like(sensor_positions)
63
+ pos_offset[:,2] = 0 # in 2d we only have offset in x and y so zero z
64
+
65
+ angle_offset = np.zeros_like(sensor_positions)
66
+ angle_offset[:,0] = 5.0 # only rotate about z in 2D
67
+
68
+ time_offset = 1.0*np.ones_like(disp_sensors.get_sample_times())
69
+
70
+ field_error_data = pyv.ErrFieldData(pos_offset_xyz=pos_offset,
71
+ ang_offset_zyx=angle_offset,
72
+ time_offset=time_offset)
73
+
74
+ error_chain = []
75
+ error_chain.append(pyv.ErrSysField(disp_field,field_error_data))
76
+ error_integrator = pyv.ErrIntegrator(error_chain,
77
+ sensor_data,
78
+ disp_sensors.get_measurement_shape())
79
+
80
+ disp_sensors.set_error_integrator(error_integrator)
81
+
82
+ measurements = disp_sensors.calc_measurements()
83
+
84
+ #---------------------------------------------------------------------------
85
+ print(80*"-")
86
+ sens_num = 4
87
+ print("The last 5 time steps (measurements) of sensor {sens_num}:")
88
+ pyv.print_measurements(disp_sensors,
89
+ (sens_num-1,sens_num),
90
+ (0,1),
91
+ (measurements.shape[2]-5,measurements.shape[2]))
92
+ print(80*"-")
93
+
94
+ #---------------------------------------------------------------------------
95
+ plot_field = "disp_x"
96
+
97
+ pv_plot = pyv.plot_point_sensors_on_sim(disp_sensors,plot_field)
98
+ pv_plot.show(cpos="xy")
99
+
100
+ pyv.plot_time_traces(disp_sensors,plot_field)
101
+ plt.show()
102
+
103
+
104
+ if __name__ == "__main__":
105
+ main()
@@ -0,0 +1,57 @@
1
+ '''
2
+ ================================================================================
3
+ Example: strain gauges on a 2d plate
4
+
5
+ pyvale: the python validation engine
6
+ License: MIT
7
+ Copyright (C) 2025 The Computer Aided Validation Team
8
+ ================================================================================
9
+ '''
10
+ from pathlib import Path
11
+ import numpy as np
12
+ import matplotlib.pyplot as plt
13
+ import mooseherder as mh
14
+ import pyvale as pyv
15
+
16
+ def main() -> None:
17
+ """pyvale example: strain sensors on a 2D plate with a hole
18
+ ----------------------------------------------------------------------------
19
+ """
20
+ data_path = pyv.DataSet.mechanical_2d_path()
21
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
22
+ # Scale to mm to make 3D visualisation scaling easier
23
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
24
+
25
+ n_sens = (2,3,1)
26
+ x_lims = (0.0,100.0)
27
+ y_lims = (0.0,150.0)
28
+ z_lims = (0.0,0.0)
29
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
30
+
31
+ use_sim_time = False
32
+ if use_sim_time:
33
+ sample_times = None
34
+ else:
35
+ sample_times = np.linspace(0.0,np.max(sim_data.time),50)
36
+
37
+ sens_data = pyv.SensorData(positions=sens_pos,
38
+ sample_times=sample_times)
39
+
40
+ straingauge_array = pyv.SensorArrayFactory \
41
+ .strain_gauges_basic_errs(sim_data,
42
+ sens_data,
43
+ "strain",
44
+ spat_dims=2)
45
+
46
+ plot_field = 'strain_yy'
47
+ pv_plot = pyv.plot_point_sensors_on_sim(straingauge_array,plot_field)
48
+ pv_plot.show(cpos="xy")
49
+
50
+ pyv.plot_time_traces(straingauge_array,'strain_xx')
51
+ pyv.plot_time_traces(straingauge_array,'strain_yy')
52
+ pyv.plot_time_traces(straingauge_array,'strain_xy')
53
+ plt.show()
54
+
55
+
56
+ if __name__ == "__main__":
57
+ main()
@@ -0,0 +1,79 @@
1
+ '''
2
+ ================================================================================
3
+ Example: strain gauges on a 2d plate
4
+
5
+ pyvale: the python validation engine
6
+ License: MIT
7
+ Copyright (C) 2025 The Computer Aided Validation Team
8
+ ================================================================================
9
+ '''
10
+ import numpy as np
11
+ import matplotlib.pyplot as plt
12
+ import mooseherder as mh
13
+ import pyvale as pyv
14
+
15
+ def main() -> None:
16
+ """pyvale example: strain sensors on a 2D plate with a hole
17
+ ----------------------------------------------------------------------------
18
+ """
19
+ data_path = pyv.DataSet.mechanical_2d_path()
20
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
21
+ # Scale to mm to make 3D visualisation scaling easier
22
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
23
+
24
+ descriptor = pyv.SensorDescriptor()
25
+ descriptor.name = 'Strain'
26
+ descriptor.symbol = r'\varepsilon'
27
+ descriptor.units = r'-'
28
+ descriptor.tag = 'SG'
29
+ descriptor.components = ('xx','yy','xy')
30
+
31
+ spat_dims = 2
32
+ field_key = 'strain'
33
+ norm_components = ('strain_xx','strain_yy')
34
+ dev_components = ('strain_xy',)
35
+ strain_field = pyv.FieldTensor(sim_data,
36
+ field_key,
37
+ norm_components,
38
+ dev_components,
39
+ spat_dims)
40
+
41
+ n_sens = (2,3,1)
42
+ x_lims = (0.0,100.0)
43
+ y_lims = (0.0,150.0)
44
+ z_lims = (0.0,0.0)
45
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
46
+
47
+ use_sim_time = False
48
+ if use_sim_time:
49
+ sample_times = None
50
+ else:
51
+ sample_times = np.linspace(0.0,np.max(sim_data.time),50)
52
+
53
+ sens_data = pyv.SensorData(positions=sens_pos,
54
+ sample_times=sample_times)
55
+
56
+ straingauge_array = pyv.SensorArrayPoint(sens_data,
57
+ strain_field,
58
+ descriptor)
59
+
60
+ error_chain = []
61
+ error_chain.append(pyv.ErrSysUniform(low=-0.1e-3,high=0.1e-3))
62
+ error_chain.append(pyv.ErrRandNormal(std=0.1e-3))
63
+ error_int = pyv.ErrIntegrator(error_chain,
64
+ sens_data,
65
+ straingauge_array.get_measurement_shape())
66
+ straingauge_array.set_error_integrator(error_int)
67
+
68
+ plot_field = 'strain_yy'
69
+ pv_plot = pyv.plot_point_sensors_on_sim(straingauge_array,plot_field)
70
+ pv_plot.show(cpos="xy")
71
+
72
+ pyv.plot_time_traces(straingauge_array,'strain_xx')
73
+ pyv.plot_time_traces(straingauge_array,'strain_yy')
74
+ pyv.plot_time_traces(straingauge_array,'strain_xy')
75
+ plt.show()
76
+
77
+
78
+ if __name__ == "__main__":
79
+ main()