4from abc
import abstractmethod
7from numpy.polynomial.legendre
import leggauss
8from scipy.interpolate
import lagrange
10from itertools
import product
15 Base class for generating matrices that we pipe into the C++ code
17 Every method marked abstract is intended to be overwritten in child classes, but some will come
18 with default behaviour.
38 Method to create a list of 1D polynomials.
40 We promote these to higher dimensions by
41 taking tensor products.
43 By default, we will return Lagrange polynomials,
44 but we can overwrite this in child class
49 take a linspace from -1 -> 1 as this is how
50 gaussian quadrature points are defined. Note
51 this may later require us to convert from
52 coordinates in [-1,1] to the global mesh
59 polys.append( lagrange(x,y) )
65 Method to set the quadrature points, used for
68 Provide a method here to produce Gauss-Legendre
69 points, but this can be overwritten in child
72 Slightly redundant use of the leggauss function
73 here, but I thought it better to separate the
74 calculation of points and weights for ease of
75 implementing in child class.
83 Most schemes define the integration point over the interval [-1,1]
84 whereas MGHyPE often needs it on the unit interval. Therefore, I
85 offer this genereric recalibration routine.
90 return [ (x+shift)*scaling
for x
in self.
get_points1d() ]
95 Method to set the quadrature weights, used for
98 Provide a method here to produce Gauss-Legendre
99 weights, but this can be overwritten in child
102 Slightly redundant use of the leggauss function
103 here, but I thought it better to separate the
104 calculation of points and weights for ease of
105 implementing in child class.
112 We promote the 1D quadrature points
113 in into the dimensions of our problem
114 by taking cartesian product. This works
115 for any dimension and does not need to
116 be implemented in the child class.
118 We may need to produce arrays of points
119 for number of dimensions which is less
125 points = [self.
points1d for _
in range(dim)]
128 This is a bit of python magic. We unpack points, so we
129 are in effect passing Dimensions different arguments to
130 iterools.product. itertools.product then produces every
131 possible combination, in tuple form. We then capture this
132 in a list, and return it. Ie if we start with a list of
133 1d points: [p0,p1,p2,p3,...], we return, for Dimensions==3:
141 return [ *product( *points ) ]
145 We promote the 1D quadrature weights
146 in into the dimensions of our problem
147 by taking cartesian product. This works
148 for any dimension and does not need to
149 be implemented in the child class.
154 def arrayProduct(array):
156 for el
in array: output *= el
161 weights = [self.
weights1d for _
in range(dim)]
164 This time, given 1d weights [w0,w1,w2,...], we want to
173 return [ arrayProduct(array)
for array
in product( *weights ) ]
177 This method helps with indexing. Typically,
178 for polynomial degree p, we have (p+1) nodal
179 points per coordinate axis, for a total of
180 @f$ p^d @f$. This method converts an index
181 in the range @f$ (0, ..., p^d) @f$ into a
182 tuple of (x,y,z) coordinates.
187 assert index
in range((self.
poly_degree+1) ** dim),
"index outside of range!"
188 output = [0
for _
in range(dim)]
189 for d
in range(dim-1,-1,-1):
191 output[d] = (index - index%pToD) // pToD
197 Promote 1d polynomials to many dimensions
200 We pass in an index and a dimension, which will, by default
201 be set to the number of dimensions of the problem.
203 The index should be betweeen 0 and (self.poly_degree)^self.dimensions
205 We convert the index into a tuple (x,y,z) of indices, pull
206 out appropriate polynomials and return a function object.
207 This function object will expect dim arguments.
218 def returnFunc(*args):
220 The intention of this part is as follows:
221 We have (for example) 3 arguments for a 3d function: [arg_x, arg_y, arg_z]
222 We have correspondingly 3 polynomials, since we promote a 1d basis to a 3d
223 basis by taking products: [poly_x, poly_y, poly_z].
224 Then, we return poly_x(arg_x) * poly_y(arg_y) * poly_z(arg_z)
226 The polys don't go out of scope.
228 assert(len(args)==dim), f
"Supplied {len(args)} args to a {dim}d function!"
230 for i, arg
in enumerate(args):
240 dimForDeriv is the singular dimension that we wanna take a polyderiv in
242 Behaves the same as get_polynomial, except in that in the specified
243 dimension, we take a derivative rather than the poly itself
247 assert dimForDeriv
in range(dim), f
"dimForDeriv={dimForDeriv}, dim={dim}"
254 for i, index
in enumerate(indices):
262 def returnFunc(*args):
263 assert(len(args)==dim), f
"Supplied {len(args)} args to a {dim}d function!"
265 for i, arg
in enumerate(args):
280 for p, w
in zip(points, weights):
282 for func
in functions:
286 localEval *= func( *p )
288 output += w * localEval
289 return output * factor
295 Construct the Laplacian
297 Create the Laplacian. This routine represents the fact
298 that the Laplacian is kind of the evergreen of many
299 PDEs, and we therefore provide a factory method for
302 These factory methods all return two lists. The first
303 one is a list of matrices @f$ A_1, A_2, ... @f$ defined relative to the unit
304 cube or square, respectively. The second list has the
305 same length as the first list, and stores integer indices
306 @f$ k_1, k_2, k_3, ... @f$. Throughout the assemly, you
307 should then apply the local matrix
308 @f$ A = h^{k_1} A_1 + h^{k_2} A_2 + ... @f$. The mass
309 matrix typically is only one matrix scaled with d, i.e.
310 we return a list hosting only one matrix as first argument
311 and the second list only hosts the integer self.dimensions.
313 Implement this in child class.
315 @return [Matrix] x [Int]
316 The two lists have to have the same number of entries.
319 raise NotImplementedError
324 Factory for cell mass matrix.
326 Consult get_cell_system_matrix_for_laplacian() for an overview
327 of the result types. As the mass matrix is typically fairly
328 simple (it does not host any derivative), and as we work within
329 a finite element mindset, this routine returns a list with one
330 matrix as first argument, and then a list with the integer
334 raise NotImplementedError
340 Construct identity for this particular equation system
342 Not that this is identity construction has to take the number of
343 unknowns into account as well as the number of degrees of freedom
344 hosted within a cell.
347 raise NotImplementedError
Base class for generating matrices that we pipe into the C++ code.
get_cell_system_matrix_for_laplacian(self)
Construct the Laplacian.
__init__(self, dimensions, poly_degree, unknowns_per_node=1)
get_integration_points_over_unit_interval(self)
Most schemes define the integration point over the interval [-1,1] whereas MGHyPE often needs it on t...
get_weights_for_dimension(self, dim=-1)
We promote the 1D quadrature weights in into the dimensions of our problem by taking cartesian produc...
get_polynomial1d(self)
Method to create a list of 1D polynomials.
get_cell_identity_matrix(self)
Construct identity for this particular equation system.
get_points1d(self)
Method to set the quadrature points, used for integration.
get_weights1d(self)
Method to set the quadrature weights, used for integration.
eval_integral(self, functions, dim=-1, factor=1)
get_points_for_dimension(self, dim=-1)
We promote the 1D quadrature points in into the dimensions of our problem by taking cartesian product...
convert_index_to_dim(self, index, dim=-1)
This method helps with indexing.
get_cell_mass_matrix(self)
Factory for cell mass matrix.
get_deriv(self, index, dimForDeriv, dim=-1)
dimForDeriv is the singular dimension that we wanna take a polyderiv in
get_polynomial(self, index, dim=-1)
Promote 1d polynomials to many dimensions by taking products.