pyvale 2025.7.2__cp311-cp311-macosx_14_0_arm64.whl → 2025.8.1__cp311-cp311-macosx_14_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyvale might be problematic. Click here for more details.

Files changed (176) hide show
  1. pyvale/__init__.py +12 -92
  2. pyvale/blender/__init__.py +23 -0
  3. pyvale/{pyvaleexceptions.py → blender/blenderexceptions.py} +0 -3
  4. pyvale/{blenderlightdata.py → blender/blenderlightdata.py} +3 -3
  5. pyvale/{blendermaterialdata.py → blender/blendermaterialdata.py} +1 -1
  6. pyvale/{blenderrenderdata.py → blender/blenderrenderdata.py} +5 -3
  7. pyvale/{blenderscene.py → blender/blenderscene.py} +33 -30
  8. pyvale/{blendertools.py → blender/blendertools.py} +14 -10
  9. pyvale/dataset/__init__.py +7 -0
  10. pyvale/dataset/dataset.py +443 -0
  11. pyvale/dic/__init__.py +20 -0
  12. pyvale/{dic2d.py → dic/dic2d.py} +31 -36
  13. pyvale/dic/dic2dconv.py +6 -0
  14. pyvale/{dic2dcpp.cpython-311-darwin.so → dic/dic2dcpp.cpython-311-darwin.so} +0 -0
  15. pyvale/{dicdataimport.py → dic/dicdataimport.py} +8 -8
  16. pyvale/{dicregionofinterest.py → dic/dicregionofinterest.py} +1 -1
  17. pyvale/{dicresults.py → dic/dicresults.py} +1 -1
  18. pyvale/{dicstrain.py → dic/dicstrain.py} +9 -9
  19. pyvale/examples/basics/{ex1_1_basicscalars_therm2d.py → ex1a_basicscalars_therm2d.py} +12 -9
  20. pyvale/examples/basics/{ex1_2_sensormodel_therm2d.py → ex1b_sensormodel_therm2d.py} +17 -14
  21. pyvale/examples/basics/{ex1_3_customsens_therm3d.py → ex1c_customsens_therm3d.py} +27 -24
  22. pyvale/examples/basics/{ex1_4_basicerrors_therm3d.py → ex1d_basicerrors_therm3d.py} +32 -29
  23. pyvale/examples/basics/{ex1_5_fielderrs_therm3d.py → ex1e_fielderrs_therm3d.py} +19 -15
  24. pyvale/examples/basics/{ex1_6_caliberrs_therm2d.py → ex1f_caliberrs_therm2d.py} +20 -16
  25. pyvale/examples/basics/{ex1_7_spatavg_therm2d.py → ex1g_spatavg_therm2d.py} +19 -16
  26. pyvale/examples/basics/{ex2_1_basicvectors_disp2d.py → ex2a_basicvectors_disp2d.py} +13 -10
  27. pyvale/examples/basics/{ex2_2_vectorsens_disp2d.py → ex2b_vectorsens_disp2d.py} +19 -15
  28. pyvale/examples/basics/{ex2_3_sensangle_disp2d.py → ex2c_sensangle_disp2d.py} +21 -18
  29. pyvale/examples/basics/{ex2_4_chainfielderrs_disp2d.py → ex2d_chainfielderrs_disp2d.py} +31 -29
  30. pyvale/examples/basics/{ex2_5_vectorfields3d_disp3d.py → ex2e_vectorfields3d_disp3d.py} +21 -18
  31. pyvale/examples/basics/{ex3_1_basictensors_strain2d.py → ex3a_basictensors_strain2d.py} +16 -14
  32. pyvale/examples/basics/{ex3_2_tensorsens2d_strain2d.py → ex3b_tensorsens2d_strain2d.py} +17 -14
  33. pyvale/examples/basics/{ex3_3_tensorsens3d_strain3d.py → ex3c_tensorsens3d_strain3d.py} +25 -22
  34. pyvale/examples/basics/{ex4_1_expsim2d_thermmech2d.py → ex4a_expsim2d_thermmech2d.py} +17 -14
  35. pyvale/examples/basics/{ex4_2_expsim3d_thermmech3d.py → ex4b_expsim3d_thermmech3d.py} +37 -34
  36. pyvale/examples/basics/ex5_nomesh.py +24 -0
  37. pyvale/examples/dic/ex1_2_blenderdeformed.py +174 -0
  38. pyvale/examples/dic/ex1_region_of_interest.py +6 -3
  39. pyvale/examples/dic/ex2_plate_with_hole.py +21 -18
  40. pyvale/examples/dic/ex3_plate_with_hole_strain.py +8 -6
  41. pyvale/examples/dic/ex4_dic_blender.py +17 -15
  42. pyvale/examples/dic/ex5_dic_challenge.py +19 -14
  43. pyvale/examples/genanalyticdata/ex1_1_scalarvisualisation.py +16 -10
  44. pyvale/examples/genanalyticdata/ex1_2_scalarcasebuild.py +3 -3
  45. pyvale/examples/genanalyticdata/ex2_1_analyticsensors.py +29 -23
  46. pyvale/examples/genanalyticdata/ex2_2_analyticsensors_nomesh.py +67 -0
  47. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +12 -9
  48. pyvale/examples/mooseherder/ex0_create_moose_config.py +65 -0
  49. pyvale/examples/mooseherder/ex1a_modify_moose_input.py +71 -0
  50. pyvale/examples/mooseherder/ex1b_modify_gmsh_input.py +69 -0
  51. pyvale/examples/mooseherder/ex2a_run_moose_once.py +80 -0
  52. pyvale/examples/mooseherder/ex2b_run_gmsh_once.py +64 -0
  53. pyvale/examples/mooseherder/ex2c_run_both_once.py +114 -0
  54. pyvale/examples/mooseherder/ex3_run_moose_seq_para.py +157 -0
  55. pyvale/examples/mooseherder/ex4_run_gmsh-moose_seq_para.py +176 -0
  56. pyvale/examples/mooseherder/ex5_run_moose_paramulti.py +136 -0
  57. pyvale/examples/mooseherder/ex6_read_moose_exodus.py +163 -0
  58. pyvale/examples/mooseherder/ex7a_read_moose_herd_results.py +153 -0
  59. pyvale/examples/mooseherder/ex7b_read_multi_herd_results.py +116 -0
  60. pyvale/examples/mooseherder/ex7c_read_multi_gmshmoose_results.py +127 -0
  61. pyvale/examples/mooseherder/ex7d_readconfig_multi_gmshmoose_results.py +143 -0
  62. pyvale/examples/mooseherder/ex8_read_existing_sweep_output.py +72 -0
  63. pyvale/examples/renderblender/ex1_1_blenderscene.py +24 -20
  64. pyvale/examples/renderblender/ex1_2_blenderdeformed.py +22 -18
  65. pyvale/examples/renderblender/ex2_1_stereoscene.py +36 -29
  66. pyvale/examples/renderblender/ex2_2_stereodeformed.py +26 -20
  67. pyvale/examples/renderblender/ex3_1_blendercalibration.py +24 -17
  68. pyvale/examples/renderrasterisation/ex_rastenp.py +14 -12
  69. pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +14 -15
  70. pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +13 -11
  71. pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +13 -11
  72. pyvale/mooseherder/__init__.py +32 -0
  73. pyvale/mooseherder/directorymanager.py +416 -0
  74. pyvale/mooseherder/exodusreader.py +763 -0
  75. pyvale/mooseherder/gmshrunner.py +163 -0
  76. pyvale/mooseherder/inputmodifier.py +236 -0
  77. pyvale/mooseherder/mooseconfig.py +226 -0
  78. pyvale/mooseherder/mooseherd.py +527 -0
  79. pyvale/mooseherder/mooserunner.py +303 -0
  80. pyvale/mooseherder/outputreader.py +22 -0
  81. pyvale/mooseherder/simdata.py +92 -0
  82. pyvale/mooseherder/simrunner.py +31 -0
  83. pyvale/mooseherder/sweepreader.py +356 -0
  84. pyvale/mooseherder/sweeptools.py +76 -0
  85. pyvale/sensorsim/__init__.py +82 -0
  86. pyvale/{camera.py → sensorsim/camera.py} +7 -7
  87. pyvale/{camerasensor.py → sensorsim/camerasensor.py} +7 -7
  88. pyvale/{camerastereo.py → sensorsim/camerastereo.py} +2 -2
  89. pyvale/{cameratools.py → sensorsim/cameratools.py} +4 -4
  90. pyvale/{cython → sensorsim/cython}/rastercyth.c +596 -596
  91. pyvale/{cython → sensorsim/cython}/rastercyth.cpython-311-darwin.so +0 -0
  92. pyvale/{cython → sensorsim/cython}/rastercyth.py +16 -17
  93. pyvale/{errorcalculator.py → sensorsim/errorcalculator.py} +1 -1
  94. pyvale/{errorintegrator.py → sensorsim/errorintegrator.py} +2 -2
  95. pyvale/{errorrand.py → sensorsim/errorrand.py} +4 -4
  96. pyvale/{errorsyscalib.py → sensorsim/errorsyscalib.py} +2 -2
  97. pyvale/{errorsysdep.py → sensorsim/errorsysdep.py} +2 -2
  98. pyvale/{errorsysfield.py → sensorsim/errorsysfield.py} +8 -8
  99. pyvale/{errorsysindep.py → sensorsim/errorsysindep.py} +3 -3
  100. pyvale/sensorsim/exceptions.py +8 -0
  101. pyvale/{experimentsimulator.py → sensorsim/experimentsimulator.py} +23 -3
  102. pyvale/{field.py → sensorsim/field.py} +1 -1
  103. pyvale/{fieldconverter.py → sensorsim/fieldconverter.py} +72 -19
  104. pyvale/sensorsim/fieldinterp.py +37 -0
  105. pyvale/sensorsim/fieldinterpmesh.py +124 -0
  106. pyvale/sensorsim/fieldinterppoints.py +55 -0
  107. pyvale/{fieldsampler.py → sensorsim/fieldsampler.py} +4 -4
  108. pyvale/{fieldscalar.py → sensorsim/fieldscalar.py} +28 -24
  109. pyvale/{fieldtensor.py → sensorsim/fieldtensor.py} +33 -31
  110. pyvale/{fieldvector.py → sensorsim/fieldvector.py} +33 -31
  111. pyvale/{imagedef2d.py → sensorsim/imagedef2d.py} +9 -5
  112. pyvale/{integratorfactory.py → sensorsim/integratorfactory.py} +6 -6
  113. pyvale/{integratorquadrature.py → sensorsim/integratorquadrature.py} +3 -3
  114. pyvale/{integratorrectangle.py → sensorsim/integratorrectangle.py} +3 -3
  115. pyvale/{integratorspatial.py → sensorsim/integratorspatial.py} +1 -1
  116. pyvale/{rastercy.py → sensorsim/rastercy.py} +5 -5
  117. pyvale/{rasternp.py → sensorsim/rasternp.py} +9 -9
  118. pyvale/{rasteropts.py → sensorsim/rasteropts.py} +1 -1
  119. pyvale/{renderer.py → sensorsim/renderer.py} +1 -1
  120. pyvale/{rendermesh.py → sensorsim/rendermesh.py} +5 -5
  121. pyvale/{renderscene.py → sensorsim/renderscene.py} +2 -2
  122. pyvale/{sensorarray.py → sensorsim/sensorarray.py} +1 -1
  123. pyvale/{sensorarrayfactory.py → sensorsim/sensorarrayfactory.py} +12 -12
  124. pyvale/{sensorarraypoint.py → sensorsim/sensorarraypoint.py} +10 -8
  125. pyvale/{sensordata.py → sensorsim/sensordata.py} +1 -1
  126. pyvale/{sensortools.py → sensorsim/sensortools.py} +2 -20
  127. pyvale/sensorsim/simtools.py +174 -0
  128. pyvale/{visualexpplotter.py → sensorsim/visualexpplotter.py} +3 -3
  129. pyvale/{visualimages.py → sensorsim/visualimages.py} +2 -2
  130. pyvale/{visualsimanimator.py → sensorsim/visualsimanimator.py} +4 -4
  131. pyvale/{visualsimplotter.py → sensorsim/visualsimplotter.py} +5 -5
  132. pyvale/{visualsimsensors.py → sensorsim/visualsimsensors.py} +12 -12
  133. pyvale/{visualtools.py → sensorsim/visualtools.py} +1 -1
  134. pyvale/{visualtraceplotter.py → sensorsim/visualtraceplotter.py} +2 -2
  135. pyvale/simcases/case17.geo +3 -0
  136. pyvale/simcases/case17.i +4 -4
  137. pyvale/simcases/run_1case.py +1 -9
  138. pyvale/simcases/run_all_cases.py +1 -1
  139. pyvale/simcases/run_build_case.py +1 -1
  140. pyvale/simcases/run_example_cases.py +1 -1
  141. pyvale/verif/__init__.py +12 -0
  142. pyvale/{analyticsimdatafactory.py → verif/analyticsimdatafactory.py} +2 -2
  143. pyvale/{analyticsimdatagenerator.py → verif/analyticsimdatagenerator.py} +2 -2
  144. pyvale/verif/psens.py +125 -0
  145. pyvale/verif/psensconst.py +18 -0
  146. pyvale/verif/psensmech.py +227 -0
  147. pyvale/verif/psensmultiphys.py +187 -0
  148. pyvale/verif/psensscalar.py +347 -0
  149. pyvale/verif/psenstensor.py +123 -0
  150. pyvale/verif/psensvector.py +116 -0
  151. {pyvale-2025.7.2.dist-info → pyvale-2025.8.1.dist-info}/METADATA +6 -7
  152. pyvale-2025.8.1.dist-info/RECORD +262 -0
  153. pyvale/dataset.py +0 -415
  154. pyvale/simtools.py +0 -67
  155. pyvale-2025.7.2.dist-info/RECORD +0 -214
  156. /pyvale/{blendercalibrationdata.py → blender/blendercalibrationdata.py} +0 -0
  157. /pyvale/{dicchecks.py → dic/dicchecks.py} +0 -0
  158. /pyvale/{dicspecklegenerator.py → dic/dicspecklegenerator.py} +0 -0
  159. /pyvale/{dicspecklequality.py → dic/dicspecklequality.py} +0 -0
  160. /pyvale/{dicstrainresults.py → dic/dicstrainresults.py} +0 -0
  161. /pyvale/{cameradata.py → sensorsim/cameradata.py} +0 -0
  162. /pyvale/{cameradata2d.py → sensorsim/cameradata2d.py} +0 -0
  163. /pyvale/{errordriftcalc.py → sensorsim/errordriftcalc.py} +0 -0
  164. /pyvale/{fieldtransform.py → sensorsim/fieldtransform.py} +0 -0
  165. /pyvale/{generatorsrandom.py → sensorsim/generatorsrandom.py} +0 -0
  166. /pyvale/{imagetools.py → sensorsim/imagetools.py} +0 -0
  167. /pyvale/{integratortype.py → sensorsim/integratortype.py} +0 -0
  168. /pyvale/{output.py → sensorsim/output.py} +0 -0
  169. /pyvale/{raster.py → sensorsim/raster.py} +0 -0
  170. /pyvale/{sensordescriptor.py → sensorsim/sensordescriptor.py} +0 -0
  171. /pyvale/{visualimagedef.py → sensorsim/visualimagedef.py} +0 -0
  172. /pyvale/{visualopts.py → sensorsim/visualopts.py} +0 -0
  173. /pyvale/{analyticmeshgen.py → verif/analyticmeshgen.py} +0 -0
  174. {pyvale-2025.7.2.dist-info → pyvale-2025.8.1.dist-info}/WHEEL +0 -0
  175. {pyvale-2025.7.2.dist-info → pyvale-2025.8.1.dist-info}/licenses/LICENSE +0 -0
  176. {pyvale-2025.7.2.dist-info → pyvale-2025.8.1.dist-info}/top_level.txt +0 -0
