Coverage for src/methodsnm/fes.py: 55%
175 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.fe_1d import *
5from methodsnm.fe_2d import *
7class FESpace(ABC):
8 """
9 Abstract base class for finite element spaces.
10 """
11 ndof = None
12 mesh = None
13 def __init__(self, mesh):
14 pass
16 @abstractmethod
17 def _finite_element(self, elnr):
18 raise Exception("Not implemented - Base class should not be used")
20 @abstractmethod
21 def _element_dofs(self, elnr):
22 raise Exception("Not implemented - Base class should not be used")
24 def _bndry_finite_element(self, elnr):
25 raise Exception("_bndry_finite_element not implemented - Base class should not be used")
27 def _bndry_element_dofs(self, elnr):
28 raise Exception("_bndry_element_dofs not implemented - Base class should not be used")
30 def finite_element(self, elnr, bndry=False):
31 """
32 Returns the finite element for the given element number.
33 """
34 if bndry:
35 return self._bndry_finite_element(elnr)
36 else:
37 return self._finite_element(elnr)
39 def element_dofs(self, elnr, bndry=False):
40 """
41 Returns the dofs for the given element number.
42 """
43 if bndry:
44 return self._bndry_element_dofs(elnr)
45 else:
46 return self._element_dofs(elnr)
48class VertexFirstSpace_1D(FESpace):
49 def __init__(self, mesh):
50 self.sfe = Node_FE()
51 self.mesh = mesh
53 def _bndry_element_dofs(self, bndry_elnr):
54 return self.mesh.elements(bndry=True)[bndry_elnr]
56 def _bndry_finite_element(self, bndry_elnr):
57 return self.sfe
59class P1_Segments_Space(VertexFirstSpace_1D):
61 def __init__(self, mesh, periodic=False):
62 super().__init__(mesh)
63 self.periodic = periodic
64 if periodic:
65 self.ndof = len(mesh.points) - 1
66 else:
67 self.ndof = len(mesh.points)
68 self.fe = P1_Segment_FE()
70 def _finite_element(self, elnr):
71 return self.fe
73 def _element_dofs(self, elnr):
74 dofs = self.mesh.edges[elnr]
75 if self.periodic and elnr == len(self.mesh.edges) - 1:
76 return [dofs[0],0]
77 else:
78 return dofs
80 def _bndry_element_dofs(self, bndry_elnr):
81 dofs = self.mesh.elements(bndry=True)[bndry_elnr]
82 if self.periodic:
83 return [0]
84 else:
85 return dofs
87class P1disc_Segments_Space(FESpace):
89 def __init__(self, mesh):
90 self.ndof = 2*len(mesh.edges)
91 self.mesh = mesh
92 self.fe = P1_Segment_FE()
94 def _finite_element(self, elnr):
95 return self.fe
97 def _element_dofs(self, elnr):
98 return [2*elnr, 2*elnr+1]
100 def _bndry_finite_element(self, bndry_elnr):
101 raise Exception("No boundary evaluation for Discontinuous elements")
103 def _bndry_element_dofs(self, bndry_elnr):
104 raise Exception("No boundary evaluation for Discontinuous elements")
106class Lagrange_Segments_Space(VertexFirstSpace_1D):
108 def __init__(self, mesh, order=1):
109 super().__init__(mesh)
110 self.nv = len(mesh.points)
111 self.ne = len(mesh.edges)
112 self.order = order
113 self.ndof = self.nv + self.ne*(order-1)
114 self.fe=Lagrange_Segment_FE(order=self.order)
116 def _finite_element(self, elnr):
117 return self.fe
119 def _element_dofs(self, elnr):
120 offset = self.nv + elnr*(self.order-1)
121 dofs = [self.mesh.edges[elnr][0]] + [offset + i for i in range(0,self.order-1)] + [self.mesh.edges[elnr][1]]
122 return dofs
126class Pk_IntLeg_Segments_Space(VertexFirstSpace_1D):
128 def __init__(self, mesh, order=1):
129 super().__init__(mesh)
130 self.nv = len(mesh.points)
131 self.ne = len(mesh.edges)
132 self.order = order
133 self.ndof = self.nv + self.ne*(order-1)
134 self.fe=IntegratedLegendre_Segment_FE(order=self.order)
136 def _finite_element(self, elnr):
137 return self.fe
139 def _element_dofs(self, elnr):
140 offset = self.nv + elnr*(self.order-1)
141 dofs = [self.mesh.edges[elnr][0]] + [self.mesh.edges[elnr][1]] + [offset + i for i in range(0,self.order-1)]
142 return dofs
146class P1_Triangle_Space(FESpace):
148 def __init__(self, mesh):
149 self.ndof = len(mesh.points)
150 self.mesh = mesh
151 self.fe = P1_Triangle_FE()
152 self.sfe = P1_Segment_FE()
154 def _finite_element(self, elnr):
155 return self.fe
157 def _bndry_finite_element(self, bndry_elnr):
158 return self.sfe
160 def _element_dofs(self, elnr):
161 return self.mesh.elements()[elnr]
163 def _bndry_element_dofs(self, bndry_elnr):
164 return self.mesh.elements(bndry=True)[bndry_elnr]
167class P2_Triangle_Space(FESpace):
169 def __init__(self, mesh):
170 self.ndof = len(mesh.points) + len(mesh.edges)
171 self.nv = len(mesh.points)
172 self.mesh = mesh
173 self.fe = P2_Triangle_FE()
174 self.sfe = Lagrange_Segment_FE(order=2)
176 def _finite_element(self, elnr):
177 return self.fe
179 def _bndry_finite_element(self, bndry_elnr):
180 return self.sfe
182 def _element_dofs(self, elnr):
183 return np.append(self.mesh.elements()[elnr], [self.nv + i for i in self.mesh.faces2edges[elnr]])
185 def _bndry_element_dofs(self, bndry_elnr):
186 verts = self.mesh.elements(bndry=True)[bndry_elnr]
187 edge = self.mesh.bndry_edges[bndry_elnr]
188 return [verts[0], self.nv + edge, verts[1]]
190class P3_Triangle_Space(FESpace):
192 def __init__(self, mesh):
193 self.ndof = len(mesh.points) + 2 * len(mesh.edges) + len(mesh.faces)
194 self.nv = len(mesh.points)
195 self.ned = len(mesh.edges)
196 self.nf = len(mesh.faces)
197 self.mesh = mesh
198 self.fe = P3_Triangle_FE()
199 self.sfe = Lagrange_Segment_FE(order=3)
201 def _finite_element(self, elnr):
202 return self.fe
204 def _element_dofs(self, elnr):
205 dofs = np.empty(10, dtype=int)
206 vnums = self.mesh.elements()[elnr]
207 dofs[0:3] = vnums
208 j = 3
209 enums = self.mesh.faces2edges[elnr]
210 ref_verts_list = [[1,2],[0,2],[0,1]]
211 for ref_edge, edge in enumerate(enums):
212 tverts = vnums[ref_verts_list[ref_edge]]
213 if (tverts[0] < tverts[1]):
214 dofs[j] = self.nv + 2*edge + 0
215 j += 1
216 dofs[j] = self.nv + 2*edge + 1
217 j += 1
218 else:
219 dofs[j] = self.nv + 2*edge + 1
220 j += 1
221 dofs[j] = self.nv + 2*edge + 0
222 j += 1
223 dofs[9] = self.nv + 2 * self.ned + elnr
224 return dofs
226 def _bndry_finite_element(self, bndry_elnr):
227 return self.sfe
229 def _bndry_element_dofs(self, bndry_elnr):
230 verts = self.mesh.elements(bndry=True)[bndry_elnr]
231 edge = self.mesh.bndry_edges[bndry_elnr]
232 return [verts[0], self.nv + 2 * edge, self.nv + 2 * edge + 1, verts[1]]
235class P1Edge_Triangle_Space(FESpace):
237 def __init__(self, mesh):
238 self.ndof = len(mesh.edges)
239 self.mesh = mesh
240 self.fe = P1Edge_Triangle_FE()
242 def _finite_element(self, elnr):
243 return self.fe
245 def _element_dofs(self, elnr):
246 edges = self.mesh.faces2edges[elnr]
247 return edges