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