@@ -7,11 +7,12 @@
7
7
  import numpy as np
8
8
  import pyvista as pv
9
9
  from scipy.spatial.transform import Rotation
10
- import mooseherder as mh
10
+ import pyvale.mooseherder as mh
11
11
 
12
- from pyvale.field import IField
13
- from pyvale.fieldconverter import simdata_to_pyvista
14
- from pyvale.fieldsampler import sample_pyvista_grid
12
+ from pyvale.sensorsim.field import IField
13
+ from pyvale.sensorsim.fieldconverter import simdata_to_pyvista_vis
14
+ from pyvale.sensorsim.fieldinterpmesh import FieldInterpMesh
15
+ from pyvale.sensorsim.fieldinterppoints import FieldInterpPoints
15
16
 
16
17
 
17
18
  class FieldScalar(IField):
@@ -20,8 +21,8 @@ class FieldScalar(IField):
20
21
 
21
22
  Implements the `IField` interface.
22
23
  """
23
- __slots__ = ("_field_key","_elem_dims","_sim_data","_pyvista_grid",
24
- "_pyvista_vis")
24
+ __slots__ = ("_field_key","_elem_dims","_sim_data","_interpolator",
25
+ "_visualiser")
25
26
 
26
27
  def __init__(self,
27
28
  sim_data: mh.SimData,
@@ -36,18 +37,20 @@ class FieldScalar(IField):
36
37
  String key for the scalar field component in the `SimData` object.
37
38
  elem_dims : int
38
39
  Number of spatial dimensions (2 or 3) used for identifying element
39
- types.
40
+ types. If point cloud data then set to the number of dimensions of
41
+ the problem as 2D triangulation is much faster than 3D.
40
42
  """
