pyvale 2025.4.0__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.

Files changed (157) hide show
  1. pyvale/__init__.py +75 -0
  2. pyvale/core/__init__.py +7 -0
  3. pyvale/core/analyticmeshgen.py +59 -0
  4. pyvale/core/analyticsimdatafactory.py +63 -0
  5. pyvale/core/analyticsimdatagenerator.py +160 -0
  6. pyvale/core/camera.py +146 -0
  7. pyvale/core/cameradata.py +64 -0
  8. pyvale/core/cameradata2d.py +82 -0
  9. pyvale/core/cameratools.py +328 -0
  10. pyvale/core/cython/rastercyth.c +32267 -0
  11. pyvale/core/cython/rastercyth.py +636 -0
  12. pyvale/core/dataset.py +250 -0
  13. pyvale/core/errorcalculator.py +112 -0
  14. pyvale/core/errordriftcalc.py +146 -0
  15. pyvale/core/errorintegrator.py +339 -0
  16. pyvale/core/errorrand.py +614 -0
  17. pyvale/core/errorsysdep.py +331 -0
  18. pyvale/core/errorsysfield.py +407 -0
  19. pyvale/core/errorsysindep.py +905 -0
  20. pyvale/core/experimentsimulator.py +99 -0
  21. pyvale/core/field.py +136 -0
  22. pyvale/core/fieldconverter.py +154 -0
  23. pyvale/core/fieldsampler.py +112 -0
  24. pyvale/core/fieldscalar.py +167 -0
  25. pyvale/core/fieldtensor.py +221 -0
  26. pyvale/core/fieldtransform.py +384 -0
  27. pyvale/core/fieldvector.py +215 -0
  28. pyvale/core/generatorsrandom.py +528 -0
  29. pyvale/core/imagedef2d.py +566 -0
  30. pyvale/core/integratorfactory.py +241 -0
  31. pyvale/core/integratorquadrature.py +192 -0
  32. pyvale/core/integratorrectangle.py +88 -0
  33. pyvale/core/integratorspatial.py +90 -0
  34. pyvale/core/integratortype.py +44 -0
  35. pyvale/core/optimcheckfuncs.py +153 -0
  36. pyvale/core/raster.py +31 -0
  37. pyvale/core/rastercy.py +76 -0
  38. pyvale/core/rasternp.py +604 -0
  39. pyvale/core/rendermesh.py +156 -0
  40. pyvale/core/sensorarray.py +179 -0
  41. pyvale/core/sensorarrayfactory.py +210 -0
  42. pyvale/core/sensorarraypoint.py +280 -0
  43. pyvale/core/sensordata.py +72 -0
  44. pyvale/core/sensordescriptor.py +101 -0
  45. pyvale/core/sensortools.py +143 -0
  46. pyvale/core/visualexpplotter.py +151 -0
  47. pyvale/core/visualimagedef.py +71 -0
  48. pyvale/core/visualimages.py +75 -0
  49. pyvale/core/visualopts.py +180 -0
  50. pyvale/core/visualsimanimator.py +83 -0
  51. pyvale/core/visualsimplotter.py +182 -0
  52. pyvale/core/visualtools.py +81 -0
  53. pyvale/core/visualtraceplotter.py +256 -0
  54. pyvale/data/__init__.py +7 -0
  55. pyvale/data/case13_out.e +0 -0
  56. pyvale/data/case16_out.e +0 -0
  57. pyvale/data/case17_out.e +0 -0
  58. pyvale/data/case18_1_out.e +0 -0
  59. pyvale/data/case18_2_out.e +0 -0
  60. pyvale/data/case18_3_out.e +0 -0
  61. pyvale/data/case25_out.e +0 -0
  62. pyvale/data/case26_out.e +0 -0
  63. pyvale/data/optspeckle_2464x2056px_spec5px_8bit_gblur1px.tiff +0 -0
  64. pyvale/examples/__init__.py +7 -0
  65. pyvale/examples/analyticdatagen/__init__.py +7 -0
  66. pyvale/examples/analyticdatagen/ex1_1_scalarvisualisation.py +38 -0
  67. pyvale/examples/analyticdatagen/ex1_2_scalarcasebuild.py +46 -0
  68. pyvale/examples/analyticdatagen/ex2_1_analyticsensors.py +83 -0
  69. pyvale/examples/ex1_1_thermal2d.py +89 -0
  70. pyvale/examples/ex1_2_thermal2d.py +111 -0
  71. pyvale/examples/ex1_3_thermal2d.py +113 -0
  72. pyvale/examples/ex1_4_thermal2d.py +89 -0
  73. pyvale/examples/ex1_5_thermal2d.py +105 -0
  74. pyvale/examples/ex2_1_thermal3d .py +87 -0
  75. pyvale/examples/ex2_2_thermal3d.py +51 -0
  76. pyvale/examples/ex2_3_thermal3d.py +109 -0
  77. pyvale/examples/ex3_1_displacement2d.py +47 -0
  78. pyvale/examples/ex3_2_displacement2d.py +79 -0
  79. pyvale/examples/ex3_3_displacement2d.py +104 -0
  80. pyvale/examples/ex3_4_displacement2d.py +105 -0
  81. pyvale/examples/ex4_1_strain2d.py +57 -0
  82. pyvale/examples/ex4_2_strain2d.py +79 -0
  83. pyvale/examples/ex4_3_strain2d.py +100 -0
  84. pyvale/examples/ex5_1_multiphysics2d.py +78 -0
  85. pyvale/examples/ex6_1_multiphysics2d_expsim.py +118 -0
  86. pyvale/examples/ex6_2_multiphysics3d_expsim.py +158 -0
  87. pyvale/examples/features/__init__.py +7 -0
  88. pyvale/examples/features/ex_animation_tools_3dmonoblock.py +83 -0
  89. pyvale/examples/features/ex_area_avg.py +89 -0
  90. pyvale/examples/features/ex_calibration_error.py +108 -0
  91. pyvale/examples/features/ex_chain_field_errs.py +141 -0
  92. pyvale/examples/features/ex_field_errs.py +78 -0
  93. pyvale/examples/features/ex_sensor_single_angle_batch.py +110 -0
  94. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +86 -0
  95. pyvale/examples/rasterisation/ex_rastenp.py +154 -0
  96. pyvale/examples/rasterisation/ex_rastercyth_oneframe.py +220 -0
  97. pyvale/examples/rasterisation/ex_rastercyth_static_cypara.py +194 -0
  98. pyvale/examples/rasterisation/ex_rastercyth_static_pypara.py +193 -0
  99. pyvale/simcases/case00_HEX20.i +242 -0
  100. pyvale/simcases/case00_HEX27.i +242 -0
  101. pyvale/simcases/case00_TET10.i +242 -0
  102. pyvale/simcases/case00_TET14.i +242 -0
  103. pyvale/simcases/case01.i +101 -0
  104. pyvale/simcases/case02.i +156 -0
  105. pyvale/simcases/case03.i +136 -0
  106. pyvale/simcases/case04.i +181 -0
  107. pyvale/simcases/case05.i +234 -0
  108. pyvale/simcases/case06.i +305 -0
  109. pyvale/simcases/case07.geo +135 -0
  110. pyvale/simcases/case07.i +87 -0
  111. pyvale/simcases/case08.geo +144 -0
  112. pyvale/simcases/case08.i +153 -0
  113. pyvale/simcases/case09.geo +204 -0
  114. pyvale/simcases/case09.i +87 -0
  115. pyvale/simcases/case10.geo +204 -0
  116. pyvale/simcases/case10.i +257 -0
  117. pyvale/simcases/case11.geo +337 -0
  118. pyvale/simcases/case11.i +147 -0
  119. pyvale/simcases/case12.geo +388 -0
  120. pyvale/simcases/case12.i +329 -0
  121. pyvale/simcases/case13.i +140 -0
  122. pyvale/simcases/case14.i +159 -0
  123. pyvale/simcases/case15.geo +337 -0
  124. pyvale/simcases/case15.i +150 -0
  125. pyvale/simcases/case16.geo +391 -0
  126. pyvale/simcases/case16.i +357 -0
  127. pyvale/simcases/case17.geo +135 -0
  128. pyvale/simcases/case17.i +144 -0
  129. pyvale/simcases/case18.i +254 -0
  130. pyvale/simcases/case18_1.i +254 -0
  131. pyvale/simcases/case18_2.i +254 -0
  132. pyvale/simcases/case18_3.i +254 -0
  133. pyvale/simcases/case19.geo +252 -0
  134. pyvale/simcases/case19.i +99 -0
  135. pyvale/simcases/case20.geo +252 -0
  136. pyvale/simcases/case20.i +250 -0
  137. pyvale/simcases/case21.geo +74 -0
  138. pyvale/simcases/case21.i +155 -0
  139. pyvale/simcases/case22.geo +82 -0
  140. pyvale/simcases/case22.i +140 -0
  141. pyvale/simcases/case23.geo +164 -0
  142. pyvale/simcases/case23.i +140 -0
  143. pyvale/simcases/case24.geo +79 -0
  144. pyvale/simcases/case24.i +123 -0
  145. pyvale/simcases/case25.geo +82 -0
  146. pyvale/simcases/case25.i +140 -0
  147. pyvale/simcases/case26.geo +166 -0
  148. pyvale/simcases/case26.i +140 -0
  149. pyvale/simcases/run_1case.py +61 -0
  150. pyvale/simcases/run_all_cases.py +69 -0
  151. pyvale/simcases/run_build_case.py +64 -0
  152. pyvale/simcases/run_example_cases.py +69 -0
  153. pyvale-2025.4.0.dist-info/METADATA +140 -0
  154. pyvale-2025.4.0.dist-info/RECORD +157 -0
  155. pyvale-2025.4.0.dist-info/WHEEL +5 -0
  156. pyvale-2025.4.0.dist-info/licenses/LICENSE +21 -0
  157. pyvale-2025.4.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,215 @@
