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.
- pyvale/__init__.py +75 -0
- pyvale/core/__init__.py +7 -0
- pyvale/core/analyticmeshgen.py +59 -0
- pyvale/core/analyticsimdatafactory.py +63 -0
- pyvale/core/analyticsimdatagenerator.py +160 -0
- pyvale/core/camera.py +146 -0
- pyvale/core/cameradata.py +64 -0
- pyvale/core/cameradata2d.py +82 -0
- pyvale/core/cameratools.py +328 -0
- pyvale/core/cython/rastercyth.c +32267 -0
- pyvale/core/cython/rastercyth.py +636 -0
- pyvale/core/dataset.py +250 -0
- pyvale/core/errorcalculator.py +112 -0
- pyvale/core/errordriftcalc.py +146 -0
- pyvale/core/errorintegrator.py +339 -0
- pyvale/core/errorrand.py +614 -0
- pyvale/core/errorsysdep.py +331 -0
- pyvale/core/errorsysfield.py +407 -0
- pyvale/core/errorsysindep.py +905 -0
- pyvale/core/experimentsimulator.py +99 -0
- pyvale/core/field.py +136 -0
- pyvale/core/fieldconverter.py +154 -0
- pyvale/core/fieldsampler.py +112 -0
- pyvale/core/fieldscalar.py +167 -0
- pyvale/core/fieldtensor.py +221 -0
- pyvale/core/fieldtransform.py +384 -0
- pyvale/core/fieldvector.py +215 -0
- pyvale/core/generatorsrandom.py +528 -0
- pyvale/core/imagedef2d.py +566 -0
- pyvale/core/integratorfactory.py +241 -0
- pyvale/core/integratorquadrature.py +192 -0
- pyvale/core/integratorrectangle.py +88 -0
- pyvale/core/integratorspatial.py +90 -0
- pyvale/core/integratortype.py +44 -0
- pyvale/core/optimcheckfuncs.py +153 -0
- pyvale/core/raster.py +31 -0
- pyvale/core/rastercy.py +76 -0
- pyvale/core/rasternp.py +604 -0
- pyvale/core/rendermesh.py +156 -0
- pyvale/core/sensorarray.py +179 -0
- pyvale/core/sensorarrayfactory.py +210 -0
- pyvale/core/sensorarraypoint.py +280 -0
- pyvale/core/sensordata.py +72 -0
- pyvale/core/sensordescriptor.py +101 -0
- pyvale/core/sensortools.py +143 -0
- pyvale/core/visualexpplotter.py +151 -0
- pyvale/core/visualimagedef.py +71 -0
- pyvale/core/visualimages.py +75 -0
- pyvale/core/visualopts.py +180 -0
- pyvale/core/visualsimanimator.py +83 -0
- pyvale/core/visualsimplotter.py +182 -0
- pyvale/core/visualtools.py +81 -0
- pyvale/core/visualtraceplotter.py +256 -0
- pyvale/data/__init__.py +7 -0
- pyvale/data/case13_out.e +0 -0
- pyvale/data/case16_out.e +0 -0
- pyvale/data/case17_out.e +0 -0
- pyvale/data/case18_1_out.e +0 -0
- pyvale/data/case18_2_out.e +0 -0
- pyvale/data/case18_3_out.e +0 -0
- pyvale/data/case25_out.e +0 -0
- pyvale/data/case26_out.e +0 -0
- pyvale/data/optspeckle_2464x2056px_spec5px_8bit_gblur1px.tiff +0 -0
- pyvale/examples/__init__.py +7 -0
- pyvale/examples/analyticdatagen/__init__.py +7 -0
- pyvale/examples/analyticdatagen/ex1_1_scalarvisualisation.py +38 -0
- pyvale/examples/analyticdatagen/ex1_2_scalarcasebuild.py +46 -0
- pyvale/examples/analyticdatagen/ex2_1_analyticsensors.py +83 -0
- pyvale/examples/ex1_1_thermal2d.py +89 -0
- pyvale/examples/ex1_2_thermal2d.py +111 -0
- pyvale/examples/ex1_3_thermal2d.py +113 -0
- pyvale/examples/ex1_4_thermal2d.py +89 -0
- pyvale/examples/ex1_5_thermal2d.py +105 -0
- pyvale/examples/ex2_1_thermal3d .py +87 -0
- pyvale/examples/ex2_2_thermal3d.py +51 -0
- pyvale/examples/ex2_3_thermal3d.py +109 -0
- pyvale/examples/ex3_1_displacement2d.py +47 -0
- pyvale/examples/ex3_2_displacement2d.py +79 -0
- pyvale/examples/ex3_3_displacement2d.py +104 -0
- pyvale/examples/ex3_4_displacement2d.py +105 -0
- pyvale/examples/ex4_1_strain2d.py +57 -0
- pyvale/examples/ex4_2_strain2d.py +79 -0
- pyvale/examples/ex4_3_strain2d.py +100 -0
- pyvale/examples/ex5_1_multiphysics2d.py +78 -0
- pyvale/examples/ex6_1_multiphysics2d_expsim.py +118 -0
- pyvale/examples/ex6_2_multiphysics3d_expsim.py +158 -0
- pyvale/examples/features/__init__.py +7 -0
- pyvale/examples/features/ex_animation_tools_3dmonoblock.py +83 -0
- pyvale/examples/features/ex_area_avg.py +89 -0
- pyvale/examples/features/ex_calibration_error.py +108 -0
- pyvale/examples/features/ex_chain_field_errs.py +141 -0
- pyvale/examples/features/ex_field_errs.py +78 -0
- pyvale/examples/features/ex_sensor_single_angle_batch.py +110 -0
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +86 -0
- pyvale/examples/rasterisation/ex_rastenp.py +154 -0
- pyvale/examples/rasterisation/ex_rastercyth_oneframe.py +220 -0
- pyvale/examples/rasterisation/ex_rastercyth_static_cypara.py +194 -0
- pyvale/examples/rasterisation/ex_rastercyth_static_pypara.py +193 -0
- pyvale/simcases/case00_HEX20.i +242 -0
- pyvale/simcases/case00_HEX27.i +242 -0
- pyvale/simcases/case00_TET10.i +242 -0
- pyvale/simcases/case00_TET14.i +242 -0
- pyvale/simcases/case01.i +101 -0
- pyvale/simcases/case02.i +156 -0
- pyvale/simcases/case03.i +136 -0
- pyvale/simcases/case04.i +181 -0
- pyvale/simcases/case05.i +234 -0
- pyvale/simcases/case06.i +305 -0
- pyvale/simcases/case07.geo +135 -0
- pyvale/simcases/case07.i +87 -0
- pyvale/simcases/case08.geo +144 -0
- pyvale/simcases/case08.i +153 -0
- pyvale/simcases/case09.geo +204 -0
- pyvale/simcases/case09.i +87 -0
- pyvale/simcases/case10.geo +204 -0
- pyvale/simcases/case10.i +257 -0
- pyvale/simcases/case11.geo +337 -0
- pyvale/simcases/case11.i +147 -0
- pyvale/simcases/case12.geo +388 -0
- pyvale/simcases/case12.i +329 -0
- pyvale/simcases/case13.i +140 -0
- pyvale/simcases/case14.i +159 -0
- pyvale/simcases/case15.geo +337 -0
- pyvale/simcases/case15.i +150 -0
- pyvale/simcases/case16.geo +391 -0
- pyvale/simcases/case16.i +357 -0
- pyvale/simcases/case17.geo +135 -0
- pyvale/simcases/case17.i +144 -0
- pyvale/simcases/case18.i +254 -0
- pyvale/simcases/case18_1.i +254 -0
- pyvale/simcases/case18_2.i +254 -0
- pyvale/simcases/case18_3.i +254 -0
- pyvale/simcases/case19.geo +252 -0
- pyvale/simcases/case19.i +99 -0
- pyvale/simcases/case20.geo +252 -0
- pyvale/simcases/case20.i +250 -0
- pyvale/simcases/case21.geo +74 -0
- pyvale/simcases/case21.i +155 -0
- pyvale/simcases/case22.geo +82 -0
- pyvale/simcases/case22.i +140 -0
- pyvale/simcases/case23.geo +164 -0
- pyvale/simcases/case23.i +140 -0
- pyvale/simcases/case24.geo +79 -0
- pyvale/simcases/case24.i +123 -0
- pyvale/simcases/case25.geo +82 -0
- pyvale/simcases/case25.i +140 -0
- pyvale/simcases/case26.geo +166 -0
- pyvale/simcases/case26.i +140 -0
- pyvale/simcases/run_1case.py +61 -0
- pyvale/simcases/run_all_cases.py +69 -0
- pyvale/simcases/run_build_case.py +64 -0
- pyvale/simcases/run_example_cases.py +69 -0
- pyvale-2025.4.0.dist-info/METADATA +140 -0
- pyvale-2025.4.0.dist-info/RECORD +157 -0
- pyvale-2025.4.0.dist-info/WHEEL +5 -0
- pyvale-2025.4.0.dist-info/licenses/LICENSE +21 -0
- pyvale-2025.4.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'''
|
|
2
|
+
================================================================================
|
|
3
|
+
DEV: calibration check
|
|
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 mooseherder as mh
|
|
13
|
+
import pyvale
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def assumed_calib(signal: np.ndarray) -> np.ndarray:
|
|
17
|
+
return 24.3*signal + 0.616
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def truth_calib(signal: np.ndarray) -> np.ndarray:
|
|
21
|
+
return -0.01897 + 25.41881*signal - 0.42456*signal**2 + 0.04365*signal**3
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def main() -> None:
|
|
25
|
+
"""pyvale example: sensor calibration error
|
|
26
|
+
Based on K-type thermocouple calibration
|
|
27
|
+
"""
|
|
28
|
+
n_divs = 10000
|
|
29
|
+
signal_calib_range = np.array((0,6))
|
|
30
|
+
v = np.linspace(signal_calib_range[0],signal_calib_range[1],n_divs)
|
|
31
|
+
|
|
32
|
+
temp_truth = -0.01897 + 25.41881*v - 0.42456*v**2 + 0.04365*v**3
|
|
33
|
+
temp_assumed = 24.3*v + 0.616
|
|
34
|
+
calib_error = temp_assumed - temp_truth
|
|
35
|
+
print()
|
|
36
|
+
print(80*"-")
|
|
37
|
+
print(f"Calibration error over signal:"+\
|
|
38
|
+
f" {signal_calib_range[0]} to {signal_calib_range[1]} mV")
|
|
39
|
+
print(calib_error)
|
|
40
|
+
print(f"Max calib error: {np.max(calib_error)}")
|
|
41
|
+
print(f"Min calib error: {np.min(calib_error)}")
|
|
42
|
+
print()
|
|
43
|
+
|
|
44
|
+
data_path = pyvale.DataSet.thermal_2d_path()
|
|
45
|
+
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
46
|
+
# Scale to mm to make 3D visualisation scaling easier
|
|
47
|
+
sim_data.coords = sim_data.coords*1000.0
|
|
48
|
+
|
|
49
|
+
descriptor = pyvale.SensorDescriptorFactory.temperature_descriptor()
|
|
50
|
+
|
|
51
|
+
field_key = 'temperature'
|
|
52
|
+
t_field = pyvale.FieldScalar(sim_data,
|
|
53
|
+
field_key=field_key,
|
|
54
|
+
spat_dims=2)
|
|
55
|
+
|
|
56
|
+
n_sens = (4,1,1)
|
|
57
|
+
x_lims = (0.0,100.0)
|
|
58
|
+
y_lims = (0.0,50.0)
|
|
59
|
+
z_lims = (0.0,0.0)
|
|
60
|
+
sens_pos = pyvale.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
|
|
61
|
+
|
|
62
|
+
use_sim_time = False
|
|
63
|
+
if use_sim_time:
|
|
64
|
+
sample_times = None
|
|
65
|
+
else:
|
|
66
|
+
sample_times = np.linspace(0.0,np.max(sim_data.time),50)
|
|
67
|
+
|
|
68
|
+
sens_data = pyvale.SensorData(positions=sens_pos,
|
|
69
|
+
sample_times=sample_times)
|
|
70
|
+
|
|
71
|
+
tc_array = pyvale.SensorArrayPoint(sens_data,
|
|
72
|
+
t_field,
|
|
73
|
+
descriptor)
|
|
74
|
+
|
|
75
|
+
cal_err = pyvale.ErrSysCalibration(assumed_calib,
|
|
76
|
+
truth_calib,
|
|
77
|
+
signal_calib_range,
|
|
78
|
+
n_cal_divs=10000)
|
|
79
|
+
sys_err_int = pyvale.ErrIntegrator([cal_err],
|
|
80
|
+
sens_data,
|
|
81
|
+
tc_array.get_measurement_shape())
|
|
82
|
+
tc_array.set_error_integrator(sys_err_int)
|
|
83
|
+
|
|
84
|
+
measurements = tc_array.get_measurements()
|
|
85
|
+
|
|
86
|
+
print('\n'+80*'-')
|
|
87
|
+
print('For a sensor: measurement = truth + sysematic error + random error')
|
|
88
|
+
print(f'measurements.shape = {measurements.shape} = '+
|
|
89
|
+
'(n_sensors,n_field_components,n_timesteps)\n')
|
|
90
|
+
print("The truth, systematic error and random error arrays have the same "+
|
|
91
|
+
"shape.")
|
|
92
|
+
|
|
93
|
+
print(80*'-')
|
|
94
|
+
print('Looking at the last 5 time steps (measurements) of sensor 0:')
|
|
95
|
+
pyvale.print_measurements(tc_array,
|
|
96
|
+
(0,1),
|
|
97
|
+
(0,1),
|
|
98
|
+
(measurements.shape[2]-5,measurements.shape[2]))
|
|
99
|
+
print(80*'-')
|
|
100
|
+
|
|
101
|
+
pyvale.plot_time_traces(tc_array,field_key)
|
|
102
|
+
plt.show()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
if __name__ == "__main__":
|
|
108
|
+
main()
|
|
@@ -0,0 +1,141 @@
|
|
|
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
|
+
import mooseherder as mh
|
|
13
|
+
import pyvale
|
|
14
|
+
|
|
15
|
+
def main() -> None:
|
|
16
|
+
data_path = pyvale.DataSet.mechanical_2d_path()
|
|
17
|
+
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
18
|
+
# Scale to mm to make 3D visualisation scaling easier
|
|
19
|
+
sim_data.coords = sim_data.coords*1000.0 # type: ignore
|
|
20
|
+
|
|
21
|
+
descriptor = pyvale.SensorDescriptorFactory.displacement_descriptor()
|
|
22
|
+
|
|
23
|
+
spat_dims = 2
|
|
24
|
+
field_key = "disp"
|
|
25
|
+
components = ("disp_x","disp_y")
|
|
26
|
+
disp_field = pyvale.FieldVector(sim_data,field_key,components,spat_dims)
|
|
27
|
+
|
|
28
|
+
n_sens = (2,3,1)
|
|
29
|
+
x_lims = (0.0,100.0)
|
|
30
|
+
y_lims = (0.0,150.0)
|
|
31
|
+
z_lims = (0.0,0.0)
|
|
32
|
+
sensor_positions = pyvale.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
|
|
33
|
+
|
|
34
|
+
use_sim_time = True
|
|
35
|
+
if use_sim_time:
|
|
36
|
+
sample_times = None
|
|
37
|
+
else:
|
|
38
|
+
sample_times = np.linspace(0.0,np.max(sim_data.time),50)
|
|
39
|
+
|
|
40
|
+
sensor_data = pyvale.SensorData(positions=sensor_positions,
|
|
41
|
+
sample_times=sample_times)
|
|
42
|
+
|
|
43
|
+
disp_sens_array = pyvale.SensorArrayPoint(sensor_data,
|
|
44
|
+
disp_field,
|
|
45
|
+
descriptor)
|
|
46
|
+
|
|
47
|
+
pos_offset = -1.0*np.ones_like(sensor_positions)
|
|
48
|
+
pos_offset[:,2] = 0 # in 2d we only have offset in x and y so zero z
|
|
49
|
+
pos_error_data = pyvale.ErrFieldData(pos_offset_xyz=pos_offset)
|
|
50
|
+
|
|
51
|
+
angle_offset = np.zeros_like(sensor_positions)
|
|
52
|
+
angle_offset[:,0] = 1.0 # only rotate about z in 2D
|
|
53
|
+
angle_error_data = pyvale.ErrFieldData(ang_offset_zyx=angle_offset)
|
|
54
|
+
|
|
55
|
+
time_offset = 2.0*np.ones_like(disp_sens_array.get_sample_times())
|
|
56
|
+
time_error_data = pyvale.ErrFieldData(time_offset=time_offset)
|
|
57
|
+
|
|
58
|
+
field_errs = []
|
|
59
|
+
field_errs.append(pyvale.ErrSysField(disp_field,
|
|
60
|
+
time_error_data))
|
|
61
|
+
field_errs.append(pyvale.ErrSysField(disp_field,
|
|
62
|
+
time_error_data))
|
|
63
|
+
|
|
64
|
+
field_errs.append(pyvale.ErrSysField(disp_field,
|
|
65
|
+
pos_error_data))
|
|
66
|
+
field_errs.append(pyvale.ErrSysField(disp_field,
|
|
67
|
+
pos_error_data))
|
|
68
|
+
|
|
69
|
+
field_errs.append(pyvale.ErrSysField(disp_field,
|
|
70
|
+
angle_error_data))
|
|
71
|
+
field_errs.append(pyvale.ErrSysField(disp_field,
|
|
72
|
+
angle_error_data))
|
|
73
|
+
|
|
74
|
+
err_int_opts = pyvale.ErrIntOpts(force_dependence=True,
|
|
75
|
+
store_all_errs=True)
|
|
76
|
+
error_int = pyvale.ErrIntegrator(field_errs,
|
|
77
|
+
sensor_data,
|
|
78
|
+
disp_sens_array.get_measurement_shape(),
|
|
79
|
+
err_int_opts)
|
|
80
|
+
disp_sens_array.set_error_integrator(error_int)
|
|
81
|
+
|
|
82
|
+
measurements = disp_sens_array.calc_measurements()
|
|
83
|
+
|
|
84
|
+
sens_data_by_chain = error_int.get_sens_data_by_chain()
|
|
85
|
+
if sens_data_by_chain is not None:
|
|
86
|
+
for ii,ss in enumerate(sens_data_by_chain):
|
|
87
|
+
print(80*"-")
|
|
88
|
+
if ss is not None:
|
|
89
|
+
print(f"SensorData @ [{ii}]")
|
|
90
|
+
print("TIME")
|
|
91
|
+
print(ss.sample_times)
|
|
92
|
+
print()
|
|
93
|
+
print("POSITIONS")
|
|
94
|
+
print(ss.positions)
|
|
95
|
+
print()
|
|
96
|
+
print("ANGLES")
|
|
97
|
+
for aa in ss.angles:
|
|
98
|
+
print(aa.as_euler("zyx",degrees=True))
|
|
99
|
+
print()
|
|
100
|
+
print(80*"-")
|
|
101
|
+
|
|
102
|
+
print()
|
|
103
|
+
print(80*"=")
|
|
104
|
+
sens_data_accumulated = error_int.get_sens_data_accumulated()
|
|
105
|
+
print("TIME")
|
|
106
|
+
print(sens_data_accumulated.sample_times)
|
|
107
|
+
print()
|
|
108
|
+
print("POSITIONS")
|
|
109
|
+
print(sens_data_accumulated.positions)
|
|
110
|
+
print()
|
|
111
|
+
print("ANGLES")
|
|
112
|
+
for aa in sens_data_accumulated.angles:
|
|
113
|
+
print(aa.as_euler("zyx",degrees=True))
|
|
114
|
+
print()
|
|
115
|
+
print(80*"=")
|
|
116
|
+
|
|
117
|
+
print(80*"-")
|
|
118
|
+
sens_num = 4
|
|
119
|
+
print("The last 5 time steps (measurements) of sensor {sens_num}:")
|
|
120
|
+
pyvale.print_measurements(disp_sens_array,
|
|
121
|
+
(sens_num-1,sens_num),
|
|
122
|
+
(0,1),
|
|
123
|
+
(measurements.shape[2]-5,measurements.shape[2]))
|
|
124
|
+
print(80*"-")
|
|
125
|
+
|
|
126
|
+
plot_field = "disp_x"
|
|
127
|
+
|
|
128
|
+
if plot_field == "disp_x":
|
|
129
|
+
pv_plot = pyvale.plot_point_sensors_on_sim(disp_sens_array,"disp_x")
|
|
130
|
+
pv_plot.show()
|
|
131
|
+
elif plot_field == "disp_y":
|
|
132
|
+
pv_plot = pyvale.plot_point_sensors_on_sim(disp_sens_array,"disp_y")
|
|
133
|
+
pv_plot.show()
|
|
134
|
+
|
|
135
|
+
pyvale.plot_time_traces(disp_sens_array,"disp_x")
|
|
136
|
+
pyvale.plot_time_traces(disp_sens_array,"disp_y")
|
|
137
|
+
plt.show()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if __name__ == "__main__":
|
|
141
|
+
main()
|
|
@@ -0,0 +1,78 @@
|
|
|
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
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def main() -> None:
|
|
17
|
+
"""pyvale example: point sensors on a 2D thermal simulation
|
|
18
|
+
----------------------------------------------------------------------------
|
|
19
|
+
"""
|
|
20
|
+
data_path = pyvale.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 = pyvale.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 = pyvale.SensorData(positions=sens_pos,
|
|
35
|
+
sample_times=sample_times)
|
|
36
|
+
|
|
37
|
+
tc_array = pyvale.SensorArrayFactory \
|
|
38
|
+
.thermocouples_no_errs(sim_data,
|
|
39
|
+
sensor_data,
|
|
40
|
+
field_key,
|
|
41
|
+
spat_dims=2)
|
|
42
|
+
|
|
43
|
+
#---------------------------------------------------------------------------
|
|
44
|
+
# Standard independent systematic errors
|
|
45
|
+
pos_rand = pyvale.GeneratorNormal(std=1.0) # mm
|
|
46
|
+
pos_lock = np.full_like(sensor_data.positions,False,dtype=bool)
|
|
47
|
+
pos_lock[:,2] = True
|
|
48
|
+
field_err_data = pyvale.ErrFieldData(
|
|
49
|
+
pos_rand_xyz=(pos_rand,pos_rand,pos_rand),
|
|
50
|
+
pos_lock_xyz=pos_lock
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
err_chain = []
|
|
54
|
+
err_chain.append(pyvale.ErrSysField(tc_array.get_field(),
|
|
55
|
+
field_err_data))
|
|
56
|
+
err_int = pyvale.ErrIntegrator(err_chain,
|
|
57
|
+
sensor_data,
|
|
58
|
+
tc_array.get_measurement_shape())
|
|
59
|
+
tc_array.set_error_integrator(err_int)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
#---------------------------------------------------------------------------
|
|
63
|
+
measurements = tc_array.calc_measurements()
|
|
64
|
+
print(80*'-')
|
|
65
|
+
sens_num = 4
|
|
66
|
+
print('The last 5 time steps (measurements) of sensor {sens_num}:')
|
|
67
|
+
pyvale.print_measurements(tc_array,
|
|
68
|
+
(sens_num-1,sens_num),
|
|
69
|
+
(0,1),
|
|
70
|
+
(measurements.shape[2]-5,measurements.shape[2]))
|
|
71
|
+
print(80*'-')
|
|
72
|
+
|
|
73
|
+
pyvale.plot_time_traces(tc_array,field_key)
|
|
74
|
+
plt.show()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == '__main__':
|
|
78
|
+
main()
|
|
@@ -0,0 +1,110 @@
|
|
|
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
|
|
15
|
+
|
|
16
|
+
def main() -> None:
|
|
17
|
+
"""pyvale example: single rotation batch processing
|
|
18
|
+
----------------------------------------------------------------------------
|
|
19
|
+
- Tests that when only one sensor rotation is provided that
|
|
20
|
+
all sensors are assumed to have the same rotation and batch processed.
|
|
21
|
+
"""
|
|
22
|
+
data_path = pyvale.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 = pyvale.SensorDescriptorFactory.displacement_descriptor()
|
|
28
|
+
|
|
29
|
+
spat_dims = 2
|
|
30
|
+
field_key = "disp"
|
|
31
|
+
components = ("disp_x","disp_y")
|
|
32
|
+
disp_field = pyvale.FieldVector(sim_data,field_key,components,spat_dims)
|
|
33
|
+
|
|
34
|
+
#---------------------------------------------------------------------------
|
|
35
|
+
n_sens = (2,3,1)
|
|
36
|
+
x_lims = (0.0,100.0)
|
|
37
|
+
y_lims = (0.0,150.0)
|
|
38
|
+
z_lims = (0.0,0.0)
|
|
39
|
+
sensor_positions = pyvale.create_sensor_pos_array(n_sens,
|
|
40
|
+
x_lims,
|
|
41
|
+
y_lims,
|
|
42
|
+
z_lims)
|
|
43
|
+
|
|
44
|
+
use_sim_time = False
|
|
45
|
+
if use_sim_time:
|
|
46
|
+
sample_times = None
|
|
47
|
+
else:
|
|
48
|
+
sample_times = np.linspace(0.0,np.max(sim_data.time),50)
|
|
49
|
+
|
|
50
|
+
# Provide only a single rotation for the 6 sensors
|
|
51
|
+
sensor_angles = (Rotation.from_euler("zyx", [180, 0, 0], degrees=True),)
|
|
52
|
+
|
|
53
|
+
sensor_data_norot = pyvale.SensorData(positions=sensor_positions,
|
|
54
|
+
sample_times=sample_times)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
sensor_data_rot = pyvale.SensorData(positions=sensor_positions,
|
|
58
|
+
sample_times=sample_times,
|
|
59
|
+
angles=sensor_angles)
|
|
60
|
+
|
|
61
|
+
#---------------------------------------------------------------------------
|
|
62
|
+
disp_sensors_norot = pyvale.SensorArrayPoint(sensor_data_norot,
|
|
63
|
+
disp_field,
|
|
64
|
+
descriptor)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
disp_sensors_rot = pyvale.SensorArrayPoint(sensor_data_rot,
|
|
68
|
+
disp_field,
|
|
69
|
+
descriptor)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
measurements_norot = disp_sensors_norot.calc_measurements()
|
|
74
|
+
measurements_rot = disp_sensors_rot.calc_measurements()
|
|
75
|
+
|
|
76
|
+
#---------------------------------------------------------------------------
|
|
77
|
+
sens_to_print = 1
|
|
78
|
+
print(80*"-")
|
|
79
|
+
print(f"The last 5 time steps (measurements) of non-rotated sensor {sens_to_print}:")
|
|
80
|
+
pyvale.print_measurements(disp_sensors_norot,
|
|
81
|
+
(sens_to_print-1,sens_to_print),
|
|
82
|
+
(0,1),
|
|
83
|
+
(measurements_norot.shape[2]-5,measurements_norot.shape[2]))
|
|
84
|
+
print(80*"-")
|
|
85
|
+
print(f"The last 5 time steps (measurements) of rotated sensor {sens_to_print}:")
|
|
86
|
+
pyvale.print_measurements(disp_sensors_rot,
|
|
87
|
+
(sens_to_print-1,sens_to_print),
|
|
88
|
+
(0,1),
|
|
89
|
+
(measurements_rot.shape[2]-5,measurements_rot.shape[2]))
|
|
90
|
+
print(80*"-")
|
|
91
|
+
|
|
92
|
+
#---------------------------------------------------------------------------
|
|
93
|
+
plot_field = "disp_x"
|
|
94
|
+
|
|
95
|
+
if plot_field == "disp_x":
|
|
96
|
+
pv_plot = pyvale.plot_point_sensors_on_sim(disp_sensors_rot,"disp_x")
|
|
97
|
+
pv_plot.show(cpos="xy")
|
|
98
|
+
elif plot_field == "disp_y":
|
|
99
|
+
pv_plot = pyvale.plot_point_sensors_on_sim(disp_sensors_rot,"disp_y")
|
|
100
|
+
pv_plot.show(cpos="xy")
|
|
101
|
+
|
|
102
|
+
(fig,ax) = pyvale.plot_time_traces(disp_sensors_norot,plot_field)
|
|
103
|
+
ax.set_title("No rotation")
|
|
104
|
+
(fig,ax) = pyvale.plot_time_traces(disp_sensors_rot,plot_field)
|
|
105
|
+
ax.set_title("Rotated")
|
|
106
|
+
plt.show()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
if __name__ == "__main__":
|
|
110
|
+
main()
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
================================================================================
|
|
3
|
+
pyvale: the python computer aided validation engine
|
|
4
|
+
|
|
5
|
+
License: MIT
|
|
6
|
+
Copyright (C) 2025 The Computer Aided Validation Team
|
|
7
|
+
================================================================================
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
import numpy as np
|
|
12
|
+
import mooseherder as mh
|
|
13
|
+
import pyvale as pyv
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def main() -> None:
|
|
17
|
+
#---------------------------------------------------------------------------
|
|
18
|
+
# LOAD FILES
|
|
19
|
+
sim_path = pyv.DataSet.mechanical_2d_path()
|
|
20
|
+
sim_data = mh.ExodusReader(sim_path).read_all_sim_data()
|
|
21
|
+
|
|
22
|
+
image_path = pyv.DataSet.dic_pattern_5mpx_path()
|
|
23
|
+
image_speckle = pyv.CameraTools.load_image(image_path)
|
|
24
|
+
|
|
25
|
+
save_path = Path.cwd()/"exampleoutput"
|
|
26
|
+
|
|
27
|
+
coords = sim_data.coords
|
|
28
|
+
connectivity = (sim_data.connect["connect1"]-1).T # Beware 0 indexing here
|
|
29
|
+
disp_x = sim_data.node_vars["disp_x"][:,:]
|
|
30
|
+
disp_y = sim_data.node_vars["disp_y"][:,:]
|
|
31
|
+
|
|
32
|
+
print()
|
|
33
|
+
print(80*"-")
|
|
34
|
+
print(f"{coords.shape=}")
|
|
35
|
+
print(f"{connectivity.shape=}")
|
|
36
|
+
print(f"{disp_x.shape=}")
|
|
37
|
+
print(f"{disp_y.shape=}")
|
|
38
|
+
print(80*"-")
|
|
39
|
+
|
|
40
|
+
#---------------------------------------------------------------------------
|
|
41
|
+
# INPUT DATA
|
|
42
|
+
cam_data = pyv.CameraData2D(pixels_count=np.array((1040,1540)),
|
|
43
|
+
leng_per_px=0.1e-3,
|
|
44
|
+
bits=8,
|
|
45
|
+
roi_cent_world=np.mean(coords,axis=0),
|
|
46
|
+
subsample=3)
|
|
47
|
+
id_opts = pyv.ImageDefOpts(save_path=save_path,
|
|
48
|
+
crop_on=True,
|
|
49
|
+
add_static_ref=True)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
#---------------------------------------------------------------------------
|
|
53
|
+
# PRE-PROCESS IMAGES
|
|
54
|
+
(upsampled_image,
|
|
55
|
+
image_mask,
|
|
56
|
+
image_input,
|
|
57
|
+
disp_x,
|
|
58
|
+
disp_y) = pyv.ImageDef2D.preprocess(cam_data,
|
|
59
|
+
image_speckle,
|
|
60
|
+
coords,
|
|
61
|
+
connectivity,
|
|
62
|
+
disp_x,
|
|
63
|
+
disp_y,
|
|
64
|
+
id_opts,
|
|
65
|
+
print_on=True)
|
|
66
|
+
|
|
67
|
+
ff = -1
|
|
68
|
+
disp = np.array((disp_x[:,ff],disp_y[:,ff])).T
|
|
69
|
+
print(f"{disp.shape=}")
|
|
70
|
+
|
|
71
|
+
#---------------------------------------------------------------------------
|
|
72
|
+
# DEFORM IMAGES AND SAVE
|
|
73
|
+
pyv.ImageDef2D.deform_images_to_disk(cam_data,
|
|
74
|
+
upsampled_image,
|
|
75
|
+
coords,
|
|
76
|
+
connectivity,
|
|
77
|
+
disp_x,
|
|
78
|
+
disp_y,
|
|
79
|
+
image_mask,
|
|
80
|
+
id_opts,
|
|
81
|
+
print_on=True)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
if __name__ == "__main__":
|
|
85
|
+
main()
|
|
86
|
+
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""
|
|
2
|
+
================================================================================
|
|
3
|
+
pyvale: the python validation engine
|
|
4
|
+
License: MIT
|
|
5
|
+
Copyright (C) 2025 The Computer Aided Validation Team
|
|
6
|
+
================================================================================
|
|
7
|
+
"""
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import time
|
|
10
|
+
import numpy as np
|
|
11
|
+
from scipy.spatial.transform import Rotation
|
|
12
|
+
import matplotlib.pyplot as plt
|
|
13
|
+
import mooseherder as mh
|
|
14
|
+
import pyvale as pyv
|
|
15
|
+
|
|
16
|
+
# TODO
|
|
17
|
+
# - Fix the image averaging function to use cython
|
|
18
|
+
# - Saving of the rendered images for post processing or analysis
|
|
19
|
+
# - Collapse image display functions into visual to simplify code
|
|
20
|
+
#
|
|
21
|
+
# CAMERA:
|
|
22
|
+
# - Need option to work camera rotation based on a given position
|
|
23
|
+
# - The z axis is easy as we can just do roi-cam_pos but what about x and y
|
|
24
|
+
#
|
|
25
|
+
# SCENE OBJECT:
|
|
26
|
+
# - Allow multiple objects in the scene with their own transformations
|
|
27
|
+
# - Allow multiple cameras in the scene
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def main() -> None:
|
|
31
|
+
"""pyvale example: rasterisation field renderer
|
|
32
|
+
----------------------------------------------------------------------------
|
|
33
|
+
- TODO
|
|
34
|
+
"""
|
|
35
|
+
# This a path to an exodus *.e output file from MOOSE, this can be
|
|
36
|
+
# replaced with a path to your own simulation file
|
|
37
|
+
#sim_path = Path.home()/"pyvale"/"src"/"pyvale"/"simcases"/"case21_out.e"
|
|
38
|
+
sim_path = pyv.DataSet.render_mechanical_3d_path()
|
|
39
|
+
|
|
40
|
+
disp_comps = ("disp_x","disp_y","disp_z")
|
|
41
|
+
|
|
42
|
+
sim_data = mh.ExodusReader(sim_path).read_all_sim_data()
|
|
43
|
+
|
|
44
|
+
# Scale m -> mm
|
|
45
|
+
sim_data = pyv.scale_length_units(sim_data,disp_comps,1000.0)
|
|
46
|
+
|
|
47
|
+
# Extracts the surface mesh from a full 3d simulation for rendering
|
|
48
|
+
render_mesh = pyv.create_render_mesh(sim_data,
|
|
49
|
+
("disp_y","disp_x"),
|
|
50
|
+
sim_spat_dim=3,
|
|
51
|
+
field_disp_keys=disp_comps)
|
|
52
|
+
|
|
53
|
+
print()
|
|
54
|
+
print(80*"-")
|
|
55
|
+
print("MESH DATA:")
|
|
56
|
+
print(80*"-")
|
|
57
|
+
print("connectivity.shape=(num_elems,num_nodes_per_elem)")
|
|
58
|
+
print(f"{render_mesh.connectivity.shape=}")
|
|
59
|
+
print()
|
|
60
|
+
print("coords.shape=(num_nodes,coord[x,y,z])")
|
|
61
|
+
print(f"{render_mesh.coords.shape=}")
|
|
62
|
+
print()
|
|
63
|
+
print("fields.shape=(num_coords,num_time_steps,num_components)")
|
|
64
|
+
print(f"{render_mesh.fields_render.shape=}")
|
|
65
|
+
if render_mesh.fields_disp is not None:
|
|
66
|
+
print(f"{render_mesh.fields_disp.shape=}")
|
|
67
|
+
print(80*"-")
|
|
68
|
+
print()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
pixel_num = np.array((960,1280))
|
|
72
|
+
pixel_size = np.array((5.3e-3,5.3e-3))
|
|
73
|
+
focal_leng: float = 50
|
|
74
|
+
cam_rot = Rotation.from_euler("zyx",(0.0,-30.0,-10.0),degrees=True)
|
|
75
|
+
fov_scale_factor: float = 1.1
|
|
76
|
+
|
|
77
|
+
(roi_pos_world,
|
|
78
|
+
cam_pos_world) = pyv.CameraTools.pos_fill_frame_from_rotation(
|
|
79
|
+
coords_world=render_mesh.coords,
|
|
80
|
+
pixel_num=pixel_num,
|
|
81
|
+
pixel_size=pixel_size,
|
|
82
|
+
focal_leng=focal_leng,
|
|
83
|
+
cam_rot=cam_rot,
|
|
84
|
+
frame_fill=fov_scale_factor,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
cam_data = pyv.CameraData(
|
|
88
|
+
pixels_num=pixel_num,
|
|
89
|
+
pixels_size=pixel_size,
|
|
90
|
+
pos_world=cam_pos_world,
|
|
91
|
+
rot_world=cam_rot,
|
|
92
|
+
roi_cent_world=roi_pos_world,
|
|
93
|
+
focal_length=focal_leng,
|
|
94
|
+
sub_samp=2,
|
|
95
|
+
back_face_removal=True,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
print(80*"-")
|
|
99
|
+
print("CAMERA DATA:")
|
|
100
|
+
print(80*"-")
|
|
101
|
+
print(f"{roi_pos_world=}")
|
|
102
|
+
print(f"{cam_pos_world=}")
|
|
103
|
+
print()
|
|
104
|
+
print("World to camera matrix:")
|
|
105
|
+
print(cam_data.world_to_cam_mat)
|
|
106
|
+
print(80*"-")
|
|
107
|
+
print()
|
|
108
|
+
|
|
109
|
+
print(80*"-")
|
|
110
|
+
total_frames = render_mesh.fields_render.shape[1]*render_mesh.fields_render.shape[2]
|
|
111
|
+
print(f"Time steps to render: {render_mesh.fields_render.shape[1]}")
|
|
112
|
+
print(f"Fields to render: {render_mesh.fields_render.shape[2]}")
|
|
113
|
+
print(f"Total frames to render: {total_frames}")
|
|
114
|
+
print(80*"-")
|
|
115
|
+
|
|
116
|
+
print()
|
|
117
|
+
print(80*"=")
|
|
118
|
+
print("RASTER LOOP START")
|
|
119
|
+
|
|
120
|
+
#save_path = Path.cwd()/"example_output"
|
|
121
|
+
save_path = None
|
|
122
|
+
static_mesh = False
|
|
123
|
+
|
|
124
|
+
time_start_loop = time.perf_counter()
|
|
125
|
+
if static_mesh:
|
|
126
|
+
images = pyv.RasterNP.raster_static_mesh(
|
|
127
|
+
cam_data,render_mesh,save_path,threads_num=8
|
|
128
|
+
)
|
|
129
|
+
else:
|
|
130
|
+
time_start_loop = time.perf_counter()
|
|
131
|
+
images = pyv.RasterNP.raster_deformed_mesh(
|
|
132
|
+
cam_data,render_mesh,save_path,parallel=8
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
time_end_loop = time.perf_counter()
|
|
136
|
+
render_time = time_end_loop - time_start_loop
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
print("RASTER LOOP END")
|
|
140
|
+
print(80*"=")
|
|
141
|
+
print("PERFORMANCE")
|
|
142
|
+
print(f"Total frames = {total_frames}")
|
|
143
|
+
print(f"Total render time = {render_time:.4f} seconds")
|
|
144
|
+
print(f"Time per frame = {(render_time/total_frames):.4f} seconds")
|
|
145
|
+
print(80*"=")
|
|
146
|
+
|
|
147
|
+
plot_on = True
|
|
148
|
+
if plot_on:
|
|
149
|
+
(fig,ax) = pyv.plot_field_image(images[:,:,-1,0],
|
|
150
|
+
title_str="Disp. y, [mm]")
|
|
151
|
+
plt.show()
|
|
152
|
+
|
|
153
|
+
if __name__ == "__main__":
|
|
154
|
+
main()
|