41
43
 
42
44
  self._field_key = field_key
43
45
  self._elem_dims = elem_dims
44
46
 
45
- self._sim_data = sim_data
46
- (self._pyvista_grid,self._pyvista_vis) = simdata_to_pyvista(
47
- self._sim_data,
48
- (self._field_key,),
49
- self._elem_dims
50
- )
47
+ # NOTE: these get set in the function call to `set_sim_data` - this is
48
+ # separated out to allow inserting a new simdata object
49
+ self._sim_data = None
50
+ self._visualiser = None
51
+ self._interpolator = None
52
+ self.set_sim_data(sim_data)
53
+
51
54
 
52
55
  def set_sim_data(self, sim_data: mh.SimData) -> None:
53
56
  """Sets the `SimData` object that will be interpolated to obtain sensor
@@ -60,12 +63,17 @@ class FieldScalar(IField):
60
63
  Mooseherder SimData object. Contains a mesh and a simulated
61
64
  physical field.
62
65
  """
66
+
63
67
  self._sim_data = sim_data
64
- (self._pyvista_grid,self._pyvista_vis) = simdata_to_pyvista(
65
- sim_data,
66
- (self._field_key,),
67
- self._elem_dims
68
- )
68
+
69
+ self._visualiser = simdata_to_pyvista_vis(sim_data,
70
+ self._elem_dims)
71
+ if self._sim_data.connect is None:
72
+ self._interpolator = None #FieldInterpPoints()
73
+ else:
74
+ self._interpolator = FieldInterpMesh(self._sim_data,
75
+ (self._field_key,),
76
+ self._elem_dims)
69
77
 
