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,83 @@
1
+ '''
2
+ ================================================================================
3
+ Analytic test case data - linear
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 numpy as np
12
+ import pyvale
13
+
14
+ def main() -> None:
15
+ (sim_data,_) = pyvale.AnalyticCaseFactory.scalar_linear_2d()
16
+
17
+ descriptor = pyvale.SensorDescriptorFactory.temperature_descriptor()
18
+
19
+ field_key = 'scalar'
20
+ t_field = pyvale.FieldScalar(sim_data,
21
+ field_key=field_key,
22
+ spat_dims=2)
23
+
24
+ n_sens = (4,1,1)
25
+ x_lims = (0.0,10.0)
26
+ y_lims = (0.0,7.5)
27
+ z_lims = (0.0,0.0)
28
+ sens_pos = pyvale.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
29
+
30
+ use_sim_time = False
31
+ if use_sim_time:
32
+ sample_times = None
33
+ else:
34
+ sample_times = np.linspace(0.0,np.max(sim_data.time),50)
35
+
36
+ sensor_data = pyvale.SensorData(positions=sens_pos,
37
+ sample_times=sample_times)
38
+
39
+ tc_array = pyvale.SensorArrayPoint(sensor_data,
40
+ t_field,
41
+ descriptor)
42
+
43
+ errors_on = {'indep_sys': True,
44
+ 'rand': True,
45
+ 'dep_sys': True}
46
+
47
+ error_chain = []
48
+ if errors_on['indep_sys']:
49
+ error_chain.append(pyvale.ErrSysOffset(offset=-5.0))
50
+ error_chain.append(pyvale.ErrSysUniform(low=-5.0,
51
+ high=5.0))
52
+ gen_norm = pyvale.GeneratorNormal(std=1.0)
53
+
54
+ if errors_on['rand']:
55
+ error_chain.append(pyvale.ErrRandNormPercent(std_percent=1.0))
56
+ error_chain.append(pyvale.ErrRandUnifPercent(low_percent=-1.0,
57
+ high_percent=1.0))
58
+
59
+ if errors_on['dep_sys']:
60
+ error_chain.append(pyvale.ErrSysDigitisation(bits_per_unit=2**8/100))
61
+ error_chain.append(pyvale.ErrSysSaturation(meas_min=0.0,meas_max=300.0))
62
+
63
+ if len(error_chain) > 0:
64
+ error_integrator = pyvale.ErrIntegrator(error_chain,
65
+ sensor_data,
66
+ tc_array.get_measurement_shape())
67
+ tc_array.set_error_integrator(error_integrator)
68
+
69
+ measurements = tc_array.get_measurements()
70
+
71
+ pyvale.print_measurements(tc_array,
72
+ (0,1), # Sensor 1
73
+ (0,1), # Component 1: scalar field = 1 component
74
+ (measurements.shape[2]-5,measurements.shape[2]))
75
+
76
+ (fig,_) = pyvale.plot_time_traces(tc_array,field_key)
77
+ plt.show()
78
+
79
+ pv_plot = pyvale.plot_point_sensors_on_sim(tc_array,field_key)
80
+ pv_plot.show(cpos="xy")
81
+
82
+ if __name__ == '__main__':
83
+ main()
@@ -0,0 +1,89 @@
1
+ """
2
+ ================================================================================
3
+ Example: thermocouples 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 matplotlib.pyplot as plt
12
+ import mooseherder as mh
13
+ import pyvale as pyv
14
+
15
+
16
+ def main() -> None:
17
+ """pyvale example: point sensors on a 2D thermal simulation
18
+ ----------------------------------------------------------------------------
19
+ - Quick start
20
+ - Basic sensor array construction using the sensor array factory
21
+ - Basic visualisation of sensor locations and sensor traces with the pyvale
22
+ wrapper for pyvista and matplotlib.
23
+ """
24
+
25
+ data_path = pyv.DataSet.thermal_2d_path()
26
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
27
+ field_key = "temperature"
28
+ # Scale to mm to make 3D visualisation scaling easier
29
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
30
+
31
+ n_sens = (3,2,1)
32
+ x_lims = (0.0,100.0)
33
+ y_lims = (0.0,50.0)
34
+ z_lims = (0.0,0.0)
35
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
36
+ sens_data = pyv.SensorData(positions=sens_pos)
37
+
38
+ tc_array = pyv.SensorArrayFactory \
39
+ .thermocouples_basic_errs(sim_data,
40
+ sens_data,
41
+ field_key,
42
+ spat_dims=2)
43
+
44
+ measurements = tc_array.get_measurements()
45
+ print(f"\nMeasurements for last sensor:\n{measurements[-1,0,:]}\n")
46
+
47
+ pv_plot = pyv.plot_point_sensors_on_sim(tc_array,field_key)
48
+ # Set this to "interactive" to get an interactive 3D plot of the simulation
49
+ # and labelled sensor locations, set to "save_fig" to create a vector
50
+ # graphic using a specified camera position.
51
+ pv_plot_mode = "interactive"
52
+
53
+ if pv_plot_mode == "interactive":
54
+ pv_plot.camera_position = [(-7.547, 59.753, 134.52),
55
+ (41.916, 25.303, 9.297),
56
+ (0.0810, 0.969, -0.234)]
57
+ pv_plot.show()
58
+
59
+ print(80*"=")
60
+ print("Camera positions = ")
61
+ print(pv_plot.camera_position)
62
+ print(80*"="+"\n")
63
+
64
+ if pv_plot_mode == "save_fig":
65
+ # Determined manually by moving camera and then dumping camera position
66
+ # to console after window close - see "interactive above"
67
+ pv_plot.camera_position = [(-7.547, 59.753, 134.52),
68
+ (41.916, 25.303, 9.297),
69
+ (0.0810, 0.969, -0.234)]
70
+ save_render = Path("src/examples/plate_thermal_2d_sim_view.svg")
71
+ pv_plot.save_graphic(save_render) # only for .svg .eps .ps .pdf .tex
72
+ pv_plot.screenshot(save_render.with_suffix(".png"))
73
+
74
+ # Set this to "interactive" to get a matplotlib.pyplot with the sensor
75
+ # traces plotted over time. Set to "save_fig" to save an image of the plot
76
+ # to file.
77
+ trace_plot_mode = "interactive"
78
+
79
+ (fig,_) = pyv.plot_time_traces(tc_array,field_key)
80
+
81
+ if trace_plot_mode == "interactive":
82
+ plt.show()
83
+ if trace_plot_mode == "save_fig":
84
+ save_traces = Path("src/examples/plate_thermal_2d_traces.png")
85
+ fig.savefig(save_traces, dpi=300, format="png", bbox_inches="tight")
86
+
87
+
88
+ if __name__ == "__main__":
89
+ main()
@@ -0,0 +1,111 @@
1
+ """
2
+ ================================================================================
3
+ Example: thermocouples 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
+
15
+ def main() -> None:
16
+ """pyvale example: Point sensors on a 2D thermal simulation
17
+ ----------------------------------------------------------------------------
18
+ - Explanation of the usage of "get_measurements()" and "calc_measurements()"
19
+
20
+ NOTES:
21
+ - A sensor measurement is defined as:
22
+ measurement = truth + systematic error + random error.
23
+ - Calling the "get" methods of the sensor array will retrieve the results
24
+ for the current experiment.
25
+ - Calling the "calc" methods will generate a new
26
+ experiment by sampling/calculating the systematic and random errors.
27
+ """
28
+ data_path = pyv.DataSet.thermal_2d_path()
29
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
30
+ field_key = list(sim_data.node_vars.keys())[0] # type: ignore
31
+ # Scale to mm to make 3D visualisation scaling easier
32
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
33
+
34
+ n_sens = (4,1,1)
35
+ x_lims = (0.0,100.0)
36
+ y_lims = (0.0,50.0)
37
+ z_lims = (0.0,0.0)
38
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
39
+ sens_data = pyv.SensorData(positions=sens_pos)
40
+
41
+ tc_array = pyv.SensorArrayFactory \
42
+ .thermocouples_basic_errs(sim_data,
43
+ sens_data,
44
+ field_key,
45
+ spat_dims=2)
46
+
47
+
48
+ measurements = tc_array.get_measurements()
49
+
50
+ print("\n"+80*"-")
51
+ print("For a sensor: measurement = truth + sysematic error + random error")
52
+ print(f"measurements.shape = {measurements.shape} = "+
53
+ "(n_sensors,n_field_components,n_timesteps)\n")
54
+ print("The truth, systematic error and random error arrays have the same "+
55
+ "shape.")
56
+
57
+ print(80*"-")
58
+ print("Looking at the last 5 time steps (measurements) of sensor 0:")
59
+ pyv.print_measurements(tc_array,
60
+ (0,1),
61
+ (0,1),
62
+ (measurements.shape[2]-5,measurements.shape[2]))
63
+ print(80*"-")
64
+ print("If we call the \"calc_measurements()\" method then the errors are "+
65
+ "(re)calculated or sampled.")
66
+ measurements = tc_array.calc_measurements()
67
+
68
+ pyv.print_measurements(tc_array,
69
+ (0,1),
70
+ (0,1),
71
+ (measurements.shape[2]-5,measurements.shape[2]))
72
+
73
+
74
+ (_,ax) = pyv.plot_time_traces(tc_array,field_key)
75
+ ax.set_title("Exp 1: called calc_measurements()")
76
+
77
+ print(80*"-")
78
+ print("If we call the \"get_measurements()\" method then the errors are the "+
79
+ "same:")
80
+ measurements = tc_array.get_measurements()
81
+
82
+ pyv.print_measurements(tc_array,
83
+ (0,1),
84
+ (0,1),
85
+ (measurements.shape[2]-5,measurements.shape[2]))
86
+
87
+ (_,ax) = pyv.plot_time_traces(tc_array,field_key)
88
+ ax.set_title("Exp 2: called get_measurements()")
89
+
90
+ print(80*"-")
91
+ print("If we call the \"calc_measurements()\" method again we generate/sample"+
92
+ "new errors:")
93
+ measurements = tc_array.calc_measurements()
94
+
95
+ pyv.print_measurements(tc_array,
96
+ (0,1),
97
+ (0,1),
98
+ (measurements.shape[2]-5,measurements.shape[2]))
99
+
100
+ (_,ax) = pyv.plot_time_traces(tc_array,field_key)
101
+ ax.set_title("Exp 3: called calc_measurements()")
102
+
103
+ print(80*"-")
104
+
105
+ plot_on = True
106
+ if plot_on:
107
+ plt.show()
108
+
109
+
110
+ if __name__ == "__main__":
111
+ main()
@@ -0,0 +1,113 @@
1
+ """
2
+ ================================================================================
3
+ Example: thermocouples 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
+
16
+ def main() -> None:
17
+ """pyvale example: Point sensors on a 2D thermal simulation
18
+ ----------------------------------------------------------------------------
19
+ - Full construction of a point sensor array from scratch
20
+ - Explanation of the different types of error models
21
+ - There are flags throughout the example allowing the user to toggle on/off
22
+ parts of the sensor array construction
23
+ """
24
+ data_path = pyv.DataSet.thermal_2d_path()
25
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
26
+ # Scale to mm to make 3D visualisation scaling easier
27
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
28
+
29
+ use_auto_descriptor = "blank"
30
+ if use_auto_descriptor == "factory":
31
+ descriptor = pyv.SensorDescriptorFactory.temperature_descriptor()
32
+ elif use_auto_descriptor == "manual":
33
+ descriptor = pyv.SensorDescriptor()
34
+ descriptor.name = "Temperature"
35
+ descriptor.symbol = "T"
36
+ descriptor.units = r"^{\circ}C"
37
+ descriptor.tag = "TC"
38
+ else:
39
+ descriptor = pyv.SensorDescriptor()
40
+
41
+ field_key = "temperature" # ("disp_x","disp_y")
42
+ t_field = pyv.FieldScalar(sim_data,
43
+ field_key=field_key,
44
+ spat_dims=2)
45
+
46
+ n_sens = (4,1,1)
47
+ x_lims = (0.0,100.0)
48
+ y_lims = (0.0,50.0)
49
+ z_lims = (0.0,0.0)
50
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
51
+
52
+ use_sim_time = False
53
+ if use_sim_time:
54
+ sample_times = None
55
+ else:
56
+ sample_times = np.linspace(0.0,np.max(sim_data.time),50)
57
+
58
+ sensor_data = pyv.SensorData(positions=sens_pos,
59
+ sample_times=sample_times)
60
+
61
+ tc_array = pyv.SensorArrayPoint(sensor_data,
62
+ t_field,
63
+ descriptor)
64
+
65
+ errors_on = {"indep_sys": True,
66
+ "rand": True,
67
+ "dep_sys": True}
68
+
69
+ error_chain = []
70
+ if errors_on["indep_sys"]:
71
+ error_chain.append(pyv.ErrSysOffset(offset=-5.0))
72
+ error_chain.append(pyv.ErrSysUniform(low=-5.0,
73
+ high=5.0))
74
+
75
+ if errors_on["rand"]:
76
+ error_chain.append(pyv.ErrRandNormPercent(std_percent=1.0))
77
+ error_chain.append(pyv.ErrRandUnifPercent(low_percent=-1.0,
78
+ high_percent=1.0))
79
+
80
+ if errors_on["dep_sys"]:
81
+ error_chain.append(pyv.ErrSysDigitisation(bits_per_unit=2**8/100))
82
+ error_chain.append(pyv.ErrSysSaturation(meas_min=0.0,meas_max=300.0))
83
+
84
+ if len(error_chain) > 0:
85
+ error_integrator = pyv.ErrIntegrator(error_chain,
86
+ sensor_data,
87
+ tc_array.get_measurement_shape())
88
+ tc_array.set_error_integrator(error_integrator)
89
+
90
+
91
+ measurements = tc_array.get_measurements()
92
+
93
+ print("\n"+80*"-")
94
+ print("For a sensor: measurement = truth + sysematic error + random error")
95
+ print(f"measurements.shape = {measurements.shape} = "+
96
+ "(n_sensors,n_field_components,n_timesteps)\n")
97
+ print("The truth, systematic error and random error arrays have the same "+
98
+ "shape.")
99
+
100
+ print(80*"-")
101
+ print("Looking at the last 5 time steps (measurements) of sensor 0:")
102
+ pyv.print_measurements(tc_array,
103
+ (0,1),
104
+ (0,1),
105
+ (measurements.shape[2]-5,measurements.shape[2]))
106
+ print(80*"-")
107
+
108
+ pyv.plot_time_traces(tc_array,field_key)
109
+ plt.show()
110
+
111
+
112
+ if __name__ == "__main__":
113
+ main()
@@ -0,0 +1,89 @@
1
+ """
2
+ ================================================================================
3
+ Example: thermocouples 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
+
16
+ def main() -> None:
17
+ """pyvale example: point sensors on a 2D thermal simulation
18
+ ----------------------------------------------------------------------------
19
+ - Demonstrates options for controlling plots of points sensor traces using
20
+ matplotlib
21
+ """
22
+ data_path = pyv.DataSet.thermal_2d_path()
23
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
24
+ field_key = list(sim_data.node_vars.keys())[0] # type: ignore
25
+ # Scale to mm to make 3D visualisation scaling easier
26
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
27
+
28
+ n_sens = (4,1,1)
29
+ x_lims = (0.0,100.0)
30
+ y_lims = (0.0,50.0)
31
+ z_lims = (0.0,0.0)
32
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
33
+
34
+ sample_times = np.linspace(0.0,np.max(sim_data.time),12)
35
+
36
+ sens_data = pyv.SensorData(positions=sens_pos,
37
+ sample_times=sample_times)
38
+
39
+ tc_array = pyv.SensorArrayFactory \
40
+ .thermocouples_basic_errs(sim_data,
41
+ sens_data,
42
+ field_key,
43
+ spat_dims=2)
44
+
45
+ err_int = pyv.ErrIntegrator([pyv.ErrSysOffset(offset=-5.0)],
46
+ sens_data,
47
+ tc_array.get_measurement_shape())
48
+ tc_array.set_error_integrator(err_int)
49
+
50
+ measurements = tc_array.get_measurements()
51
+
52
+ print(80*"-")
53
+ print("Looking at the last 5 time steps (measurements) of sensor 0:")
54
+ pyv.print_measurements(tc_array,
55
+ (0,1),
56
+ (0,1),
57
+ (measurements.shape[2]-5,measurements.shape[2]))
58
+ print(80*"-")
59
+
60
+ trace_props = pyv.TraceOptsSensor()
61
+
62
+ trace_props.truth_line = None
63
+ trace_props.sim_line = None
64
+ pyv.plot_time_traces(tc_array,field_key,trace_props)
65
+
66
+ trace_props.meas_line = "--o"
67
+ trace_props.truth_line = "-x"
68
+ trace_props.sim_line = ":+"
69
+ pyv.plot_time_traces(tc_array,field_key,trace_props)
70
+
71
+ trace_props.sensors_to_plot = np.arange(measurements.shape[0]-2
72
+ ,measurements.shape[0])
73
+ pyv.plot_time_traces(tc_array,field_key,trace_props)
74
+
75
+ trace_props.sensors_to_plot = None
76
+ trace_props.time_min_max = (0.0,100.0)
77
+ pyv.plot_time_traces(tc_array,field_key,trace_props)
78
+
79
+ plt.show()
80
+
81
+ pv_plot = pyv.plot_point_sensors_on_sim(tc_array,field_key)
82
+ pv_plot.camera_position = [(-7.547, 59.753, 134.52),
83
+ (41.916, 25.303, 9.297),
84
+ (0.0810, 0.969, -0.234)]
85
+ pv_plot.show()
86
+
87
+
88
+ if __name__ == "__main__":
89
+ main()
@@ -0,0 +1,105 @@
1
+ '''
2
+ ================================================================================
3
+ Example: thermocouples 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
+
16
+ def main() -> None:
17
+ """pyvale example: point sensors on a 2D thermal simulation
18
+ ----------------------------------------------------------------------------
19
+ """
20
+ data_path = pyv.DataSet.thermal_2d_path()
21
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
22
+ field_key = list(sim_data.node_vars.keys())[0] # type: ignore
23
+ # Scale to mm to make 3D visualisation scaling easier
24
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
25
+
26
+ n_sens = (4,1,1)
27
+ x_lims = (0.0,100.0)
28
+ y_lims = (0.0,50.0)
29
+ z_lims = (0.0,0.0)
30
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
31
+
32
+ sample_times = np.linspace(0.0,np.max(sim_data.time),50) # | None
33
+
34
+ sensor_data = pyv.SensorData(positions=sens_pos,
35
+ sample_times=sample_times)
36
+
37
+ tc_array = pyv.SensorArrayFactory \
38
+ .thermocouples_no_errs(sim_data,
39
+ sensor_data,
40
+ field_key,
41
+ spat_dims=2)
42
+
43
+ #===========================================================================
44
+ # Examples of full error library
45
+
46
+ #---------------------------------------------------------------------------
47
+ # Standard independent systematic errors
48
+ err_chain = []
49
+ err_chain.append(pyv.ErrSysOffset(offset=-1.0))
50
+ err_chain.append(pyv.ErrSysOffsetPercent(offset_percent=-1.0))
51
+
52
+ err_chain.append(pyv.ErrSysUniform(low=-2.0,
53
+ high=2.0))
54
+ err_chain.append(pyv.ErrSysUniformPercent(low_percent=-2.0,
55
+ high_percent=2.0))
56
+
57
+ err_chain.append(pyv.ErrSysNormal(std=1.0))
58
+ err_chain.append(pyv.ErrSysNormPercent(std_percent=2.0))
59
+
60
+ sys_gen = pyv.GeneratorTriangular(left=-1.0,
61
+ mode=0.0,
62
+ right=1.0)
63
+ err_chain.append(pyv.ErrSysGenerator(sys_gen))
64
+
65
+ #---------------------------------------------------------------------------
66
+ err_chain.append(pyv.ErrRandNormal(std = 2.0))
67
+ err_chain.append(pyv.ErrRandNormPercent(std_percent=2.0))
68
+
69
+ err_chain.append(pyv.ErrRandUniform(low=-2.0,high=2.0))
70
+ err_chain.append(pyv.ErrRandUnifPercent(low_percent=-2.0,
71
+ high_percent=2.0))
72
+
73
+ rand_gen = pyv.GeneratorTriangular(left=-5.0,
74
+ mode=0.0,
75
+ right=5.0)
76
+ err_chain.append(pyv.ErrRandGenerator(rand_gen))
77
+
78
+ #---------------------------------------------------------------------------
79
+ err_chain.append(pyv.ErrSysDigitisation(bits_per_unit=2**8/100))
80
+ err_chain.append(pyv.ErrSysSaturation(meas_min=0.0,meas_max=300.0))
81
+
82
+ err_int = pyv.ErrIntegrator(err_chain,
83
+ sensor_data,
84
+ tc_array.get_measurement_shape())
85
+ tc_array.set_error_integrator(err_int)
86
+
87
+
88
+ #===========================================================================
89
+
90
+ measurements = tc_array.calc_measurements()
91
+ print(80*'-')
92
+ sens_num = 4
93
+ print('The last 5 time steps (measurements) of sensor {sens_num}:')
94
+ pyv.print_measurements(tc_array,
95
+ (sens_num-1,sens_num),
96
+ (0,1),
97
+ (measurements.shape[2]-5,measurements.shape[2]))
98
+ print(80*'-')
99
+
100
+ pyv.plot_time_traces(tc_array,field_key)
101
+ plt.show()
102
+
103
+
104
+ if __name__ == '__main__':
105
+ main()
@@ -0,0 +1,87 @@
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 matplotlib.pyplot as plt
12
+ import mooseherder as mh
13
+ import pyvale as pyv
14
+
15
+
16
+ def main() -> None:
17
+ """pyvale example: thermocouples on a 3D divertor monoblock heatsink
18
+ ----------------------------------------------------------------------------
19
+ """
20
+ #data_path = pyv.DataSet.thermal_3d_path()
21
+ data_path = Path.cwd()/"src"/"pyvale"/"simcases"/"case16_out.e"
22
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
23
+ field_name = 'temperature'
24
+ # Scale to mm to make 3D visualisation scaling easier
25
+ sim_data.coords = sim_data.coords*1000.0 # type: ignore
26
+
27
+ n_sens = (1,4,1)
28
+ x_lims = (12.5,12.5)
29
+ y_lims = (0.0,33.0)
30
+ z_lims = (0.0,12.0)
31
+ sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
32
+
33
+ sens_data = pyv.SensorData(positions=sens_pos)
34
+
35
+ tc_array = pyv.SensorArrayFactory \
36
+ .thermocouples_basic_errs(sim_data,
37
+ sens_data,
38
+ field_name,
39
+ spat_dims=3)
40
+
41
+ measurements = tc_array.get_measurements()
42
+ print(f'\nMeasurements for sensor at top of block:\n{measurements[-1,0,:]}\n')
43
+
44
+ pv_plot = pyv.plot_point_sensors_on_sim(tc_array,field_name)
45
+
46
+ # Set this to 'interactive' to get an interactive 3D plot of the simulation
47
+ # and labelled sensor locations, set to 'save_fig' to create a vector
48
+ # graphic using a specified camera position.
49
+ pv_plot_mode = 'interactive'
50
+
51
+ if pv_plot_mode == 'interactive':
52
+ pv_plot.camera_position = [(59.354, 43.428, 69.946),
53
+ (-2.858, 13.189, 4.523),
54
+ (-0.215, 0.948, -0.233)]
55
+ pv_plot.show()
56
+
57
+ print(80*"=")
58
+ print('Camera positions = ')
59
+ print(pv_plot.camera_position)
60
+ print(80*"="+"\n")
61
+
62
+ if pv_plot_mode == 'save_fig':
63
+ # Determined manually by moving camera and then dumping camera position
64
+ # to console after window close - see 'interactive above'
65
+ pv_plot.camera_position = [(59.354, 43.428, 69.946),
66
+ (-2.858, 13.189, 4.523),
67
+ (-0.215, 0.948, -0.233)]
68
+ save_render = Path('src/examples/monoblock_thermal_sim_view.svg')
69
+ pv_plot.save_graphic(save_render) # only for .svg .eps .ps .pdf .tex
70
+ pv_plot.screenshot(save_render.with_suffix('.png'))
71
+
72
+ # Set this to 'interactive' to get a matplotlib.pyplot with the sensor
73
+ # traces plotted over time. Set to 'save_fig' to save an image of the plot
74
+ # to file.
75
+ trace_plot_mode = 'interactive'
76
+
77
+ (fig,_) = pyv.plot_time_traces(tc_array,field_name)
78
+
79
+ if trace_plot_mode == 'interactive':
80
+ plt.show()
81
+ if trace_plot_mode == 'save_fig':
82
+ save_traces = Path('src/examples/monoblock_thermal_traces.png')
83
+ fig.savefig(save_traces, dpi=300, format='png', bbox_inches='tight')
84
+
85
+
86
+ if __name__ == '__main__':
87
+ main()