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,30 +1,66 @@
|
|
|
1
|
+
#===============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
#===============================================================================
|
|
6
|
+
|
|
1
7
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
================================================================================
|
|
8
|
+
Accesors for data that comes pre-packaged with pyvale for demonstrating its
|
|
9
|
+
functionality. This includes moose simulation outputs as exodus files, input
|
|
10
|
+
files for moose and gmsh for additional simulation cases, and images required
|
|
11
|
+
for testing the image deformation and digital image correlation modules.
|
|
7
12
|
"""
|
|
13
|
+
|
|
14
|
+
from enum import Enum
|
|
8
15
|
from pathlib import Path
|
|
9
16
|
from importlib.resources import files
|
|
10
17
|
|
|
11
18
|
|
|
12
19
|
SIM_CASE_COUNT = 26
|
|
20
|
+
"""Constant describing the number of simulation test case input files for moose
|
|
21
|
+
and gmsh that come packaged with pyvale.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
class EElemTest(Enum):
|
|
25
|
+
"""Enumeration used to specify different 3D element types for extracting
|
|
26
|
+
specific test simulation datasets.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
TET4 = "TET4"
|
|
30
|
+
"""Tetrahedral element, linear with 4 nodes.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
TET10 = "TET10"
|
|
34
|
+
"""Tetrahedral element, quadratic with 10 nodes.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
TET14 = "TET14"
|
|
38
|
+
"""Tetrahedral element, quadratic with 14 nodes.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
HEX8 = "HEX8"
|
|
42
|
+
"""Hexahedral element, linear with 8 nodes.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
HEX20 = "HEX20"
|
|
46
|
+
"""Hexahedral element, quadratic with 20 nodes.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
HEX27 = "HEX27"
|
|
50
|
+
"""Hexahedral element, quadratic with 27 nodes.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __str__(self):
|
|
54
|
+
return self.value
|
|
13
55
|
|
|
14
56
|
|
|
15
57
|
class DataSetError(Exception):
|
|
16
58
|
"""Custom error class for file io errors associated with retrieving datasets
|
|
17
59
|
and files packaged with pyvale.
|
|
18
60
|
"""
|
|
19
|
-
pass
|
|
20
61
|
|
|
21
62
|
|
|
22
63
|
class DataSet:
|
|
23
|
-
"""A static namespace class for handling datasets packaged with pyvale.
|
|
24
|
-
Contains a series of static methods returning a Path object to each data
|
|
25
|
-
file that is packaged with pyvale.
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
64
|
@staticmethod
|
|
29
65
|
def sim_case_input_file_path(case_num: int) -> Path:
|
|
30
66
|
"""Gets the path to MOOSE input file (*.i) for a particular simulation
|
|
@@ -50,7 +86,7 @@ class DataSet:
|
|
|
50
86
|
raise DataSetError("Simulation case number must be greater than 0")
|
|
51
87
|
elif case_num > SIM_CASE_COUNT:
|
|
52
88
|
raise DataSetError("Simulation case number must be less than " \
|
|
53
|
-
|
|
89
|
+
+ f"{SIM_CASE_COUNT}")
|
|
54
90
|
|
|
55
91
|
case_num_str = str(case_num).zfill(2)
|
|
56
92
|
case_file = f"case{case_num_str}.i"
|
|
@@ -85,7 +121,7 @@ class DataSet:
|
|
|
85
121
|
raise DataSetError("Simulation case number must be greater than 0")
|
|
86
122
|
elif case_num > SIM_CASE_COUNT:
|
|
87
123
|
raise DataSetError("Simulation case number must be less than " \
|
|
88
|
-
|
|
124
|
+
+ f"{SIM_CASE_COUNT}")
|
|
89
125
|
|
|
90
126
|
case_num_str = str(case_num).zfill(2)
|
|
91
127
|
case_file = f"case{case_num_str}.geo"
|
|
@@ -236,15 +272,54 @@ class DataSet:
|
|
|
236
272
|
|
|
237
273
|
@staticmethod
|
|
238
274
|
def render_mechanical_3d_path() -> Path:
|
|
239
|
-
"""
|
|
275
|
+
"""Path to a MOOSE simulation output in exodus format. This case is a
|
|
276
|
+
purely mechanical test case in 3D meant for testing image rendering
|
|
277
|
+
algorithms for digital image correlation simulation. The simulation
|
|
278
|
+
consists of a linear elastic thin plate with a hole loaded in tension.
|
|
279
|
+
The simulation uses linear tetrahedral elements for rendering tests.
|
|
240
280
|
|
|
241
281
|
Returns
|
|
242
282
|
-------
|
|
243
283
|
Path
|
|
244
|
-
|
|
284
|
+
Path to the exodus (*.e) output file for this simulation case.
|
|
245
285
|
"""
|
|
246
286
|
return Path(files("pyvale.data").joinpath("case26_out.e"))
|
|
247
287
|
|
|
248
288
|
@staticmethod
|
|
249
289
|
def render_simple_block_path() -> Path:
|
|
250
|
-
|
|
290
|
+
"""Path to a MOOSE simulation output in exodus format. This case is a
|
|
291
|
+
a simple rectangular block in 3D loaded in tension. It uses a minimum
|
|
292
|
+
number of elements and is intended purely for testing image rendering
|
|
293
|
+
algorithms. This simulation uses linear tetrahedral elements.
|
|
294
|
+
|
|
295
|
+
Returns
|
|
296
|
+
-------
|
|
297
|
+
Path
|
|
298
|
+
Path to the exodus (*.e) output file for this simulation case.
|
|
299
|
+
"""
|
|
300
|
+
return Path(files("pyvale.data").joinpath("case25_out.e"))
|
|
301
|
+
|
|
302
|
+
@staticmethod
|
|
303
|
+
def element_case_path(elem_type: EElemTest) -> Path:
|
|
304
|
+
"""Path to a MOOSE simulation output in exodus format. This case is a
|
|
305
|
+
10mm cube undergoing thermo-mechanical loading solved for the
|
|
306
|
+
temperature displacement and strain fields. This case is solved using a
|
|
307
|
+
variety of tetrahedral and hexahedral elements with linear or quadratic
|
|
308
|
+
shapes functions. These simulation cases are intended for testing
|
|
309
|
+
purposes and contain a minimal number of elements.
|
|
310
|
+
|
|
311
|
+
Parameters
|
|
312
|
+
----------
|
|
313
|
+
elem_type : EElemTest
|
|
314
|
+
Enumeration specifying the element type for this test case.
|
|
315
|
+
|
|
316
|
+
Returns
|
|
317
|
+
-------
|
|
318
|
+
Path
|
|
319
|
+
Path to the exodus (*.e) output file for this simulation case.
|
|
320
|
+
"""
|
|
321
|
+
return Path(files("pyvale.data")
|
|
322
|
+
.joinpath(f"case00_{elem_type.value}_out.e"))
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
|
|
@@ -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
|
import enum
|
|
9
8
|
from abc import ABC, abstractmethod
|
|
10
9
|
import numpy as np
|
|
11
|
-
from pyvale.
|
|
10
|
+
from pyvale.sensordata import SensorData
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class EErrType(enum.Enum):
|
|
@@ -28,14 +27,14 @@ class EErrType(enum.Enum):
|
|
|
28
27
|
RANDOM = enum.auto()
|
|
29
28
|
|
|
30
29
|
|
|
31
|
-
class
|
|
30
|
+
class EErrDep(enum.Enum):
|
|
32
31
|
"""Enumeration defining error dependence.
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
EErrDep.INDEPENDENT:
|
|
35
34
|
Errors are calculated based on the ground truth sensor values
|
|
36
35
|
interpolated from the input simulation.
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
EErrDep.DEPENDENT:
|
|
39
38
|
Errors are calculated based on the accumulated sensor reading due
|
|
40
39
|
to all preceeding errors in the chain.
|
|
41
40
|
"""
|
|
@@ -47,6 +46,7 @@ class IErrCalculator(ABC):
|
|
|
47
46
|
"""Interface (abstract base class) for sensor error calculation allowing for
|
|
48
47
|
chaining of errors.
|
|
49
48
|
"""
|
|
49
|
+
|
|
50
50
|
@abstractmethod
|
|
51
51
|
def get_error_type(self) -> EErrType:
|
|
52
52
|
"""Abstract method for getting the error type.
|
|
@@ -56,10 +56,9 @@ class IErrCalculator(ABC):
|
|
|
56
56
|
EErrType
|
|
57
57
|
Enumeration definining RANDOM or SYSTEMATIC error types.
|
|
58
58
|
"""
|
|
59
|
-
pass
|
|
60
59
|
|
|
61
60
|
@abstractmethod
|
|
62
|
-
def get_error_dep(self) ->
|
|
61
|
+
def get_error_dep(self) -> EErrDep:
|
|
63
62
|
"""Abstract method for getting the error dependence.
|
|
64
63
|
|
|
65
64
|
Returns
|
|
@@ -67,10 +66,9 @@ class IErrCalculator(ABC):
|
|
|
67
66
|
EErrDependence
|
|
68
67
|
Enumeration definining RANDOM or SYSTEMATIC error types.
|
|
69
68
|
"""
|
|
70
|
-
pass
|
|
71
69
|
|
|
72
70
|
@abstractmethod
|
|
73
|
-
def set_error_dep(self, dependence:
|
|
71
|
+
def set_error_dep(self, dependence: EErrDep) -> None:
|
|
74
72
|
"""Abstract method for setting the error dependence.
|
|
75
73
|
|
|
76
74
|
Parameters
|
|
@@ -105,7 +103,6 @@ class IErrCalculator(ABC):
|
|
|
105
103
|
the error chain. Note that many errors do not modify the sensor data
|
|
106
104
|
so the sensor data class is passed through this function unchanged.
|
|
107
105
|
"""
|
|
108
|
-
pass
|
|
109
106
|
|
|
110
107
|
|
|
111
108
|
|
|
@@ -1,10 +1,9 @@
|
|
|
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 abc import ABC, abstractmethod
|
|
9
8
|
import numpy as np
|
|
10
9
|
|
|
@@ -33,7 +32,6 @@ class IDriftCalculator(ABC):
|
|
|
33
32
|
Array of drift errors having the same shape as the input drift_var
|
|
34
33
|
array.
|
|
35
34
|
"""
|
|
36
|
-
pass
|
|
37
35
|
|
|
38
36
|
|
|
39
37
|
class DriftConstant(IDriftCalculator):
|
|
@@ -41,9 +39,10 @@ class DriftConstant(IDriftCalculator):
|
|
|
41
39
|
|
|
42
40
|
Implements the IDriftCalculator interface.
|
|
43
41
|
"""
|
|
44
|
-
|
|
45
|
-
"""Initialiser for the `DriftConstant` class.
|
|
42
|
+
__slots__ = ("_offset",)
|
|
46
43
|
|
|
44
|
+
def __init__(self, offset: float) -> None:
|
|
45
|
+
"""
|
|
47
46
|
Parameters
|
|
48
47
|
----------
|
|
49
48
|
offset : float
|
|
@@ -74,10 +73,10 @@ class DriftLinear(IDriftCalculator):
|
|
|
74
73
|
|
|
75
74
|
Implements the IDriftCalculator interface.
|
|
76
75
|
"""
|
|
76
|
+
__slots__ = ("_slope","_offset")
|
|
77
77
|
|
|
78
78
|
def __init__(self, slope: float, offset: float = 0.0) -> None:
|
|
79
|
-
"""
|
|
80
|
-
|
|
79
|
+
"""
|
|
81
80
|
Parameters
|
|
82
81
|
----------
|
|
83
82
|
slope : float
|
|
@@ -114,9 +113,10 @@ class DriftPolynomial(IDriftCalculator):
|
|
|
114
113
|
Implements the IDriftCalculator interface.
|
|
115
114
|
"""
|
|
116
115
|
|
|
117
|
-
|
|
118
|
-
"""Initialiser for the `DriftPolynomial` class.
|
|
116
|
+
__slots__ = ("_coeffs",)
|
|
119
117
|
|
|
118
|
+
def __init__(self, coeffs: np.ndarray) -> None:
|
|
119
|
+
"""
|
|
120
120
|
Parameters
|
|
121
121
|
----------
|
|
122
122
|
coeffs : np.ndarray
|
|
@@ -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 copy
|
|
9
8
|
from dataclasses import dataclass
|
|
10
9
|
import numpy as np
|
|
11
|
-
from pyvale.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
from pyvale.
|
|
10
|
+
from pyvale.errorcalculator import (IErrCalculator,
|
|
11
|
+
EErrType,
|
|
12
|
+
EErrDep)
|
|
13
|
+
from pyvale.sensordata import SensorData
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
@dataclass(slots=True)
|
|
@@ -20,12 +19,9 @@ class ErrIntOpts:
|
|
|
20
19
|
errors are calculated and stored in memory for later use.
|
|
21
20
|
"""
|
|
22
21
|
|
|
23
|
-
force_dependence:
|
|
24
|
-
"""Forces all errors to be calculated
|
|
25
|
-
|
|
26
|
-
errors are calculated based on the ground truth whereas dependent errors are
|
|
27
|
-
calculated based on the accumulated sensor measurement at that stage in the
|
|
28
|
-
error chain.
|
|
22
|
+
force_dependence: EErrDep | None = None
|
|
23
|
+
"""Forces all errors to be calculated with the specified dependence. If set
|
|
24
|
+
to None then all errors will use their default/preset dependence.
|
|
29
25
|
|
|
30
26
|
Note that some errors are inherently independent so will not change. For
|
|
31
27
|
example: `ErrRandNormal` is purely independent whereas `ErrRandNormPercent`
|
|
@@ -72,8 +68,7 @@ class ErrIntegrator:
|
|
|
72
68
|
sensor_data_initial: SensorData,
|
|
73
69
|
meas_shape: tuple[int,int,int],
|
|
74
70
|
err_int_opts: ErrIntOpts | None = None) -> None:
|
|
75
|
-
"""
|
|
76
|
-
|
|
71
|
+
"""
|
|
77
72
|
Parameters
|
|
78
73
|
----------
|
|
79
74
|
err_chain : list[IErrCalculator]
|
|
@@ -118,7 +113,7 @@ class ErrIntegrator:
|
|
|
118
113
|
"""Sets the error chain that will be looped over to calculate the sensor
|
|
119
114
|
measurement errors. If the error integration options are forcing error
|
|
120
115
|
dependence then all errors in the chain will have their dependence set
|
|
121
|
-
to
|
|
116
|
+
to the specified value.
|
|
122
117
|
|
|
123
118
|
Parameters
|
|
124
119
|
----------
|
|
@@ -127,9 +122,9 @@ class ErrIntegrator:
|
|
|
127
122
|
"""
|
|
128
123
|
self._err_chain = err_chain
|
|
129
124
|
|
|
130
|
-
if self._err_int_opts.force_dependence:
|
|
125
|
+
if self._err_int_opts.force_dependence is not None:
|
|
131
126
|
for ee in self._err_chain:
|
|
132
|
-
ee.set_error_dep(
|
|
127
|
+
ee.set_error_dep(self._err_int_opts.force_dependence)
|
|
133
128
|
|
|
134
129
|
|
|
135
130
|
def calc_errors_from_chain(self, truth: np.ndarray) -> np.ndarray:
|
|
@@ -188,14 +183,15 @@ class ErrIntegrator:
|
|
|
188
183
|
|
|
189
184
|
for ii,ee in enumerate(self._err_chain):
|
|
190
185
|
|
|
191
|
-
if ee.get_error_dep() ==
|
|
186
|
+
if ee.get_error_dep() == EErrDep.DEPENDENT:
|
|
192
187
|
(error_array,sens_data) = ee.calc_errs(truth+accumulated_error,
|
|
193
188
|
self._sens_data_accumulated)
|
|
194
|
-
|
|
189
|
+
|
|
195
190
|
else:
|
|
196
191
|
(error_array,sens_data) = ee.calc_errs(truth,
|
|
197
192
|
self._sens_data_initial)
|
|
198
193
|
|
|
194
|
+
self._sens_data_accumulated = sens_data
|
|
199
195
|
self._sens_data_by_chain.append(sens_data)
|
|
200
196
|
|
|
201
197
|
if ee.get_error_type() == EErrType.SYSTEMATIC:
|
|
@@ -234,10 +230,11 @@ class ErrIntegrator:
|
|
|
234
230
|
|
|
235
231
|
for ee in self._err_chain:
|
|
236
232
|
|
|
237
|
-
if ee.get_error_dep() ==
|
|
238
|
-
(error_array,sens_data) = ee.calc_errs(
|
|
239
|
-
|
|
240
|
-
|
|
233
|
+
if ee.get_error_dep() == EErrDep.DEPENDENT:
|
|
234
|
+
(error_array,sens_data) = ee.calc_errs(
|
|
235
|
+
truth+accumulated_error,
|
|
236
|
+
self._sens_data_accumulated
|
|
237
|
+
)
|
|
241
238
|
else:
|
|
242
239
|
(error_array,sens_data) = ee.calc_errs(truth,
|
|
243
240
|
self._sens_data_initial)
|
|
@@ -1,19 +1,18 @@
|
|
|
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.
|
|
8
|
+
from pyvale.sensordata import SensorData
|
|
9
|
+
from pyvale.errorcalculator import (IErrCalculator,
|
|
11
10
|
EErrType,
|
|
12
|
-
|
|
13
|
-
from pyvale.
|
|
11
|
+
EErrDep)
|
|
12
|
+
from pyvale.generatorsrandom import IGenRandom
|
|
14
13
|
|
|
15
14
|
|
|
16
|
-
class
|
|
15
|
+
class ErrRandUnif(IErrCalculator):
|
|
17
16
|
"""Random error calculator based on uniform sampling of an interval
|
|
18
17
|
specified by its upper and lower bound.
|
|
19
18
|
|
|
@@ -24,10 +23,9 @@ class ErrRandUniform(IErrCalculator):
|
|
|
24
23
|
def __init__(self,
|
|
25
24
|
low: float,
|
|
26
25
|
high: float,
|
|
27
|
-
err_dep:
|
|
26
|
+
err_dep: EErrDep = EErrDep.INDEPENDENT,
|
|
28
27
|
seed: int | None = None) -> None:
|
|
29
|
-
"""
|
|
30
|
-
|
|
28
|
+
"""
|
|
31
29
|
Parameters
|
|
32
30
|
----------
|
|
33
31
|
low : float
|
|
@@ -55,7 +53,7 @@ class ErrRandUniform(IErrCalculator):
|
|
|
55
53
|
self.rng = np.random.default_rng(seed)
|
|
56
54
|
self.err_dep = err_dep
|
|
57
55
|
|
|
58
|
-
def get_error_dep(self) ->
|
|
56
|
+
def get_error_dep(self) -> EErrDep:
|
|
59
57
|
"""Gets the error dependence state for this error calculator. An
|
|
60
58
|
independent error is calculated based on the input truth values as the
|
|
61
59
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -70,7 +68,7 @@ class ErrRandUniform(IErrCalculator):
|
|
|
70
68
|
"""
|
|
71
69
|
return self.err_dep
|
|
72
70
|
|
|
73
|
-
def set_error_dep(self, dependence:
|
|
71
|
+
def set_error_dep(self, dependence: EErrDep) -> None:
|
|
74
72
|
"""Sets the error dependence state for this error calculator. An
|
|
75
73
|
independent error is calculated based on the input truth values as the
|
|
76
74
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -139,10 +137,9 @@ class ErrRandUnifPercent(IErrCalculator):
|
|
|
139
137
|
def __init__(self,
|
|
140
138
|
low_percent: float,
|
|
141
139
|
high_percent: float,
|
|
142
|
-
err_dep:
|
|
140
|
+
err_dep: EErrDep = EErrDep.INDEPENDENT,
|
|
143
141
|
seed: int | None = None) -> None:
|
|
144
|
-
"""
|
|
145
|
-
|
|
142
|
+
"""
|
|
146
143
|
Parameters
|
|
147
144
|
----------
|
|
148
145
|
low_percent : float
|
|
@@ -171,7 +168,7 @@ class ErrRandUnifPercent(IErrCalculator):
|
|
|
171
168
|
self.rng = np.random.default_rng(seed)
|
|
172
169
|
self.err_dep = err_dep
|
|
173
170
|
|
|
174
|
-
def get_error_dep(self) ->
|
|
171
|
+
def get_error_dep(self) -> EErrDep:
|
|
175
172
|
"""Gets the error dependence state for this error calculator. An
|
|
176
173
|
independent error is calculated based on the input truth values as the
|
|
177
174
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -184,7 +181,7 @@ class ErrRandUnifPercent(IErrCalculator):
|
|
|
184
181
|
"""
|
|
185
182
|
return self.err_dep
|
|
186
183
|
|
|
187
|
-
def set_error_dep(self, dependence:
|
|
184
|
+
def set_error_dep(self, dependence: EErrDep) -> None:
|
|
188
185
|
"""Sets the error dependence state for this error calculator. An
|
|
189
186
|
independent error is calculated based on the input truth values as the
|
|
190
187
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -235,7 +232,7 @@ class ErrRandUnifPercent(IErrCalculator):
|
|
|
235
232
|
return (err_basis*norm_rand,sens_data)
|
|
236
233
|
|
|
237
234
|
|
|
238
|
-
class
|
|
235
|
+
class ErrRandNorm(IErrCalculator):
|
|
239
236
|
"""Random error calculator based on sampling of a normal (Gaussian)
|
|
240
237
|
distribution specified using the standard deviation with an assumed zero
|
|
241
238
|
mean. A non-zero mean is a systematic error and should be specified using
|
|
@@ -247,10 +244,9 @@ class ErrRandNormal(IErrCalculator):
|
|
|
247
244
|
|
|
248
245
|
def __init__(self,
|
|
249
246
|
std: float,
|
|
250
|
-
err_dep:
|
|
247
|
+
err_dep: EErrDep = EErrDep.INDEPENDENT,
|
|
251
248
|
seed: int | None = None) -> None:
|
|
252
|
-
"""
|
|
253
|
-
|
|
249
|
+
"""
|
|
254
250
|
Parameters
|
|
255
251
|
----------
|
|
256
252
|
std : float
|
|
@@ -265,7 +261,7 @@ class ErrRandNormal(IErrCalculator):
|
|
|
265
261
|
self.rng = np.random.default_rng(seed)
|
|
266
262
|
self.err_dep = err_dep
|
|
267
263
|
|
|
268
|
-
def get_error_dep(self) ->
|
|
264
|
+
def get_error_dep(self) -> EErrDep:
|
|
269
265
|
"""Gets the error dependence state for this error calculator. An
|
|
270
266
|
independent error is calculated based on the input truth values as the
|
|
271
267
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -280,7 +276,7 @@ class ErrRandNormal(IErrCalculator):
|
|
|
280
276
|
"""
|
|
281
277
|
return self.err_dep
|
|
282
278
|
|
|
283
|
-
def set_error_dep(self, dependence:
|
|
279
|
+
def set_error_dep(self, dependence: EErrDep) -> None:
|
|
284
280
|
"""Sets the error dependence state for this error calculator. An
|
|
285
281
|
independent error is calculated based on the input truth values as the
|
|
286
282
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -350,10 +346,9 @@ class ErrRandNormPercent(IErrCalculator):
|
|
|
350
346
|
|
|
351
347
|
def __init__(self,
|
|
352
348
|
std_percent: float,
|
|
353
|
-
err_dep:
|
|
349
|
+
err_dep: EErrDep = EErrDep.INDEPENDENT,
|
|
354
350
|
seed: int | None = None) -> None:
|
|
355
|
-
"""
|
|
356
|
-
|
|
351
|
+
"""
|
|
357
352
|
Parameters
|
|
358
353
|
----------
|
|
359
354
|
std_percent : float
|
|
@@ -369,7 +364,7 @@ class ErrRandNormPercent(IErrCalculator):
|
|
|
369
364
|
self._rng = np.random.default_rng(seed)
|
|
370
365
|
self._err_dep = err_dep
|
|
371
366
|
|
|
372
|
-
def get_error_dep(self) ->
|
|
367
|
+
def get_error_dep(self) -> EErrDep:
|
|
373
368
|
"""Gets the error dependence state for this error calculator. An
|
|
374
369
|
independent error is calculated based on the input truth values as the
|
|
375
370
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -382,7 +377,7 @@ class ErrRandNormPercent(IErrCalculator):
|
|
|
382
377
|
"""
|
|
383
378
|
return self._err_dep
|
|
384
379
|
|
|
385
|
-
def set_error_dep(self, dependence:
|
|
380
|
+
def set_error_dep(self, dependence: EErrDep) -> None:
|
|
386
381
|
"""Sets the error dependence state for this error calculator. An
|
|
387
382
|
independent error is calculated based on the input truth values as the
|
|
388
383
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -442,10 +437,9 @@ class ErrRandGenerator(IErrCalculator):
|
|
|
442
437
|
__slots__ = ("_generator","_err_dep")
|
|
443
438
|
|
|
444
439
|
def __init__(self,
|
|
445
|
-
generator:
|
|
446
|
-
err_dep:
|
|
447
|
-
"""
|
|
448
|
-
|
|
440
|
+
generator: IGenRandom,
|
|
441
|
+
err_dep: EErrDep = EErrDep.INDEPENDENT) -> None:
|
|
442
|
+
"""
|
|
449
443
|
Parameters
|
|
450
444
|
----------
|
|
451
445
|
generator : IGeneratorRandom
|
|
@@ -456,7 +450,7 @@ class ErrRandGenerator(IErrCalculator):
|
|
|
456
450
|
self._generator = generator
|
|
457
451
|
self._err_dep = err_dep
|
|
458
452
|
|
|
459
|
-
def get_error_dep(self) ->
|
|
453
|
+
def get_error_dep(self) -> EErrDep:
|
|
460
454
|
"""Gets the error dependence state for this error calculator. An
|
|
461
455
|
independent error is calculated based on the input truth values as the
|
|
462
456
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -471,7 +465,7 @@ class ErrRandGenerator(IErrCalculator):
|
|
|
471
465
|
"""
|
|
472
466
|
return self._err_dep
|
|
473
467
|
|
|
474
|
-
def set_error_dep(self, dependence:
|
|
468
|
+
def set_error_dep(self, dependence: EErrDep) -> None:
|
|
475
469
|
"""Sets the error dependence state for this error calculator. An
|
|
476
470
|
independent error is calculated based on the input truth values as the
|
|
477
471
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -537,10 +531,9 @@ class ErrRandGenPercent(IErrCalculator):
|
|
|
537
531
|
__slots__ = ("_generator","_err_dep")
|
|
538
532
|
|
|
539
533
|
def __init__(self,
|
|
540
|
-
generator:
|
|
541
|
-
err_dep:
|
|
542
|
-
"""
|
|
543
|
-
|
|
534
|
+
generator: IGenRandom,
|
|
535
|
+
err_dep: EErrDep = EErrDep.INDEPENDENT) -> None:
|
|
536
|
+
"""
|
|
544
537
|
Parameters
|
|
545
538
|
----------
|
|
546
539
|
generator : IGeneratorRandom
|
|
@@ -551,7 +544,7 @@ class ErrRandGenPercent(IErrCalculator):
|
|
|
551
544
|
self._generator = generator
|
|
552
545
|
self._err_dep = err_dep
|
|
553
546
|
|
|
554
|
-
def get_error_dep(self) ->
|
|
547
|
+
def get_error_dep(self) -> EErrDep:
|
|
555
548
|
"""Gets the error dependence state for this error calculator. An
|
|
556
549
|
independent error is calculated based on the input truth values as the
|
|
557
550
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -564,7 +557,7 @@ class ErrRandGenPercent(IErrCalculator):
|
|
|
564
557
|
"""
|
|
565
558
|
return self._err_dep
|
|
566
559
|
|
|
567
|
-
def set_error_dep(self, dependence:
|
|
560
|
+
def set_error_dep(self, dependence: EErrDep) -> None:
|
|
568
561
|
"""Sets the error dependence state for this error calculator. An
|
|
569
562
|
independent error is calculated based on the input truth values as the
|
|
570
563
|
error basis. A dependent error is calculated based on the accumulated
|
|
@@ -609,6 +602,6 @@ class ErrRandGenPercent(IErrCalculator):
|
|
|
609
602
|
error array has the same shape as the input error basis.
|
|
610
603
|
"""
|
|
611
604
|
rand_errs = err_basis \
|
|
612
|
-
* self._generator.generate(shape=err_basis.shape)/100
|
|
605
|
+
* self._generator.generate(shape=err_basis.shape)/100.0
|
|
613
606
|
|
|
614
607
|
return (rand_errs,sens_data)
|