70
78
  def get_sim_data(self) -> mh.SimData:
71
79
  """Gets the simulation data object associated with this field. Used by
@@ -99,7 +107,7 @@ class FieldScalar(IField):
99
107
  Pyvista unstructured grid object containing only a mesh without any
100
108
  physical field data attached.
101
109
  """
102
- return self._pyvista_vis
110
+ return self._visualiser
103
111
 
104
112
  def get_all_components(self) -> tuple[str, ...]:
105
113
  """Gets the string key for the component of the physical field. A scalar
@@ -158,9 +166,5 @@ class FieldScalar(IField):
158
166
  An array of sampled (interpolated) values with the following
159
167
  dimensions: shape=(num_points,num_components,num_time_steps).
160
168
  """
161
- return sample_pyvista_grid((self._field_key,),
162
- self._pyvista_grid,
163
- self._sim_data.time,
164
- points,
165
- times)
169
+ return self._interpolator.interp_field(points,times)
166
170
 
@@ -7,15 +7,18 @@
7
7
  import numpy as np
8
8
  import pyvista as pv
9
9
  from scipy.spatial.transform import Rotation
10
- import mooseherder as mh
11
-
12
- from pyvale.field import IField
13
- from pyvale.fieldconverter import simdata_to_pyvista
14
- from pyvale.fieldsampler import sample_pyvista_grid
15
- from pyvale.fieldtransform import (transform_tensor_2d,
16
- transform_tensor_2d_batch,
17
- transform_tensor_3d,
18
- transform_tensor_3d_batch)
10
+ import pyvale.mooseherder as mh
11
+
12
+ from pyvale.sensorsim.field import IField
13
+ from pyvale.sensorsim.fieldconverter import (simdata_to_pyvista_vis,
14
+ simdata_to_pyvista_interp)
15
+ from pyvale.sensorsim.fieldinterpmesh import FieldInterpMesh
16
+ from pyvale.sensorsim.fieldinterppoints import FieldInterpPoints
17
+ #TODO: cythonise these transformations
18
+ from pyvale.sensorsim.fieldtransform import (transform_tensor_2d,
19
+ transform_tensor_2d_batch,
20
+ transform_tensor_3d,
21
+ transform_tensor_3d_batch)
19
22
 
20
23
  # TODO:
21
24
  # - Checking to ensure normal and dev components are consistent
@@ -26,7 +29,7 @@ class FieldTensor(IField):
26
29
 
27
30
  Implements the `IField` interface.
