pyvale 2025.4.0__py3-none-any.whl → 2025.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyvale might be problematic. Click here for more details.
- pyvale/__init__.py +78 -64
- pyvale/analyticmeshgen.py +102 -0
- pyvale/{core/analyticsimdatafactory.py → analyticsimdatafactory.py} +44 -16
- pyvale/analyticsimdatagenerator.py +323 -0
- pyvale/blendercalibrationdata.py +15 -0
- pyvale/blenderlightdata.py +26 -0
- pyvale/blendermaterialdata.py +15 -0
- pyvale/blenderrenderdata.py +30 -0
- pyvale/blenderscene.py +488 -0
- pyvale/blendertools.py +420 -0
- pyvale/{core/camera.py → camera.py} +15 -15
- pyvale/{core/cameradata.py → cameradata.py} +27 -22
- pyvale/{core/cameradata2d.py → cameradata2d.py} +8 -6
- pyvale/camerastereo.py +217 -0
- pyvale/{core/cameratools.py → cameratools.py} +220 -26
- pyvale/{core/cython → cython}/rastercyth.py +11 -7
- pyvale/data/__init__.py +5 -7
- pyvale/data/cal_target.tiff +0 -0
- pyvale/data/case00_HEX20_out.e +0 -0
- pyvale/data/case00_HEX27_out.e +0 -0
- pyvale/data/case00_HEX8_out.e +0 -0
- pyvale/data/case00_TET10_out.e +0 -0
- pyvale/data/case00_TET14_out.e +0 -0
- pyvale/data/case00_TET4_out.e +0 -0
- pyvale/{core/dataset.py → dataset.py} +91 -16
- pyvale/{core/errorcalculator.py → errorcalculator.py} +13 -16
- pyvale/{core/errordriftcalc.py → errordriftcalc.py} +14 -14
- pyvale/{core/errorintegrator.py → errorintegrator.py} +25 -28
- pyvale/{core/errorrand.py → errorrand.py} +39 -46
- pyvale/errorsyscalib.py +134 -0
- pyvale/{core/errorsysdep.py → errorsysdep.py} +25 -29
- pyvale/{core/errorsysfield.py → errorsysfield.py} +59 -52
- pyvale/{core/errorsysindep.py → errorsysindep.py} +85 -182
- pyvale/examples/__init__.py +5 -7
- pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +131 -0
- pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +158 -0
- pyvale/examples/basics/ex1_3_customsens_therm3d.py +216 -0
- pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +153 -0
- pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +168 -0
- pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +133 -0
- pyvale/examples/basics/ex1_7_spatavg_therm2d.py +123 -0
- pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +112 -0
- pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +111 -0
- pyvale/examples/basics/ex2_3_sensangle_disp2d.py +139 -0
- pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +196 -0
- pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +109 -0
- pyvale/examples/basics/ex3_1_basictensors_strain2d.py +114 -0
- pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +111 -0
- pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +182 -0
- pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +171 -0
- pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +252 -0
- pyvale/examples/{analyticdatagen → genanalyticdata}/ex1_1_scalarvisualisation.py +6 -9
- pyvale/examples/{analyticdatagen → genanalyticdata}/ex1_2_scalarcasebuild.py +8 -11
- pyvale/examples/{analyticdatagen → genanalyticdata}/ex2_1_analyticsensors.py +9 -12
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +8 -15
- pyvale/examples/renderblender/ex1_1_blenderscene.py +121 -0
- pyvale/examples/renderblender/ex1_2_blenderdeformed.py +119 -0
- pyvale/examples/renderblender/ex2_1_stereoscene.py +128 -0
- pyvale/examples/renderblender/ex2_2_stereodeformed.py +131 -0
- pyvale/examples/renderblender/ex3_1_blendercalibration.py +120 -0
- pyvale/examples/{rasterisation → renderrasterisation}/ex_rastenp.py +6 -7
- pyvale/examples/{rasterisation → renderrasterisation}/ex_rastercyth_oneframe.py +5 -7
- pyvale/examples/{rasterisation → renderrasterisation}/ex_rastercyth_static_cypara.py +6 -13
- pyvale/examples/{rasterisation → renderrasterisation}/ex_rastercyth_static_pypara.py +9 -12
- pyvale/examples/{ex1_4_thermal2d.py → visualisation/ex1_1_plot_traces.py} +33 -20
- pyvale/examples/{features/ex_animation_tools_3dmonoblock.py → visualisation/ex2_1_animate_sim.py} +37 -31
- pyvale/experimentsimulator.py +175 -0
- pyvale/{core/field.py → field.py} +6 -14
- pyvale/fieldconverter.py +351 -0
- pyvale/{core/fieldsampler.py → fieldsampler.py} +9 -10
- pyvale/{core/fieldscalar.py → fieldscalar.py} +17 -18
- pyvale/{core/fieldtensor.py → fieldtensor.py} +23 -26
- pyvale/{core/fieldtransform.py → fieldtransform.py} +9 -5
- pyvale/{core/fieldvector.py → fieldvector.py} +14 -16
- pyvale/{core/generatorsrandom.py → generatorsrandom.py} +29 -52
- pyvale/{core/imagedef2d.py → imagedef2d.py} +11 -8
- pyvale/{core/integratorfactory.py → integratorfactory.py} +12 -13
- pyvale/{core/integratorquadrature.py → integratorquadrature.py} +57 -32
- pyvale/integratorrectangle.py +165 -0
- pyvale/{core/integratorspatial.py → integratorspatial.py} +9 -10
- pyvale/{core/integratortype.py → integratortype.py} +7 -8
- pyvale/output.py +17 -0
- pyvale/pyvaleexceptions.py +11 -0
- pyvale/{core/raster.py → raster.py} +8 -8
- pyvale/{core/rastercy.py → rastercy.py} +11 -10
- pyvale/{core/rasternp.py → rasternp.py} +12 -13
- pyvale/{core/rendermesh.py → rendermesh.py} +10 -19
- pyvale/{core/sensorarray.py → sensorarray.py} +7 -8
- pyvale/{core/sensorarrayfactory.py → sensorarrayfactory.py} +64 -78
- pyvale/{core/sensorarraypoint.py → sensorarraypoint.py} +39 -41
- pyvale/{core/sensordata.py → sensordata.py} +7 -8
- pyvale/sensordescriptor.py +213 -0
- pyvale/{core/sensortools.py → sensortools.py} +8 -9
- pyvale/simcases/case00_HEX20.i +5 -5
- pyvale/simcases/case00_HEX27.i +5 -5
- pyvale/simcases/case00_HEX8.i +242 -0
- pyvale/simcases/case00_TET10.i +2 -2
- pyvale/simcases/case00_TET14.i +2 -2
- pyvale/simcases/case00_TET4.i +242 -0
- pyvale/simcases/run_1case.py +1 -1
- pyvale/simtools.py +67 -0
- pyvale/visualexpplotter.py +191 -0
- pyvale/{core/visualimagedef.py → visualimagedef.py} +13 -10
- pyvale/{core/visualimages.py → visualimages.py} +10 -9
- pyvale/visualopts.py +493 -0
- pyvale/{core/visualsimanimator.py → visualsimanimator.py} +47 -19
- pyvale/visualsimsensors.py +318 -0
- pyvale/visualtools.py +136 -0
- pyvale/visualtraceplotter.py +142 -0
- {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/METADATA +17 -14
- pyvale-2025.5.1.dist-info/RECORD +172 -0
- {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/WHEEL +1 -1
- pyvale/core/__init__.py +0 -7
- pyvale/core/analyticmeshgen.py +0 -59
- pyvale/core/analyticsimdatagenerator.py +0 -160
- pyvale/core/cython/rastercyth.c +0 -32267
- pyvale/core/experimentsimulator.py +0 -99
- pyvale/core/fieldconverter.py +0 -154
- pyvale/core/integratorrectangle.py +0 -88
- pyvale/core/optimcheckfuncs.py +0 -153
- pyvale/core/sensordescriptor.py +0 -101
- pyvale/core/visualexpplotter.py +0 -151
- pyvale/core/visualopts.py +0 -180
- pyvale/core/visualsimplotter.py +0 -182
- pyvale/core/visualtools.py +0 -81
- pyvale/core/visualtraceplotter.py +0 -256
- pyvale/examples/analyticdatagen/__init__.py +0 -7
- pyvale/examples/ex1_1_thermal2d.py +0 -89
- pyvale/examples/ex1_2_thermal2d.py +0 -111
- pyvale/examples/ex1_3_thermal2d.py +0 -113
- pyvale/examples/ex1_5_thermal2d.py +0 -105
- pyvale/examples/ex2_1_thermal3d .py +0 -87
- pyvale/examples/ex2_2_thermal3d.py +0 -51
- pyvale/examples/ex2_3_thermal3d.py +0 -109
- pyvale/examples/ex3_1_displacement2d.py +0 -47
- pyvale/examples/ex3_2_displacement2d.py +0 -79
- pyvale/examples/ex3_3_displacement2d.py +0 -104
- pyvale/examples/ex3_4_displacement2d.py +0 -105
- pyvale/examples/ex4_1_strain2d.py +0 -57
- pyvale/examples/ex4_2_strain2d.py +0 -79
- pyvale/examples/ex4_3_strain2d.py +0 -100
- pyvale/examples/ex5_1_multiphysics2d.py +0 -78
- pyvale/examples/ex6_1_multiphysics2d_expsim.py +0 -118
- pyvale/examples/ex6_2_multiphysics3d_expsim.py +0 -158
- pyvale/examples/features/__init__.py +0 -7
- pyvale/examples/features/ex_area_avg.py +0 -89
- pyvale/examples/features/ex_calibration_error.py +0 -108
- pyvale/examples/features/ex_chain_field_errs.py +0 -141
- pyvale/examples/features/ex_field_errs.py +0 -78
- pyvale/examples/features/ex_sensor_single_angle_batch.py +0 -110
- pyvale-2025.4.0.dist-info/RECORD +0 -157
- {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/licenses/LICENSE +0 -0
- {pyvale-2025.4.0.dist-info → pyvale-2025.5.1.dist-info}/top_level.txt +0 -0
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"""
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
8
7
|
import numpy as np
|
|
9
|
-
from pyvale.
|
|
10
|
-
from pyvale.
|
|
11
|
-
from pyvale.
|
|
12
|
-
from pyvale.
|
|
13
|
-
from pyvale.
|
|
14
|
-
from pyvale.
|
|
8
|
+
from pyvale.field import IField
|
|
9
|
+
from pyvale.sensorarray import ISensorArray
|
|
10
|
+
from pyvale.errorintegrator import ErrIntegrator
|
|
11
|
+
from pyvale.sensordescriptor import SensorDescriptor
|
|
12
|
+
from pyvale.sensordata import SensorData
|
|
13
|
+
from pyvale.fieldsampler import sample_field_with_sensor_data
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
class SensorArrayPoint(ISensorArray):
|
|
@@ -53,16 +52,15 @@ class SensorArrayPoint(ISensorArray):
|
|
|
53
52
|
simulated physical fields quickly using finite element shape functions.
|
|
54
53
|
"""
|
|
55
54
|
|
|
56
|
-
__slots__ = ("
|
|
57
|
-
"
|
|
55
|
+
__slots__ = ("_field","_descriptor","_sensor_data","_truth","_measurements",
|
|
56
|
+
"_error_integrator")
|
|
58
57
|
|
|
59
58
|
def __init__(self,
|
|
60
59
|
sensor_data: SensorData,
|
|
61
60
|
field: IField,
|
|
62
61
|
descriptor: SensorDescriptor | None = None,
|
|
63
62
|
) -> None:
|
|
64
|
-
"""
|
|
65
|
-
|
|
63
|
+
"""
|
|
66
64
|
Parameters
|
|
67
65
|
----------
|
|
68
66
|
sensor_data : SensorData
|
|
@@ -76,13 +74,13 @@ class SensorArrayPoint(ISensorArray):
|
|
|
76
74
|
Contains descriptive information about the sensor array for display
|
|
77
75
|
and visualisations, by default None.
|
|
78
76
|
"""
|
|
79
|
-
self.
|
|
80
|
-
self.
|
|
81
|
-
self.
|
|
77
|
+
self._sensor_data = sensor_data
|
|
78
|
+
self._field = field
|
|
79
|
+
self._error_integrator = None
|
|
82
80
|
|
|
83
|
-
self.
|
|
81
|
+
self._descriptor = SensorDescriptor()
|
|
84
82
|
if descriptor is not None:
|
|
85
|
-
self.
|
|
83
|
+
self._descriptor = descriptor
|
|
86
84
|
|
|
87
85
|
self._truth = None
|
|
88
86
|
self._measurements = None
|
|
@@ -97,10 +95,10 @@ class SensorArrayPoint(ISensorArray):
|
|
|
97
95
|
np.ndarray
|
|
98
96
|
Sample times with shape: (num_time_steps,)
|
|
99
97
|
"""
|
|
100
|
-
if self.
|
|
101
|
-
return self.
|
|
98
|
+
if self._sensor_data.sample_times is None:
|
|
99
|
+
return self._field.get_time_steps()
|
|
102
100
|
|
|
103
|
-
return self.
|
|
101
|
+
return self._sensor_data.sample_times
|
|
104
102
|
|
|
105
103
|
def get_measurement_shape(self) -> tuple[int,int,int]:
|
|
106
104
|
"""Gets the shape of the sensor measurement array. shape=(num_sensors,
|
|
@@ -113,8 +111,8 @@ class SensorArrayPoint(ISensorArray):
|
|
|
113
111
|
num_field_components,num_time_steps)
|
|
114
112
|
"""
|
|
115
113
|
|
|
116
|
-
return (self.
|
|
117
|
-
len(self.
|
|
114
|
+
return (self._sensor_data.positions.shape[0],
|
|
115
|
+
len(self._field.get_all_components()),
|
|
118
116
|
self.get_sample_times().shape[0])
|
|
119
117
|
|
|
120
118
|
def get_field(self) -> IField:
|
|
@@ -126,7 +124,7 @@ class SensorArrayPoint(ISensorArray):
|
|
|
126
124
|
IField
|
|
127
125
|
Reference to an `IField` interface.
|
|
128
126
|
"""
|
|
129
|
-
return self.
|
|
127
|
+
return self._field
|
|
130
128
|
|
|
131
129
|
|
|
132
130
|
def calc_truth_values(self) -> np.ndarray:
|
|
@@ -140,8 +138,8 @@ class SensorArrayPoint(ISensorArray):
|
|
|
140
138
|
Array of ground truth sensor values. shape=(num_sensors,
|
|
141
139
|
num_field_components,num_time_steps).
|
|
142
140
|
"""
|
|
143
|
-
self._truth = sample_field_with_sensor_data(self.
|
|
144
|
-
self.
|
|
141
|
+
self._truth = sample_field_with_sensor_data(self._field,
|
|
142
|
+
self._sensor_data)
|
|
145
143
|
|
|
146
144
|
return self._truth
|
|
147
145
|
|
|
@@ -171,7 +169,7 @@ class SensorArrayPoint(ISensorArray):
|
|
|
171
169
|
err_int : ErrIntegrator
|
|
172
170
|
Error integration object with a chain of user defined sensor errors.
|
|
173
171
|
"""
|
|
174
|
-
self.
|
|
172
|
+
self._error_integrator = err_int
|
|
175
173
|
|
|
176
174
|
def get_sensor_data_perturbed(self) -> SensorData | None:
|
|
177
175
|
"""Gets the final sensor array parameters after all errors in the error
|
|
@@ -184,10 +182,10 @@ class SensorArrayPoint(ISensorArray):
|
|
|
184
182
|
The accumulated sensor array parameters as a SensorData object.
|
|
185
183
|
Returns None if no error integrator has been specified.
|
|
186
184
|
"""
|
|
187
|
-
if self.
|
|
185
|
+
if self._error_integrator is None:
|
|
188
186
|
return None
|
|
189
187
|
|
|
190
|
-
return self.
|
|
188
|
+
return self._error_integrator.get_sens_data_accumulated()
|
|
191
189
|
|
|
192
190
|
def get_errors_systematic(self) -> np.ndarray | None:
|
|
193
191
|
"""Gets the systematic error array from the previously calculated sensor
|
|
@@ -200,10 +198,10 @@ class SensorArrayPoint(ISensorArray):
|
|
|
200
198
|
,num_field_components,num_time_steps). Returns None if no error
|
|
201
199
|
integrator has been set.
|
|
202
200
|
"""
|
|
203
|
-
if self.
|
|
201
|
+
if self._error_integrator is None:
|
|
204
202
|
return None
|
|
205
203
|
|
|
206
|
-
return self.
|
|
204
|
+
return self._error_integrator.get_errs_systematic()
|
|
207
205
|
|
|
208
206
|
def get_errors_random(self) -> np.ndarray | None:
|
|
209
207
|
"""Gets the random error array from the previously calculated sensor
|
|
@@ -216,10 +214,10 @@ class SensorArrayPoint(ISensorArray):
|
|
|
216
214
|
,num_field_components,num_time_steps). Returns None if no error
|
|
217
215
|
integrator has been set.
|
|
218
216
|
"""
|
|
219
|
-
if self.
|
|
217
|
+
if self._error_integrator is None:
|
|
220
218
|
return None
|
|
221
219
|
|
|
222
|
-
return self.
|
|
220
|
+
return self._error_integrator.get_errs_random()
|
|
223
221
|
|
|
224
222
|
def get_errors_total(self) -> np.ndarray | None:
|
|
225
223
|
"""Gets the total error array from the previously calculated sensor
|
|
@@ -232,10 +230,10 @@ class SensorArrayPoint(ISensorArray):
|
|
|
232
230
|
,num_field_components,num_time_steps). Returns None if no error
|
|
233
231
|
integrator has been set.
|
|
234
232
|
"""
|
|
235
|
-
if self.
|
|
233
|
+
if self._error_integrator is None:
|
|
236
234
|
return None
|
|
237
235
|
|
|
238
|
-
return self.
|
|
236
|
+
return self._error_integrator.get_errs_total()
|
|
239
237
|
|
|
240
238
|
def calc_measurements(self) -> np.ndarray:
|
|
241
239
|
"""Calculates a set of sensor measurements using the specified sensor
|
|
@@ -254,11 +252,11 @@ class SensorArrayPoint(ISensorArray):
|
|
|
254
252
|
systematic errors if an error integrator is specified. shape=(
|
|
255
253
|
num_sensors,num_field_components,num_time_steps).
|
|
256
254
|
"""
|
|
257
|
-
if self.
|
|
255
|
+
if self._error_integrator is None:
|
|
258
256
|
self._measurements = self.get_truth()
|
|
259
257
|
else:
|
|
260
258
|
self._measurements = self.get_truth() + \
|
|
261
|
-
self.
|
|
259
|
+
self._error_integrator.calc_errors_from_chain(self.get_truth())
|
|
262
260
|
|
|
263
261
|
return self._measurements
|
|
264
262
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"""
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
8
7
|
from dataclasses import dataclass
|
|
9
8
|
import numpy as np
|
|
10
9
|
from scipy.spatial.transform import Rotation
|
|
11
|
-
from pyvale.
|
|
10
|
+
from pyvale.integratortype import EIntSpatialType
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
@dataclass(slots=True)
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
|
|
2
|
+
# ==============================================================================
|
|
3
|
+
# pyvale: the python validation engine
|
|
4
|
+
# License: MIT
|
|
5
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
6
|
+
# ==============================================================================
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
This module is used to create sensor descriptors which are strings used to label
|
|
10
|
+
plots and visualisations for virtual sensor simulations.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(slots=True)
|
|
18
|
+
class SensorDescriptor:
|
|
19
|
+
"""Dataclass for storing string descriptors for sensor array vis2ualisation.
|
|
20
|
+
Used for labelling matplotlib and pyvista plots with the sensor name,
|
|
21
|
+
physical units and other descriptors.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
name: str = "Measured Value"
|
|
25
|
+
"""String describing the field that the sensor measures e.g. temperature
|
|
26
|
+
, strain etc. Defaults to 'Measured Value'.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
units: str = r"-"
|
|
30
|
+
"""String describing the sensor measurement units. Defaults to '-'. Latex
|
|
31
|
+
symbols can be used with a raw string.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
time_units: str = r"s"
|
|
35
|
+
"""String describing time units. Defaults to 's'.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
symbol: str = r"m"
|
|
39
|
+
"""Symbol for describing the field the sensor measures. For example 'T' for
|
|
40
|
+
temperature of r'\epsilon' for strain. Latex symbols can be used with a raw
|
|
41
|
+
string.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
tag: str = "S"
|
|
45
|
+
"""String shorthand tag used to label sensors on pyvista plots. Defaults to
|
|
46
|
+
'S'.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
components: tuple[str,...] | None = None
|
|
50
|
+
"""Tuple of strings describing the field components. Defaults to None which
|
|
51
|
+
is used for scalar fields. For vector fields use ('x','y','z') for 3D and
|
|
52
|
+
for tensor fields use ('xx','yy','zz','xy','yz','xz').
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def create_label(self, comp_ind: int | None = None) -> str:
|
|
57
|
+
"""Creates an axis label for a matplotlib plot based on the sensor
|
|
58
|
+
descriptor string. The axis label takes the form: 'name, symbol [units]'
|
|
59
|
+
This version creates a label with line breaks which is useful for
|
|
60
|
+
vertical colourbars.
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
comp_ind : int | None, optional
|
|
65
|
+
Index of the field component to create a label for, by default None.
|
|
66
|
+
If None the first field component is used.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
str
|
|
71
|
+
Axis label for field component in the form: 'name, symbol [units]'.
|
|
72
|
+
"""
|
|
73
|
+
label = ""
|
|
74
|
+
if self.name != "":
|
|
75
|
+
label = label + rf"{self.name} "
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
symbol = rf"${self.symbol}$ "
|
|
79
|
+
if comp_ind is not None and self.components is not None:
|
|
80
|
+
symbol = rf"${self.symbol}_{{{self.components[comp_ind]}}}$ "
|
|
81
|
+
if symbol != "":
|
|
82
|
+
label = label + symbol
|
|
83
|
+
|
|
84
|
+
if self.units != "":
|
|
85
|
+
label = label + "\n" + rf"[${self.units}$]"
|
|
86
|
+
|
|
87
|
+
return label
|
|
88
|
+
|
|
89
|
+
def create_label_flat(self, comp_ind: int | None = None) -> str:
|
|
90
|
+
"""Creates an axis label for a matplotlib plot based on the sensor
|
|
91
|
+
descriptor string. The axis label takes the form: 'name, symbol [units]'
|
|
92
|
+
This version creates a label with no line breaks which is useful for
|
|
93
|
+
axis labels on plots.
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
comp_ind : int | None, optional
|
|
98
|
+
Index of the field component to create a label for, by default None.
|
|
99
|
+
If None the first field component is used.
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
str
|
|
104
|
+
Axis label for field component in the form: 'name, symbol [units]'.
|
|
105
|
+
"""
|
|
106
|
+
label = ""
|
|
107
|
+
if self.name != "":
|
|
108
|
+
label = label + rf"{self.name} "
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
symbol = rf"${self.symbol}$ "
|
|
112
|
+
if comp_ind is not None and self.components is not None:
|
|
113
|
+
symbol = rf"${self.symbol}_{{{self.components[comp_ind]}}}$ "
|
|
114
|
+
if symbol != "":
|
|
115
|
+
label = label + symbol
|
|
116
|
+
|
|
117
|
+
if self.units != "":
|
|
118
|
+
label = label + " " + rf"[${self.units}$]"
|
|
119
|
+
|
|
120
|
+
return label
|
|
121
|
+
|
|
122
|
+
def create_sensor_tags(self,n_sensors: int) -> list[str]:
|
|
123
|
+
"""Creates a list of numbered sensor tags for labelling sensor locations
|
|
124
|
+
or for graph legends. Tags are shorthand names for sensors such as TC
|
|
125
|
+
for thermocouples or SG for strain gauges.
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
n_sensors : int
|
|
130
|
+
The number of sensors to create tags for.
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
list[str]
|
|
135
|
+
A list of sensor tags
|
|
136
|
+
"""
|
|
137
|
+
z_width = int(np.log10(n_sensors))+1
|
|
138
|
+
|
|
139
|
+
sensor_names = list()
|
|
140
|
+
for ss in range(n_sensors):
|
|
141
|
+
num_str = f"{ss+1}".zfill(z_width)
|
|
142
|
+
sensor_names.append(f"{self.tag}{num_str}")
|
|
143
|
+
|
|
144
|
+
return sensor_names
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class SensorDescriptorFactory:
|
|
148
|
+
"""A factory for building common sensor descriptors for scalar, vector and
|
|
149
|
+
tensor fields. Builds descriptors for thermcouples, displacement sensors
|
|
150
|
+
and strain sensors.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
@staticmethod
|
|
154
|
+
def temperature_descriptor() -> SensorDescriptor:
|
|
155
|
+
"""Creates a generic temperature sensor descriptor. Assumes the sensor
|
|
156
|
+
is measuring a temperature in degrees C.
|
|
157
|
+
|
|
158
|
+
Returns
|
|
159
|
+
-------
|
|
160
|
+
SensorDescriptor
|
|
161
|
+
The default temperature sensor descriptor.
|
|
162
|
+
"""
|
|
163
|
+
descriptor = SensorDescriptor(name="Temp.",
|
|
164
|
+
symbol="T",
|
|
165
|
+
units=r"^{\circ}C",
|
|
166
|
+
tag="TC")
|
|
167
|
+
return descriptor
|
|
168
|
+
|
|
169
|
+
@staticmethod
|
|
170
|
+
def displacement_descriptor() -> SensorDescriptor:
|
|
171
|
+
"""Creates a generic displacement sensor descriptor. Assumes units of mm
|
|
172
|
+
and vector components of x,y,z.
|
|
173
|
+
|
|
174
|
+
Returns
|
|
175
|
+
-------
|
|
176
|
+
SensorDescriptor
|
|
177
|
+
The default displacement sensor descriptor.
|
|
178
|
+
"""
|
|
179
|
+
descriptor = SensorDescriptor(name="Disp.",
|
|
180
|
+
symbol="u",
|
|
181
|
+
units=r"mm",
|
|
182
|
+
tag="DS",
|
|
183
|
+
components=("x","y","z"))
|
|
184
|
+
return descriptor
|
|
185
|
+
|
|
186
|
+
@staticmethod
|
|
187
|
+
def strain_descriptor(spat_dims: int = 3) -> SensorDescriptor:
|
|
188
|
+
"""Creates a generic strain sensor descriptor. Assumes strain is
|
|
189
|
+
unitless and that the components are xx,yy,xy for 2D and xx,yy,zz,xy,yz,
|
|
190
|
+
xz for 3D.
|
|
191
|
+
|
|
192
|
+
Parameters
|
|
193
|
+
----------
|
|
194
|
+
spat_dims : int, optional
|
|
195
|
+
Number of spatial dimensions used for setting the components of the
|
|
196
|
+
tensor strain field, by default 3.
|
|
197
|
+
|
|
198
|
+
Returns
|
|
199
|
+
-------
|
|
200
|
+
SensorDescriptor
|
|
201
|
+
The default strain sensor descriptor.
|
|
202
|
+
"""
|
|
203
|
+
descriptor = SensorDescriptor(name="Strain",
|
|
204
|
+
symbol=r"\varepsilon",
|
|
205
|
+
units=r"-",
|
|
206
|
+
tag="SG")
|
|
207
|
+
|
|
208
|
+
if spat_dims == 2:
|
|
209
|
+
descriptor.components = ("xx","yy","xy")
|
|
210
|
+
else:
|
|
211
|
+
descriptor.components = ("xx","yy","zz","xy","yz","xz")
|
|
212
|
+
|
|
213
|
+
return descriptor
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"""
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
8
7
|
import numpy as np
|
|
9
8
|
import mooseherder as mh
|
|
10
|
-
from pyvale.
|
|
9
|
+
from pyvale.sensorarray import ISensorArray
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
def create_sensor_pos_array(num_sensors: tuple[int,int,int],
|
|
@@ -116,7 +115,7 @@ def print_measurements(sens_array: ISensorArray,
|
|
|
116
115
|
print_toterrs = tot_errs[sensors[0]:sensors[1],
|
|
117
116
|
components[0]:components[1],
|
|
118
117
|
time_steps[0]:time_steps[1]]
|
|
119
|
-
print(f"total errors = \n {
|
|
118
|
+
print(f"total errors = \n {print_toterrs}")
|
|
120
119
|
|
|
121
120
|
print()
|
|
122
121
|
|
pyvale/simcases/case00_HEX20.i
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
#-------------------------------------------------------------------------
|
|
6
6
|
#_* MOOSEHERDER VARIABLES - START
|
|
7
7
|
|
|
8
|
-
endTime =
|
|
8
|
+
endTime = 20
|
|
9
9
|
timeStep = 1
|
|
10
10
|
|
|
11
11
|
# Geometric Properties
|
|
@@ -14,9 +14,9 @@ lengY = 10e-3 # m
|
|
|
14
14
|
lengZ = 10e-3 # m
|
|
15
15
|
|
|
16
16
|
# Mesh Properties
|
|
17
|
-
nElemX =
|
|
18
|
-
nElemY =
|
|
19
|
-
nElemZ =
|
|
17
|
+
nElemX = 2
|
|
18
|
+
nElemY = 2
|
|
19
|
+
nElemZ = 2
|
|
20
20
|
eType = HEX20 # TET10, TET11, HEX20, HEX27
|
|
21
21
|
|
|
22
22
|
# Thermal BCs
|
|
@@ -89,7 +89,7 @@ ThermExp = 17.8e-6 # 1/degC
|
|
|
89
89
|
add_variables = true
|
|
90
90
|
material_output_family = MONOMIAL # MONOMIAL, LAGRANGE
|
|
91
91
|
material_output_order = FIRST # CONSTANT, FIRST, SECOND,
|
|
92
|
-
generate_output = '
|
|
92
|
+
generate_output = 'strain_xx strain_yy strain_zz strain_xy strain_yz strain_xz'
|
|
93
93
|
[]
|
|
94
94
|
[]
|
|
95
95
|
|
pyvale/simcases/case00_HEX27.i
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
#-------------------------------------------------------------------------
|
|
6
6
|
#_* MOOSEHERDER VARIABLES - START
|
|
7
7
|
|
|
8
|
-
endTime =
|
|
8
|
+
endTime = 20
|
|
9
9
|
timeStep = 1
|
|
10
10
|
|
|
11
11
|
# Geometric Properties
|
|
@@ -14,9 +14,9 @@ lengY = 10e-3 # m
|
|
|
14
14
|
lengZ = 10e-3 # m
|
|
15
15
|
|
|
16
16
|
# Mesh Properties
|
|
17
|
-
nElemX =
|
|
18
|
-
nElemY =
|
|
19
|
-
nElemZ =
|
|
17
|
+
nElemX = 2
|
|
18
|
+
nElemY = 2
|
|
19
|
+
nElemZ = 2
|
|
20
20
|
eType = HEX27 # TET10, TET11, HEX20, HEX27
|
|
21
21
|
|
|
22
22
|
# Thermal BCs
|
|
@@ -89,7 +89,7 @@ ThermExp = 17.8e-6 # 1/degC
|
|
|
89
89
|
add_variables = true
|
|
90
90
|
material_output_family = MONOMIAL # MONOMIAL, LAGRANGE
|
|
91
91
|
material_output_order = FIRST # CONSTANT, FIRST, SECOND,
|
|
92
|
-
generate_output = '
|
|
92
|
+
generate_output = 'strain_xx strain_yy strain_zz strain_xy strain_yz strain_xz'
|
|
93
93
|
[]
|
|
94
94
|
[]
|
|
95
95
|
|