Source code for pyfem.models.Contact

# SPDX-License-Identifier: MIT
# Copyright (c) 2011–2026 Joris J.C. Remmers

import numpy as np
from numpy import append,repeat
from pyfem.models.BaseModel import BaseModel

#===============================================================================
#
#===============================================================================

[docs] class Contact(BaseModel): """ Contact model for enforcing contact constraints in finite element simulations. Attributes: flag (bool): Indicates if contact is active. dispDofs (list[str]): Displacement DOF names. centre (np.ndarray): Centre of the contact surface. direction (np.ndarray): Contact movement direction. radius (float): Contact surface radius. penalty (float): Penalty parameter for contact enforcement. """ def __init__(self, props: object, globdat: object) -> None: """ Initialize a Contact model instance with given properties and global data. Args: props: Model-specific properties (should include centre, radius, penalty, direction, type). globdat: Global data/state object. """ BaseModel.__init__(self, props, globdat) self.flag = False self.dispDofs = ["u", "v"] self.centre = [1., 1.] self.direction = [0.0, 0.0] self.radius = 10. self.penalty = 1.e6 if self.type == "sphere": self.dispDofs = ["u", "v", "w"] self.flag = True self.centre = np.array(props.centre) self.radius = props.radius self.penalty = props.penalty self.direction = np.array(props.direction) #------------------------------------------------------------------------------- # checkContact (with flag) #-------------------------------------------------------------------------------
[docs] def getTangentStiffness(self, props: object, globdat: object ) -> None: """ Compute and assemble the contact tangent stiffness matrix contribution. Args: props: Global properties object. globdat: Global data/state object. """ mbuilder = globdat.mbuilder centre = self.centre + globdat.lam * self.direction for nodeID in list(globdat.nodes.keys()): crd = globdat.nodes.getNodeCoords(nodeID) idofs = globdat.dofs.getForTypes([nodeID], self.dispDofs) crd += globdat.state[idofs] ds = crd - centre dsnorm = np.linalg.norm(ds) overlap = self.radius - dsnorm if overlap > 0: normal = ds / dsnorm mbuilder.B[idofs] += -self.penalty * overlap * normal mat = self.penalty * np.outer(normal, normal) mbuilder.append(mat, idofs)