28
31
  """
29
- __slots__ = ("_field_key","_spat_dims","_time_steps","_pyvista_grid",
32
+ __slots__ = ("_field_key","_elem_dims","_time_steps","_interpolator",
30
33
  "_norm_components","_dev_components")
31
34
 
32
35
  def __init__(self,
@@ -52,14 +55,13 @@ class FieldTensor(IField):
52
55
  self._field_key = field_name
53
56
  self._norm_components = norm_comps
54
57
  self._dev_components = dev_comps
55
- self._spat_dims = elem_dims
56
-
58
+ self._elem_dims = elem_dims
57
59
  self._sim_data = sim_data
58
- (self._pyvista_grid,self._pyvista_vis) = simdata_to_pyvista(
59
- self._sim_data,
60
- self._norm_components+self._dev_components,
61
- self._spat_dims
62
- )
60
+ self._visualiser = None
61
+ self._interpolator = None
62
+
63
+ self.set_sim_data(sim_data)
64
+
63
65
 
64
66
  def set_sim_data(self, sim_data: mh.SimData) -> None:
65
67
  """Sets the `SimData` object that will be interpolated to obtain sensor
@@ -73,11 +75,16 @@ class FieldTensor(IField):
73
75
  physical field.
74
76
  """
75
77
  self._sim_data = sim_data
76
- (self._pyvista_grid,self._pyvista_vis) = simdata_to_pyvista(
77
- sim_data,
78
- self._norm_components+self._dev_components,
79
- self._spat_dims
80
- )
78
+ self._visualiser = simdata_to_pyvista_vis(sim_data,self._elem_dims)
79
+
80
+ if self._sim_data.connect is None:
81
+ self._interpolator = None #FieldInterpPoints()
82
+ else:
83
+ self._interpolator = FieldInterpMesh(self._sim_data,
84
+ self._norm_components
85
+ + self._dev_components,
86
+ self._elem_dims)
87
+
81
88
 
82
89
  def get_sim_data(self) -> mh.SimData:
83
90
  """Gets the simulation data object associated with this field. Used by
@@ -111,7 +118,7 @@ class FieldTensor(IField):
111
118
  Pyvista unstructured grid object containing only a mesh without any
112
119
  physical field data attached.
113
120
  """
114
- return self._pyvista_vis
121
+ return self._visualiser
115
122
 
116
123
  def get_all_components(self) -> tuple[str, ...]:
117
124
  """Gets the string keys for the component of the physical field. For
@@ -172,11 +179,7 @@ class FieldTensor(IField):
172
179
  An array of sampled (interpolated) values with the following
173
180
  dimensions: shape=(num_points,num_components,num_time_steps).
174
181
  """
175
- field_data = sample_pyvista_grid(self._norm_components+self._dev_components,
176
- self._pyvista_grid,
177
- self._sim_data.time,
178
- points,
179
- times)
182
+ field_data = self._interpolator.interp_field(points,times)
180
183
 
181
184
  if angles is None:
182
185
  return field_data
@@ -187,14 +190,13 @@ class FieldTensor(IField):
187
190
  # TRANSFORMATION= coords rotate with object fixed
188
191
  # For Z transformation: sin negative in row 2, transpose scipy mat.
189
192
 
190
-
191
193
  # If we only have one angle we assume all sensors have the same angle
192
194
  # and we can batch process the rotations
193
195
  if len(angles) == 1:
194
196
  rmat = angles[0].as_matrix().T
195
197
 
196
198
  #TODO: assumes 2D in the x-y plane
197
- if self._spat_dims == 2:
199
+ if self._elem_dims == 2:
198
200
  rmat = rmat[:2,:2]
199
201
  field_data = transform_tensor_2d_batch(rmat,field_data)
200
202
  else:
@@ -202,7 +204,7 @@ class FieldTensor(IField):
202
204
 
203
205
  else: # Need to rotate each sensor using individual rotation = loop :(
204
206
  #TODO: assumes 2D in the x-y plane
205
- if self._spat_dims == 2:
207
+ if self._elem_dims == 2:
206
208
  for ii,rr in enumerate(angles):
207
209
  rmat = rr.as_matrix().T
208
210
  rmat = rmat[:2,:2]
@@ -7,15 +7,17 @@
7
7
  import numpy as np
8
8
  import pyvista as pv
9
9
  from scipy.spatial.transform import Rotation
10
- import mooseherder as mh
11
-
12
- from pyvale.field import IField
13
- from pyvale.fieldconverter import simdata_to_pyvista
14
- from pyvale.fieldsampler import sample_pyvista_grid
15
- from pyvale.fieldtransform import (transform_vector_2d,
16
- transform_vector_2d_batch,
17
- transform_vector_3d,
18
- transform_vector_3d_batch)
10
+ import pyvale.mooseherder as mh
11
+
12
+ from pyvale.sensorsim.field import IField
13
+ from pyvale.sensorsim.fieldconverter import (simdata_to_pyvista_interp,
14
+ simdata_to_pyvista_vis)
15
+ from pyvale.sensorsim.fieldinterpmesh import FieldInterpMesh
16
+ from pyvale.sensorsim.fieldinterppoints import FieldInterpPoints
17
+ from pyvale.sensorsim.fieldtransform import (transform_vector_2d,
18
+ transform_vector_2d_batch,
19
+ transform_vector_3d,
20
+ transform_vector_3d_batch)
19
21
 
20
22
  class FieldVector(IField):
21
23
  """Class for sampling (interpolating) vector fields from simulations to
@@ -23,8 +25,8 @@ class FieldVector(IField):
23
25
 
24
26
  Implements the `IField` interface.
25
27
  """
26
- __slots__ = ("_field_key","_components","_spat_dims","_sim_data",
27
- "_pyvista_grid","_pyvista_vis")
28
+ __slots__ = ("_field_key","_components","_elem_dims","_sim_data",
29
+ "_interpolator","_visualiser")
28
30
 
29
31
  def __init__(self,
30
32
  sim_data: mh.SimData,
@@ -47,14 +49,14 @@ class FieldVector(IField):
47
49
  """
