5from sympy.integrals.quadrature
import gauss_legendre, gauss_lobatto
7from abc
import abstractmethod
20 Method representing a Lagrange basis which is used as a factory mechanism
21 to produce all the vectors and matrices that we need within the DG solvers.
22 Never use this class directly, but always rely on GaussLegendre or
23 GaussLobatto. The only two things that are relevant for a user are the two
24 routines quadrature_points() and quadrature_weights() as well as the routine
25 to befill a map with replacement rules: init_dictionary_with_default_parameters()
55 self._init_dictionary_with_default_parameters(d)
56 return "<{}.{} object>: {}".format(self.__class__.__module__,self.__class__.__name__,d)
63 Evaluates a lagrange polynomial and its first derivative at a given point.
67 The reference element point the basis functions are evaluated at.
68 Here, xi refers to the greek letter that is often used as a reference element coordinate.
71 Basis function values.
73 First derivatives of the basis functions.
82 phi[m] = phi[m]*(xi-xin[j])/(xin[m]-xin[j])
92 tmp = tmp*(xi-xin[j])/(xin[m]-xin[j])
93 phi_xi[m] += tmp/(xin[m]-xin[i])
100 https://people.maths.ox.ac.uk/trefethen/barycentric.pdf
108 result[j] = 1.0/divisor
114 Computes the (reference) element mass matrix for an approximation of
115 order self.__max_poly_order.
117 We evaluate the scalar product:
119 (phi_i, phi_j)_[0,1], i,j = 1 ... N > 0
121 where phi_i,phi_j are Lagrange basis functions associated with
122 N support points x_i and x_j within the unit-interval.
123 They are polynomials of maximum order N-1.
125 We evaluate the scalar product via a degree N Gauss quadrature rule that uses basis function support points
126 as evaluation points.
127 If we use Legendre nodes as support points, this is an exact evaluation if
128 we use Lobatto nodes, this is an approximation.
132 :return: The (reference) element mass matrix. Exact for Gauss-Legrende nodes, inexact for Gauss-Lobatto (diagnoal lumping).
150 Computes the (reference) element stiffness matrix for an approximation of order self.__max_poly_order.
154 K_ij = <d/dx phi_i, phi_j>_[0,1] = w_j (d/dx phi_j) (x_i)
156 where phi_i,phi_j are Lagrange basis functions associated with
157 N support points x_i and x_j within the unit-interval.
158 They are polynomials of maximum order N-1.
160 :note: Exact for both Lobatto and Legendre nodes due to the reduced degree in one scalar product operand.
162 :return: The (reference) element stiffness matrix.
181 Computes the difference between the reference element mass operator
182 evaluated at point xi=1.0 and the element stiffness matrix.
184 :return: delta between the reference element mass operator at point xi=1.0 and the element stiffness matrix
195 K1[k][l] = phi1[k]*phi1[l] - Kxi[k][l]
207 Computes basis function derivatives at each support point.
208 Transposes the resulting operator.
212 => d/dx u = sum_j (d/dx phi_j) u_j
214 To construct the gradient field, we make the ansatz:
216 grad u = sum_i g_i phi_i
220 g_i = ( d/dx u, phi_i )_[0,1] / (phi_i,phi_i)_[0,1] = sum_j (d/dx phi_j, phi_i)_[0,1] / w_i
222 = w_i (d/dx phi_j) (x_i) / w_i = (d/dx phi_j) (x_i)
226 where DUDX is the operator computed by this function:
228 DUDX_ij = (d/dx phi_i) (x_j)
230 It can be further written as
232 DUDX_ij = 1/w_i * K^T_ij
234 where the stiffness matrix K is defined as
236 K_ij = <d/dx phi_i, phi_j>_[0,1] = w_j (d/dx phi_j) (x_i)
238 :return: transposed derivative operator
240 :note: If you want to use this operator to compute the gradient of the solution,
241 you need to use the transpose.
250 dudx[i][j] = phi_xi[j]
257 Transforms the degrees of freedom located on a coarse grid edge
258 quadrature_points to degrees of freedoms located on quadrature_points of a fine grid edge.
259 The difference in levels is 1.
261 Let us denote by P the fine grid projector (= equidistantGridProjector). The fine grid DoF
262 are computed according to:
264 u^{fine;j}_i = sum_{m} P^{j}_im u^{coarse}_m
272 Operator to express polynomial function associated with original interval with basis functions associated with subinterval j
279 fineGridProjector[m][i] = phi_i[m]
280 return fineGridProjector
285 Transforms the degrees of freedom located at non-equidistant Lagrange support points
286 quadrature_points to degrees of freedoms located at quadrature_points of an equidistant grid over (0,1).
288 Let us denote by P the projection operator (= equidistantGridProjector). The equidistant DoF
289 are computed according to:
291 u^eq_i = sum_{m} P_im u^DG_m
294 equidistantGridProjector:
295 The corresponding degrees of freedom located at quadrature_points of an equidistant grid over (0,1).
298 subxi = mp.linspace(mp.mpf(0.0), mp.mpf(1.0), self.
__num_points)
303 equidistantGridProjector[m][i] = phi_i[m]
304 return equidistantGridProjector
312 This implementation is a little bit nasty: We use the resulting strings within
313 jinja2 templates which are then repeatedly resolved/rendered. Therefore, we have
314 to be carefully not to write {{ where we want to have two brackets. Instead, we
315 have to write { { (not the space) so the render engine does not consider an
316 initialisation list with nested arrays as a jinja2 token.
318 :param rendered_tensor: (nested) list of str elements
319 :return: C++ initializer list for tensor
322 def descend(current):
323 if type(current)
is list:
325 for element
in current[:-1]:
326 result += descend(element)
328 result += descend(current[-1])
333 return descend(rendered_tensor)
339 Converts nested list or numpy matrix to nested list of strings.
340 :param tensor: list or numpy vector storing mpmath numbers
344 result.append(mp.nstr(elem,n=RENDER_DIGITS))
351 Converts nested list or numpy matrix to nested list of strings.
352 :param tensor: nested list or numpy matrix storing mpmath numbers
358 resultRow.append(mp.nstr(elem,n=RENDER_DIGITS))
360 result.append(resultRow)
369 Converts nested list or numpy matrix to nested list of strings.
370 :param tensor: nested list or numpy matrix storing mpmath numbers
378 tmp2.append(mp.nstr(elem,n=RENDER_DIGITS))
392 To be implemented by subclass.
394 assert False,
"To be implemented by subclass."
399 Transform quadrature quadrature_points and quadrature_weights for interval [-1,1]
400 to quadrature_points and quadrature_weights for interval [0,1].
402 transformed_quadrature_weights = []
403 transformed_quadrature_points = []
405 for i,w
in enumerate(quadrature_weights):
406 x = quadrature_points[i]
407 wT = mp.mpf(w)/mp.mpf(2.0)
408 xT = (mp.mpf(x)+mp.mpf(1.0))/mp.mpf(2.0)
409 transformed_quadrature_weights.append(wT)
410 transformed_quadrature_points.append(xT)
412 sorted_transformed_quadrature_points = sorted(transformed_quadrature_points)
413 sorted_transformed_quadrature_weights = []
414 for i,xs
in enumerate(sorted_transformed_quadrature_points):
415 n = transformed_quadrature_points.index(xs)
416 ws = transformed_quadrature_weights[n]
417 sorted_transformed_quadrature_weights.append(ws)
418 return sorted_transformed_quadrature_points, sorted_transformed_quadrature_weights
422 def snake_to_camel(word):
423 return ''.join(x.capitalize()
or '_' for x
in word.lower().split(
'_'))
425 basisDeclarations =
""
426 basisInitializers =
""
427 for var
in [
"quadrature_points",
"quadrature_weights",
"barycentric_weights",
"basis_function_values_left",
"basis_function_values_right",
"derivative_operator",
"mass_matrix",
"stiffness_operator",
"inverted_predictor_lhs_operator",
"equidistant_grid_projector",
"fine_grid_projector"]:
428 var_key =
"_LagrangeBasis__" + var
429 var_name = snake_to_camel(var)
430 if var ==
"quadrature_points":
431 var_name =
"QuadraturePoints1d"
432 if var
in [
"quadrature_points",
"quadrature_weights",
"barycentric_weights",
"basis_function_values_left",
"basis_function_values_right"]:
433 basisDeclarations +=
"const double {var_name}[{order}+1];\n".format(indent=
" "*2,var_name=var_name,order=self.
__max_poly_order)
434 basisInitializers +=
"{var_name}{initializer},\n".format(var_name=var_name,\
435 initializer=LagrangeBasis.__make_initializer_list(LagrangeBasis.__render_tensor_1(getattr(self,var_key))))
436 elif var
in [
"fine_grid_projector"]:
438 basisDeclarations +=
"const double {var_name}[3][{order}+1][{order}+1];\n".format(indent=
" "*2,var_name=var_name,order=self.
__max_poly_order)
440 basisDeclarations +=
"const double {var_name}[3][({order}+1)*({order}+1)];\n".format(indent=
" "*2,var_name=var_name,order=self.
__max_poly_order)
441 basisInitializers +=
"{var_name}{initializer},\n".format(var_name=var_name,\
443 ",".join([LagrangeBasis.__make_initializer_list(LagrangeBasis.__render_tensor_2(elem,multiDimArrays))
for elem
in self.
__fine_grid_projector]) +\
447 basisDeclarations +=
"const double {var_name}[{order}+1][{order}+1];\n".format(indent=
" "*2,var_name=var_name,order=self.
__max_poly_order)
449 basisDeclarations +=
"const double {var_name}[({order}+1)*({order}+1)];\n".format(indent=
" "*2,var_name=var_name,order=self.
__max_poly_order)
450 basisInitializers +=
"{var_name}{initializer},\n".format(var_name=var_name,\
451 initializer=LagrangeBasis.__make_initializer_list(LagrangeBasis.__render_tensor_2(getattr(self,var_key),multiDimArrays)))
454 d[
"BASIS_DECLARATIONS"] = basisDeclarations
455 d[
"BASIS_INITIALIZERS"] = basisInitializers
467 x,w = gauss_legendre(num_points,PREC_DIGITS)
471 return "GaussLegendreBasis"
475 x,w = gauss_lobatto(num_points,PREC_DIGITS)
479 return "GaussLobattoBasis"
_compute_quadrature_points_and_weights(self, num_points)
To be implemented by subclass.
_compute_quadrature_points_and_weights(self, num_points)
To be implemented by subclass.
Method representing a Lagrange basis which is used as a factory mechanism to produce all the vectors ...
__make_initializer_list(cls, rendered_tensor)
This implementation is a little bit nasty: We use the resulting strings within jinja2 templates which...
quadrature_weights(self, render=True)
__init__(self, num_points)
_compute_quadrature_points_and_weights(self, num_points)
To be implemented by subclass.
__compute_derivative_operator(self)
Computes basis function derivatives at each support point.
__render_tensor_1(cls, tensor)
Converts nested list or numpy matrix to nested list of strings.
__basis_function_values_left
__compute_mass_matrix(self)
Computes the (reference) element mass matrix for an approximation of order self.__max_poly_order.
__render_tensor_3(cls, tensor, multiDimArray=True)
Converts nested list or numpy matrix to nested list of strings.
quadrature_points(self, render=True)
_transform_and_sort_points_and_weights(self, quadrature_points, quadrature_weights)
Transform quadrature quadrature_points and quadrature_weights for interval [-1,1] to quadrature_point...
__equidistant_grid_projector
__compute_fine_grid_projector(self, j)
Transforms the degrees of freedom located on a coarse grid edge quadrature_points to degrees of freed...
__compute_barycentric_weights(self)
See Eq.
__inverted_predictor_lhs_operator
__compute_K1(self)
Computes the difference between the reference element mass operator evaluated at point xi=1....
init_dictionary_with_default_parameters(self, d, multiDimArrays=False)
__compute_stiffness_operator(self)
Computes the (reference) element stiffness matrix for an approximation of order self....
__evaluate(self, xi)
Evaluates a lagrange polynomial and its first derivative at a given point.
__basis_function_values_right
__compute_equidistant_grid_projector(self)
Transforms the degrees of freedom located at non-equidistant Lagrange support points quadrature_point...
__render_tensor_2(cls, tensor, multiDimArray=True)
Converts nested list or numpy matrix to nested list of strings.