1
+ """
2
+ ================================================================================
3
+ pyvale: the python validation engine
4
+ License: MIT
5
+ Copyright (C) 2025 The Computer Aided Validation Team
6
+ ================================================================================
7
+ """
8
+ import numpy as np
9
+ import pyvista as pv
10
+ from scipy.spatial.transform import Rotation
11
+ import mooseherder as mh
12
+
13
+ from pyvale.core.field import IField
14
+ from pyvale.core.fieldconverter import simdata_to_pyvista
15
+ from pyvale.core.fieldsampler import sample_pyvista_grid
16
+ from pyvale.core.fieldtransform import (transform_vector_2d,
17
+ transform_vector_2d_batch,
18
+ transform_vector_3d,
19
+ transform_vector_3d_batch)
20
+
21
+ class FieldVector(IField):
22
+ """Class for sampling (interpolating) vector fields from simulations to
23
+ provide sensor values at specified locations and times.
24
+
25
+ Implements the `IField` interface.
26
+ """
27
+ __slots__ = ("_field_key","_components","_spat_dims","_sim_data",
28
+ "_pyvista_grid","_pyvista_vis")
29
+
30
+ def __init__(self,
31
+ sim_data: mh.SimData,
32
+ field_key: str,
33
+ components: tuple[str,...],
34
+ spat_dims: int) -> None:
35
+ """Initialiser for the `FieldVector` class.
36
+
37
+ Parameters
38
+ ----------
39
+ sim_data : mh.SimData
40
+ Simulation data object containing the mesh and field to interpolate.
41
+ field_key : str
42
+ String describing the vector field. For example: 'disp'.
43
+ components : tuple[str,...]
44
+ String keys to the field components in the `SimData` object. For
45
+ example ('disp_x','disp_y').
46
+ spat_dims : int
47
+ Number of spatial dimensions (2 or 3) used for identifying element
48
+ types.
49
+ """
50
+ self._field_key = field_key
51
+ self._components = components
52
+ self._spat_dims = spat_dims
53
+
54
+ self._sim_data = sim_data
55
+ (self._pyvista_grid,self._pyvista_vis) = simdata_to_pyvista(
56
+ self._sim_data,
57
+ self._components,
58
+ self._spat_dims
59
+ )
60
+
61
+ def set_sim_data(self, sim_data: mh.SimData) -> None:
62
+ """Sets the `SimData` object that will be interpolated to obtain sensor
63
+ values. The purpose of this is to be able to apply the same sensor array
64
+ to an array of different simulations by setting a different `SimData`.
65
+
66
+ Parameters
67
+ ----------
68
+ sim_data : mh.SimData
69
+ Mooseherder SimData object. Contains a mesh and a simulated
70
+ physical field.
71
+ """
72
+ self._sim_data = sim_data
73
+ (self._pyvista_grid,self._pyvista_vis) = simdata_to_pyvista(
74
+ sim_data,
75
+ self._components,
76
+ self._spat_dims
77
+ )
78
+
79
+ def get_sim_data(self) -> mh.SimData:
80
+ """Gets the simulation data object associated with this field. Used by
81
+ pyvale visualisation tools to display simulation data with simulated
82
+ sensor values.
83
+
84
+ Returns
85
+ -------
86
+ mh.SimData
87
+ Mooseherder SimData object. Contains a mesh and a simulated
88
+ physical field.
89
+ """
90
+ return self._sim_data
91
+
92
+ def get_time_steps(self) -> np.ndarray:
93
+ """Gets a 1D array of time steps from the simulation data.
94
+
95
+ Returns
96
+ -------
97
+ np.ndarray
98
+ 1D array of simulation time steps. shape=(num_time_steps,)
99
+ """
100
+ return self._sim_data.time
101
+
102
+ def get_visualiser(self) -> pv.UnstructuredGrid:
103
+ """Gets a pyvista unstructured grid object for visualisation purposes.
104
+
105
+ Returns
106
+ -------
107
+ pv.UnstructuredGrid
108
+ Pyvista unstructured grid object containing only a mesh without any
109
+ physical field data attached.
110
+ """
111
+ return self._pyvista_vis
112
+
113
+ def get_all_components(self) -> tuple[str, ...]:
114
+ """Gets the string keys for the component of the physical field. For
115
+ example: a vector field might have ('disp_x','disp_y','disp_z') in 3D
116
+ and just ('disp_x','disp_y') in 2D.
117
+
118
+ Returns
119
+ -------
120
+ tuple[str,...]
121
+ Tuple containing the string keys for all components of the physical
122
+ field.
123
+ """
124
+ return self._components
125
+
126
+ def get_component_index(self,comp: str) -> int:
127
+ """Gets the index for a component of the physical field. Used for
128
+ getting the index of a component in the sensor measurement array.
129
+
130
+ Parameters
131
+ ----------
132
+ component : str
133
+ String key for the field component (e.g. 'temperature' or 'disp_x').
134
+
135
+ Returns
136
+ -------
137
+ int
138
+ Index for the selected field component
139
+ """
140
+ return self._components.index(comp)
141
+
142
+ def sample_field(self,
143
+ points: np.ndarray,
144
+ times: np.ndarray | None = None,
145
+ angles: tuple[Rotation,...] | None = None,
146
+ ) -> np.ndarray:
147
+ """Samples (interpolates) the simulation field at the specified
148
+ positions, times, and angles.
149
+
150
+ Parameters
151
+ ----------
152
+ points : np.ndarray
153
+ Spatial points to be sampled with the rows indicating the point
154
+ number of the columns indicating the X,Y and Z coordinates.
155
+ times : np.ndarray | None, optional
156
+ Times to sample the underlying simulation. If None then the
157
+ simulation time steps are used and no temporal interpolation is
158
+ performed, by default None.
159
+ angles : tuple[Rotation,...] | None, optional
160
+ Angles to rotate the sampled values into with rotations specified
161
+ with respect to the simulation world coordinates. If a single
162
+ rotation is specified then all points are assumed to have the same
163
+ angle and are batch processed for speed. If None then no rotation is
164
+ performed, by default None.
165
+
166
+ Returns
167
+ -------
168
+ np.ndarray
169
+ An array of sampled (interpolated) values with the following
170
+ dimensions: shape=(num_points,num_components,num_time_steps).
171
+ """
172
+
173
+ field_data = sample_pyvista_grid(self._components,
174
+ self._pyvista_grid,
175
+ self._sim_data.time,
176
+ points,
177
+ times)
178
+
179
+ if angles is None:
180
+ return field_data
181
+
182
+ # NOTE:
183
+ # ROTATION= object rotates with coords fixed
184
+ # For Z rotation: sin negative in row 1.
185
+ # TRANSFORMATION= coords rotate with object fixed
186
+ # For Z transformation: sin negative in row 2, transpose scipy mat.
187
+
188
+ # If we only have one angle we assume all sensors have the same angle
189
+ # and we can batch process the rotations
190
+ if len(angles) == 1:
191
+ rmat = angles[0].as_matrix().T
192
+
193
+ #TODO: assumes 2D in the x-y plane
194
+ if self._spat_dims == 2:
195
+ rmat = rmat[:2,:2]
196
+ field_data = transform_vector_2d_batch(rmat,field_data)
197
+ else:
198
+ field_data = transform_vector_3d_batch(rmat,field_data)
199
+
200
+ else: # Need to rotate each sensor using individual rotation = loop :(
201
+ #TODO: assumes 2D in the x-y plane
202
+ if self._spat_dims == 2:
203
+ for ii,rr in enumerate(angles):
204
+ rmat = rr.as_matrix().T
205
+ rmat = rmat[:2,:2]
206
+ field_data[ii,:,:] = transform_vector_2d(rmat,field_data[ii,:,:])
207
+
208
+ else:
209
+ for ii,rr in enumerate(angles):
210
+ rmat = rr.as_matrix().T
211
+ field_data[ii,:,:] = transform_vector_3d(rmat,field_data[ii,:,:])
212
+
213
+ #field_data[ii,:,:] = np.matmul(rmat,field_data[ii,:,:])
214
+ return field_data
215
+