Source code for pyvale.sensorsim.fieldscalar

# ==============================================================================
# pyvale: the python validation engine
# License: MIT
# Copyright (C) 2025 The Computer Aided Validation Team
# ==============================================================================

import numpy as np
import pyvista as pv
from scipy.spatial.transform import Rotation
import pyvale.mooseherder as mh

from pyvale.sensorsim.field import IField
from pyvale.sensorsim.fieldconverter import simdata_to_pyvista_vis
from pyvale.sensorsim.fieldinterpmesh import FieldInterpMesh
from pyvale.sensorsim.fieldinterppoints import FieldInterpPoints
from pyvale.sensorsim.enums import EDim

[docs] class FieldScalar(IField): """Class for sampling (interpolating) scalar fields from simulations to provide sensor values at specified locations and times. Supports interpolation of mesh-based data (with a connectivity table) and point clouds. Implements the `IField` interface. """ __slots__ = ("_comp_key","_spatial_dims","_sim_data","_interpolator", "_visualiser")
[docs] def __init__(self, sim_data: mh.SimData, comp_key: str, spatial_dims: EDim) -> None: """ Parameters ---------- sim_data : mh.SimData Simulation data object containing the mesh and field to interpolate. comp_key : str String key for the scalar field component in the `SimData` nodal variables dictionary. spatial_dims : EDim Number of spatial dimensions (TWOD or THREED) used for identifying element types. If point cloud data then set to the number of dimensions of the problem as 2D triangulation is much faster than 3D. """ self._comp_key = comp_key self._spatial_dims = spatial_dims # NOTE: these get set in the function call to `set_sim_data` - this is # separated out to allow inserting a new simdata object self._sim_data = None self._visualiser = None self._interpolator = None self.set_sim_data(sim_data)
[docs] def set_sim_data(self, sim_data: mh.SimData) -> None: self._sim_data = sim_data self._visualiser = simdata_to_pyvista_vis(sim_data, self._spatial_dims) if self._sim_data.connect is None: self._interpolator = FieldInterpPoints(self._sim_data, (self._comp_key,), self._spatial_dims) else: self._interpolator = FieldInterpMesh(self._sim_data, (self._comp_key,), self._spatial_dims)
[docs] def get_sim_data(self) -> mh.SimData: return self._sim_data
[docs] def get_time_steps(self) -> np.ndarray: return self._sim_data.time
[docs] def get_visualiser(self) -> pv.UnstructuredGrid: return self._visualiser
[docs] def get_all_components(self) -> tuple[str, ...]: return (self._comp_key,)
[docs] def get_component_index(self, comp_key: str) -> int: return 0 # scalar fields only have one component!
[docs] def sample_field(self, points: np.ndarray, times: np.ndarray | None = None, angles: tuple[Rotation,...] | None = None, ) -> np.ndarray: return self._interpolator.interp_field(points,times)