pyvale 2025.7.1__cp311-cp311-win_amd64.whl → 2025.8.1__cp311-cp311-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyvale might be problematic. Click here for more details.
- pyvale/__init__.py +12 -92
- pyvale/blender/__init__.py +23 -0
- pyvale/{pyvaleexceptions.py → blender/blenderexceptions.py} +0 -3
- pyvale/{blenderlightdata.py → blender/blenderlightdata.py} +3 -3
- pyvale/{blendermaterialdata.py → blender/blendermaterialdata.py} +1 -1
- pyvale/{blenderrenderdata.py → blender/blenderrenderdata.py} +5 -3
- pyvale/{blenderscene.py → blender/blenderscene.py} +33 -30
- pyvale/{blendertools.py → blender/blendertools.py} +14 -10
- pyvale/dataset/__init__.py +7 -0
- pyvale/dataset/dataset.py +443 -0
- pyvale/dic/__init__.py +20 -0
- pyvale/dic/cpp/dicfourier.cpp +36 -4
- pyvale/dic/cpp/dicinterpolator.cpp +56 -1
- pyvale/dic/cpp/dicmain.cpp +24 -19
- pyvale/dic/cpp/dicoptimizer.cpp +6 -1
- pyvale/dic/cpp/dicscanmethod.cpp +32 -32
- pyvale/dic/cpp/dicsignalhandler.cpp +16 -0
- pyvale/dic/cpp/dicstrain.cpp +7 -3
- pyvale/dic/cpp/dicutil.cpp +79 -23
- pyvale/{dic2d.py → dic/dic2d.py} +51 -29
- pyvale/dic/dic2dconv.py +6 -0
- pyvale/dic/dic2dcpp.cp311-win_amd64.pyd +0 -0
- pyvale/{dicchecks.py → dic/dicchecks.py} +28 -16
- pyvale/dic/dicdataimport.py +370 -0
- pyvale/{dicregionofinterest.py → dic/dicregionofinterest.py} +169 -12
- pyvale/{dicresults.py → dic/dicresults.py} +4 -1
- pyvale/{dicstrain.py → dic/dicstrain.py} +9 -9
- pyvale/examples/basics/{ex1_1_basicscalars_therm2d.py → ex1a_basicscalars_therm2d.py} +12 -9
- pyvale/examples/basics/{ex1_2_sensormodel_therm2d.py → ex1b_sensormodel_therm2d.py} +17 -14
- pyvale/examples/basics/{ex1_3_customsens_therm3d.py → ex1c_customsens_therm3d.py} +27 -24
- pyvale/examples/basics/{ex1_4_basicerrors_therm3d.py → ex1d_basicerrors_therm3d.py} +32 -29
- pyvale/examples/basics/{ex1_5_fielderrs_therm3d.py → ex1e_fielderrs_therm3d.py} +19 -15
- pyvale/examples/basics/{ex1_6_caliberrs_therm2d.py → ex1f_caliberrs_therm2d.py} +20 -16
- pyvale/examples/basics/{ex1_7_spatavg_therm2d.py → ex1g_spatavg_therm2d.py} +19 -16
- pyvale/examples/basics/{ex2_1_basicvectors_disp2d.py → ex2a_basicvectors_disp2d.py} +13 -10
- pyvale/examples/basics/{ex2_2_vectorsens_disp2d.py → ex2b_vectorsens_disp2d.py} +19 -15
- pyvale/examples/basics/{ex2_3_sensangle_disp2d.py → ex2c_sensangle_disp2d.py} +21 -18
- pyvale/examples/basics/{ex2_4_chainfielderrs_disp2d.py → ex2d_chainfielderrs_disp2d.py} +31 -29
- pyvale/examples/basics/{ex2_5_vectorfields3d_disp3d.py → ex2e_vectorfields3d_disp3d.py} +21 -18
- pyvale/examples/basics/{ex3_1_basictensors_strain2d.py → ex3a_basictensors_strain2d.py} +16 -14
- pyvale/examples/basics/{ex3_2_tensorsens2d_strain2d.py → ex3b_tensorsens2d_strain2d.py} +17 -14
- pyvale/examples/basics/{ex3_3_tensorsens3d_strain3d.py → ex3c_tensorsens3d_strain3d.py} +25 -22
- pyvale/examples/basics/{ex4_1_expsim2d_thermmech2d.py → ex4a_expsim2d_thermmech2d.py} +17 -14
- pyvale/examples/basics/{ex4_2_expsim3d_thermmech3d.py → ex4b_expsim3d_thermmech3d.py} +37 -34
- pyvale/examples/basics/ex5_nomesh.py +24 -0
- pyvale/examples/dic/ex1_2_blenderdeformed.py +174 -0
- pyvale/examples/dic/ex1_region_of_interest.py +6 -3
- pyvale/examples/dic/ex2_plate_with_hole.py +21 -18
- pyvale/examples/dic/ex3_plate_with_hole_strain.py +8 -6
- pyvale/examples/dic/ex4_dic_blender.py +17 -15
- pyvale/examples/dic/ex5_dic_challenge.py +19 -14
- pyvale/examples/genanalyticdata/ex1_1_scalarvisualisation.py +16 -10
- pyvale/examples/genanalyticdata/ex1_2_scalarcasebuild.py +3 -3
- pyvale/examples/genanalyticdata/ex2_1_analyticsensors.py +29 -23
- pyvale/examples/genanalyticdata/ex2_2_analyticsensors_nomesh.py +67 -0
- pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +12 -9
- pyvale/examples/mooseherder/ex0_create_moose_config.py +65 -0
- pyvale/examples/mooseherder/ex1a_modify_moose_input.py +71 -0
- pyvale/examples/mooseherder/ex1b_modify_gmsh_input.py +69 -0
- pyvale/examples/mooseherder/ex2a_run_moose_once.py +80 -0
- pyvale/examples/mooseherder/ex2b_run_gmsh_once.py +64 -0
- pyvale/examples/mooseherder/ex2c_run_both_once.py +114 -0
- pyvale/examples/mooseherder/ex3_run_moose_seq_para.py +157 -0
- pyvale/examples/mooseherder/ex4_run_gmsh-moose_seq_para.py +176 -0
- pyvale/examples/mooseherder/ex5_run_moose_paramulti.py +136 -0
- pyvale/examples/mooseherder/ex6_read_moose_exodus.py +163 -0
- pyvale/examples/mooseherder/ex7a_read_moose_herd_results.py +153 -0
- pyvale/examples/mooseherder/ex7b_read_multi_herd_results.py +116 -0
- pyvale/examples/mooseherder/ex7c_read_multi_gmshmoose_results.py +127 -0
- pyvale/examples/mooseherder/ex7d_readconfig_multi_gmshmoose_results.py +143 -0
- pyvale/examples/mooseherder/ex8_read_existing_sweep_output.py +72 -0
- pyvale/examples/renderblender/ex1_1_blenderscene.py +24 -20
- pyvale/examples/renderblender/ex1_2_blenderdeformed.py +22 -18
- pyvale/examples/renderblender/ex2_1_stereoscene.py +36 -29
- pyvale/examples/renderblender/ex2_2_stereodeformed.py +26 -20
- pyvale/examples/renderblender/ex3_1_blendercalibration.py +24 -17
- pyvale/examples/renderrasterisation/ex_rastenp.py +14 -12
- pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +14 -15
- pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +13 -11
- pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +13 -11
- pyvale/mooseherder/__init__.py +32 -0
- pyvale/mooseherder/directorymanager.py +416 -0
- pyvale/mooseherder/exodusreader.py +763 -0
- pyvale/mooseherder/gmshrunner.py +163 -0
- pyvale/mooseherder/inputmodifier.py +236 -0
- pyvale/mooseherder/mooseconfig.py +226 -0
- pyvale/mooseherder/mooseherd.py +527 -0
- pyvale/mooseherder/mooserunner.py +303 -0
- pyvale/mooseherder/outputreader.py +22 -0
- pyvale/mooseherder/simdata.py +92 -0
- pyvale/mooseherder/simrunner.py +31 -0
- pyvale/mooseherder/sweepreader.py +356 -0
- pyvale/mooseherder/sweeptools.py +76 -0
- pyvale/sensorsim/__init__.py +82 -0
- pyvale/{camera.py → sensorsim/camera.py} +7 -7
- pyvale/{camerasensor.py → sensorsim/camerasensor.py} +7 -7
- pyvale/{camerastereo.py → sensorsim/camerastereo.py} +2 -2
- pyvale/{cameratools.py → sensorsim/cameratools.py} +4 -4
- pyvale/{cython → sensorsim/cython}/rastercyth.c +596 -596
- pyvale/{cython → sensorsim/cython}/rastercyth.cp311-win_amd64.pyd +0 -0
- pyvale/{cython → sensorsim/cython}/rastercyth.py +16 -17
- pyvale/{errorcalculator.py → sensorsim/errorcalculator.py} +1 -1
- pyvale/{errorintegrator.py → sensorsim/errorintegrator.py} +2 -2
- pyvale/{errorrand.py → sensorsim/errorrand.py} +4 -4
- pyvale/{errorsyscalib.py → sensorsim/errorsyscalib.py} +2 -2
- pyvale/{errorsysdep.py → sensorsim/errorsysdep.py} +2 -2
- pyvale/{errorsysfield.py → sensorsim/errorsysfield.py} +8 -8
- pyvale/{errorsysindep.py → sensorsim/errorsysindep.py} +3 -3
- pyvale/sensorsim/exceptions.py +8 -0
- pyvale/{experimentsimulator.py → sensorsim/experimentsimulator.py} +23 -3
- pyvale/{field.py → sensorsim/field.py} +1 -1
- pyvale/{fieldconverter.py → sensorsim/fieldconverter.py} +72 -19
- pyvale/sensorsim/fieldinterp.py +37 -0
- pyvale/sensorsim/fieldinterpmesh.py +124 -0
- pyvale/sensorsim/fieldinterppoints.py +55 -0
- pyvale/{fieldsampler.py → sensorsim/fieldsampler.py} +4 -4
- pyvale/{fieldscalar.py → sensorsim/fieldscalar.py} +28 -24
- pyvale/{fieldtensor.py → sensorsim/fieldtensor.py} +33 -31
- pyvale/{fieldvector.py → sensorsim/fieldvector.py} +33 -31
- pyvale/{imagedef2d.py → sensorsim/imagedef2d.py} +9 -5
- pyvale/{integratorfactory.py → sensorsim/integratorfactory.py} +6 -6
- pyvale/{integratorquadrature.py → sensorsim/integratorquadrature.py} +3 -3
- pyvale/{integratorrectangle.py → sensorsim/integratorrectangle.py} +3 -3
- pyvale/{integratorspatial.py → sensorsim/integratorspatial.py} +1 -1
- pyvale/{rastercy.py → sensorsim/rastercy.py} +5 -5
- pyvale/{rasternp.py → sensorsim/rasternp.py} +9 -9
- pyvale/{rasteropts.py → sensorsim/rasteropts.py} +1 -1
- pyvale/{renderer.py → sensorsim/renderer.py} +1 -1
- pyvale/{rendermesh.py → sensorsim/rendermesh.py} +5 -5
- pyvale/{renderscene.py → sensorsim/renderscene.py} +2 -2
- pyvale/{sensorarray.py → sensorsim/sensorarray.py} +1 -1
- pyvale/{sensorarrayfactory.py → sensorsim/sensorarrayfactory.py} +12 -12
- pyvale/{sensorarraypoint.py → sensorsim/sensorarraypoint.py} +10 -8
- pyvale/{sensordata.py → sensorsim/sensordata.py} +1 -1
- pyvale/{sensortools.py → sensorsim/sensortools.py} +2 -20
- pyvale/sensorsim/simtools.py +174 -0
- pyvale/{visualexpplotter.py → sensorsim/visualexpplotter.py} +3 -3
- pyvale/{visualimages.py → sensorsim/visualimages.py} +2 -2
- pyvale/{visualsimanimator.py → sensorsim/visualsimanimator.py} +4 -4
- pyvale/{visualsimplotter.py → sensorsim/visualsimplotter.py} +5 -5
- pyvale/{visualsimsensors.py → sensorsim/visualsimsensors.py} +12 -12
- pyvale/{visualtools.py → sensorsim/visualtools.py} +1 -1
- pyvale/{visualtraceplotter.py → sensorsim/visualtraceplotter.py} +2 -2
- pyvale/simcases/case17.geo +3 -0
- pyvale/simcases/case17.i +4 -4
- pyvale/simcases/run_1case.py +1 -9
- pyvale/simcases/run_all_cases.py +1 -1
- pyvale/simcases/run_build_case.py +1 -1
- pyvale/simcases/run_example_cases.py +1 -1
- pyvale/verif/__init__.py +12 -0
- pyvale/{analyticsimdatafactory.py → verif/analyticsimdatafactory.py} +2 -2
- pyvale/{analyticsimdatagenerator.py → verif/analyticsimdatagenerator.py} +2 -2
- pyvale/verif/psens.py +125 -0
- pyvale/verif/psensconst.py +18 -0
- pyvale/verif/psensmech.py +227 -0
- pyvale/verif/psensmultiphys.py +187 -0
- pyvale/verif/psensscalar.py +347 -0
- pyvale/verif/psenstensor.py +123 -0
- pyvale/verif/psensvector.py +116 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/METADATA +6 -7
- pyvale-2025.8.1.dist-info/RECORD +260 -0
- pyvale/dataset.py +0 -415
- pyvale/dic2dcpp.cp311-win_amd64.pyd +0 -0
- pyvale/dicdataimport.py +0 -247
- pyvale/simtools.py +0 -67
- pyvale-2025.7.1.dist-info/RECORD +0 -211
- /pyvale/{blendercalibrationdata.py → blender/blendercalibrationdata.py} +0 -0
- /pyvale/{dicspecklegenerator.py → dic/dicspecklegenerator.py} +0 -0
- /pyvale/{dicspecklequality.py → dic/dicspecklequality.py} +0 -0
- /pyvale/{dicstrainresults.py → dic/dicstrainresults.py} +0 -0
- /pyvale/{cameradata.py → sensorsim/cameradata.py} +0 -0
- /pyvale/{cameradata2d.py → sensorsim/cameradata2d.py} +0 -0
- /pyvale/{errordriftcalc.py → sensorsim/errordriftcalc.py} +0 -0
- /pyvale/{fieldtransform.py → sensorsim/fieldtransform.py} +0 -0
- /pyvale/{generatorsrandom.py → sensorsim/generatorsrandom.py} +0 -0
- /pyvale/{imagetools.py → sensorsim/imagetools.py} +0 -0
- /pyvale/{integratortype.py → sensorsim/integratortype.py} +0 -0
- /pyvale/{output.py → sensorsim/output.py} +0 -0
- /pyvale/{raster.py → sensorsim/raster.py} +0 -0
- /pyvale/{sensordescriptor.py → sensorsim/sensordescriptor.py} +0 -0
- /pyvale/{visualimagedef.py → sensorsim/visualimagedef.py} +0 -0
- /pyvale/{visualopts.py → sensorsim/visualopts.py} +0 -0
- /pyvale/{analyticmeshgen.py → verif/analyticmeshgen.py} +0 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/WHEEL +0 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/licenses/LICENSE +0 -0
- {pyvale-2025.7.1.dist-info → pyvale-2025.8.1.dist-info}/top_level.txt +0 -0
|
Binary file
|
|
@@ -12,7 +12,7 @@ import numpy as np
|
|
|
12
12
|
import cython
|
|
13
13
|
#from cython.parallel import prange, parallel, threadid
|
|
14
14
|
from cython.cimports.libc.math import floor, ceil
|
|
15
|
-
from pyvale.cameradata import CameraData
|
|
15
|
+
from pyvale.sensorsim.cameradata import CameraData
|
|
16
16
|
|
|
17
17
|
# NOTE: This module is a feature under developement.
|
|
18
18
|
|
|
@@ -382,23 +382,22 @@ def raster_static_frame(coords: cython.double[:,:],
|
|
|
382
382
|
|
|
383
383
|
|
|
384
384
|
#---------------------------------------------------------------------------
|
|
385
|
-
|
|
386
385
|
elems_in_image: cython.size_t = _raster_frame(coords[:,:],
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
386
|
+
connect[:,:],
|
|
387
|
+
fields_to_render[:,:],
|
|
388
|
+
world_to_cam_mat[:,:],
|
|
389
|
+
pixels_num[:],
|
|
390
|
+
image_dims[:],
|
|
391
|
+
image_dist,
|
|
392
|
+
sub_samp,
|
|
393
|
+
image_buff_avg[:,:,:],
|
|
394
|
+
depth_buff_avg[:,:],
|
|
395
|
+
image_buff_subpx[:,:,:],
|
|
396
|
+
depth_buff_subpx[:,:],
|
|
397
|
+
nodes_raster_buff[:,:],
|
|
398
|
+
field_raster_buff[:],
|
|
399
|
+
px_coord_buff[:],
|
|
400
|
+
weights_buff[:])
|
|
402
401
|
|
|
403
402
|
return (image_buff_avg_np,depth_buff_avg_np,elems_in_image)
|
|
404
403
|
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
import copy
|
|
8
8
|
from dataclasses import dataclass
|
|
9
9
|
import numpy as np
|
|
10
|
-
from pyvale.errorcalculator import (IErrCalculator,
|
|
10
|
+
from pyvale.sensorsim.errorcalculator import (IErrCalculator,
|
|
11
11
|
EErrType,
|
|
12
12
|
EErrDep)
|
|
13
|
-
from pyvale.sensordata import SensorData
|
|
13
|
+
from pyvale.sensorsim.sensordata import SensorData
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
@dataclass(slots=True)
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
# ==============================================================================
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
|
-
from pyvale.sensordata import SensorData
|
|
9
|
-
from pyvale.errorcalculator import (IErrCalculator,
|
|
8
|
+
from pyvale.sensorsim.sensordata import SensorData
|
|
9
|
+
from pyvale.sensorsim.errorcalculator import (IErrCalculator,
|
|
10
10
|
EErrType,
|
|
11
11
|
EErrDep)
|
|
12
|
-
from pyvale.generatorsrandom import IGenRandom
|
|
12
|
+
from pyvale.sensorsim.generatorsrandom import IGenRandom
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class ErrRandUnif(IErrCalculator):
|
|
@@ -428,7 +428,7 @@ class ErrRandNormPercent(IErrCalculator):
|
|
|
428
428
|
return (err_basis*self._std*norm_rand,sens_data)
|
|
429
429
|
|
|
430
430
|
|
|
431
|
-
class
|
|
431
|
+
class ErrRandGen(IErrCalculator):
|
|
432
432
|
"""Sensor random error calculator based on sampling a user specified random
|
|
433
433
|
number generator implementing the `IGeneratorRandom` interface.
|
|
434
434
|
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
from typing import Callable
|
|
8
8
|
import numpy as np
|
|
9
|
-
from pyvale.errorcalculator import (IErrCalculator,
|
|
9
|
+
from pyvale.sensorsim.errorcalculator import (IErrCalculator,
|
|
10
10
|
EErrType,
|
|
11
11
|
EErrDep)
|
|
12
|
-
from pyvale.sensordata import SensorData
|
|
12
|
+
from pyvale.sensorsim.sensordata import SensorData
|
|
13
13
|
|
|
14
14
|
# TODO: add option to use Newton's method for function inversion instead of a
|
|
15
15
|
# cal table.
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
import enum
|
|
8
8
|
from typing import Callable
|
|
9
9
|
import numpy as np
|
|
10
|
-
from pyvale.sensordata import SensorData
|
|
11
|
-
from pyvale.errorcalculator import (IErrCalculator,
|
|
10
|
+
from pyvale.sensorsim.sensordata import SensorData
|
|
11
|
+
from pyvale.sensorsim.errorcalculator import (IErrCalculator,
|
|
12
12
|
EErrType,
|
|
13
13
|
EErrDep)
|
|
14
14
|
|
|
@@ -9,15 +9,15 @@ from dataclasses import dataclass
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
from scipy.spatial.transform import Rotation
|
|
11
11
|
|
|
12
|
-
from pyvale.field import IField
|
|
13
|
-
from pyvale.fieldsampler import sample_field_with_sensor_data
|
|
14
|
-
from pyvale.sensordata import SensorData
|
|
15
|
-
from pyvale.integratortype import EIntSpatialType
|
|
16
|
-
from pyvale.errorcalculator import (IErrCalculator,
|
|
12
|
+
from pyvale.sensorsim.field import IField
|
|
13
|
+
from pyvale.sensorsim.fieldsampler import sample_field_with_sensor_data
|
|
14
|
+
from pyvale.sensorsim.sensordata import SensorData
|
|
15
|
+
from pyvale.sensorsim.integratortype import EIntSpatialType
|
|
16
|
+
from pyvale.sensorsim.errorcalculator import (IErrCalculator,
|
|
17
17
|
EErrType,
|
|
18
18
|
EErrDep)
|
|
19
|
-
from pyvale.errordriftcalc import IDriftCalculator
|
|
20
|
-
from pyvale.generatorsrandom import IGenRandom
|
|
19
|
+
from pyvale.sensorsim.errordriftcalc import IDriftCalculator
|
|
20
|
+
from pyvale.sensorsim.generatorsrandom import IGenRandom
|
|
21
21
|
|
|
22
22
|
# TODO:
|
|
23
23
|
# - Implement different perturbed sampling times for each sensor or allow all
|
|
@@ -402,7 +402,7 @@ def _perturb_sensor_angles(n_sensors: int,
|
|
|
402
402
|
for jj,rand_ang in enumerate(rand_ang_zyx): # loop over components
|
|
403
403
|
if rand_ang is not None:
|
|
404
404
|
sensor_rot_angs[jj] = sensor_rot_angs[jj] + \
|
|
405
|
-
rand_ang.generate(shape=1)
|
|
405
|
+
rand_ang.generate(shape=(1,))[0]
|
|
406
406
|
|
|
407
407
|
if angle_loc_zyx is not None:
|
|
408
408
|
# No rotation about locked axes using mask
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
# ==============================================================================
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
|
-
from pyvale.errorcalculator import (IErrCalculator,
|
|
8
|
+
from pyvale.sensorsim.errorcalculator import (IErrCalculator,
|
|
9
9
|
EErrType,
|
|
10
10
|
EErrDep)
|
|
11
|
-
from pyvale.generatorsrandom import IGenRandom
|
|
12
|
-
from pyvale.sensordata import SensorData
|
|
11
|
+
from pyvale.sensorsim.generatorsrandom import IGenRandom
|
|
12
|
+
from pyvale.sensorsim.sensordata import SensorData
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class ErrSysOffset(IErrCalculator):
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
class VisError(Exception):
|
|
8
|
+
pass
|
|
@@ -11,8 +11,8 @@ of input simulation cases and sensor arrays.
|
|
|
11
11
|
|
|
12
12
|
from dataclasses import dataclass
|
|
13
13
|
import numpy as np
|
|
14
|
-
import mooseherder as mh
|
|
15
|
-
from pyvale.sensorarray import ISensorArray
|
|
14
|
+
import pyvale.mooseherder as mh
|
|
15
|
+
from pyvale.sensorsim.sensorarray import ISensorArray
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@dataclass(slots=True)
|
|
@@ -104,6 +104,26 @@ class ExperimentSimulator:
|
|
|
104
104
|
self._exp_data = None
|
|
105
105
|
self._exp_stats = None
|
|
106
106
|
|
|
107
|
+
def get_sim_list(self) -> list[mh.SimData]:
|
|
108
|
+
"""Gets the list of simulations to run simulated experiments for.
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
list[mh.SimData]
|
|
113
|
+
List of simulation data objects.
|
|
114
|
+
"""
|
|
115
|
+
return self._sim_list
|
|
116
|
+
|
|
117
|
+
def get_sensor_arrays(self) -> list[ISensorArray]:
|
|
118
|
+
"""Gets the sensor array list for this experiment.
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
list[ISensorArray]
|
|
123
|
+
List of sensor arrays for the simulated experiment.
|
|
124
|
+
"""
|
|
125
|
+
return self._sensor_arrays
|
|
126
|
+
|
|
107
127
|
def run_experiments(self) -> list[np.ndarray]:
|
|
108
128
|
"""Runs the specified number of virtual experiments over the number of
|
|
109
129
|
input simulation cases and virtual sensor arrays.
|
|
@@ -122,7 +142,7 @@ class ExperimentSimulator:
|
|
|
122
142
|
|
|
123
143
|
for ii,aa in enumerate(self._sensor_arrays):
|
|
124
144
|
meas_array = np.zeros((n_sims,self._num_exp_per_sim)+
|
|
125
|
-
|
|
145
|
+
aa.get_measurement_shape())
|
|
126
146
|
|
|
127
147
|
for jj,ss in enumerate(self._sim_list):
|
|
128
148
|
aa.get_field().set_sim_data(ss)
|
|
@@ -12,14 +12,15 @@ compatible with the underlying machinery of pyvale.
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
import pyvista as pv
|
|
14
14
|
from pyvista import CellType
|
|
15
|
-
import mooseherder as mh
|
|
15
|
+
import pyvale.mooseherder as mh
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
|
|
18
|
+
def simdata_to_pyvista_interp(sim_data: mh.SimData,
|
|
19
|
+
components: tuple[str,...] | None,
|
|
20
|
+
elem_dims: int
|
|
21
|
+
) -> pv.UnstructuredGrid:
|
|
21
22
|
"""Converts the mesh and field data in a `SimData` object into a pyvista
|
|
22
|
-
UnstructuredGrid for
|
|
23
|
+
UnstructuredGrid for interpolating the data.
|
|
23
24
|
|
|
24
25
|
Parameters
|
|
25
26
|
----------
|
|
@@ -34,9 +35,67 @@ def simdata_to_pyvista(sim_data: mh.SimData,
|
|
|
34
35
|
|
|
35
36
|
Returns
|
|
36
37
|
-------
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
pv.UnstructuredGrid
|
|
39
|
+
As pyvista grid with attached field data to allow for interpolation on
|
|
40
|
+
the mesh using the element shape functions.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
pv_grid = _gen_pyvista_grid(sim_data,elem_dims)
|
|
44
|
+
|
|
45
|
+
if components is not None and sim_data.node_vars is not None:
|
|
46
|
+
for cc in components:
|
|
47
|
+
pv_grid[cc] = sim_data.node_vars[cc]
|
|
48
|
+
|
|
49
|
+
return pv_grid
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def simdata_to_pyvista_vis(sim_data: mh.SimData,
|
|
53
|
+
elem_dims: int
|
|
54
|
+
) -> pv.UnstructuredGrid | pv.PolyData:
|
|
55
|
+
"""Converts the mesh and field data in a `SimData` object into a pyvista
|
|
56
|
+
UnstructuredGrid or PolyData object for visualisation.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
sim_data : mh.SimData
|
|
61
|
+
Object containing a mesh and associated field data from a simulation.
|
|
62
|
+
elem_dim : int
|
|
63
|
+
Number of spatial dimensions (2 or 3) used to determine the element
|
|
64
|
+
types in the mesh from the number of nodes per element. Set to the
|
|
65
|
+
dimensionality of the problem for point cloud data as 2D triangulation
|
|
66
|
+
will be much faster if possible.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
pv.UnstructuredGrid | pv.PolyData
|
|
71
|
+
A pyvista unstructured grid or poly data object that has no field data
|
|
72
|
+
attached for visualisation purposes.
|
|
73
|
+
"""
|
|
74
|
+
if sim_data.connect is None:
|
|
75
|
+
return pv.PolyData(sim_data.coords)
|
|
76
|
+
|
|
77
|
+
return _gen_pyvista_grid(sim_data,elem_dims)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _gen_pyvista_grid(sim_data: mh.SimData,
|
|
82
|
+
elem_dims: int) -> pv.UnstructuredGrid:
|
|
83
|
+
"""Helper function for generating a blank pyvista unstructure grid mesh from
|
|
84
|
+
a SimData object.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
sim_data : mh.SimData
|
|
89
|
+
Object containing a mesh and associated field data from a simulation.
|
|
90
|
+
elem_dims : int
|
|
91
|
+
Number of spatial dimensions (2 or 3) used to determine the element
|
|
92
|
+
types in the mesh from the number of nodes per element.
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
pv.UnstructuredGrid
|
|
98
|
+
A pyvista unstructured grid that has no field data attached.
|
|
40
99
|
"""
|
|
41
100
|
flat_connect = np.array([],dtype=np.int64)
|
|
42
101
|
cell_types = np.array([],dtype=np.int64)
|
|
@@ -65,13 +124,7 @@ def simdata_to_pyvista(sim_data: mh.SimData,
|
|
|
65
124
|
|
|
66
125
|
points = sim_data.coords
|
|
67
126
|
pv_grid = pv.UnstructuredGrid(cells, cell_types, points)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if components is not None and sim_data.node_vars is not None:
|
|
71
|
-
for cc in components:
|
|
72
|
-
pv_grid[cc] = sim_data.node_vars[cc]
|
|
73
|
-
|
|
74
|
-
return (pv_grid,pv_grid_vis)
|
|
127
|
+
return pv_grid
|
|
75
128
|
|
|
76
129
|
|
|
77
130
|
def scale_length_units(scale: float,
|
|
@@ -208,7 +261,7 @@ def extract_surf_mesh(sim_data: mh.SimData) -> mh.SimData:
|
|
|
208
261
|
|
|
209
262
|
return face_data
|
|
210
263
|
|
|
211
|
-
|
|
264
|
+
#TODO: make this support triangular prisms in 3D.
|
|
212
265
|
def _get_pyvista_cell_type(nodes_per_elem: int, spat_dim: int) -> CellType | None:
|
|
213
266
|
"""Helper function to identify the pyvista element type in the mesh.
|
|
214
267
|
|
|
@@ -253,7 +306,7 @@ def _get_pyvista_cell_type(nodes_per_elem: int, spat_dim: int) -> CellType | Non
|
|
|
253
306
|
|
|
254
307
|
return cell_type
|
|
255
308
|
|
|
256
|
-
|
|
309
|
+
#TODO: make this support triangular prisms in 3D.
|
|
257
310
|
def _exodus_to_pyvista_connect(cell_type: CellType,
|
|
258
311
|
connect: np.ndarray) -> np.ndarray:
|
|
259
312
|
"""Helper function that specifies the nodal winding map for higher order
|
|
@@ -290,7 +343,7 @@ def _exodus_to_pyvista_connect(cell_type: CellType,
|
|
|
290
343
|
|
|
291
344
|
return connect
|
|
292
345
|
|
|
293
|
-
|
|
346
|
+
#TODO: make this support triangular prisms in 3D.
|
|
294
347
|
def _get_surf_map(nodes_per_elem: int) -> np.ndarray:
|
|
295
348
|
"""Helper function specifying the mapping from 3D tet and hex elements to
|
|
296
349
|
the individual faces consistent with the exodus output format.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FieldInterp(ABC):
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def interp_field(self,
|
|
14
|
+
points: np.ndarray,
|
|
15
|
+
sample_times: np.ndarray | None = None,
|
|
16
|
+
) -> np.ndarray:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def interp_to_sample_time(sample_at_sim_time: np.ndarray,
|
|
21
|
+
sim_time_steps: np.ndarray,
|
|
22
|
+
sample_times: np.ndarray,
|
|
23
|
+
) -> np.ndarray:
|
|
24
|
+
|
|
25
|
+
def sample_time_interp(x):
|
|
26
|
+
return np.interp(sample_times, sim_time_steps, x)
|
|
27
|
+
|
|
28
|
+
n_time_steps = sample_times.shape[0]
|
|
29
|
+
n_sensors = sample_at_sim_time.shape[0]
|
|
30
|
+
n_comps = sample_at_sim_time.shape[1]
|
|
31
|
+
sample_at_spec_time = np.empty((n_sensors,n_comps,n_time_steps))
|
|
32
|
+
|
|
33
|
+
for ii in range(n_comps):
|
|
34
|
+
sample_at_spec_time[:,ii,:] = np.apply_along_axis(sample_time_interp,-1,
|
|
35
|
+
sample_at_sim_time[:,ii,:])
|
|
36
|
+
|
|
37
|
+
return sample_at_spec_time
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# pyvale: the python validation engine
|
|
3
|
+
# License: MIT
|
|
4
|
+
# Copyright (C) 2025 The Computer Aided Validation Team
|
|
5
|
+
# ==============================================================================
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import pyvista as pv
|
|
10
|
+
import pyvale.mooseherder as mh
|
|
11
|
+
from pyvale.sensorsim.fieldconverter import simdata_to_pyvista_interp
|
|
12
|
+
from pyvale.sensorsim.fieldinterp import (FieldInterp,
|
|
13
|
+
interp_to_sample_time)
|
|
14
|
+
|
|
15
|
+
class FieldInterpMesh(FieldInterp):
|
|
16
|
+
"""TODO
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
__slots__ = ("_sim_time_steps","_components","_pyvista_interp")
|
|
20
|
+
|
|
21
|
+
def __init__(self,
|
|
22
|
+
sim_data: mh.SimData,
|
|
23
|
+
components: tuple[str,...],
|
|
24
|
+
elem_dims: int,
|
|
25
|
+
) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
sim_data : mh.SimData
|
|
30
|
+
_description_
|
|
31
|
+
components : tuple[str,...]
|
|
32
|
+
_description_
|
|
33
|
+
elem_dims : int
|
|
34
|
+
_description_
|
|
35
|
+
"""
|
|
36
|
+
self._sim_time_steps = sim_data.time
|
|
37
|
+
self._components = components
|
|
38
|
+
self._pyvista_interp = simdata_to_pyvista_interp(sim_data,
|
|
39
|
+
self._components,
|
|
40
|
+
elem_dims=elem_dims)
|
|
41
|
+
|
|
42
|
+
def interp_field(self,
|
|
43
|
+
points: np.ndarray,
|
|
44
|
+
sample_times: np.ndarray | None = None,
|
|
45
|
+
) -> np.ndarray:
|
|
46
|
+
"""_summary_
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
points : np.ndarray
|
|
51
|
+
_description_
|
|
52
|
+
times : np.ndarray | None, optional
|
|
53
|
+
_description_, by default None
|
|
54
|
+
|
|
55
|
+
Returns
|
|
56
|
+
-------
|
|
57
|
+
np.ndarray
|
|
58
|
+
_description_
|
|
59
|
+
"""
|
|
60
|
+
return sample_pyvista_grid(self._components,
|
|
61
|
+
self._pyvista_interp,
|
|
62
|
+
self._sim_time_steps,
|
|
63
|
+
points,
|
|
64
|
+
sample_times)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def sample_pyvista_grid(components: tuple[str,...],
|
|
68
|
+
pyvista_interp: pv.UnstructuredGrid,
|
|
69
|
+
sim_time_steps: np.ndarray,
|
|
70
|
+
points: np.ndarray,
|
|
71
|
+
sample_times: np.ndarray | None = None
|
|
72
|
+
) -> np.ndarray:
|
|
73
|
+
"""Function for sampling (interpolating) a pyvista grid object containing
|
|
74
|
+
simulated field data. The pyvista sample method uses VTK to perform the
|
|
75
|
+
spatial interpolation using the element shape functions. If the sampling
|
|
76
|
+
time steps are not the same as the simulation time then a linear
|
|
77
|
+
interpolation over time is performed using numpy.
|
|
78
|
+
|
|
79
|
+
NOTE: sampling outside the mesh bounds of the sample returns a value of 0.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
components : tuple[str,...]
|
|
84
|
+
String keys for the components to be sampled in the pyvista grid object.
|
|
85
|
+
Useful for only interpolating the field components of interest for speed
|
|
86
|
+
and memory reduction.
|
|
87
|
+
pyvista_interp : pv.UnstructuredGrid
|
|
88
|
+
Pyvista grid object containing the simulation mesh and the components of
|
|
89
|
+
the physical field that will be sampled.
|
|
90
|
+
sim_time_steps : np.ndarray
|
|
91
|
+
Simulation time steps corresponding to the fields in the pyvista grid
|
|
92
|
+
object.
|
|
93
|
+
points : np.ndarray
|
|
94
|
+
Coordinates of the points at which to sample the pyvista grid object.
|
|
95
|
+
shape=(num_points,3) where the columns are the X, Y and Z coordinates of
|
|
96
|
+
the sample points in simulation world coordintes.
|
|
97
|
+
sample_times : np.ndarray | None, optional
|
|
98
|
+
Array of time steps at which to sample the pyvista grid. If None then no
|
|
99
|
+
temporal interpolation is performed and the sample times are assumed to
|
|
100
|
+
be the simulation time steps.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
np.ndarray
|
|
105
|
+
Array of sampled sensor measurements with shape=(num_sensors,
|
|
106
|
+
num_field_components,num_time_steps).
|
|
107
|
+
"""
|
|
108
|
+
pv_points = pv.PolyData(points)
|
|
109
|
+
sample_data = pv_points.sample(pyvista_interp)
|
|
110
|
+
|
|
111
|
+
n_comps = len(components)
|
|
112
|
+
(n_sensors,n_time_steps) = np.array(sample_data[components[0]]).shape
|
|
113
|
+
sample_at_sim_time = np.empty((n_sensors,n_comps,n_time_steps))
|
|
114
|
+
|
|
115
|
+
for ii,cc in enumerate(components):
|
|
116
|
+
sample_at_sim_time[:,ii,:] = np.array(sample_data[cc])
|
|
117
|
+
|
|
118
|
+
if sample_times is None:
|
|
119
|
+
return sample_at_sim_time
|
|
120
|
+
|
|
121
|
+
return interp_to_sample_time(sample_at_sim_time,
|
|
122
|
+
sim_time_steps,
|
|
123
|
+
sample_times)
|
|
124
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
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 scipy.spatial import Delaunay
|
|
9
|
+
from scipy.interpolate import LinearNDInterpolator
|
|
10
|
+
from pyvale.sensorsim.fieldinterp import (FieldInterp,
|
|
11
|
+
interp_to_sample_time)
|
|
12
|
+
|
|
13
|
+
class FieldInterpPoints(FieldInterp):
|
|
14
|
+
|
|
15
|
+
def __init__(self,
|
|
16
|
+
coords: np.ndarray,
|
|
17
|
+
sim_time_steps: np.ndarray,
|
|
18
|
+
components: tuple[str,...],
|
|
19
|
+
) -> None:
|
|
20
|
+
pass
|
|
21
|
+
# self._coords = coords
|
|
22
|
+
# self._sim_time_steps = sim_time_steps
|
|
23
|
+
# self._components = components
|
|
24
|
+
|
|
25
|
+
# self._triangulation = Delaunay()
|
|
26
|
+
# self._interp_funcs = []
|
|
27
|
+
|
|
28
|
+
# for ii in range(self._sim_time_steps.shape[0]):
|
|
29
|
+
# interp = LinearNDInterpolator(coords,)
|
|
30
|
+
# self._interp_funcs.append(interp)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def interp_field(self,
|
|
34
|
+
points: np.ndarray,
|
|
35
|
+
sample_times: np.ndarray | None = None,
|
|
36
|
+
) -> np.ndarray:
|
|
37
|
+
pass
|
|
38
|
+
# n_points = points.shape[0]
|
|
39
|
+
# n_comps = len(self._components)
|
|
40
|
+
# n_sim_time = self._sim_time_steps.shape[0]
|
|
41
|
+
# sample_at_sim_time = np.empty((n_points,n_comps,n_sim_time),
|
|
42
|
+
# dtype=np.float64)
|
|
43
|
+
|
|
44
|
+
# for ii in range(self._sim_time_steps.shape[0]):
|
|
45
|
+
|
|
46
|
+
# sample_at_sim_time[:,]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# if sample_times is None:
|
|
51
|
+
# return sample_at_sim_time
|
|
52
|
+
|
|
53
|
+
# return interp_to_sample_time(sample_at_sim_time,
|
|
54
|
+
# sim_time_steps,
|
|
55
|
+
# sample_times)
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
import pyvista as pv
|
|
9
|
-
from pyvale.field import IField
|
|
10
|
-
from pyvale.sensordata import SensorData
|
|
11
|
-
from pyvale.integratorfactory import build_spatial_averager
|
|
9
|
+
from pyvale.sensorsim.field import IField
|
|
10
|
+
from pyvale.sensorsim.sensordata import SensorData
|
|
11
|
+
from pyvale.sensorsim.integratorfactory import build_spatial_averager
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def sample_field_with_sensor_data(field: IField, sensor_data: SensorData
|
|
@@ -40,7 +40,7 @@ def sample_field_with_sensor_data(field: IField, sensor_data: SensorData
|
|
|
40
40
|
return spatial_integrator.calc_averages()
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
#
|
|
43
|
+
# TODO: move this into the fieldinterpmesh object
|
|
44
44
|
def sample_pyvista_grid(components: tuple[str,...],
|
|
45
45
|
pyvista_grid: pv.UnstructuredGrid,
|
|
46
46
|
sim_time_steps: np.ndarray,
|