Peano
Loading...
Searching...
No Matches
DGPoisson2dBlockMatrix.py
Go to the documentation of this file.
1# from .block_matrix import BlockMatrix
2# from .nodal_basis import NodalBasisGaussLegendre
3# from .finiteelement import DGScalarElement, DGFacetElement
4# from .quadrature import GaussianQuadrature, Quadrature2d
5# import numpy as np
6
7from .BlockMatrix import BlockMatrix
8from .nodal_basis import NodalBasisGaussLegendre
9from .finiteelement import DGScalarElement, DGFacetElement
10from .quadrature import GaussianQuadrature, Quadrature2d
11#from ..MatrixGenerator import MatrixGenerator
12import numpy as np
13
15 """Classical DG discretisation of 2d classical Poisson formulation with spurious facet function spaces
16
17 Order of function spaces (used in the output dictionaries):
18 0 | 0 1 2
19 p | q^+ q^- q^f
20 """
21
22 def __init__(self, r_press, basis=NodalBasisGaussLegendre(2)):
23 """Initialise instance
24 :arg r_press: polynomial degree of pressure space
25 :arg r_vel: polynomial degree of velocity
26 :arg basis: nodal basis
27 """
28 dim = 2
29 super().__init__(dim, basis)
30 self.basis = basis
31 self._L_C_L_C = [r_press]
32 self._L_F_L_F = 3 * [r_press]
34 self._fs_labels_F_fs_labels_F = ["q+", "q-", "qf"] # projections of the normal derivative onto facets and "flux"
35
36 # All pairs of function spaces that couple
37 self._coupling_CC = [(0, 0)] # _p_p
38
39 self._coupling_CF = [(0, 2)] # _p_qf
40
41 self._coupling_FC = [(0, 0), # _q+_p
42 (1, 0) # _q-_p
43 ]
44
45 self._coupling_FF = [(0, 0), # _q+_q+
46 (1, 1), # _q-_q-
47 (2, 0), # _qf_q+
48 (2, 1), # _qf_q-
49 (2, 2) # _qf_qf
50 ]
51
52 # Lists of entity types
53 self._ent_types_CF_FC = ["left", "right", "bottom", "top"] # ! All the facet integrals will be now assembled for the left facet only !
54 self._ent_types_FF = self._ent_types_CF_FC # ! All the facet integrals will be now assembled for the left facet only !
55 #self._ent_types_FF = ["ih", "iv", "bl", "br", "bb", "bt"] # "interior horizontal/vertical" and "boundary left/right/bottom/top"
56
57 # Cell elements
58 self._fe_C = [None] * len(self._L_C_L_C)
59 for i in range(len(self._L_C_L_C)):
60 self._fe_C[i] = DGScalarElement(dim, self._L_C_L_C[i])
61
62 # Facet elements
63 self._fe_F = [None] * len(self._L_F_L_F)
64 for i in range(len(self._L_F_L_F)):
65 self._fe_F[i] = DGFacetElement(dim, self._L_F_L_F[i])
66
67
68 self._A_CC_A_CC = {fs_pair: self._assemble_A_CC(fs_pair) for fs_pair in self._coupling_CC}
69
70 self._A_CF_A_CF = {fs_pair: {ent_type: self._assemble_A_CF(fs_pair, ent_type) for ent_type in self._ent_types_CF_FC}
71 for fs_pair in self._coupling_CF
72 }
73
74 self._A_FC_A_FC = {fs_pair: {ent_type: self._assemble_A_FC(fs_pair, ent_type) for ent_type in self._ent_types_CF_FC}
75 for fs_pair in self._coupling_FC
76 }
77
78 self._A_FF_A_FF = {fs_pair: {ent_type: self._assemble_A_FF(fs_pair, ent_type) for ent_type in self._ent_types_FF}
79 for fs_pair in self._coupling_FF
80 }
81
82 #MG = MatrixGenerator(r_)
83
84
87 def _assemble_A_CC(self, fs_pair):
88 """Assemble weak form for A_{CC}^{(k,ell)}
89 :arg fs_pair: pair of cell function space indices that couple
90 k = fs_pair[0]: first function space (to-space): a cell function space
91 ell = fs_pair[1]: second function space (from-space): a cell function space
92 """
93 #assert fs_pair in self._coupling_CC
94
95 k = fs_pair[0]
96 ell = fs_pair[1]
97 ndof_k = self._fe_C[k].ndof
98 ndof_ell = self._fe_C[ell].ndof
99 A_k_ell = np.empty((ndof_k, ndof_ell))
100 gamma = (0, 0) # no sacling, as the contribution h^2 from dxdy is compensated by 1/h^2 from derivatives \nambla u \cdot \nabla v
101
102 # Quadrature rule: based on the max degree of basis in the function spaces pair
103 max_degree = max(self._fe_C[k].degree, self._fe_C[ell].degree)
104 quad2d = Quadrature2d(GaussianQuadrature(max_degree + 1))
105
106 if fs_pair == (0, 0):
107 #func_k = self._fe_C[k].evaluate
108 #func_ell = self._fe_C[ell].evaluate
109 factor = 1.0
110
111 # Assemble local matrix A^(k,ell)
112 for i in range(ndof_k):
113 for j in range(ndof_ell):
114 A_k_ell[i, j] = 0.0
115 for q, w in zip(quad2d.points, quad2d.weights):
116 A_k_ell[i, j] += factor * w * ( self._fe_C[k].evaluate_derivative(i, 0, q) * self._fe_C[ell].evaluate_derivative(j, 0, q)
117 +
118 self._fe_C[k].evaluate_derivative(i, 1, q) * self._fe_C[ell].evaluate_derivative(j, 1, q)
119 )
120 else:
121 A_k_ell = np.zeros((k, ell))
122
123 return {gamma: A_k_ell}
124
125
128 def _assemble_A_CF(self, fs_pair, relative_position):
129 """Assemble weak form for A_{CF}^{(k,ell)}
130 :arg fs_pair: pair of function space indices that couple
131 k = fs_pair[0]: first function space (to-space): a cell function space
132 ell = fs_pair[1]: second function space (from-space): a facet function space
133 :arg relative_position: relative position of the facet within a cell given by
134 the "type of entity"
135 """
136 k = fs_pair[0]
137 ell = fs_pair[1]
138 ndof_k = self._fe_C[k].ndof
139 ndof_ell = self._fe_F[ell].ndof
140 A_k_ell = np.empty((ndof_k, ndof_ell))
141 gamma = (0, 0)
142
143 # Quadrature rule: based on the max degree of basis in the function spaces pair
144 max_degree = max(self._fe_C[k].degree, self._fe_F[ell].degree)
145 quad = GaussianQuadrature(max_degree + 1)
146
147 # Matrix restr applied to [1, q] gives [-1, q], [1, q], [q, -1] or [q, 1] --
148 # 2D coordinates on a facet depending on its relative location
149 # Is's used to later restrict a cell-function to a facet for integrating over facet
150 if relative_position == "left":
151 restr = np.array([[-1.0, 0.0],
152 [ 0.0, 1.0]])
153 # nx, ny = -1.0, 0.0 # outward unit normal components
154 elif relative_position == "right":
155 restr = np.array([[1.0, 0.0],
156 [0.0, 1.0]])
157 # nx, ny = +1.0, 0.0
158 elif relative_position == "bottom":
159 restr = np.array([[ 0.0, 1.0],
160 [-1.0, 0.0]])
161 # nx, ny = 0.0, -1.0
162 elif relative_position == "top":
163 restr = np.array([[0.0, 1.0],
164 [1.0, 0.0]])
165 # nx, ny = 0.0, +1.0
166 else:
167 raise ValueError("Invalid value of relative_position")
168
169 # The following sets factors and integrands for all the pairs (k,ell);
170 if fs_pair == (0, 2): # -int_F q^f v^p dF
171 factor = -0.5 # minus befor the boundary int. in the weak formulation
172
173 if relative_position in ["left", "right"]:
174 gamma = (0, 1) # scale by hy
175 else: # ["top", "bottom"]
176 gamma = (1, 0) # scale by hx
177
178 # Define the integrand function for different
179 def func_k(i, q):
180 facet_coord = np.dot(restr, np.array([1.0, q])) # gives [-1, q], [1, q], [q, -1] or [q, 1]
181 return self._fe_C[k].evaluate(i, facet_coord) # restriction of the cell-function to a facet
182 func_ell = self._fe_F[ell].evaluate
183
184 # Assemble local matrix A^(k,ell)
185 for i in range(ndof_k):
186 for j in range(ndof_ell):
187 A_k_ell[i, j] = 0.0
188 for q, w in zip(quad.points, quad.weights):
189 A_k_ell[i, j] += factor * w * func_k(i, q) * func_ell(j, q)
190
191 else:
192 A_k_ell = np.zeros((ndof_k, ndof_ell))
193
194 #print(k, ell, relative_position, "\n", A_k_ell, "\n")
195 return {gamma: A_k_ell}
196
197
200 def _assemble_A_FC(self, fs_pair, relative_position):
201 """Assemble weak form for A_{CF}^{(k,ell)}
202 :arg fs_pair: pair of function space indices that couple
203 k = fs_pair[0]: first function space (to-space): a facet function space
204 ell = fs_pair[1]: second function space (from-space): a cell function space
205 :arg relative_position: relative position of the facet within a cell
206 """
207 k = fs_pair[0]
208 ell = fs_pair[1]
209 ndof_k = self._fe_F[k].ndof
210 ndof_ell = self._fe_C[ell].ndof
211 A_k_ell = np.empty((ndof_k, ndof_ell))
212
213 # Quadrature rule: based on the max degree of basis in the function spaces pair
214 max_degree = max(self._fe_F[k].degree, self._fe_C[ell].degree)
215 quad = GaussianQuadrature(max_degree + 1)
216
217 # Matrix restr applied to [1, q] gives [-1, q], [1, q], [q, -1] or [q, 1] --
218 # 2D coordinates on a facet depending on its relative location
219 # Is's used to later restrict a cell-function to a facet for integrating over facet
220 if relative_position == "left":
221 restr = np.array([[-1.0, 0.0],
222 [ 0.0, 1.0]])
223 # nx, ny = -1.0, 0.0 # outward unit normal components
224 elif relative_position == "right":
225 restr = np.array([[1.0, 0.0],
226 [0.0, 1.0]])
227 # nx, ny = +1.0, 0.0
228 elif relative_position == "bottom":
229 restr = np.array([[ 0.0, 1.0],
230 [-1.0, 0.0]])
231 # nx, ny = 0.0, -1.0
232 elif relative_position == "top":
233 restr = np.array([[0.0, 1.0],
234 [1.0, 0.0]])
235 # nx, ny = 0.0, +1.0
236 else:
237 raise ValueError("Invalid value of relative_position")
238
239 factor = -1.0 # minus from the def. of projection: M*q^\pm - A*p = 0
240 gamma = (0, 0) # no scaling as it's compensated by the derivative dp/dx or dp/dy
241
242 if fs_pair == (0, 0): # A_q+_p
243 if relative_position in ["left", "bottom"]: # "+"-projection from a give cell is defined on the left and bottom facets
244 # Define the integrand functions
245 func_k = self._fe_F[k].evaluate
246 def func_ell(i, q):
247 facet_coord = np.dot(restr, np.array([1.0, q])) # gives [-1, q], [1, q], [q, -1] or [q, 1]
248 if relative_position == "left":
249 # Define the integrand function: projecting x-derivative of p
250 return self._fe_C[ell].evaluate_derivative(i, 0, facet_coord) # restriction of the cell-function to a facet
251 else: # relative_position == "bottom"
252 # projecting y-derivative of p
253 return self._fe_C[ell].evaluate_derivative(i, 1, facet_coord)
254
255 # Assemble local matrix A^(k,ell)
256 for i in range(ndof_k):
257 for j in range(ndof_ell):
258 A_k_ell[i, j] = 0.0
259 for q, w in zip(quad.points, quad.weights):
260 A_k_ell[i, j] += factor * w * func_k(i, q) * func_ell(j, q)
261
262 else: # return 0 for the right and top
263 A_k_ell = np.zeros((ndof_k, ndof_ell))
264
265 elif fs_pair == (1, 0): # A_q-_p
266 if relative_position in ["right", "top"]: # "-"-projection from a give cell is defined on the right and top facets
267 # Define the integrand functions
268 func_k = self._fe_F[k].evaluate
269 def func_ell(i, q):
270 facet_coord = np.dot(restr, np.array([1.0, q])) # gives [-1, q], [1, q], [q, -1] or [q, 1]
271 if relative_position == "right":
272 # Define the integrand function: projecting x-derivative of p
273 return self._fe_C[ell].evaluate_derivative(i, 0, facet_coord) # restriction of the cell-function to a facet
274 else: # relative_position == "top"
275 # projecting y-derivative of p
276 return self._fe_C[ell].evaluate_derivative(i, 1, facet_coord)
277
278 # Assemble local matrix A^(k,ell)
279 for i in range(ndof_k):
280 for j in range(ndof_ell):
281 A_k_ell[i, j] = 0.0
282 for q, w in zip(quad.points, quad.weights):
283 A_k_ell[i, j] += factor * w * func_k(i, q) * func_ell(j, q)
284
285 else: # return 0 for the left and bottom
286 A_k_ell = np.zeros((ndof_k, ndof_ell))
287
288 else:
289 A_k_ell = np.zeros((ndof_k, ndof_ell))
290
291 #print(k, ell, relative_position, "\n", A_k_ell, "\n")
292 return {gamma: A_k_ell}
293
294
297 def _assemble_A_FF(self, fs_pair, relative_position):
298 """Assemble weak form for A_{FF}^{(k,ell)}
299 :arg fs_pair: pair of function space indices that couple
300 k = fs_pair[0]: first function space (to-space): a facet function space
301 ell = fs_pair[1]: second function space (from-space): a facet function space
302 :arg relative_position: relative position of the facet within a cell
303 """
304 k = fs_pair[0]
305 ell = fs_pair[1]
306 ndof_k = self._fe_F[k].ndof
307 ndof_ell = self._fe_F[ell].ndof
308 A_k_ell = np.empty((ndof_k, ndof_ell))
309 gamma = (0, 0)
310
311 # Quadrature rule: based on the max degree of basis in the function spaces pair
312 max_degree = max(self._fe_F[k].degree, self._fe_F[ell].degree)
313 quad = GaussianQuadrature(max_degree + 1)
314
315 if fs_pair in [(0,0), (1,1)]: # Facet space mass matrices A_q+_q+, A_q-_q-
316 func_k = self._fe_F[k].evaluate
317 func_ell = self._fe_F[ell].evaluate
318 factor = 0.5
319
320 if relative_position in ["left", "right"]:
321 gamma = (0, 1) # scale by hy
322 else:
323 gamma = (1, 0) # scale by hx
324
325 # Assemble local matrix A^(k,ell)
326 for i in range(ndof_k):
327 for j in range(ndof_ell):
328 A_k_ell[i, j] = 0.0
329 for q, w in zip(quad.points, quad.weights):
330 A_k_ell[i, j] += factor * w * func_k(i, q) * func_ell(j, q)
331
332 elif fs_pair == (2, 2): # A_qf_qf
333 gamma = (0, 0)
334 A_k_ell = np.eye(ndof_k)
335
336 elif fs_pair in [(2,0), (2,1)]: # A_q+_qf, A_q-_qf
337 gamma = (0, 0)
338 A_k_ell = -0.5*np.eye(ndof_k)
339
340 else:
341 gamma = (0, 0)
342 A_k_ell = np.zeros((ndof_k, ndof_ell))
343
344 #print(k, ell, relative_position, "\n", A_k_ell, "\n")
345 return {gamma: A_k_ell}
346
347# r_press = 1
348# BM = DGPoisson2dBlockMatrix(r_press)
Base class for block matrix storage format, defining the interface.
Definition BlockMatrix.py:5
Classical DG discretisation of 2d classical Poisson formulation with spurious facet function spaces.
__init__(self, r_press, basis=NodalBasisGaussLegendre(2))
Initialise instance :arg r_press: polynomial degree of pressure space :arg r_vel: polynomial degree o...
_assemble_A_CF(self, fs_pair, relative_position)
Assemble weak form for A_CF ###.
_assemble_A_FF(self, fs_pair, relative_position)
Assemble weak form for A_FF ###.
_assemble_A_FC(self, fs_pair, relative_position)
Assemble weak form for A_FC ###.
Gaussian quadrature on the reference interval [-1,+1].
Definition quadrature.py:16