pyvale 2025.4.0__py3-none-any.whl → 2025.5.1__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 (153) hide show
  1. pyvale/__init__.py +78 -64
  2. pyvale/analyticmeshgen.py +102 -0
  3. pyvale/{core/analyticsimdatafactory.py → analyticsimdatafactory.py} +44 -16
  4. pyvale/analyticsimdatagenerator.py +323 -0
  5. pyvale/blendercalibrationdata.py +15 -0
  6. pyvale/blenderlightdata.py +26 -0
  7. pyvale/blendermaterialdata.py +15 -0
  8. pyvale/blenderrenderdata.py +30 -0
  9. pyvale/blenderscene.py +488 -0
  10. pyvale/blendertools.py +420 -0
  11. pyvale/{core/camera.py → camera.py} +15 -15
  12. pyvale/{core/cameradata.py → cameradata.py} +27 -22
  13. pyvale/{core/cameradata2d.py → cameradata2d.py} +8 -6
  14. pyvale/camerastereo.py +217 -0
  15. pyvale/{core/cameratools.py → cameratools.py} +220 -26
  16. pyvale/{core/cython → cython}/rastercyth.py +11 -7
  17. pyvale/data/__init__.py +5 -7
  18. pyvale/data/cal_target.tiff +0 -0
  19. pyvale/data/case00_HEX20_out.e +0 -0
  20. pyvale/data/case00_HEX27_out.e +0 -0
  21. pyvale/data/case00_HEX8_out.e +0 -0
  22. pyvale/data/case00_TET10_out.e +0 -0
  23. pyvale/data/case00_TET14_out.e +0 -0
  24. pyvale/data/case00_TET4_out.e +0 -0
  25. pyvale/{core/dataset.py → dataset.py} +91 -16
  26. pyvale/{core/errorcalculator.py → errorcalculator.py} +13 -16
  27. pyvale/{core/errordriftcalc.py → errordriftcalc.py} +14 -14
  28. pyvale/{core/errorintegrator.py → errorintegrator.py} +25 -28
  29. pyvale/{core/errorrand.py → errorrand.py} +39 -46
  30. pyvale/errorsyscalib.py +134 -0
  31. pyvale/{core/errorsysdep.py → errorsysdep.py} +25 -29
  32. pyvale/{core/errorsysfield.py → errorsysfield.py} +59 -52
  33. pyvale/{core/errorsysindep.py → errorsysindep.py} +85 -182
  34. pyvale/examples/__init__.py +5 -7
  35. pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +131 -0
  36. pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +158 -0
  37. pyvale/examples/basics/ex1_3_customsens_therm3d.py +216 -0
  38. pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +153 -0
  39. pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +168 -0
  40. pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +133 -0
  41. pyvale/examples/basics/ex1_7_spatavg_therm2d.py +123 -0
  42. pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +112 -0
  43. pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +111 -0
  44. pyvale/examples/basics/ex2_3_sensangle_disp2d.py +139 -0
  45. pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +196 -0
  46. pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +109 -0
  47. pyvale/examples/basics/ex3_1_basictensors_strain2d.py +114 -0
  48. pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +111 -0
  49. pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +182 -0
  50. pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +171 -0
  51. pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +252 -0
  52. pyvale/examples/{analyticdatagen → genanalyticdata}/ex1_1_scalarvisualisation.py +6 -9
  53. pyvale/examples/{analyticdatagen → genanalyticdata}/ex1_2_scalarcasebuild.py +8 -11
  54. pyvale/examples/{analyticdatagen → genanalyticdata}/ex2_1_analyticsensors.py +9 -12
  55. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +8 -15
  56. pyvale/examples/renderblender/ex1_1_blenderscene.py +121 -0
  57. pyvale/examples/renderblender/ex1_2_blenderdeformed.py +119 -0
  58. pyvale/examples/renderblender/ex2_1_stereoscene.py +128 -0
  59. pyvale/examples/renderblender/ex2_2_stereodeformed.py +131 -0
  60. pyvale/examples/renderblender/ex3_1_blendercalibration.py +120 -0
  61. pyvale/examples/{rasterisation → renderrasterisation}/ex_rastenp.py +6 -7
  62. pyvale/examples/{rasterisation → renderrasterisation}/ex_rastercyth_oneframe.py +5 -7
  63. pyvale/examples/{rasterisation → renderrasterisation}/ex_rastercyth_static_cypara.py +6 -13
  64. pyvale/examples/{rasterisation → renderrasterisation}/ex_rastercyth_static_pypara.py +9 -12
  65. pyvale/examples/{ex1_4_thermal2d.py → visualisation/ex1_1_plot_traces.py} +33 -20
  66. pyvale/examples/{features/ex_animation_tools_3dmonoblock.py → visualisation/ex2_1_animate_sim.py} +37 -31
  67. pyvale/experimentsimulator.py +175 -0
  68. pyvale/{core/field.py → field.py} +6 -14
  69. pyvale/fieldconverter.py +351 -0
  70. pyvale/{core/fieldsampler.py → fieldsampler.py} +9 -10
  71. pyvale/{core/fieldscalar.py → fieldscalar.py} +17 -18
  72. pyvale/{core/fieldtensor.py → fieldtensor.py} +23 -26
  73. pyvale/{core/fieldtransform.py → fieldtransform.py} +9 -5
  74. pyvale/{core/fieldvector.py → fieldvector.py} +14 -16
  75. pyvale/{core/generatorsrandom.py → generatorsrandom.py} +29 -52
  76. pyvale/{core/imagedef2d.py → imagedef2d.py} +11 -8
  77. pyvale/{core/integratorfactory.py → integratorfactory.py} +12 -13
  78. pyvale/{core/integratorquadrature.py → integratorquadrature.py} +57 -32
  79. pyvale/integratorrectangle.py +165 -0
  80. pyvale/{core/integratorspatial.py → integratorspatial.py} +9 -10
  81. pyvale/{core/integratortype.py → integratortype.py} +7 -8
  82. pyvale/output.py +17 -0
  83. pyvale/pyvaleexceptions.py +11 -0
  84. pyvale/{core/raster.py → raster.py} +8 -8
  85. pyvale/{core/rastercy.py → rastercy.py} +11 -10
  86. pyvale/{core/rasternp.py → rasternp.py} +12 -13
  87. pyvale/{core/rendermesh.py → rendermesh.py} +10 -19
  88. pyvale/{core/sensorarray.py → sensorarray.py} +7 -8
  89. pyvale/{core/sensorarrayfactory.py → sensorarrayfactory.py} +64 -78
  90. pyvale/{core/sensorarraypoint.py → sensorarraypoint.py} +39 -41
  91. pyvale/{core/sensordata.py → sensordata.py} +7 -8
  92. pyvale/sensordescriptor.py +213 -0
  93. pyvale/{core/sensortools.py → sensortools.py} +8 -9
  94. pyvale/simcases/case00_HEX20.i +5 -5
  95. pyvale/simcases/case00_HEX27.i +5 -5
  96. pyvale/simcases/case00_HEX8.i +242 -0
  97. pyvale/simcases/case00_TET10.i +2 -2
  98. pyvale/simcases/case00_TET14.i +2 -2
  99. pyvale/simcases/case00_TET4.i +242 -0
  100. pyvale/simcases/run_1case.py +1 -1
  101. pyvale/simtools.py +67 -0
  102. pyvale/visualexpplotter.py +191 -0
  103. pyvale/{core/visualimagedef.py → visualimagedef.py} +13 -10
  104. pyvale/{core/visualimages.py → visualimages.py} +10 -9
  105. pyvale/visualopts.py +493 -0
  106. pyvale/{core/visualsimanimator.py → visualsimanimator.py} +47 -19
  107. pyvale/visualsimsensors.py +318 -0
  108. pyvale/visualtools.py +136 -0
  109. pyvale/visualtraceplotter.py +142 -0
  110. {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/METADATA +17 -14
  111. pyvale-2025.5.1.dist-info/RECORD +172 -0
  112. {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/WHEEL +1 -1
  113. pyvale/core/__init__.py +0 -7
  114. pyvale/core/analyticmeshgen.py +0 -59
  115. pyvale/core/analyticsimdatagenerator.py +0 -160
  116. pyvale/core/cython/rastercyth.c +0 -32267
  117. pyvale/core/experimentsimulator.py +0 -99
  118. pyvale/core/fieldconverter.py +0 -154
  119. pyvale/core/integratorrectangle.py +0 -88
  120. pyvale/core/optimcheckfuncs.py +0 -153
  121. pyvale/core/sensordescriptor.py +0 -101
  122. pyvale/core/visualexpplotter.py +0 -151
  123. pyvale/core/visualopts.py +0 -180
  124. pyvale/core/visualsimplotter.py +0 -182
  125. pyvale/core/visualtools.py +0 -81
  126. pyvale/core/visualtraceplotter.py +0 -256
  127. pyvale/examples/analyticdatagen/__init__.py +0 -7
  128. pyvale/examples/ex1_1_thermal2d.py +0 -89
  129. pyvale/examples/ex1_2_thermal2d.py +0 -111
  130. pyvale/examples/ex1_3_thermal2d.py +0 -113
  131. pyvale/examples/ex1_5_thermal2d.py +0 -105
  132. pyvale/examples/ex2_1_thermal3d .py +0 -87
  133. pyvale/examples/ex2_2_thermal3d.py +0 -51
  134. pyvale/examples/ex2_3_thermal3d.py +0 -109
  135. pyvale/examples/ex3_1_displacement2d.py +0 -47
  136. pyvale/examples/ex3_2_displacement2d.py +0 -79
  137. pyvale/examples/ex3_3_displacement2d.py +0 -104
  138. pyvale/examples/ex3_4_displacement2d.py +0 -105
  139. pyvale/examples/ex4_1_strain2d.py +0 -57
  140. pyvale/examples/ex4_2_strain2d.py +0 -79
  141. pyvale/examples/ex4_3_strain2d.py +0 -100
  142. pyvale/examples/ex5_1_multiphysics2d.py +0 -78
  143. pyvale/examples/ex6_1_multiphysics2d_expsim.py +0 -118
  144. pyvale/examples/ex6_2_multiphysics3d_expsim.py +0 -158
  145. pyvale/examples/features/__init__.py +0 -7
  146. pyvale/examples/features/ex_area_avg.py +0 -89
  147. pyvale/examples/features/ex_calibration_error.py +0 -108
  148. pyvale/examples/features/ex_chain_field_errs.py +0 -141
  149. pyvale/examples/features/ex_field_errs.py +0 -78
  150. pyvale/examples/features/ex_sensor_single_angle_batch.py +0 -110
  151. pyvale-2025.4.0.dist-info/RECORD +0 -157
  152. {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/licenses/LICENSE +0 -0
  153. {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/top_level.txt +0 -0
@@ -1,256 +0,0 @@
1
- """
2
- ================================================================================
3
- pyvale: the python validation engine
4
- License: MIT
5
- Copyright (C) 2025 The Computer Aided Validation Team
6
- ================================================================================
7
- """
8
- from typing import Any
9
-
10
- import numpy as np
11
- import matplotlib.pyplot as plt
12
- from pyvale.core.sensorarraypoint import SensorArrayPoint
13
- from pyvale.core.visualopts import (PlotOptsGeneral,
14
- TraceOptsSensor,
15
- TraceOptsExperiment)
16
- from pyvale.core.experimentsimulator import ExperimentSimulator
17
-
18
- #TODO: Docstrings
19
-
20
- def plot_time_traces(sensor_array: SensorArrayPoint,
21
- component: str,
22
- trace_opts: TraceOptsSensor | None = None,
23
- plot_opts: PlotOptsGeneral | None = None
24
- ) -> tuple[Any,Any]:
25
-
26
- #---------------------------------------------------------------------------
27
- field = sensor_array.field
28
- comp_ind = sensor_array.field.get_component_index(component)
29
- samp_time = sensor_array.get_sample_times()
30
- measurements = sensor_array.get_measurements()
31
- n_sensors = sensor_array.sensor_data.positions.shape[0]
32
- descriptor = sensor_array.descriptor
33
- sensors_perturbed = sensor_array.get_sensor_data_perturbed()
34
-
35
- #---------------------------------------------------------------------------
36
- if plot_opts is None:
37
- plot_opts = PlotOptsGeneral()
38
-
39
- if trace_opts is None:
40
- trace_opts = TraceOptsSensor()
41
-
42
- if trace_opts.sensors_to_plot is None:
43
- sensors_to_plot = range(n_sensors)
44
- else:
45
- sensors_to_plot = trace_opts.sensors_to_plot
46
-
47
- #---------------------------------------------------------------------------
48
- # Figure canvas setup
49
- fig, ax = plt.subplots(figsize=plot_opts.single_fig_size_landscape,
50
- layout='constrained')
51
- fig.set_dpi(plot_opts.resolution)
52
-
53
- #---------------------------------------------------------------------------
54
- # Plot simulation and truth lines
55
- if trace_opts.sim_line is not None:
56
- sim_time = field.get_time_steps()
57
- sim_vals = field.sample_field(sensor_array.sensor_data.positions,
58
- None,
59
- sensor_array.sensor_data.angles)
60
-
61
- for ii,ss in enumerate(sensors_to_plot):
62
- ax.plot(sim_time,
63
- sim_vals[ss,comp_ind,:],
64
- trace_opts.sim_line,
65
- lw=plot_opts.lw,
66
- ms=plot_opts.ms,
67
- color=plot_opts.colors[ii % plot_opts.n_colors])
68
-
69
- if trace_opts.truth_line is not None:
70
- truth = sensor_array.get_truth()
71
- for ii,ss in enumerate(sensors_to_plot):
72
- ax.plot(samp_time,
73
- truth[ss,comp_ind,:],
74
- trace_opts.truth_line,
75
- lw=plot_opts.lw,
76
- ms=plot_opts.ms,
77
- color=plot_opts.colors[ii % plot_opts.n_colors])
78
-
79
- sensor_tags = descriptor.create_sensor_tags(n_sensors)
80
- for ii,ss in enumerate(sensors_to_plot):
81
- sensor_time = samp_time
82
- if sensors_perturbed is not None:
83
- if sensors_perturbed.sample_times is not None:
84
- sensor_time = sensors_perturbed.sample_times
85
-
86
- ax.plot(sensor_time,
87
- measurements[ss,comp_ind,:],
88
- trace_opts.meas_line,
89
- label=sensor_tags[ss],
90
- lw=plot_opts.lw,
91
- ms=plot_opts.ms,
92
- color=plot_opts.colors[ii % plot_opts.n_colors])
93
-
94
- #---------------------------------------------------------------------------
95
- # Axis / legend labels and options
96
- ax.set_xlabel(trace_opts.time_label,
97
- fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
98
- ax.set_ylabel(descriptor.create_label(comp_ind),
99
- fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
100
-
101
- if trace_opts.time_min_max is None:
102
- min_time = np.min((np.min(samp_time),np.min(sensor_time)))
103
- max_time = np.max((np.max(samp_time),np.max(sensor_time)))
104
- ax.set_xlim((min_time,max_time)) # type: ignore
105
- else:
106
- ax.set_xlim(trace_opts.time_min_max)
107
-
108
- if trace_opts.legend:
109
- ax.legend(prop={"size":plot_opts.font_leg_size},loc='best')
110
-
111
- plt.grid(True)
112
- plt.draw()
113
-
114
- return (fig,ax)
115
-
116
-
117
- def plot_exp_traces(exp_sim: ExperimentSimulator,
118
- component: str,
119
- sens_array_num: int,
120
- sim_num: int,
121
- trace_opts: TraceOptsExperiment | None = None,
122
- plot_opts: PlotOptsGeneral | None = None) -> tuple[Any,Any]:
123
- #---------------------------------------------------------------------------
124
- n_sensors = exp_sim.sensor_arrays[sens_array_num].sensor_data.positions.shape[0]
125
- descriptor = exp_sim.sensor_arrays[sens_array_num].descriptor
126
- comp_ind = exp_sim.sensor_arrays[sens_array_num].field.get_component_index(component)
127
- samp_time = exp_sim.sensor_arrays[sens_array_num].get_sample_times()
128
- num_sens = exp_sim.sensor_arrays[sens_array_num].get_measurement_shape()[0]
129
-
130
- #---------------------------------------------------------------------------
131
- if trace_opts is None:
132
- trace_opts = TraceOptsExperiment()
133
-
134
- if plot_opts is None:
135
- plot_opts = PlotOptsGeneral()
136
-
137
- #---------------------------------------------------------------------------
138
- exp_data = exp_sim.get_data()
139
- exp_stats = exp_sim.get_stats()
140
-
141
- if trace_opts.sensors_to_plot is None:
142
- sensors_to_plot = range(num_sens)
143
- else:
144
- sensors_to_plot = trace_opts.sensors_to_plot
145
-
146
- #---------------------------------------------------------------------------
147
- # Figure canvas setup
148
- fig, ax = plt.subplots(figsize=plot_opts.single_fig_size_landscape,
149
- layout='constrained')
150
- fig.set_dpi(plot_opts.resolution)
151
-
152
- #---------------------------------------------------------------------------
153
- # Plot all simulated experimental points
154
- if trace_opts.plot_all_exp_points:
155
- for ii,ss in enumerate(sensors_to_plot):
156
- for ee in range(exp_sim.num_exp_per_sim):
157
- ax.plot(samp_time,
158
- exp_data[sens_array_num][sim_num,ee,ss,comp_ind,:],
159
- "+",
160
- lw=plot_opts.lw,
161
- ms=plot_opts.ms,
162
- color=plot_opts.colors[ii % plot_opts.n_colors])
163
-
164
- #---------------------------------------------------------------------------
165
- sensor_tags = descriptor.create_sensor_tags(n_sensors)
166
- for ii,ss in enumerate(sensors_to_plot):
167
- if trace_opts.centre == "median":
168
- ax.plot(samp_time,
169
- exp_stats[sens_array_num].median[sim_num,ss,comp_ind,:],
170
- trace_opts.exp_mean_line,
171
- label=sensor_tags[ss],
172
- lw=plot_opts.lw,
173
- ms=plot_opts.ms,
174
- color=plot_opts.colors[ii % plot_opts.n_colors])
175
- else:
176
- ax.plot(samp_time,
177
- exp_stats[sens_array_num].mean[sim_num,ss,comp_ind,:],
178
- trace_opts.exp_mean_line,
179
- label=sensor_tags[ss],
180
- lw=plot_opts.lw,
181
- ms=plot_opts.ms,
182
- color=plot_opts.colors[ii % plot_opts.n_colors])
183
-
184
- if trace_opts is not None:
185
- upper = np.zeros_like(exp_stats[sens_array_num].min)
186
- lower = np.zeros_like(exp_stats[sens_array_num].min)
187
-
188
- if trace_opts.fill_between == 'max':
189
- upper = exp_stats[sens_array_num].min
190
- lower = exp_stats[sens_array_num].max
191
-
192
- elif trace_opts.fill_between == 'quartile':
193
- upper = exp_stats[sens_array_num].q25
194
- lower = exp_stats[sens_array_num].q75
195
-
196
- elif trace_opts.fill_between == '2std':
197
- upper = exp_stats[sens_array_num].mean + \
198
- 2*exp_stats[sens_array_num].std
199
- lower = exp_stats[sens_array_num].mean - \
200
- 2*exp_stats[sens_array_num].std
201
-
202
- elif trace_opts.fill_between == '3std':
203
- upper = exp_stats[sens_array_num].mean + \
204
- 3*exp_stats[sens_array_num].std
205
- lower = exp_stats[sens_array_num].mean - \
206
- 3*exp_stats[sens_array_num].std
207
-
208
- ax.fill_between(samp_time,
209
- upper[sim_num,ss,comp_ind,:],
210
- lower[sim_num,ss,comp_ind,:],
211
- color=plot_opts.colors[ii % plot_opts.n_colors],
212
- alpha=0.2)
213
-
214
- #---------------------------------------------------------------------------
215
- # Plot simulation and truth line
216
- if trace_opts.sim_line is not None:
217
- sim_time = exp_sim.sensor_arrays[sens_array_num].field.get_time_steps()
218
- sim_vals = exp_sim.sensor_arrays[sens_array_num].field.sample_field(
219
- exp_sim.sensor_arrays[sens_array_num].positions)
220
-
221
- for ss in sensors_to_plot:
222
- ax.plot(sim_time,
223
- sim_vals[ss,comp_ind,:],
224
- trace_opts.sim_line,
225
- lw=plot_opts.lw,
226
- ms=plot_opts.ms)
227
-
228
- if trace_opts.truth_line is not None:
229
- truth = exp_sim.sensor_arrays[sens_array_num].get_truth()
230
- for ss in sensors_to_plot:
231
- ax.plot(samp_time,
232
- truth[ss,comp_ind,:],
233
- trace_opts.truth_line,
234
- lw=plot_opts.lw,
235
- ms=plot_opts.ms,
236
- color=plot_opts.colors[ii % plot_opts.n_colors])
237
-
238
- #---------------------------------------------------------------------------
239
- # Axis / legend labels and options
240
- ax.set_xlabel(trace_opts.time_label,
241
- fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
242
- ax.set_ylabel(descriptor.create_label(comp_ind),
243
- fontsize=plot_opts.font_ax_size, fontname=plot_opts.font_name)
244
-
245
- if trace_opts.time_min_max is None:
246
- ax.set_xlim((np.min(samp_time),np.max(samp_time))) # type: ignore
247
- else:
248
- ax.set_xlim(trace_opts.time_min_max)
249
-
250
- if trace_opts.legend:
251
- ax.legend(prop={"size":plot_opts.font_leg_size},loc='best')
252
-
253
- plt.grid(True)
254
- plt.draw()
255
-
256
- return (fig,ax)
@@ -1,7 +0,0 @@
1
- """
2
- ================================================================================
3
- pyvale: the python validation engine
4
- License: MIT
5
- Copyright (C) 2025 The Computer Aided Validation Team
6
- ================================================================================
7
- """
@@ -1,89 +0,0 @@
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()
@@ -1,111 +0,0 @@
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()
@@ -1,113 +0,0 @@
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()
@@ -1,105 +0,0 @@
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()