48
50
  self._field_key = field_key
49
51
  self._components = components
50
- self._spat_dims = elem_dims
52
+ self._elem_dims = elem_dims
51
53
 
52
- self._sim_data = sim_data
53
- (self._pyvista_grid,self._pyvista_vis) = simdata_to_pyvista(
54
- self._sim_data,
55
- self._components,
56
- self._spat_dims
57
- )
54
+ # NOTE: these get set in the function call to `set_sim_data` - this is
55
+ # separated out to allow inserting a new simdata object
56
+ self._sim_data = None
57
+ self._interpolator = None
58
+ self._visualiser = None
59
+ self.set_sim_data(sim_data)
58
60
 
59
61
  def set_sim_data(self, sim_data: mh.SimData) -> None:
60
62
  """Sets the `SimData` object that will be interpolated to obtain sensor
@@ -68,11 +70,15 @@ class FieldVector(IField):
68
70
  physical field.
69
71
  """
70
72
  self._sim_data = sim_data
71
- (self._pyvista_grid,self._pyvista_vis) = simdata_to_pyvista(
72
- sim_data,
73
- self._components,
74
- self._spat_dims
75
- )
73
+
74
+ self._visualiser = simdata_to_pyvista_vis(sim_data,
75
+ self._elem_dims)
76
+ if self._sim_data.connect is None:
77
+ self._interpolator = None #FieldInterpPoints()
78
+ else:
79
+ self._interpolator = FieldInterpMesh(self._sim_data,
80
+ self._components,
81
+ self._elem_dims)
76
82
 
77
83
  def get_sim_data(self) -> mh.SimData:
78
84
  """Gets the simulation data object associated with this field. Used by
@@ -106,7 +112,7 @@ class FieldVector(IField):
106
112
  Pyvista unstructured grid object containing only a mesh without any
107
113
  physical field data attached.
108
114
  """
109
- return self._pyvista_vis
115
+ return self._visualiser
110
116
 
111
117
  def get_all_components(self) -> tuple[str, ...]:
112
118
  """Gets the string keys for the component of the physical field. For
@@ -168,11 +174,7 @@ class FieldVector(IField):
168
174
  dimensions: shape=(num_points,num_components,num_time_steps).
169
175
  """
170
176
 
171
- field_data = sample_pyvista_grid(self._components,
172
- self._pyvista_grid,
173
- self._sim_data.time,
174
- points,
175
- times)
177
+ field_data = self._interpolator.interp_field(points,times)
176
178
 
177
179
  if angles is None:
178
180
  return field_data
@@ -189,7 +191,7 @@ class FieldVector(IField):
189
191
  rmat = angles[0].as_matrix().T
190
192
 
191
193
  #TODO: assumes 2D in the x-y plane
192
- if self._spat_dims == 2:
194
+ if self._elem_dims == 2:
193
195
  rmat = rmat[:2,:2]
194
196
  field_data = transform_vector_2d_batch(rmat,field_data)
195
197
  else:
@@ -197,7 +199,7 @@ class FieldVector(IField):
197
199
 
198
200
  else: # Need to rotate each sensor using individual rotation = loop :(
199
201
  #TODO: assumes 2D in the x-y plane
200
- if self._spat_dims == 2:
202
+ if self._elem_dims == 2:
201
203
  for ii,rr in enumerate(angles):
202
204
  rmat = rr.as_matrix().T
203
205
  rmat = rmat[:2,:2]
@@ -8,6 +8,9 @@
8
8
  NOTE: This module is a feature under developement.
