Coverage for src/methodsnm/fe.py: 83%
52 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-27 13:22 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-27 13:22 +0000
1from abc import ABC, abstractmethod
2import numpy as np
3from numpy import array
4from methodsnm.diff import AD
6class FE(ABC):
7 """
8 This is the base class for all **scalar** finite element classes.
9 It provides a template for the evaluate method.
10 """
11 ndof = None # number of degrees of freedom
12 order = None # polynomial order
13 eltype = None # e.g. "segment", "triangle", ...
14 dim = None # dimension of the domain
15 def __init__(self):
16 pass
18 @abstractmethod
19 def _evaluate_id(self, ip):
20 """
21 Evaluates the finite element at the given integration point.
23 Parameters:
24 ip (numpy.array): The integration point at which to evaluate the finite element.
26 Returns:
27 numpy.array: The values of the finite element basis fcts. at the given integration point.
28 """
29 raise Exception("Not implemented - Base class should not be used")
31 def _evaluate_id_array(self, ips):
32 """
33 Evaluates the finite element at multiple integration points at once.
34 Base class implementation is a simple loop over the integration points.
35 Performance gains can only be obtained by overwriting this method.
37 Parameters:
38 ips (numpy.array): The integration point at which to evaluate the finite element.
40 Returns:
41 numpy.ndarray: The values of the finite element at the given integration points.
42 shape: (len(ips), ndof)
43 """
44 ret = np.empty((len(ips), self.ndof ))
45 for i in range(len(ips)):
46 ret[i,:] = self._evaluate_id(ips[i])
47 return ret
49 def _evaluate_deriv_array(self, ips):
50 """
51 Evaluates the derivative of finite element at multiple integration points at once.
52 Base class implementation is a simple loop over the integration points.
53 Performance gains can only be obtained by overwriting this method.
55 Parameters:
56 ips (numpy.array): The integration point at which to evaluate the finite element.
58 Returns:
59 numpy.ndarray: The values of the finite element at the given integration points.
60 shape: (len(ips), dim, ndof)
61 """
62 ret = np.empty((len(ips), self.dim, self.ndof))
63 for i in range(len(ips)):
64 ret[i,:,:] = self._evaluate_deriv(ips[i])
65 return ret
67 @abstractmethod
68 def _evaluate_deriv(self, ip) -> np.ndarray:
69 """
70 Evaluates the derivative of a finite element at the given integration point.
72 Parameters:
73 ip (numpy.array): The integration point at which to evaluate the finite element.
75 Returns:
76 numpy.array: The values of the derivative of the finite element basis fcts. at the given integration point.
77 shape (dim, ndof)
78 """
79 raise Exception("Not implemented - Base class should not be used")
81 def evaluate(self, ip, deriv=False):
82 """
83 Evaluates the (derivative of) finite element at given integration point(s).
85 Parameters:
86 ip (numpy.array): The integration point(s) at which to evaluate the finite element.
87 deriv (bool): Whether to evaluate the derivative of the finite element (or identity).
89 Returns:
90 numpy.array: The values of the finite element basis fcts. at the given integration point.
91 shape: (ndof) (for single ip)
92 or (dim, ndof) (for single ip and deriv = True)
93 or (len(ip), ndof) (for multiple ips)
94 or (len(ip), dim, ndof) (for multiple ips and deriv = True)
95 """
96 if isinstance(ip, np.ndarray):
97 if ip.ndim == 1:
98 if deriv:
99 return self._evaluate_deriv(ip)
100 else:
101 return self._evaluate_id(ip)
102 else:
103 if deriv:
104 return self._evaluate_deriv_array(ip)
105 else:
106 return self._evaluate_id_array(ip)
107 else:
108 raise Exception("Invalid input")
112class Lagrange_FE(FE):
113 """
114 This class represents a Lagrange finite element.
115 A Lagrange finite element associates the dofs with the nodes of the element.
116 """
117 nodes = None
119 def __str__(self):
120 return f"Lagrange-FE-obj(order={self.order},nodes={self.ndof})"
124class Node_FE(FE):
125 """
126 FE for a point (node).
127 """
129 def __init__(self):
130 self.eltype = "point"
131 self.dim = 0
132 self.ndof = 1
134 def _evaluate_id(self, ip):
135 return np.ones((1,))
137 def _evaluate_id_array(self, ip):
138 return np.ones((len(ip),1))
140 def _evaluate_deriv(self, ip):
141 raise Exception("Derivative of node FE should not be called")