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,15 +1,14 @@
|
|
|
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
|
|
|
11
10
|
|
|
12
|
-
class
|
|
11
|
+
class IGenRandom(ABC):
|
|
13
12
|
"""Interface (abstract base class) for wrapping numpy random number
|
|
14
13
|
generation to allow probability distribution parameters to be specified in
|
|
15
14
|
the initialiser whereas the generation of random numbers has a common
|
|
@@ -35,7 +34,7 @@ class IGeneratorRandom(ABC):
|
|
|
35
34
|
pass
|
|
36
35
|
|
|
37
36
|
|
|
38
|
-
class
|
|
37
|
+
class GenNormal(IGenRandom):
|
|
39
38
|
"""Class wrapping the numpy normal random number generator. Implements the
|
|
40
39
|
IGeneratorRandom interface to allow for interchangeability with other random
|
|
41
40
|
number generators.
|
|
@@ -46,9 +45,7 @@ class GeneratorNormal(IGeneratorRandom):
|
|
|
46
45
|
std: float = 1.0,
|
|
47
46
|
mean: float = 0.0,
|
|
48
47
|
seed: int | None = None) -> None:
|
|
49
|
-
"""
|
|
50
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
51
|
-
|
|
48
|
+
"""
|
|
52
49
|
Parameters
|
|
53
50
|
----------
|
|
54
51
|
std : float, optional
|
|
@@ -83,7 +80,7 @@ class GeneratorNormal(IGeneratorRandom):
|
|
|
83
80
|
size = shape)
|
|
84
81
|
|
|
85
82
|
|
|
86
|
-
class
|
|
83
|
+
class GenLogNormal(IGenRandom):
|
|
87
84
|
"""Class wrapping the numpy lognormal random generator. Implements the
|
|
88
85
|
IGeneratorRandom interface to allow for interchangeability with other random
|
|
89
86
|
number generators.
|
|
@@ -94,9 +91,7 @@ class GeneratorLogNormal(IGeneratorRandom):
|
|
|
94
91
|
std: float = 1.0,
|
|
95
92
|
mean: float = 0.0,
|
|
96
93
|
seed: int | None = None) -> None:
|
|
97
|
-
"""
|
|
98
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
99
|
-
|
|
94
|
+
"""
|
|
100
95
|
Parameters
|
|
101
96
|
----------
|
|
102
97
|
std : float, optional
|
|
@@ -130,7 +125,7 @@ class GeneratorLogNormal(IGeneratorRandom):
|
|
|
130
125
|
size = shape)
|
|
131
126
|
|
|
132
127
|
|
|
133
|
-
class
|
|
128
|
+
class GenUniform(IGenRandom):
|
|
134
129
|
"""Class wrapping the numpy uniform random number generator. Implements the
|
|
135
130
|
IGeneratorRandom interface to allow for interchangeability with other random
|
|
136
131
|
number generators.
|
|
@@ -141,9 +136,7 @@ class GeneratorUniform(IGeneratorRandom):
|
|
|
141
136
|
low: float = -1.0,
|
|
142
137
|
high: float = 1.0,
|
|
143
138
|
seed: int | None = None) -> None:
|
|
144
|
-
"""
|
|
145
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
146
|
-
|
|
139
|
+
"""
|
|
147
140
|
Parameters
|
|
148
141
|
----------
|
|
149
142
|
low : float, optional
|
|
@@ -177,7 +170,7 @@ class GeneratorUniform(IGeneratorRandom):
|
|
|
177
170
|
size = shape)
|
|
178
171
|
|
|
179
172
|
|
|
180
|
-
class
|
|
173
|
+
class GenExponential(IGenRandom):
|
|
181
174
|
"""Class wrapping the numpy exponential random generator. Implements the
|
|
182
175
|
IGeneratorRandom interface to allow for interchangeability with other random
|
|
183
176
|
number generators.
|
|
@@ -187,9 +180,7 @@ class GeneratorExponential(IGeneratorRandom):
|
|
|
187
180
|
def __init__(self,
|
|
188
181
|
scale: float = 1.0,
|
|
189
182
|
seed: int | None = None) -> None:
|
|
190
|
-
"""
|
|
191
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
192
|
-
|
|
183
|
+
"""
|
|
193
184
|
Parameters
|
|
194
185
|
----------
|
|
195
186
|
scale : float, optional
|
|
@@ -219,7 +210,7 @@ class GeneratorExponential(IGeneratorRandom):
|
|
|
219
210
|
size = shape)
|
|
220
211
|
|
|
221
212
|
|
|
222
|
-
class
|
|
213
|
+
class GenChiSquare(IGenRandom):
|
|
223
214
|
"""Class wrapping the numpy chi square random generator. Implements the
|
|
224
215
|
IGeneratorRandom interface to allow for interchangeability with other random
|
|
225
216
|
number generators.
|
|
@@ -229,9 +220,7 @@ class GeneratorChiSquare(IGeneratorRandom):
|
|
|
229
220
|
def __init__(self,
|
|
230
221
|
dofs: float,
|
|
231
222
|
seed: int | None = None) -> None:
|
|
232
|
-
"""
|
|
233
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
234
|
-
|
|
223
|
+
"""
|
|
235
224
|
Parameters
|
|
236
225
|
----------
|
|
237
226
|
dofs : float
|
|
@@ -261,7 +250,7 @@ class GeneratorChiSquare(IGeneratorRandom):
|
|
|
261
250
|
size = shape)
|
|
262
251
|
|
|
263
252
|
|
|
264
|
-
class
|
|
253
|
+
class GenDirichlet(IGenRandom):
|
|
265
254
|
"""Class wrapping the numpy dirichlet random generator. Implements the
|
|
266
255
|
IGeneratorRandom interface to allow for interchangeability with other random
|
|
267
256
|
number generators.
|
|
@@ -271,9 +260,7 @@ class GeneratorDirichlet(IGeneratorRandom):
|
|
|
271
260
|
def __init__(self,
|
|
272
261
|
alpha: float,
|
|
273
262
|
seed: int | None = None) -> None:
|
|
274
|
-
"""
|
|
275
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
276
|
-
|
|
263
|
+
"""
|
|
277
264
|
Parameters
|
|
278
265
|
----------
|
|
279
266
|
alpha : float
|
|
@@ -301,7 +288,7 @@ class GeneratorDirichlet(IGeneratorRandom):
|
|
|
301
288
|
return self._rng.dirichlet(alpha = self._alpha, size = shape)
|
|
302
289
|
|
|
303
290
|
|
|
304
|
-
class
|
|
291
|
+
class GenF(IGenRandom):
|
|
305
292
|
"""Class wrapping the numpy F distribution random generator. Implements the
|
|
306
293
|
IGeneratorRandom interface to allow for interchangeability with other random
|
|
307
294
|
number generators.
|
|
@@ -311,9 +298,7 @@ class GeneratorF(IGeneratorRandom):
|
|
|
311
298
|
def __init__(self,
|
|
312
299
|
dofs: float,
|
|
313
300
|
seed: int | None = None) -> None:
|
|
314
|
-
"""
|
|
315
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
316
|
-
|
|
301
|
+
"""
|
|
317
302
|
Parameters
|
|
318
303
|
----------
|
|
319
304
|
dofs : float
|
|
@@ -342,7 +327,7 @@ class GeneratorF(IGeneratorRandom):
|
|
|
342
327
|
return self._rng.f(dfnum = self._dofs, size = shape)
|
|
343
328
|
|
|
344
329
|
|
|
345
|
-
class
|
|
330
|
+
class GenGamma(IGenRandom):
|
|
346
331
|
"""Class wrapping the numpy gamma random generator. Implements the
|
|
347
332
|
IGeneratorRandom interface to allow for interchangeability with other random
|
|
348
333
|
number generators.
|
|
@@ -353,9 +338,7 @@ class GeneratorGamma(IGeneratorRandom):
|
|
|
353
338
|
shape: float,
|
|
354
339
|
scale: float = 1.0,
|
|
355
340
|
seed: int | None = None) -> None:
|
|
356
|
-
"""
|
|
357
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
358
|
-
|
|
341
|
+
"""
|
|
359
342
|
Parameters
|
|
360
343
|
----------
|
|
361
344
|
shape : float
|
|
@@ -388,7 +371,7 @@ class GeneratorGamma(IGeneratorRandom):
|
|
|
388
371
|
size = shape)
|
|
389
372
|
|
|
390
373
|
|
|
391
|
-
class
|
|
374
|
+
class GenStandardT(IGenRandom):
|
|
392
375
|
"""Class wrapping the numpy t distribution random generator. Implements the
|
|
393
376
|
IGeneratorRandom interface to allow for interchangeability with other random
|
|
394
377
|
number generators.
|
|
@@ -398,9 +381,7 @@ class GeneratorStandardT(IGeneratorRandom):
|
|
|
398
381
|
def __init__(self,
|
|
399
382
|
dofs: float,
|
|
400
383
|
seed: int | None = None) -> None:
|
|
401
|
-
"""
|
|
402
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
403
|
-
|
|
384
|
+
"""
|
|
404
385
|
Parameters
|
|
405
386
|
----------
|
|
406
387
|
dofs : float
|
|
@@ -430,7 +411,7 @@ class GeneratorStandardT(IGeneratorRandom):
|
|
|
430
411
|
size = shape)
|
|
431
412
|
|
|
432
413
|
|
|
433
|
-
class
|
|
414
|
+
class GenBeta(IGenRandom):
|
|
434
415
|
"""Class wrapping the numpy beta distribution random generator. Implements
|
|
435
416
|
the IGeneratorRandom interface to allow for interchangeability with other
|
|
436
417
|
random number generators.
|
|
@@ -441,9 +422,7 @@ class GeneratorBeta(IGeneratorRandom):
|
|
|
441
422
|
a: float,
|
|
442
423
|
b: float,
|
|
443
424
|
seed: int | None = None) -> None:
|
|
444
|
-
"""
|
|
445
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
446
|
-
|
|
425
|
+
"""
|
|
447
426
|
Parameters
|
|
448
427
|
----------
|
|
449
428
|
a : float
|
|
@@ -476,7 +455,7 @@ class GeneratorBeta(IGeneratorRandom):
|
|
|
476
455
|
size = shape)
|
|
477
456
|
|
|
478
457
|
|
|
479
|
-
class
|
|
458
|
+
class GenTriangular(IGenRandom):
|
|
480
459
|
"""Class wrapping the numpy triangular random generator. Implements the
|
|
481
460
|
IGeneratorRandom interface to allow for interchangeability with other random
|
|
482
461
|
number generators.
|
|
@@ -488,9 +467,7 @@ class GeneratorTriangular(IGeneratorRandom):
|
|
|
488
467
|
mode: float = 0.0,
|
|
489
468
|
right: float = 1.0,
|
|
490
469
|
seed: int | None = None) -> None:
|
|
491
|
-
"""
|
|
492
|
-
an optional seed for the random generator to allow for reproducibility.
|
|
493
|
-
|
|
470
|
+
"""
|
|
494
471
|
Parameters
|
|
495
472
|
----------
|
|
496
473
|
left : float, optional
|
|
@@ -1,10 +1,13 @@
|
|
|
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
|
-
pyvale: the python validation engine
|
|
4
|
-
License: MIT
|
|
5
|
-
Copyright (C) 2025 The Computer Aided Validation Team
|
|
6
|
-
================================================================================
|
|
8
|
+
NOTE: This module is a feature under developement.
|
|
7
9
|
"""
|
|
10
|
+
|
|
8
11
|
import time
|
|
9
12
|
import warnings
|
|
10
13
|
from dataclasses import dataclass
|
|
@@ -14,9 +17,9 @@ from scipy.interpolate import griddata
|
|
|
14
17
|
from scipy.interpolate import RectBivariateSpline
|
|
15
18
|
from scipy import ndimage
|
|
16
19
|
|
|
17
|
-
from pyvale.
|
|
18
|
-
from pyvale.
|
|
19
|
-
from pyvale.
|
|
20
|
+
from pyvale.rasternp import edge_function, RasterNP
|
|
21
|
+
from pyvale.cameradata2d import CameraData2D
|
|
22
|
+
from pyvale.cameratools import CameraTools
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
@dataclass(slots=True)
|
|
@@ -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.sensordata import SensorData
|
|
10
|
+
from pyvale.integratorspatial import IIntegratorSpatial
|
|
11
|
+
from pyvale.integratortype import EIntSpatialType
|
|
12
|
+
from pyvale.integratorrectangle import Rectangle2D
|
|
13
|
+
from pyvale.integratorquadrature import (Quadrature2D,
|
|
15
14
|
create_gauss_weights_2d_4pts,
|
|
16
15
|
create_gauss_weights_2d_9pts)
|
|
17
16
|
|
|
@@ -1,18 +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
|
from typing import Callable
|
|
9
8
|
import numpy as np
|
|
10
|
-
from pyvale.
|
|
11
|
-
from pyvale.
|
|
12
|
-
|
|
13
|
-
from pyvale.
|
|
9
|
+
from pyvale.field import IField
|
|
10
|
+
from pyvale.integratorspatial import (IIntegratorSpatial,
|
|
11
|
+
create_int_pt_array)
|
|
12
|
+
from pyvale.sensordata import SensorData
|
|
14
13
|
|
|
15
|
-
#TODO: Docstrings
|
|
16
14
|
|
|
17
15
|
class Quadrature2D(IIntegratorSpatial):
|
|
18
16
|
"""Gaussian quadrature numerical integrator for spatial averaging in 2D.
|
|
@@ -24,7 +22,7 @@ class Quadrature2D(IIntegratorSpatial):
|
|
|
24
22
|
Implements the `IIntegratorSpatial` interface allowing for interoperability
|
|
25
23
|
of different spatial integration algorithms for modelling sensor averaging.
|
|
26
24
|
"""
|
|
27
|
-
__slots__ = ("_field","_area","
|
|
25
|
+
__slots__ = ("_field","_area","_gauss_pts_num","_gauss_pt_offsets"
|
|
28
26
|
,"_gauss_weight_func","_gauss_pts","_averages","_sens_data")
|
|
29
27
|
|
|
30
28
|
def __init__(self,
|
|
@@ -32,8 +30,7 @@ class Quadrature2D(IIntegratorSpatial):
|
|
|
32
30
|
sens_data: SensorData,
|
|
33
31
|
gauss_pt_offsets: np.ndarray,
|
|
34
32
|
gauss_weight_func: Callable) -> None:
|
|
35
|
-
"""
|
|
36
|
-
|
|
33
|
+
"""
|
|
37
34
|
Parameters
|
|
38
35
|
----------
|
|
39
36
|
field : IField
|
|
@@ -58,7 +55,7 @@ class Quadrature2D(IIntegratorSpatial):
|
|
|
58
55
|
self._area = self._sens_data.spatial_dims[0] * \
|
|
59
56
|
self._sens_data.spatial_dims[1]
|
|
60
57
|
|
|
61
|
-
self.
|
|
58
|
+
self._gauss_pts_num = gauss_pt_offsets.shape[0]
|
|
62
59
|
self._gauss_pt_offsets = gauss_pt_offsets
|
|
63
60
|
self._gauss_weight_func = gauss_weight_func
|
|
64
61
|
|
|
@@ -67,43 +64,61 @@ class Quadrature2D(IIntegratorSpatial):
|
|
|
67
64
|
self._averages = None
|
|
68
65
|
|
|
69
66
|
def calc_integrals(self, sens_data: SensorData | None = None) -> np.ndarray:
|
|
70
|
-
"""
|
|
67
|
+
"""Calculates the numerical integrals for each sensor based on the
|
|
68
|
+
specified sensor data and numerical integration options (i.e. geometry
|
|
69
|
+
and integration points).
|
|
71
70
|
|
|
72
71
|
Parameters
|
|
73
72
|
----------
|
|
74
73
|
sens_data : SensorData | None, optional
|
|
75
|
-
|
|
74
|
+
Specifies the sensor parameters used to calculate the averages, by
|
|
75
|
+
default None. Is a sensor data object is passed a reference to that
|
|
76
|
+
object is stored by this class and used in later calculations. If
|
|
77
|
+
None then it uses the SensorData object stored by this class.
|
|
78
|
+
Defaults to None.
|
|
76
79
|
|
|
77
80
|
Returns
|
|
78
81
|
-------
|
|
79
82
|
np.ndarray
|
|
80
|
-
|
|
83
|
+
Array of virtual sensor integrals with shape=(n_sensors,n_comps,
|
|
84
|
+
n_timsteps). Note this is consistent with pyvales measurement array.
|
|
81
85
|
"""
|
|
82
86
|
self._averages = self.calc_averages(sens_data)
|
|
83
87
|
return self._area*self.get_averages()
|
|
84
88
|
|
|
85
89
|
def get_integrals(self) -> np.ndarray:
|
|
86
|
-
"""
|
|
90
|
+
"""Gets the most recent calculation of the spatial averages for all
|
|
91
|
+
sensors in the sensor array without performing any new interpolation. If
|
|
92
|
+
the averages have not been calculated they are first calculated and then
|
|
93
|
+
returned.
|
|
87
94
|
|
|
88
95
|
Returns
|
|
89
96
|
-------
|
|
90
97
|
np.ndarray
|
|
91
|
-
|
|
98
|
+
Array of virtual sensor averages with shape=(n_sensors,n_comps,
|
|
99
|
+
n_timsteps). Note this is consistent with pyvales measurement array.
|
|
92
100
|
"""
|
|
93
101
|
return self._area*self.get_averages()
|
|
94
102
|
|
|
95
103
|
def calc_averages(self, sens_data: SensorData | None = None) -> np.ndarray:
|
|
96
|
-
"""
|
|
104
|
+
"""Calculates the spatial averages for each sensor based on the
|
|
105
|
+
specified sensor data and numerical integration options (i.e. geometry
|
|
106
|
+
and integration points).
|
|
97
107
|
|
|
98
108
|
Parameters
|
|
99
109
|
----------
|
|
100
110
|
sens_data : SensorData | None, optional
|
|
101
|
-
|
|
111
|
+
Specifies the sensor parameters used to calculate the averages, by
|
|
112
|
+
default None. Is a sensor data object is passed a reference to that
|
|
113
|
+
object is stored by this class and used in later calculations. If
|
|
114
|
+
None then it uses the SensorData object stored by this class.
|
|
115
|
+
Defaults to None.
|
|
102
116
|
|
|
103
117
|
Returns
|
|
104
118
|
-------
|
|
105
119
|
np.ndarray
|
|
106
|
-
|
|
120
|
+
Array of virtual sensor averages with shape=(n_sensors,n_comps,
|
|
121
|
+
n_timsteps). Note this is consistent with pyvales measurement array.
|
|
107
122
|
"""
|
|
108
123
|
if sens_data is not None:
|
|
109
124
|
self._sens_data = sens_data
|
|
@@ -122,7 +137,7 @@ class Quadrature2D(IIntegratorSpatial):
|
|
|
122
137
|
gauss_vals.shape[2])
|
|
123
138
|
|
|
124
139
|
# shape=(n_gauss_pts,n_sens,n_comps,n_timesteps)
|
|
125
|
-
gauss_vals = gauss_vals.reshape((self.
|
|
140
|
+
gauss_vals = gauss_vals.reshape((self._gauss_pts_num,)+meas_shape,
|
|
126
141
|
order='F')
|
|
127
142
|
|
|
128
143
|
# shape=(n_gauss_pts,n_sens,n_comps,n_timesteps)
|
|
@@ -139,12 +154,16 @@ class Quadrature2D(IIntegratorSpatial):
|
|
|
139
154
|
return self._averages
|
|
140
155
|
|
|
141
156
|
def get_averages(self) -> np.ndarray:
|
|
142
|
-
"""
|
|
157
|
+
"""Gets the most recent calculation of the spatial averages for all
|
|
158
|
+
sensors in the sensor array without performing any new interpolation. If
|
|
159
|
+
the averages have not been calculated they are first calculated and then
|
|
160
|
+
returned.
|
|
143
161
|
|
|
144
162
|
Returns
|
|
145
163
|
-------
|
|
146
164
|
np.ndarray
|
|
147
|
-
|
|
165
|
+
Array of virtual sensor averages with shape=(n_sensors,n_comps,
|
|
166
|
+
n_timsteps). Note this is consistent with pyvales measurement array.
|
|
148
167
|
"""
|
|
149
168
|
if self._averages is None:
|
|
150
169
|
self._averages = self.calc_averages()
|
|
@@ -160,29 +179,35 @@ def create_gauss_weights_2d_4pts(meas_shape: tuple[int,int,int]) -> np.ndarray:
|
|
|
160
179
|
Parameters
|
|
161
180
|
----------
|
|
162
181
|
meas_shape : tuple[int,int,int]
|
|
163
|
-
|
|
182
|
+
Shape of the measurement array, shape=(n_sensors,n_field_comps,
|
|
183
|
+
n_time_steps).
|
|
164
184
|
|
|
165
185
|
Returns
|
|
166
186
|
-------
|
|
167
187
|
np.ndarray
|
|
168
|
-
|
|
188
|
+
Array of gaussian quadrature weights with shape = (n_gauss_pts,n_sensors
|
|
189
|
+
,n_field_comps,n_time_steps).
|
|
169
190
|
"""
|
|
170
191
|
#shape=(4,)+meas_shape
|
|
171
192
|
return np.ones((4,)+meas_shape)
|
|
172
193
|
|
|
173
194
|
|
|
174
195
|
def create_gauss_weights_2d_9pts(meas_shape: tuple[int,int,int]) -> np.ndarray:
|
|
175
|
-
"""
|
|
196
|
+
"""Helper function that creates an array of weights for gaussian quadrature
|
|
197
|
+
integration. This function provides the weights for 2D integrator with 9
|
|
198
|
+
integration points.
|
|
176
199
|
|
|
177
200
|
Parameters
|
|
178
201
|
----------
|
|
179
202
|
meas_shape : tuple[int,int,int]
|
|
180
|
-
|
|
203
|
+
Shape of the measurement array, shape=(n_sensors,n_field_comps,
|
|
204
|
+
n_time_steps).
|
|
181
205
|
|
|
182
206
|
Returns
|
|
183
207
|
-------
|
|
184
208
|
np.ndarray
|
|
185
|
-
|
|
209
|
+
Array of gaussian quadrature weights with shape = (n_gauss_pts,n_sensors
|
|
210
|
+
,n_field_comps,n_time_steps).
|
|
186
211
|
"""
|
|
187
212
|
# shape=(9,)+meas_shape
|
|
188
213
|
gauss_weights = np.vstack((25/81 * np.ones((4,)+meas_shape),
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from pyvale.field import IField
|
|
9
|
+
from pyvale.integratorspatial import (IIntegratorSpatial,
|
|
10
|
+
create_int_pt_array)
|
|
11
|
+
from pyvale.sensordata import SensorData
|
|
12
|
+
|
|
13
|
+
#NOTE: code below is very similar to quadrature integrator should be able to
|
|
14
|
+
# refactor into injected classes/functions
|
|
15
|
+
|
|
16
|
+
class Rectangle2D(IIntegratorSpatial):
|
|
17
|
+
"""Rectangular numerical integrator for spatial averaging in 2D. Used to
|
|
18
|
+
model spatial averaging of sensors over a rectangular area which is
|
|
19
|
+
specified in the SensorData object. Handles sampling of the physical field
|
|
20
|
+
at the integration points and averages them back to a single value per
|
|
21
|
+
sensor location as specified in the SensorData object.
|
|
22
|
+
|
|
23
|
+
Implements the `IIntegratorSpatial` interface allowing for interoperability
|
|
24
|
+
of different spatial integration algorithms for modelling sensor averaging.
|
|
25
|
+
"""
|
|
26
|
+
__slots__ = ("_field","sens_data","_area","_area_int","_n_int_pts",
|
|
27
|
+
"_int_pt_offsets","_int_pts","_averages")
|
|
28
|
+
|
|
29
|
+
def __init__(self,
|
|
30
|
+
field: IField,
|
|
31
|
+
sens_data: SensorData,
|
|
32
|
+
int_pt_offsets: np.ndarray) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
field : IField
|
|
37
|
+
A physical field interface that will be sampled at the integration
|
|
38
|
+
points and averaged back to single value per sensor.
|
|
39
|
+
sens_data : SensorData
|
|
40
|
+
Parameters of the sensor array including the sensor locations,
|
|
41
|
+
sampling times, type of spatial integrator and its dimensions. See
|
|
42
|
+
the `SensorData` dataclass for more details.
|
|
43
|
+
int_pt_offsets : np.ndarray
|
|
44
|
+
Offsets from the central location of the integration area with
|
|
45
|
+
shape=(n_gauss_pts,coord[X,Y,Z])
|
|
46
|
+
"""
|
|
47
|
+
self._field = field
|
|
48
|
+
self._sens_data = sens_data
|
|
49
|
+
|
|
50
|
+
self._area = (self._sens_data.spatial_dims[0]
|
|
51
|
+
* self._sens_data.spatial_dims[1])
|
|
52
|
+
self._area_int = self._area/int_pt_offsets.shape[0]
|
|
53
|
+
|
|
54
|
+
self._n_int_pts = int_pt_offsets.shape[0]
|
|
55
|
+
self._int_pt_offsets = int_pt_offsets
|
|
56
|
+
self._int_pts = create_int_pt_array(self._sens_data,
|
|
57
|
+
self._int_pt_offsets)
|
|
58
|
+
|
|
59
|
+
self._averages = None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def calc_integrals(self, sens_data: SensorData | None = None) -> np.ndarray:
|
|
63
|
+
"""Calculates the numerical integrals for each sensor based on the
|
|
64
|
+
specified sensor data and numerical integration options (i.e. geometry
|
|
65
|
+
and integration points).
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
sens_data : SensorData | None, optional
|
|
70
|
+
Specifies the sensor parameters used to calculate the averages, by
|
|
71
|
+
default None. Is a sensor data object is passed a reference to that
|
|
72
|
+
object is stored by this class and used in later calculations. If
|
|
73
|
+
None then it uses the SensorData object stored by this class.
|
|
74
|
+
Defaults to None.
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
np.ndarray
|
|
79
|
+
Array of virtual sensor integrals with shape=(n_sensors,n_comps,
|
|
80
|
+
n_timsteps). Note this is consistent with pyvales measurement array.
|
|
81
|
+
"""
|
|
82
|
+
self._averages = self.calc_averages(sens_data)
|
|
83
|
+
return self._area*self.get_averages()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def get_integrals(self) -> np.ndarray:
|
|
87
|
+
"""Gets the most recent calculation of the spatial averages for all
|
|
88
|
+
sensors in the sensor array without performing any new interpolation. If
|
|
89
|
+
the averages have not been calculated they are first calculated and then
|
|
90
|
+
returned.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
np.ndarray
|
|
95
|
+
Array of virtual sensor averages with shape=(n_sensors,n_comps,
|
|
96
|
+
n_timsteps). Note this is consistent with pyvales measurement array.
|
|
97
|
+
"""
|
|
98
|
+
return self._area*self.get_averages()
|
|
99
|
+
|
|
100
|
+
def calc_averages(self, sens_data: SensorData | None = None) -> np.ndarray:
|
|
101
|
+
"""Calculates the spatial averages for each sensor based on the
|
|
102
|
+
specified sensor data and numerical integration options (i.e. geometry
|
|
103
|
+
and integration points).
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
----------
|
|
107
|
+
sens_data : SensorData | None, optional
|
|
108
|
+
Specifies the sensor parameters used to calculate the averages, by
|
|
109
|
+
default None. Is a sensor data object is passed a reference to that
|
|
110
|
+
object is stored by this class and used in later calculations. If
|
|
111
|
+
None then it uses the SensorData object stored by this class.
|
|
112
|
+
Defaults to None.
|
|
113
|
+
|
|
114
|
+
Returns
|
|
115
|
+
-------
|
|
116
|
+
np.ndarray
|
|
117
|
+
Array of virtual sensor averages with shape=(n_sensors,n_comps,
|
|
118
|
+
n_timsteps). Note this is consistent with pyvales measurement array.
|
|
119
|
+
"""
|
|
120
|
+
if sens_data is not None:
|
|
121
|
+
self._sens_data = sens_data
|
|
122
|
+
|
|
123
|
+
# shape=(n_sens*n_int_pts,n_dims)
|
|
124
|
+
self._int_pts = create_int_pt_array(self._sens_data,
|
|
125
|
+
self._int_pt_offsets)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# shape=(n_int_pts*n_sens,n_comps,n_timesteps)
|
|
129
|
+
int_vals = self._field.sample_field(self._int_pts,
|
|
130
|
+
self._sens_data.sample_times,
|
|
131
|
+
self._sens_data.angles)
|
|
132
|
+
|
|
133
|
+
meas_shape = (self._sens_data.positions.shape[0],
|
|
134
|
+
int_vals.shape[1],
|
|
135
|
+
int_vals.shape[2])
|
|
136
|
+
|
|
137
|
+
# shape=(n_gauss_pts,n_sens,n_comps,n_timesteps)
|
|
138
|
+
int_vals = int_vals.reshape((self._n_int_pts,)+meas_shape,
|
|
139
|
+
order='F')
|
|
140
|
+
|
|
141
|
+
# shape=(n_sensors,n_comps,n_timsteps)
|
|
142
|
+
self._averages = 1/self._area * np.sum(self._area_int*int_vals,axis=0)
|
|
143
|
+
|
|
144
|
+
return self._averages
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def get_averages(self) -> np.ndarray:
|
|
148
|
+
"""Gets the most recent calculation of the spatial averages for all
|
|
149
|
+
sensors in the sensor array without performing any new interpolation. If
|
|
150
|
+
the averages have not been calculated they are first calculated and then
|
|
151
|
+
returned.
|
|
152
|
+
|
|
153
|
+
Returns
|
|
154
|
+
-------
|
|
155
|
+
np.ndarray
|
|
156
|
+
Array of virtual sensor averages with shape=(n_sensors,n_comps,
|
|
157
|
+
n_timsteps). Note this is consistent with pyvales measurement array.
|
|
158
|
+
"""
|
|
159
|
+
if self._averages is None:
|
|
160
|
+
self._averages = self.calc_averages()
|
|
161
|
+
|
|
162
|
+
return self._averages
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|