9
9
  """
10
10
 
11
+ # TODO
12
+ # - Update deformation functions to use pyvista a
13
+
11
14
  import time
12
15
  import warnings
13
16
  from dataclasses import dataclass
@@ -17,10 +20,10 @@ from scipy.interpolate import griddata
17
20
  from scipy.interpolate import RectBivariateSpline
18
21
  from scipy import ndimage
19
22
 
20
- from pyvale.rasternp import edge_function, RasterNP
21
- from pyvale.cameradata2d import CameraData2D
22
- from pyvale.cameratools import CameraTools
23
- from pyvale.imagetools import ImageTools
23
+ from pyvale.sensorsim.rasternp import edge_function, RasterNP
24
+ from pyvale.sensorsim.cameradata2d import CameraData2D
25
+ from pyvale.sensorsim.cameratools import CameraTools
26
+ from pyvale.sensorsim.imagetools import ImageTools
24
27
 
25
28
 
26
29
  @dataclass(slots=True)
@@ -180,7 +183,7 @@ class ImageDef2D:
180
183
  edge_check = np.zeros_like(edge,dtype=np.int8)
181
184
  edge_check[edge >= 0.0] = 1
182
185
  edge_check = np.sum(edge_check, axis=0)
183
- # Create a mask with the check, TODO check the 3 here for non triangles
186
+ # Create a mask with the check
184
187
  edge_mask_flat = edge_check == num_edges
185
188
  edge_mask_grid = np.reshape(edge_mask_flat,bound_coords_grid_shape)
186
189
 
@@ -536,6 +539,7 @@ def _deform_image_mask(def_image: np.ndarray,
536
539
  ) -> tuple[np.ndarray,np.ndarray]:
537
540
 
538
541
  # This is slow - might be quicker to just deform an upsampled mask
542
+ # TODO: use cython image averaging it is way faster!
539
543
  px_disp_x = CameraTools.average_subpixel_image(subpx_disp_x,
540
544
  cam_data.subsample)
541
545
  px_disp_y = CameraTools.average_subpixel_image(subpx_disp_y,
@@ -5,12 +5,12 @@
5
5
  # ==============================================================================
6
6
 
7
7
  import numpy as np
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,
8
+ from pyvale.sensorsim.field import IField
9
+ from pyvale.sensorsim.sensordata import SensorData
10
+ from pyvale.sensorsim.integratorspatial import IIntegratorSpatial
11
+ from pyvale.sensorsim.integratortype import EIntSpatialType
12
+ from pyvale.sensorsim.integratorrectangle import Rectangle2D
13
+ from pyvale.sensorsim.integratorquadrature import (Quadrature2D,
14
14
  create_gauss_weights_2d_4pts,
15
15
  create_gauss_weights_2d_9pts)
16
16
 
@@ -6,10 +6,10 @@
6
6
 
7
7
  from typing import Callable
8
8
  import numpy as np
9
- from pyvale.field import IField
10
- from pyvale.integratorspatial import (IIntegratorSpatial,
9
+ from pyvale.sensorsim.field import IField
10
+ from pyvale.sensorsim.integratorspatial import (IIntegratorSpatial,
11
11
  create_int_pt_array)
12
- from pyvale.sensordata import SensorData
12
+ from pyvale.sensorsim.sensordata import SensorData
13
13
 
14
14
 
15
15
  class Quadrature2D(IIntegratorSpatial):
@@ -5,10 +5,10 @@
5
5
  # ==============================================================================
6
6
 
7
7
  import numpy as np
8
- from pyvale.field import IField
9
- from pyvale.integratorspatial import (IIntegratorSpatial,
8
+ from pyvale.sensorsim.field import IField
9
+ from pyvale.sensorsim.integratorspatial import (IIntegratorSpatial,
10
10
  create_int_pt_array)
11
- from pyvale.sensordata import SensorData
11
+ from pyvale.sensorsim.sensordata import SensorData
12
12
 
13
13
  #NOTE: code below is very similar to quadrature integrator should be able to
14
14
  # refactor into injected classes/functions
@@ -6,7 +6,7 @@
6
6
 
7
7
  from abc import ABC, abstractmethod
8
8
  import numpy as np
9
- from pyvale.sensordata import SensorData
9
+ from pyvale.sensorsim.sensordata import SensorData
10
10
 
11
11
 
12
12
  def create_int_pt_array(sens_data: SensorData,
@@ -11,11 +11,11 @@ NOTE: this module is a feature under developement.
11
11
  from pathlib import Path
12
12
  from multiprocessing.pool import Pool
13
13
  import numpy as np
14
- from pyvale.cameradata import CameraData
15
- from pyvale.rendermesh import RenderMesh
16
- from pyvale.renderer import IRenderer
17
- from pyvale.rasteropts import RasterOpts
18
- import pyvale.cython.rastercyth as rastercyth
14
+ from pyvale.sensorsim.cameradata import CameraData
15
+ from pyvale.sensorsim.rendermesh import RenderMesh
16
+ from pyvale.sensorsim.renderer import IRenderer
17
+ from pyvale.sensorsim.rasteropts import RasterOpts
18
+ import pyvale.sensorsim.cython.rastercyth as rastercyth
19
19
 
20
20
  # NOTE: This module is a feature under developement.
21
21
 
@@ -14,15 +14,15 @@ from multiprocessing.pool import Pool
14
14
  import numpy as np
15
15
  import numba
16
16
  #import matplotlib.pyplot as plt
17
- from pyvale.dataset import DataSet
18
- from pyvale.cameradata import CameraData
19
- from pyvale.cameratools import CameraTools
20
- from pyvale.rendermesh import RenderMesh
21
- from pyvale.renderer import IRenderer, RenderScene
22
- from pyvale.rasteropts import RasterOpts, save_raster
23
- from pyvale.imagetools import ImageTools
24
- #from pyvale.visualimages import plot_field_image
25
- import pyvale.cython.rastercyth as rastercyth
17
+ import pyvale.dataset as dataset
18
+ from pyvale.sensorsim.cameradata import CameraData
19
+ from pyvale.sensorsim.cameratools import CameraTools
20
+ from pyvale.sensorsim.rendermesh import RenderMesh
21
+ from pyvale.sensorsim.renderer import IRenderer, RenderScene
22
+ from pyvale.sensorsim.rasteropts import RasterOpts, save_raster
23
+ from pyvale.sensorsim.imagetools import ImageTools
24
+ #from pyvale.sensorsim.visualimages import plot_field_image
25
+ import pyvale.sensorsim.cython.rastercyth as rastercyth
26
26
 
27
27
 
28
28
  # NOTE: This module is a feature under developement.
@@ -6,7 +6,7 @@
6
6
  from pathlib import Path
7
7
  from dataclasses import dataclass
8
8
  import numpy as np
9
- from pyvale.imagetools import EImageType, ImageTools
9
+ from pyvale.sensorsim.imagetools import EImageType, ImageTools
10
10
 
11
11
 
12
12
  @dataclass(slots=True)
@@ -6,7 +6,7 @@
6
6
  from abc import ABC, abstractmethod
7
7
  from pathlib import Path
8
8
  import numpy as np
9
- from pyvale.renderscene import RenderScene
9
+ from pyvale.sensorsim.renderscene import RenderScene
10
10
 
11
11
  # NOTE: This module is a feature under developement.
12
12
 
@@ -10,8 +10,8 @@ NOTE: this module is a feature under developement.
10
10
 
11
11
  import numpy as np
12
12
  from scipy.spatial.transform import Rotation
13
- import mooseherder as mh
14
- from pyvale.fieldconverter import simdata_to_pyvista
13
+ import pyvale.mooseherder as mh
14
+ from pyvale.sensorsim.fieldconverter import simdata_to_pyvista_interp
15
15
 
16
16
 
17
17
  # TODO:
@@ -79,9 +79,9 @@ def create_render_mesh(sim_data: mh.SimData,
79
79
  if field_disp_keys is not None:
80
80
  extract_keys = field_render_keys+field_disp_keys
81
81
 
82
- (pv_grid,_) = simdata_to_pyvista(sim_data,
83
- extract_keys,
84
- elem_dims=sim_spat_dim)
82
+ pv_grid = simdata_to_pyvista_interp(sim_data,
83
+ extract_keys,
84
+ elem_dims=sim_spat_dim)
85
85
 
86
86
  pv_surf = pv_grid.extract_surface()
87
87
  faces = np.array(pv_surf.faces)
@@ -5,8 +5,8 @@
5
5
  # Copyright (C) 2025 The Computer Aided Validation Team
6
6
  #===============================================================================
7
7
  import numpy as np
8
- from pyvale.cameradata import CameraData
9
- from pyvale.rendermesh import RenderMesh
8
+ from pyvale.sensorsim.cameradata import CameraData
9
+ from pyvale.sensorsim.rendermesh import RenderMesh
10
10
 
11
11
  #===============================================================================
12
12
  # TODO
@@ -6,7 +6,7 @@
6
6
 
7
7
  from abc import ABC, abstractmethod
8
8
  import numpy as np
9
- from pyvale.field import IField
9
+ from pyvale.sensorsim.field import IField
10
10
 
11
11
 
12
12
  class ISensorArray(ABC):
@@ -6,18 +6,18 @@
6
6
 
7
7
  import numpy as np
8
8
 
9
- import mooseherder as mh
10
-
11
- from pyvale.fieldscalar import FieldScalar
12
- from pyvale.fieldvector import FieldVector
13
- from pyvale.fieldtensor import FieldTensor
14
- from pyvale.sensordescriptor import SensorDescriptorFactory
15
- from pyvale.sensorarraypoint import SensorArrayPoint, SensorData
16
- from pyvale.errorintegrator import ErrIntegrator
17
- from pyvale.errorsysindep import ErrSysUnifPercent
18
- from pyvale.errorrand import ErrRandNormPercent
19
- from pyvale.errorsysdep import (ErrSysDigitisation,
20
- ErrSysSaturation)
9
+ import pyvale.mooseherder as mh
10
+
11
+ from pyvale.sensorsim.fieldscalar import FieldScalar
12
+ from pyvale.sensorsim.fieldvector import FieldVector
13
+ from pyvale.sensorsim.fieldtensor import FieldTensor
14
+ from pyvale.sensorsim.sensordescriptor import SensorDescriptorFactory
15
+ from pyvale.sensorsim.sensorarraypoint import SensorArrayPoint, SensorData
16
+ from pyvale.sensorsim.errorintegrator import ErrIntegrator
17
+ from pyvale.sensorsim.errorsysindep import ErrSysUnifPercent
18
+ from pyvale.sensorsim.errorrand import ErrRandNormPercent
19
+ from pyvale.sensorsim.errorsysdep import (ErrSysDigitisation,
20
+ ErrSysSaturation)
21
21
 
22
22
  # TODO:
23
23
  # - docstrings
@@ -5,12 +5,12 @@
5
5
  # ==============================================================================
6
6
 
7
7
  import numpy as np
8
- from pyvale.field import IField
9
- from pyvale.sensorarray import ISensorArray
10
- from pyvale.errorintegrator import ErrIntegrator
11
- from pyvale.sensordescriptor import SensorDescriptor
12
- from pyvale.sensordata import SensorData
13
- from pyvale.fieldsampler import sample_field_with_sensor_data
8
+ from pyvale.sensorsim.field import IField
9
+ from pyvale.sensorsim.sensorarray import ISensorArray
10
+ from pyvale.sensorsim.errorintegrator import ErrIntegrator
11
+ from pyvale.sensorsim.sensordescriptor import SensorDescriptor
12
+ from pyvale.sensorsim.sensordata import SensorData
13
+ from pyvale.sensorsim.fieldsampler import sample_field_with_sensor_data
14
14
 
15
15
 
16
16
  class SensorArrayPoint(ISensorArray):
@@ -159,15 +159,17 @@ class SensorArrayPoint(ISensorArray):
159
159
 
160
160
  return self._truth
161
161
 
162
- def set_error_integrator(self, err_int: ErrIntegrator) -> None:
162
+ def set_error_integrator(self, err_int: ErrIntegrator | None) -> None:
163
163
  """Sets the error intergrator that will be used to calculate the sensor
164
164
  array measurement errors when `calc_measurements()` is called. See the
165
165
  `ErrIntegrator` class for further detail.
166
166
 
167
167
  Parameters
168
168
  ----------
169
- err_int : ErrIntegrator
169
+ err_int : ErrIntegrator | None
170
170
  Error integration object with a chain of user defined sensor errors.
171
+ If None then no errors are calculated and the sensor performs pure
172
+ interpolation of the input fields.
171
173
  """
172
174
  self._error_integrator = err_int
173
175
 
@@ -7,7 +7,7 @@
7
7
  from dataclasses import dataclass
8
8
  import numpy as np
9
9
  from scipy.spatial.transform import Rotation
10
- from pyvale.integratortype import EIntSpatialType
10
+ from pyvale.sensorsim.integratortype import EIntSpatialType
11
11
 
12
12
 
13
13
  @dataclass(slots=True)