Source code for EasyFEA.fem._boundary_conditions

# Copyright (C) 2021-2025 Université Gustave Eiffel.
# This file is part of the EasyFEA project.
# EasyFEA is distributed under the terms of the GNU General Public License v3, see LICENSE.txt and CREDITS.md for more information.

"""Module containing classes used to create boundary conditions."""

import numpy as np

from ..utilities import _types


[docs] class BoundaryCondition: def __init__( self, problemType: str, nodes: _types.IntArray, dofs: _types.IntArray, unknowns: list[str], dofsValues: _types.FloatArray, description: str, ): """Creates a boundary condition object. Parameters ---------- problemType : str Problem type. nodes : _types.IntArray Nodes on which the condition is applied. dofs : _types.IntArray Degrees of freedom (associated with nodes and unknowns). unknowns : list[str] Dofs unknowns (e.g. [“x”, “y”], [“rz”]). dofsValues : _types.FloatArray Dofs values. description : str Description of the boundary condition. """ self.__problemType = problemType self.__unknowns = unknowns self.__nodes = np.asarray(nodes, dtype=int) self.__dofs = np.asarray(dofs, dtype=int) assert ( self.dofs.size % self.nodes.size == 0 ), f"dofs.size must be a multiple of {self.nodes.size}" self.__dofsValues = np.asarray(dofsValues, dtype=float) # assert dofs.size == dofsValues.size, "must be the same size." don't uncomment ! # This assertion is commented out to illustrate that using Lagrange conditions might bypass this size check. self.description = description @property def problemType(self) -> str: """type of problem""" return self.__problemType @property def nodes(self) -> _types.IntArray: """nodes on which the condition is applied""" return self.__nodes.copy() @property def dofs(self) -> _types.IntArray: """degrees of freedom associated with the nodes and unknowns""" return self.__dofs.copy() @property def dofsValues(self) -> _types.FloatArray: """values applied""" return self.__dofsValues.copy() @property def unknowns(self) -> list[str]: """dofs unknowns""" return self.__unknowns.copy()
[docs] @staticmethod def Get_nBc(problemType: str, list_Bc_Condition: list["BoundaryCondition"]) -> int: """Returns the number of conditions for the problem type. Parameters ---------- problemType : str Problem type. list_Bc_Condition : list[BoundaryCondition] List of boundary conditions. Returns ------- int Number of boundary conditions (nBc). """ return len([1 for bc in list_Bc_Condition if bc.problemType == problemType])
[docs] @staticmethod def Get_dofs( problemType: str, list_Bc_Condition: list["BoundaryCondition"] ) -> _types.IntArray: """Returns the degrees of freedom for the problem type. Parameters ---------- problemType : str Problem type. list_Bc_Condition : list[BoundaryCondition] List of boundary conditions. Returns ------- _types.IntArray degrees of freedom. """ dofs: list[int] = [] [ dofs.extend(bc.dofs) # type: ignore [func-returns-value] for bc in list_Bc_Condition if bc.problemType == problemType ] return np.asarray(dofs, dtype=int)
[docs] @staticmethod def Get_values( problemType: str, list_Bc_Condition: list["BoundaryCondition"] ) -> _types.FloatArray: """Returns the dofs values for problem type. Parameters ---------- problemType : str Problem type. list_Bc_Condition : list[BoundaryCondition] List of boundary condition. Returns ------- _types.FloatArray dofs values. """ values: list[float] = [] [ values.extend(bc.dofsValues) # type: ignore [func-returns-value] for bc in list_Bc_Condition if bc.problemType == problemType ] return np.asarray(values, dtype=float)
[docs] @staticmethod def Get_dofs_nodes( availableUnknowns: list[str], nodes: _types.IntArray, unknowns: list[str] ) -> _types.IntArray: """Retrieves degrees of freedom (dofs) associated with the nodes. Parameters ---------- availableUnknowns : list[str] Available dofs as a list of strings. Must be a unique string list. nodes : _types.IntArray Nodes for which dofs are calculated. unknowns : list[str] unknowns. Returns ------- _types.IntArray degrees of freedom. """ nodes = np.asarray(nodes, dtype=int).ravel() dim = len(availableUnknowns) nDir = len(unknowns) dofs_d = np.zeros((nodes.size, nDir), dtype=int) for d, direction in enumerate(unknowns): if direction not in availableUnknowns: from EasyFEA import Display Display.MyPrintError( f"direction ({direction}) must be in {availableUnknowns}." ) continue idx = availableUnknowns.index(direction) dofs_d[:, d] = nodes * dim + idx return dofs_d.ravel()
[docs] class LagrangeCondition(BoundaryCondition): def __init__( self, problemType: str, nodes: _types.IntArray, dofs: _types.IntArray, unknowns: list[str], dofsValues: _types.FloatArray, lagrangeCoefs: _types.FloatArray, description: str = "", ): """Creates a Lagrange condition (based on a boundary condition). Parameters ---------- problemType : str Problem type. nodes : _types.IntArray Nodes on which the condition is applied. dofs : _types.IntArray Degrees of freedom (associated with nodes and unknowns). unknowns : list[str] Dofs unknowns. dofsValues : _types.FloatArray Dofs values. lagrangeCoefs : _types.FloatArray Lagrange coefficients. description : str, optional Description of the Lagrange condition, by default "". """ super().__init__(problemType, nodes, dofs, unknowns, dofsValues, description) self.__lagrangeCoefs = np.asarray(lagrangeCoefs) @property def lagrangeCoefs(self) -> _types.FloatArray: """Lagrange coefficients.""" return self.__lagrangeCoefs.copy()