from __future__ import annotations
import os
from typing import TYPE_CHECKING
import dolfinx as df
import numpy as np
if TYPE_CHECKING:
from fenicsxconcrete.finite_element_problem.base_material import MaterialProblem
from fenicsxconcrete.sensor_definition.base_sensor import PointSensor
from fenicsxconcrete.util import ureg
[docs]
class DisplacementSensor(PointSensor):
"""A sensor that measures displacement at a specific point
Attributes:
data: list of measured values
time: list of time stamps
units : pint definition of the base unit a sensor returns
name : name of the sensor, default is class name, but can be changed
where: location where the value is measured
"""
# Type hints don't work here because they create a circular import :(
[docs]
def measure(self, problem: MaterialProblem) -> None:
"""
The displacement value at the defined point is added to the data list,
as well as the time t to the time list
Arguments:
problem : FEM problem object
t : time of measurement for time dependent problems, default is 1
"""
# get displacements
bb_tree = df.geometry.bb_tree(problem.experiment.mesh, problem.experiment.mesh.topology.dim)
cells = []
# Find cells whose bounding-box collide with the points
point = np.array(self.where, dtype=np.float64)
cell_candidates = df.geometry.compute_collisions_points(bb_tree, point)
# Choose one of the cells that contains the point
colliding_cells = df.geometry.compute_colliding_cells(problem.experiment.mesh, cell_candidates, point)
# for i, point in enumerate(self.where):
if len(colliding_cells.links(0)) > 0:
cells.append(colliding_cells.links(0)[0])
else:
raise ValueError(f"cells with point {self.where} not found in mesh")
# adding correct units to displacement
displacement_data = problem.fields.displacement.eval([self.where], cells)
self.data.append(displacement_data)
self.time.append(problem.time)
[docs]
@staticmethod
def base_unit() -> ureg:
"""Defines the base unit of this sensor
Returns:
the base unit as pint unit object
"""
return ureg.meter