pyvale 2025.5.3__cp311-cp311-musllinux_1_2_i686.whl → 2025.7.0__cp311-cp311-musllinux_1_2_i686.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyvale might be problematic. Click here for more details.

Files changed (96) hide show
  1. pyvale/__init__.py +12 -0
  2. pyvale/blendercalibrationdata.py +3 -1
  3. pyvale/blenderscene.py +7 -5
  4. pyvale/blendertools.py +27 -5
  5. pyvale/camera.py +1 -0
  6. pyvale/cameradata.py +3 -0
  7. pyvale/camerasensor.py +147 -0
  8. pyvale/camerastereo.py +4 -4
  9. pyvale/cameratools.py +23 -61
  10. pyvale/cython/rastercyth.c +1657 -1352
  11. pyvale/cython/rastercyth.cpython-311-i386-linux-musl.so +0 -0
  12. pyvale/cython/rastercyth.py +71 -26
  13. pyvale/data/plate_hole_def0000.tiff +0 -0
  14. pyvale/data/plate_hole_def0001.tiff +0 -0
  15. pyvale/data/plate_hole_ref0000.tiff +0 -0
  16. pyvale/data/plate_rigid_def0000.tiff +0 -0
  17. pyvale/data/plate_rigid_def0001.tiff +0 -0
  18. pyvale/data/plate_rigid_ref0000.tiff +0 -0
  19. pyvale/dataset.py +96 -6
  20. pyvale/dic/cpp/dicbruteforce.cpp +370 -0
  21. pyvale/dic/cpp/dicfourier.cpp +648 -0
  22. pyvale/dic/cpp/dicinterpolator.cpp +559 -0
  23. pyvale/dic/cpp/dicmain.cpp +215 -0
  24. pyvale/dic/cpp/dicoptimizer.cpp +675 -0
  25. pyvale/dic/cpp/dicrg.cpp +137 -0
  26. pyvale/dic/cpp/dicscanmethod.cpp +677 -0
  27. pyvale/dic/cpp/dicsmooth.cpp +138 -0
  28. pyvale/dic/cpp/dicstrain.cpp +383 -0
  29. pyvale/dic/cpp/dicutil.cpp +563 -0
  30. pyvale/dic2d.py +164 -0
  31. pyvale/dic2dcpp.cpython-311-i386-linux-musl.so +0 -0
  32. pyvale/dicchecks.py +476 -0
  33. pyvale/dicdataimport.py +247 -0
  34. pyvale/dicregionofinterest.py +887 -0
  35. pyvale/dicresults.py +55 -0
  36. pyvale/dicspecklegenerator.py +238 -0
  37. pyvale/dicspecklequality.py +305 -0
  38. pyvale/dicstrain.py +387 -0
  39. pyvale/dicstrainresults.py +37 -0
  40. pyvale/errorintegrator.py +10 -8
  41. pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +124 -113
  42. pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +124 -132
  43. pyvale/examples/basics/ex1_3_customsens_therm3d.py +199 -195
  44. pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +125 -121
  45. pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +145 -141
  46. pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +96 -101
  47. pyvale/examples/basics/ex1_7_spatavg_therm2d.py +109 -105
  48. pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +92 -91
  49. pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +96 -90
  50. pyvale/examples/basics/ex2_3_sensangle_disp2d.py +88 -89
  51. pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +172 -171
  52. pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +88 -86
  53. pyvale/examples/basics/ex3_1_basictensors_strain2d.py +90 -90
  54. pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +93 -91
  55. pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +172 -160
  56. pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +154 -148
  57. pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +249 -231
  58. pyvale/examples/dic/ex1_region_of_interest.py +98 -0
  59. pyvale/examples/dic/ex2_plate_with_hole.py +149 -0
  60. pyvale/examples/dic/ex3_plate_with_hole_strain.py +93 -0
  61. pyvale/examples/dic/ex4_dic_blender.py +95 -0
  62. pyvale/examples/dic/ex5_dic_challenge.py +102 -0
  63. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +4 -2
  64. pyvale/examples/renderblender/ex1_1_blenderscene.py +152 -105
  65. pyvale/examples/renderblender/ex1_2_blenderdeformed.py +151 -100
  66. pyvale/examples/renderblender/ex2_1_stereoscene.py +183 -116
  67. pyvale/examples/renderblender/ex2_2_stereodeformed.py +185 -112
  68. pyvale/examples/renderblender/ex3_1_blendercalibration.py +164 -109
  69. pyvale/examples/renderrasterisation/ex_rastenp.py +74 -35
  70. pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +6 -13
  71. pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +2 -2
  72. pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +2 -4
  73. pyvale/imagedef2d.py +3 -2
  74. pyvale/imagetools.py +137 -0
  75. pyvale/rastercy.py +34 -4
  76. pyvale/rasternp.py +300 -276
  77. pyvale/rasteropts.py +58 -0
  78. pyvale/renderer.py +47 -0
  79. pyvale/rendermesh.py +52 -62
  80. pyvale/renderscene.py +51 -0
  81. pyvale/sensorarrayfactory.py +2 -2
  82. pyvale/sensortools.py +19 -35
  83. pyvale/simcases/case21.i +1 -1
  84. pyvale/simcases/run_1case.py +8 -0
  85. pyvale/simtools.py +2 -2
  86. pyvale/visualsimplotter.py +180 -0
  87. {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/METADATA +11 -57
  88. {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/RECORD +94 -56
  89. {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/WHEEL +1 -1
  90. pyvale.libs/libgcc_s-887de51c.so.1 +0 -0
  91. pyvale.libs/libgomp-24921df4.so.1.0.0 +0 -0
  92. pyvale.libs/libstdc++-d6415257.so.6.0.33 +0 -0
  93. pyvale/examples/visualisation/ex1_1_plot_traces.py +0 -102
  94. pyvale/examples/visualisation/ex2_1_animate_sim.py +0 -89
  95. {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/licenses/LICENSE +0 -0
  96. {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/top_level.txt +0 -0
@@ -4,17 +4,18 @@
4
4
  # Copyright (C) 2025 The Computer Aided Validation Team
5
5
  # ==============================================================================
6
6
 
7
- """Pyvale example: Multi-physics experiment simulation in 2D
8
- --------------------------------------------------------------------------------
7
+ """Basics: Multi-physics experiment simulation in 2D
8
+ ================================================================================
9
+
9
10
  In previous examples we have built our virtual sensor array and used this to
10
11
  run a single simulated experiment. However, we will generally want to run many
11
12
  simulated experiments and perform statistical analysis on the results. In this
12
- example we demonstrate how pyvale can be used to run a set of simulated
13
- experiments with a series of sensor arrays one measuring temperature and the
13
+ example we demonstrate how `pyvale` can be used to run a set of simulated
14
+ experiments with a series of sensor arrays, one measuring temperature and the
14
15
  other measuring strain. We also show how this analysis can be performed over a
15
16
  set of input physics simulations.
16
17
 
17
- Note that this tutorial assumes you are familiar with the use of pyvale for
18
+ Note that this tutorial assumes you are familiar with the use of `pyvale` for
18
19
  scalar and tensor fields as described in the previous examples.
19
20
 
20
21
  Test case: thermo-mechanical analysis of a 2D plate with a temperature gradient.
@@ -25,147 +26,152 @@ import matplotlib.pyplot as plt
25
26
  import mooseherder as mh
26
27
  import pyvale as pyv
27
28
 
29
+ #%%
30
+ # Here we get a list of paths to a set of 3 simulations in this case the
31
+ # simulation is a 2D plate with a heat flux on one edge and a heat transfer
32
+ # coefficient on the other. The mechanical deformation is a result of
33
+ # thermal expansion. The 3 simulation cases cover a nominal thermal
34
+ # and a perturbation of +/-10%.
35
+ data_paths = pyv.DataSet.thermomechanical_2d_experiment_paths()
36
+ elem_dims: int = 2
37
+
38
+ #%%
39
+ # We now loop over the paths and load each into a `SimData` object. We then
40
+ # scale our length units to mm and append the simulation to a list which we
41
+ # will use to perform our simulated experiments.
42
+ disp_comps = ("disp_x","disp_y")
43
+ sim_list = []
44
+ for pp in data_paths:
45
+ sim_data = mh.ExodusReader(pp).read_all_sim_data()
46
+ sim_data = pyv.scale_length_units(scale=1000.0,
47
+ sim_data=sim_data,
48
+ disp_comps=disp_comps)
49
+ sim_list.append(sim_data)
50
+
51
+ #%%
52
+ # We will use the same sampling times for both the thermal and strain
53
+ # sensor arrays as well as the same positions.
54
+ sample_times = np.linspace(0.0,np.max(sim_data.time),50)
55
+
56
+ #%%
57
+ # We place 4 thermal sensors along the mid line of the plate in the
58
+ # direction of the temperature gradient.
59
+ n_sens = (4,1,1)
60
+ x_lims = (0.0,100.0)
61
+ y_lims = (0.0,50.0)
62
+ z_lims = (0.0,0.0)
63
+ tc_sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
64
+
65
+ tc_sens_data = pyv.SensorData(positions=tc_sens_pos,
66
+ sample_times=sample_times)
67
+
68
+ #%%
69
+ # We use the sensor array factory to give us thermocouples with basic 2%
70
+ # errors with uniform systematic error and normal random error. Note that
71
+ # we need to provide a `SimData` object to create our sensor array but when
72
+ # we run our experiment the field object that relies on this will switch the
73
+ # sim data for the required simulation in our list.
74
+ tc_field_name = "temperature"
75
+ tc_array = pyv.SensorArrayFactory \
76
+ .thermocouples_basic_errs(sim_list[0],
77
+ tc_sens_data,
78
+ elem_dims=elem_dims,
79
+ field_name=tc_field_name,
80
+ errs_pc=2.0)
81
+
82
+ #%%
83
+ # We place 3 strain gauges along the direction of the temperature gradient.
84
+ n_sens = (3,1,1)
85
+ sg_sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
86
+ sg_sens_data = pyv.SensorData(positions=sg_sens_pos,
87
+ sample_times=sample_times)
88
+
89
+ #%%
90
+ # We use the factory to give us a basic strain gauge array as well.
91
+ sg_field_name = "strain"
92
+ sg_norm_comps = ("strain_xx","strain_yy")
93
+ sg_dev_comps = ("strain_xy",)
94
+ sg_array = pyv.SensorArrayFactory \
95
+ .strain_gauges_basic_errs(sim_list[0],
96
+ sg_sens_data,
97
+ elem_dims=elem_dims,
98
+ field_name=sg_field_name,
99
+ norm_comps=sg_norm_comps,
100
+ dev_comps=sg_dev_comps,
101
+ errs_pc=2.0)
102
+
103
+ #%%
104
+ # Now we have our list of simulations and the two sensor arrays we want to
105
+ # apply to the simulations. We create a list of our two sensor arrays and
106
+ # use this to create an experiment simulator while specifying how many
107
+ # simulate experiments we want to run per simulation and sensor array.
108
+ sensor_arrays = [tc_array,sg_array]
109
+ exp_sim = pyv.ExperimentSimulator(sim_list,
110
+ sensor_arrays,
111
+ num_exp_per_sim=1000)
112
+
113
+ #%%
114
+ # We can now run our experiments for all our sensor arrays. We are returned
115
+ # a list of numpy arrays. The index in the list corresponds to the position
116
+ # of the sensor array in the list. So if we want our thermocouple results we
117
+ # want exp_data[0] and for our strain gauges exp_data[1]. The numpy array
118
+ # has the following shape:
119
+ # (n_sims,n_exps,n_sensors,n_field_comps,n_time_steps)
120
+ exp_data = exp_sim.run_experiments()
121
+
122
+ #%%
123
+ # We can also calculate summary statistics for each sensor array which is
124
+ # returned as a list where the position corresponds to the sensor array as
125
+ # in our experimental data. The experiment stats object contains numpy
126
+ # arrays for each statistic that is collapsed over the number of
127
+ # experiments. The statistics we can acces include: mean, standard deviation
128
+ # minimum, maximum, median, median absolute deviation and the 25% and 75%
129
+ # quartiles. See the `ExperimentStats` data class for details.
130
+ exp_stats = exp_sim.calc_stats()
131
+
132
+ #%%
133
+ # We will index into and print the shape of our exp_data and exp_stats
134
+ # lists to demonstrate how this works in practice:
135
+ print(80*"=")
136
+ print("exp_data and exp_stats are lists where the index is the sensor array")
137
+ print("position in the list as field components are not consistent dims.\n")
138
+
139
+ print(80*"-")
140
+ print("Thermal sensor array @ exp_data[0]")
141
+ print(80*"-")
142
+ print("shape=(n_sims,n_exps,n_sensors,n_field_comps,n_time_steps)")
143
+ print(f"{exp_data[0].shape=}")
144
+ print()
145
+ print("Stats are calculated over all experiments (axis=1)")
146
+ print("shape=(n_sims,n_sensors,n_field_comps,n_time_steps)")
147
+ print(f"{exp_stats[0].max.shape=}")
148
+ print()
149
+ print(80*"-")
150
+ print("Mechanical sensor array @ exp_data[1]")
151
+ print(80*"-")
152
+ print("shape=(n_sims,n_exps,n_sensors,n_field_comps,n_time_steps)")
153
+ print(f"{exp_data[1].shape=}")
154
+ print()
155
+ print("shape=(n_sims,n_sensors,n_field_comps,n_time_steps)")
156
+ print(f"{exp_stats[1].max.shape=}")
157
+ print(80*"=")
158
+
159
+ #%%
160
+ # We also have specific plotting tools which allow us to visualise the
161
+ # uncertainty bounds for our sensor traces. The defaults plot options show
162
+ # the mean sensor trace and uncertainty bounds of 3 times the stanard
163
+ # deviation. In the next example we will see how to control these plots.
164
+ # For now we will plot the temperature traces for the first simulation and
165
+ # the strain traces for the third simulation in our list of SimData objects.
166
+ (fig,ax) = pyv.plot_exp_traces(exp_sim,
167
+ component="temperature",
168
+ sens_array_num=0,
169
+ sim_num=0)
170
+
171
+ (fig,ax) = pyv.plot_exp_traces(exp_sim,
172
+ component="strain_yy",
173
+ sens_array_num=1,
174
+ sim_num=2)
175
+ plt.show()
176
+
28
177
 
29
- def main() -> None:
30
- # Here we get a list of paths to a set of 3 simulations in this case the
31
- # simulation is a 2D plate with a heat flux on one edge and a heat transfer
32
- # coefficient on the other. The mechanical deformation is a result of
33
- # thermal expansion. The 3 simulation cases cover a nominal thermal
34
- # and a perturbation of +/-10%.
35
- data_paths = pyv.DataSet.thermomechanical_2d_experiment_paths()
36
- elem_dims: int = 2
37
-
38
- # We now loop over the paths and load each into a `SimData` object. We then
39
- # scale our length units to mm and append the simulation to a list which we
40
- # will use to perform our simulated experiments.
41
- disp_comps = ("disp_x","disp_y")
42
- sim_list = []
43
- for pp in data_paths:
44
- sim_data = mh.ExodusReader(pp).read_all_sim_data()
45
- sim_data = pyv.scale_length_units(scale=1000.0,
46
- sim_data=sim_data,
47
- disp_comps=disp_comps)
48
- sim_list.append(sim_data)
49
-
50
-
51
- # We will use the same sampling times for both the thermal and strain
52
- # sensor arrays as well as the same positions.
53
- sample_times = np.linspace(0.0,np.max(sim_data.time),50)
54
-
55
-
56
- # We place 4 thermal sensors along the mid line of the plate in the
57
- # direction of the temperature gradient.
58
- n_sens = (4,1,1)
59
- x_lims = (0.0,100.0)
60
- y_lims = (0.0,50.0)
61
- z_lims = (0.0,0.0)
62
- tc_sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
63
-
64
- tc_sens_data = pyv.SensorData(positions=tc_sens_pos,
65
- sample_times=sample_times)
66
-
67
- # We use the sensor array factory to give use thermocouples with basic 2%
68
- # errors with uniform systematic error and normal random error. Note that
69
- # we need to provide a `SimData` object to create our sensor array but when
70
- # we run our experiment the field object that relies on this will switch the
71
- # sim data for the required simulation in our list.
72
- tc_field_name = "temperature"
73
- tc_array = pyv.SensorArrayFactory \
74
- .thermocouples_basic_errs(sim_list[0],
75
- tc_sens_data,
76
- elem_dims=elem_dims,
77
- field_name=tc_field_name,
78
- errs_pc=2.0)
79
-
80
- # We place 3 strain gauges along the direction of the temperature gradient.
81
- n_sens = (3,1,1)
82
- sg_sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
83
- sg_sens_data = pyv.SensorData(positions=sg_sens_pos,
84
- sample_times=sample_times)
85
-
86
- # We use the factory to give us a basic strain gauge array as well.
87
- sg_field_name = "strain"
88
- sg_norm_comps = ("strain_xx","strain_yy")
89
- sg_dev_comps = ("strain_xy",)
90
- sg_array = pyv.SensorArrayFactory \
91
- .strain_gauges_basic_errs(sim_list[0],
92
- sg_sens_data,
93
- elem_dims=elem_dims,
94
- field_name=sg_field_name,
95
- norm_comps=sg_norm_comps,
96
- dev_comps=sg_dev_comps,
97
- errs_pc=2.0)
98
-
99
-
100
- # Now we have our list of simulation and the two sensor arrays we want to
101
- # apply to the simulations. We create a list of our two sensor arrays and
102
- # use this to create an experiment simulator while specifying how many
103
- # simulate experiments we want to run per simulation and sensor array.
104
- sensor_arrays = [tc_array,sg_array]
105
- exp_sim = pyv.ExperimentSimulator(sim_list,
106
- sensor_arrays,
107
- num_exp_per_sim=1000)
108
-
109
- # We can now run our experiments for all our sensor arrays. We are returned
110
- # a list of numpy arrays. The index in the list corresponds to the position
111
- # of the sensor array in the list. So if we want our thermocouple results we
112
- # want exp_data[0] and for our strain gauges exp_data[1]. The numpy array
113
- # has the following shape:
114
- # (n_sims,n_exps,n_sensors,n_field_comps,n_time_steps)
115
- exp_data = exp_sim.run_experiments()
116
-
117
- # We can also calculate summary statistics for each sensor array which is
118
- # returned as a list where the position corresponds to the sensor array as
119
- # in our experimental data. The experiment stats object contains numpy
120
- # arrays for each statistic that is collapsed over the number of
121
- # experiments. The statistics we can acces include: mean, standard deviation
122
- # minimum, maximum, median, median absolute deviation and the 25% and 75%
123
- # quartiles. See the `ExperimentStats` data class for details.
124
- exp_stats = exp_sim.calc_stats()
125
-
126
- # We will index into and print the shape of our exp_data and exp_stats
127
- # lists to demonstrate how this works in practice:
128
- print(80*"=")
129
- print("exp_data and exp_stats are lists where the index is the sensor array")
130
- print("position in the list as field components are not consistent dims.\n")
131
-
132
- print(80*"-")
133
- print("Thermal sensor array @ exp_data[0]")
134
- print(80*"-")
135
- print("shape=(n_sims,n_exps,n_sensors,n_field_comps,n_time_steps)")
136
- print(f"{exp_data[0].shape=}")
137
- print()
138
- print("Stats are calculated over all experiments (axis=1)")
139
- print("shape=(n_sims,n_sensors,n_field_comps,n_time_steps)")
140
- print(f"{exp_stats[0].max.shape=}")
141
- print()
142
- print(80*"-")
143
- print("Mechanical sensor array @ exp_data[1]")
144
- print(80*"-")
145
- print("shape=(n_sims,n_exps,n_sensors,n_field_comps,n_time_steps)")
146
- print(f"{exp_data[1].shape=}")
147
- print()
148
- print("shape=(n_sims,n_sensors,n_field_comps,n_time_steps)")
149
- print(f"{exp_stats[1].max.shape=}")
150
- print(80*"=")
151
-
152
- # We also have specific plotting tools which allow us to visualise the
153
- # uncertainty bounds for our sensor traces. The defaults plot options show
154
- # the mean sensor trace and uncertainty bounds of 3 times the stanard
155
- # deviation. In the next example we will see how to control these plots.
156
- # For now we will plot the temperature traces for the first simulation and
157
- # the strain traces for the third simulation in our list of SimData objects.
158
- (fig,ax) = pyv.plot_exp_traces(exp_sim,
159
- component="temperature",
160
- sens_array_num=0,
161
- sim_num=0)
162
-
163
- (fig,ax) = pyv.plot_exp_traces(exp_sim,
164
- component="strain_yy",
165
- sens_array_num=1,
166
- sim_num=2)
167
- plt.show()
168
-
169
-
170
- if __name__ == "__main__":
171
- main()