pyvale 2025.5.3__cp311-cp311-musllinux_1_2_aarch64.whl → 2025.7.0__cp311-cp311-musllinux_1_2_aarch64.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 +12 -0
- pyvale/blendercalibrationdata.py +3 -1
- pyvale/blenderscene.py +7 -5
- pyvale/blendertools.py +27 -5
- pyvale/camera.py +1 -0
- pyvale/cameradata.py +3 -0
- pyvale/camerasensor.py +147 -0
- pyvale/camerastereo.py +4 -4
- pyvale/cameratools.py +23 -61
- pyvale/cython/rastercyth.c +1657 -1352
- pyvale/cython/rastercyth.cpython-311-aarch64-linux-musl.so +0 -0
- pyvale/cython/rastercyth.py +71 -26
- pyvale/data/plate_hole_def0000.tiff +0 -0
- pyvale/data/plate_hole_def0001.tiff +0 -0
- pyvale/data/plate_hole_ref0000.tiff +0 -0
- pyvale/data/plate_rigid_def0000.tiff +0 -0
- pyvale/data/plate_rigid_def0001.tiff +0 -0
- pyvale/data/plate_rigid_ref0000.tiff +0 -0
- pyvale/dataset.py +96 -6
- pyvale/dic/cpp/dicbruteforce.cpp +370 -0
- pyvale/dic/cpp/dicfourier.cpp +648 -0
- pyvale/dic/cpp/dicinterpolator.cpp +559 -0
- pyvale/dic/cpp/dicmain.cpp +215 -0
- pyvale/dic/cpp/dicoptimizer.cpp +675 -0
- pyvale/dic/cpp/dicrg.cpp +137 -0
- pyvale/dic/cpp/dicscanmethod.cpp +677 -0
- pyvale/dic/cpp/dicsmooth.cpp +138 -0
- pyvale/dic/cpp/dicstrain.cpp +383 -0
- pyvale/dic/cpp/dicutil.cpp +563 -0
- pyvale/dic2d.py +164 -0
- pyvale/dic2dcpp.cpython-311-aarch64-linux-musl.so +0 -0
- pyvale/dicchecks.py +476 -0
- pyvale/dicdataimport.py +247 -0
- pyvale/dicregionofinterest.py +887 -0
- pyvale/dicresults.py +55 -0
- pyvale/dicspecklegenerator.py +238 -0
- pyvale/dicspecklequality.py +305 -0
- pyvale/dicstrain.py +387 -0
- pyvale/dicstrainresults.py +37 -0
- pyvale/errorintegrator.py +10 -8
- pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +124 -113
- pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +124 -132
- pyvale/examples/basics/ex1_3_customsens_therm3d.py +199 -195
- pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +125 -121
- pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +145 -141
- pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +96 -101
- pyvale/examples/basics/ex1_7_spatavg_therm2d.py +109 -105
- pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +92 -91
- pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +96 -90
- pyvale/examples/basics/ex2_3_sensangle_disp2d.py +88 -89
- pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +172 -171
- pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +88 -86
- pyvale/examples/basics/ex3_1_basictensors_strain2d.py +90 -90
- pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +93 -91
- pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +172 -160
- pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +154 -148
- pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +249 -231
- pyvale/examples/dic/ex1_region_of_interest.py +98 -0
- pyvale/examples/dic/ex2_plate_with_hole.py +149 -0
- pyvale/examples/dic/ex3_plate_with_hole_strain.py +93 -0
- pyvale/examples/dic/ex4_dic_blender.py +95 -0
- pyvale/examples/dic/ex5_dic_challenge.py +102 -0
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +4 -2
- pyvale/examples/renderblender/ex1_1_blenderscene.py +152 -105
- pyvale/examples/renderblender/ex1_2_blenderdeformed.py +151 -100
- pyvale/examples/renderblender/ex2_1_stereoscene.py +183 -116
- pyvale/examples/renderblender/ex2_2_stereodeformed.py +185 -112
- pyvale/examples/renderblender/ex3_1_blendercalibration.py +164 -109
- pyvale/examples/renderrasterisation/ex_rastenp.py +74 -35
- pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +6 -13
- pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +2 -2
- pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +2 -4
- pyvale/imagedef2d.py +3 -2
- pyvale/imagetools.py +137 -0
- pyvale/rastercy.py +34 -4
- pyvale/rasternp.py +300 -276
- pyvale/rasteropts.py +58 -0
- pyvale/renderer.py +47 -0
- pyvale/rendermesh.py +52 -62
- pyvale/renderscene.py +51 -0
- pyvale/sensorarrayfactory.py +2 -2
- pyvale/sensortools.py +19 -35
- pyvale/simcases/case21.i +1 -1
- pyvale/simcases/run_1case.py +8 -0
- pyvale/simtools.py +2 -2
- pyvale/visualsimplotter.py +180 -0
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/METADATA +11 -57
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/RECORD +94 -56
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/WHEEL +1 -1
- pyvale.libs/libgcc_s-69c45f16.so.1 +0 -0
- pyvale.libs/libgomp-b626072d.so.1.0.0 +0 -0
- pyvale.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
- pyvale/examples/visualisation/ex1_1_plot_traces.py +0 -102
- pyvale/examples/visualisation/ex2_1_animate_sim.py +0 -89
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/licenses/LICENSE +0 -0
- {pyvale-2025.5.3.dist-info → pyvale-2025.7.0.dist-info}/top_level.txt +0 -0
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
# ==============================================================================
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Basics: 3D vector field sensors
|
|
9
|
+
================================================================================
|
|
10
|
+
|
|
10
11
|
In all our previous examples we have looked at a 2D solid mechanics simulation
|
|
11
12
|
and applied displacement sensors to the vector field. Here we will build a
|
|
12
13
|
custom vector field sensor array on a 3D simulation of a small linear elastic
|
|
13
14
|
cube loaded in tension with the addition of an applied thermal gradient.
|
|
14
15
|
|
|
15
|
-
Note that this tutorial assumes you are familiar with the use of pyvale for
|
|
16
|
+
Note that this tutorial assumes you are familiar with the use of `pyvale` for
|
|
16
17
|
scalar fields as described in the first set of examples.
|
|
17
18
|
|
|
18
19
|
Test case: Simple 3D cube thermo-mechanical in tension with temp gradient.
|
|
@@ -24,86 +25,87 @@ import mooseherder as mh
|
|
|
24
25
|
import pyvale as pyv
|
|
25
26
|
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
28
|
+
#%%
|
|
29
|
+
# First we load our simulation as a `SimData` object. In this case we are
|
|
30
|
+
# loading a 10mm cube loaded in tension in the y direction with the addition
|
|
31
|
+
# of a thermal gradient in the y direction.
|
|
32
|
+
data_path = pyv.DataSet.element_case_path(pyv.EElemTest.HEX20)
|
|
33
|
+
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
34
|
+
|
|
35
|
+
#%%
|
|
36
|
+
# As we are creating a 3D vector field sensor we now have a third
|
|
37
|
+
# displacement field component here.
|
|
38
|
+
field_name = "disp"
|
|
39
|
+
field_comps = ("disp_x","disp_y","disp_z")
|
|
40
|
+
sim_data = pyv.scale_length_units(scale=1000.0,
|
|
41
|
+
sim_data=sim_data,
|
|
42
|
+
disp_comps=field_comps)
|
|
43
|
+
|
|
44
|
+
#%%
|
|
45
|
+
# We use a helper function to print the extent of the dimensions in our
|
|
46
|
+
# `SimData` object to help us locate our sensors on the cube.
|
|
47
|
+
pyv.print_dimensions(sim_data)
|
|
48
|
+
|
|
49
|
+
descriptor = pyv.SensorDescriptorFactory.displacement_descriptor()
|
|
50
|
+
|
|
51
|
+
#%%
|
|
52
|
+
# We pass in the string keys for the three vector field components as they
|
|
53
|
+
# appear in our `SimData` object as well as specifying that our elements are
|
|
54
|
+
# 3 dimensional.
|
|
55
|
+
disp_field = pyv.FieldVector(sim_data,field_name,field_comps,elem_dims=3)
|
|
56
|
+
|
|
57
|
+
#%%
|
|
58
|
+
# Here we manually define our sensor positions to place a sensor on the
|
|
59
|
+
# centre of each face of our 10mm cube. From here everything is the same as
|
|
60
|
+
# for our 2D vector field sensor arrays.
|
|
61
|
+
sensor_positions = np.array(((5.0,0.0,5.0),
|
|
62
|
+
(5.0,10.0,5.0),
|
|
63
|
+
(5.0,5.0,0.0),
|
|
64
|
+
(5.0,5.0,10.0),
|
|
65
|
+
(0.0,5.0,5.0),
|
|
66
|
+
(10.0,5.0,5.0),))
|
|
67
|
+
|
|
68
|
+
sample_times = np.linspace(0.0,np.max(sim_data.time),50)
|
|
69
|
+
|
|
70
|
+
sensor_data = pyv.SensorData(positions=sensor_positions,
|
|
71
|
+
sample_times=sample_times)
|
|
72
|
+
|
|
73
|
+
disp_sens_array = pyv.SensorArrayPoint(sensor_data,
|
|
74
|
+
disp_field,
|
|
75
|
+
descriptor)
|
|
76
|
+
|
|
77
|
+
measurements = disp_sens_array.calc_measurements()
|
|
78
|
+
|
|
79
|
+
#%%
|
|
80
|
+
# Let's have a look at the y displacement field in relation to the location
|
|
81
|
+
# of our displacement sensors.
|
|
82
|
+
pv_plot = pyv.plot_point_sensors_on_sim(disp_sens_array,"disp_y")
|
|
83
|
+
pv_plot.show()
|
|
84
|
+
|
|
85
|
+
#%%
|
|
86
|
+
# We print the results for one of the sensors so we can see what the errors
|
|
87
|
+
# are for the last few sampling times.
|
|
88
|
+
print(80*"-")
|
|
89
|
+
|
|
90
|
+
sens_print = 0
|
|
91
|
+
comp_print = 0
|
|
92
|
+
time_last = 5
|
|
93
|
+
time_print = slice(measurements.shape[2]-time_last,measurements.shape[2])
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
print(f"These are the last {time_last} virtual measurements of sensor "
|
|
97
|
+
+ f"{sens_print} for {field_comps[comp_print]}:")
|
|
98
|
+
|
|
99
|
+
pyv.print_measurements(disp_sens_array,sens_print,comp_print,time_print)
|
|
100
|
+
|
|
101
|
+
print(80*"-")
|
|
102
|
+
|
|
103
|
+
#%%
|
|
104
|
+
# Finally, we plot the time traces for all field components noting that we
|
|
105
|
+
# expect the bottom of the cube to be fixed, the top of the cube to have the
|
|
106
|
+
# maximum y displacement, and that all sensors on the sides of the cube
|
|
107
|
+
# should give the same results.
|
|
108
|
+
for ff in field_comps:
|
|
109
|
+
pyv.plot_time_traces(disp_sens_array,ff)
|
|
110
|
+
|
|
111
|
+
plt.show()
|
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
# ==============================================================================
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Basics: Tensor field sensors (strain gauges)
|
|
9
|
+
================================================================================
|
|
10
|
+
|
|
10
11
|
In this example we use the sensor array factory to build a set of strain
|
|
11
12
|
sensors that can sample the strain tensor field from a solid mechanics
|
|
12
13
|
simulation. In the next example we will examine how we can build custom tensor
|
|
13
14
|
field sensors as we did for scalar field in the first set of examples.
|
|
14
15
|
|
|
15
|
-
Note that this tutorial assumes you are familiar with the use of pyvale for
|
|
16
|
+
Note that this tutorial assumes you are familiar with the use of `pyvale` for
|
|
16
17
|
scalar fields as described in the first set of examples.
|
|
17
18
|
|
|
18
19
|
Test case: point strain sensors on a 2D plate with hole loaded in tension
|
|
@@ -25,90 +26,89 @@ import mooseherder as mh
|
|
|
25
26
|
from mooseherder import SimData
|
|
26
27
|
import pyvale as pyv
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
main()
|
|
29
|
+
#%%
|
|
30
|
+
# First we load the same 2D solid mechanics simulation we used previously
|
|
31
|
+
# for vector displacement fields. Most of this setup code is similar to our
|
|
32
|
+
# vector field examples except we will need to specify the string keys for
|
|
33
|
+
# the normal a deviatoric components of our tensor field (as they appear in
|
|
34
|
+
# our `SimData` object).
|
|
35
|
+
data_path: Path = pyv.DataSet.mechanical_2d_path()
|
|
36
|
+
sim_data: SimData = mh.ExodusReader(data_path).read_all_sim_data()
|
|
37
|
+
sim_data: SimData = pyv.scale_length_units(scale=1000.0,
|
|
38
|
+
sim_data=sim_data,
|
|
39
|
+
disp_comps=("disp_x","disp_y"))
|
|
40
|
+
|
|
41
|
+
n_sens = (2,3,1)
|
|
42
|
+
x_lims = (0.0,100.0)
|
|
43
|
+
y_lims = (0.0,150.0)
|
|
44
|
+
z_lims = (0.0,0.0)
|
|
45
|
+
sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
|
|
46
|
+
|
|
47
|
+
sample_times = np.linspace(0.0,np.max(sim_data.time),50)
|
|
48
|
+
|
|
49
|
+
sens_data = pyv.SensorData(positions=sens_pos,
|
|
50
|
+
sample_times=sample_times)
|
|
51
|
+
|
|
52
|
+
#%%
|
|
53
|
+
# This is where we need to specify the string keys for the normal and
|
|
54
|
+
# deviatoric components of our strain field. In 2D we have two normal
|
|
55
|
+
# normal components and one deviatoric. In 3D we will have 3 of each as we
|
|
56
|
+
# will see in a later example. Otherwise this is very similar to what we
|
|
57
|
+
# have seen previously for scalar and vector fields.
|
|
58
|
+
norm_comps = ("strain_xx","strain_yy")
|
|
59
|
+
dev_comps = ("strain_xy",)
|
|
60
|
+
straingauge_array = pyv.SensorArrayFactory \
|
|
61
|
+
.strain_gauges_basic_errs(sim_data,
|
|
62
|
+
sens_data,
|
|
63
|
+
elem_dims=2,
|
|
64
|
+
field_name="strain",
|
|
65
|
+
norm_comps=norm_comps,
|
|
66
|
+
dev_comps=dev_comps,
|
|
67
|
+
errs_pc=5.0)
|
|
68
|
+
|
|
69
|
+
#%%
|
|
70
|
+
# We run our virtual sensor simulation as normal. The only thing to note is
|
|
71
|
+
# that the second dimension of our measurement array will contain our tensor
|
|
72
|
+
# components in the order they are specified in the tuples with the normal
|
|
73
|
+
# components first followed by the deviatoric. In our case this will be
|
|
74
|
+
# (strain_xx,strain_yy,strain_xy).
|
|
75
|
+
measurements = straingauge_array.calc_measurements()
|
|
76
|
+
|
|
77
|
+
#%%
|
|
78
|
+
# Here we print the shape of the measurement array so we can see that the
|
|
79
|
+
# second dimension contains both our tensor components. We also print some
|
|
80
|
+
# of the sensor measurements for the first tensor component.
|
|
81
|
+
print("\n"+80*"-")
|
|
82
|
+
print("For a virtual sensor: measurement = truth + sysematic error + random error")
|
|
83
|
+
print(f"measurements.shape = {measurements.shape} = "+
|
|
84
|
+
"(n_sensors,n_field_components,n_timesteps)\n")
|
|
85
|
+
print("The truth, systematic error and random error arrays have the same "+
|
|
86
|
+
"shape.")
|
|
87
|
+
|
|
88
|
+
print(80*"-")
|
|
89
|
+
|
|
90
|
+
sens_print = 0
|
|
91
|
+
comp_print = 0
|
|
92
|
+
time_last = 5
|
|
93
|
+
time_print = slice(measurements.shape[2]-time_last,measurements.shape[2])
|
|
94
|
+
|
|
95
|
+
print(f"These are the last {time_last} virtual measurements of sensor "
|
|
96
|
+
+ f"{sens_print}:")
|
|
97
|
+
|
|
98
|
+
pyv.print_measurements(straingauge_array,sens_print,comp_print,time_print)
|
|
99
|
+
|
|
100
|
+
print(80*"-")
|
|
101
|
+
|
|
102
|
+
#%%
|
|
103
|
+
# We can plot a given component of our tensor field and display our sensor
|
|
104
|
+
# locations with respect to the field.
|
|
105
|
+
plot_field = "strain_yy"
|
|
106
|
+
pv_plot = pyv.plot_point_sensors_on_sim(straingauge_array,plot_field)
|
|
107
|
+
pv_plot.show(cpos="xy")
|
|
108
|
+
|
|
109
|
+
#%%
|
|
110
|
+
# We can also plot time traces for all components of the tensor field.
|
|
111
|
+
for cc in (norm_comps+dev_comps):
|
|
112
|
+
pyv.plot_time_traces(straingauge_array,cc)
|
|
113
|
+
|
|
114
|
+
plt.show()
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
# ==============================================================================
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Basics: Custom tensor field sensors (strain gauges) in 2D
|
|
9
|
+
================================================================================
|
|
10
|
+
|
|
10
11
|
In this example we build a custom tensor field sensor array (i.e. a strain gauge
|
|
11
12
|
array) in 2D.
|
|
12
13
|
|
|
13
|
-
Note that this tutorial assumes you are familiar with the use of pyvale for
|
|
14
|
+
Note that this tutorial assumes you are familiar with the use of `pyvale` for
|
|
14
15
|
scalar fields as described in the first set of examples.
|
|
15
16
|
|
|
16
17
|
Test case: point strain sensors on a 2D plate with hole loaded in tension
|
|
@@ -21,91 +22,92 @@ import matplotlib.pyplot as plt
|
|
|
21
22
|
import mooseherder as mh
|
|
22
23
|
import pyvale as pyv
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
25
|
+
#%%
|
|
26
|
+
# First we load the same 2D solid mechanics simulation of a plate with a
|
|
27
|
+
# hole loaded in tension as a `SimData` object. We scale the units to mm
|
|
28
|
+
# from SI including the coordinates and displacement. Strain is unitless so
|
|
29
|
+
# we leave it alone.
|
|
30
|
+
data_path = pyv.DataSet.mechanical_2d_path()
|
|
31
|
+
sim_data = mh.ExodusReader(data_path).read_all_sim_data()
|
|
32
|
+
sim_data = pyv.scale_length_units(scale=1000.0,
|
|
33
|
+
sim_data=sim_data,
|
|
34
|
+
disp_comps=("disp_x","disp_y"))
|
|
35
|
+
|
|
36
|
+
#%%
|
|
37
|
+
# Here is the main difference when creating a tensor field sensor array. We
|
|
38
|
+
# create a tensor field where we need to specify the normal and deviatoric
|
|
39
|
+
# component string keys as they appear in our `SimData` object. We have a 2d
|
|
40
|
+
# simulation here so we have 2 normal components and 1 deviatoric (shear).
|
|
41
|
+
field_name = "strain"
|
|
42
|
+
norm_comps = ("strain_xx","strain_yy")
|
|
43
|
+
dev_comps = ("strain_xy",)
|
|
44
|
+
strain_field = pyv.FieldTensor(sim_data,
|
|
45
|
+
field_name=field_name,
|
|
46
|
+
norm_comps=norm_comps,
|
|
47
|
+
dev_comps=dev_comps,
|
|
48
|
+
elem_dims=2)
|
|
49
|
+
|
|
50
|
+
#%%
|
|
51
|
+
# The setup of our sensor data object is exactly the same as for any other
|
|
52
|
+
# point sensor array. We could optionally specify the sample time to be None
|
|
53
|
+
# in which case the sensor will sample at the simulation time steps.
|
|
54
|
+
n_sens = (2,3,1)
|
|
55
|
+
x_lims = (0.0,100.0)
|
|
56
|
+
y_lims = (0.0,150.0)
|
|
57
|
+
z_lims = (0.0,0.0)
|
|
58
|
+
sens_pos = pyv.create_sensor_pos_array(n_sens,x_lims,y_lims,z_lims)
|
|
59
|
+
|
|
60
|
+
sample_times = np.linspace(0.0,np.max(sim_data.time),50)
|
|
61
|
+
|
|
62
|
+
sens_data = pyv.SensorData(positions=sens_pos,
|
|
63
|
+
sample_times=sample_times)
|
|
64
|
+
|
|
65
|
+
#%%
|
|
66
|
+
# Here we create a descriptor that will be used to label visualisations of
|
|
67
|
+
# the sensor locations and time traces for our sensors. For the strain
|
|
68
|
+
# gauges we are modelling here we could also use the descriptor factory to
|
|
69
|
+
# get these defaults.
|
|
70
|
+
descriptor = pyv.SensorDescriptor(name="Strain",
|
|
71
|
+
symbol=r"\varepsilon",
|
|
72
|
+
units=r"-",
|
|
73
|
+
tag="SG",
|
|
74
|
+
components=("xx","yy","xy"))
|
|
75
|
+
|
|
76
|
+
#%%
|
|
77
|
+
# We build our point sensor array as normal.
|
|
78
|
+
straingauge_array = pyv.SensorArrayPoint(sens_data,
|
|
79
|
+
strain_field,
|
|
80
|
+
descriptor)
|
|
81
|
+
|
|
82
|
+
#%%
|
|
83
|
+
# We can add any errors we like to our error chain. Here we add some basic
|
|
84
|
+
# percentage errors.
|
|
85
|
+
error_chain = []
|
|
86
|
+
error_chain.append(pyv.ErrSysUnifPercent(low_percent=-2.0,high_percent=2.0))
|
|
87
|
+
error_chain.append(pyv.ErrRandNormPercent(std_percent=2.0))
|
|
88
|
+
error_int = pyv.ErrIntegrator(error_chain,
|
|
89
|
+
sens_data,
|
|
90
|
+
straingauge_array.get_measurement_shape())
|
|
91
|
+
straingauge_array.set_error_integrator(error_int)
|
|
92
|
+
|
|
93
|
+
#%%
|
|
94
|
+
# We run our virtual sensor simulation as normal. The only thing to note is
|
|
95
|
+
# that the second dimension of our measurement array will contain our tensor
|
|
96
|
+
# components in the order they are specified in the tuples with the normal
|
|
97
|
+
# components first followed by the deviatoric. In our case this will be
|
|
98
|
+
# (strain_xx,strain_yy,strain_xy).
|
|
99
|
+
measurements = straingauge_array.calc_measurements()
|
|
100
|
+
|
|
101
|
+
#%%
|
|
102
|
+
# We can plot a given component of our tensor field and display our sensor
|
|
103
|
+
# locations with respect to the field.
|
|
104
|
+
plot_field = "strain_yy"
|
|
105
|
+
pv_plot = pyv.plot_point_sensors_on_sim(straingauge_array,plot_field)
|
|
106
|
+
pv_plot.show(cpos="xy")
|
|
107
|
+
|
|
108
|
+
#%%
|
|
109
|
+
# We can also plot time traces for all components of the tensor field.
|
|
110
|
+
for cc in (norm_comps+dev_comps):
|
|
111
|
+
pyv.plot_time_traces(straingauge_array,cc)
|
|
112
|
+
|
|
113
|
+
plt.show()
|