We (or I) need an interface for gradient-enhanced models. I did some calculations, and I think it does not matter so much if we do gradient-plasticity or gradient damage. In the end, we have a local variable $\alpha$ and its nonlocal counterpart $\bar\alpha$ which is the solution of the PDE
$$
l^{2}\nabla^{2}\bar{\alpha}+\alpha-\bar{\alpha}=0.
$$
For quasi-static calculations, we then need the tangents
$$
\frac{\partial\sigma}{\partial\varepsilon},\quad \frac{\partial\sigma}{\partial\bar\alpha}, \quad \frac{\partial\alpha}{\partial\varepsilon},\quad \frac{\partial\alpha}{\partial\bar\alpha}.
$$
For dynamic simulations, the underlying PDE is
$$
l^{2}\nabla^{2}\bar{\alpha}+\alpha-\bar{\alpha}-\gamma\dot{\bar{\alpha}}=\zeta\ddot{\bar{\alpha}}.
$$
for which we do not need any of these tangents if we use an explicit solver.
The proposed interface should therefore have the tangents as optional parameters:
class IncrSmallStrainNonlocalModel(ABC):
"""
Interface for incremental small strain models.
"""
@abstractmethod
def evaluate(
self,
t: float,
del_t: float,
grad_del_u: np.ndarray,
nonlocal_quantity: np.ndarray, #NEW parameter
stress: np.ndarray,
local_quantity: np.ndarray, #NEW parameter
dsigma_deps: np.ndarray | None, #NEW parameter
dsigma_dnonlocal: np.ndarray | None, #NEW parameter
dlocal_deps: np.ndarray | None, #NEW parameter
dlocal_dnonlocal: np.ndarray | None, #NEW parameter
history: dict[str, np.ndarray] | None,
) -> None:
Or as a tuple
class IncrSmallStrainNonlocalModel(ABC):
"""
Interface for incremental small strain models.
"""
@abstractmethod
def evaluate(
self,
t: float,
del_t: float,
grad_del_u: np.ndarray,
nonlocal_quantity: np.ndarray, #NEW parameter
stress: np.ndarray,
local_quantity: np.ndarray, #NEW parameter
tangents: tuple[np.ndarray] | None, #NEW parameter
history: dict[str, np.ndarray] | None,
) -> None:
The first design could be annoying because we only want to handle the case where all tangents are either something or none. In the second approach, it is not obvious from the interface alone what the input for tangents is, but it should be somewhat easier to handle the two cases.
Another option could be a named tuple or a dataclass as input for the model
@dataclass
class NonlocalTangents:
dsigma_deps: np.ndarray
dsigma_dnonlocal: np.ndarray
dlocal_deps: np.ndarray
dlocal_dnonlocal: np.ndarray
class IncrSmallStrainNonlocalModel(ABC):
"""
Interface for incremental small strain models.
"""
@abstractmethod
def evaluate(
self,
t: float,
del_t: float,
grad_del_u: np.ndarray,
nonlocal_quantity: np.ndarray, #NEW parameter
stress: np.ndarray,
local_quantity: np.ndarray, #NEW parameter
tangents: NonlocalTangents | None, #NEW parameter
history: dict[str, np.ndarray] | None,
) -> None:
We (or I) need an interface for gradient-enhanced models. I did some calculations, and I think it does not matter so much if we do gradient-plasticity or gradient damage. In the end, we have a local variable$\alpha$ and its nonlocal counterpart $\bar\alpha$ which is the solution of the PDE
For quasi-static calculations, we then need the tangents
For dynamic simulations, the underlying PDE is
for which we do not need any of these tangents if we use an explicit solver.
The proposed interface should therefore have the tangents as optional parameters:
Or as a tuple
The first design could be annoying because we only want to handle the case where all tangents are either something or none. In the second approach, it is not obvious from the interface alone what the input for tangents is, but it should be somewhat easier to handle the two cases.
Another option could be a named tuple or a dataclass as input for the model