|
28 | 28 | polydim = expansions.polynomial_dimension |
29 | 29 |
|
30 | 30 |
|
31 | | -def WuXuRobustH3NCSpace(ref_el): |
32 | | - """Constructs a basis for the the Wu Xu H^3 nonconforming space |
33 | | - P^{(3,2)}(T) = P_3(T) + b_T P_1(T) + b_T^2 P_1(T), |
| 31 | +def WuXuH3NCSpace(ref_el, robust=False): |
| 32 | + """Constructs a basis for the the Wu Xu H^3 nonconforming spaces |
| 33 | +
|
| 34 | + P^{(3,1)}(T) = P_3(T) + b_T P_1(T), if robust = False |
| 35 | +
|
| 36 | + P^{(3,2)}(T) = P_3(T) + b_T P_1(T) + b_T^2 P_1(T), if robust = True |
| 37 | +
|
34 | 38 | where b_T is the standard cubic bubble.""" |
35 | 39 |
|
36 | 40 | sd = ref_el.get_spatial_dimension() |
37 | 41 | assert sd == 2 |
38 | 42 |
|
39 | | - em_deg = 7 |
40 | | - |
41 | 43 | # Unfortunately, b_T^2 P_1 has degree 7 (cubic squared times a linear) |
42 | 44 | # so we need a high embedded degree! |
43 | | - p7 = polynomial_set.ONPolynomialSet(ref_el, 7) |
| 45 | + embedded_degree = 7 if robust else 4 |
| 46 | + pk = polynomial_set.ONPolynomialSet(ref_el, embedded_degree) |
44 | 47 |
|
45 | 48 | dimp1 = polydim(ref_el, 1) |
46 | 49 | dimp3 = polydim(ref_el, 3) |
47 | | - dimp7 = polydim(ref_el, 7) |
| 50 | + dimpk = polydim(ref_el, embedded_degree) |
48 | 51 |
|
49 | 52 | # Here's the first bit we'll work with. It's already expressed in terms |
50 | | - # of the ON basis for P7, so we're golden. |
51 | | - p3fromp7 = p7.take(list(range(dimp3))) |
| 53 | + # of the ON basis for Pk, so we're golden. |
| 54 | + p3frompk = pk.take(list(range(dimp3))) |
52 | 55 |
|
53 | 56 | # Rather than creating the barycentric coordinates ourself, let's |
54 | 57 | # reuse the existing bubble functionality |
55 | 58 | bT = Bubble(ref_el, 3) |
56 | 59 | p1 = Lagrange(ref_el, 1) |
57 | 60 |
|
58 | | - # next, we'll have to project b_T P1 and b_T^2 P1 onto P^7 |
59 | | - Q = create_quadrature(ref_el, 14) |
| 61 | + # next, we'll have to project b_T P1 and b_T^2 P1 onto Pk |
| 62 | + Q = create_quadrature(ref_el, 2*embedded_degree) |
60 | 63 | Qpts = numpy.array(Q.get_points()) |
61 | 64 | Qwts = numpy.array(Q.get_weights()) |
62 | 65 |
|
63 | | - zero_index = tuple([0 for i in range(sd)]) |
64 | | - |
65 | 66 | # it's just one bubble function: let's get a 1d array! |
66 | | - bT_at_qpts = bT.tabulate(0, Qpts)[zero_index][0, :] |
67 | | - p1_at_qpts = p1.tabulate(0, Qpts)[zero_index] |
| 67 | + bT_at_qpts = bT.tabulate(0, Qpts)[(0,)*sd][0, :] |
| 68 | + p1_at_qpts = p1.tabulate(0, Qpts)[(0,)*sd] |
68 | 69 |
|
69 | | - # Note: difference in signature because bT, p1 are FE and p7 is a |
| 70 | + # Note: difference in signature because bT, p1 are FE and pk is a |
70 | 71 | # polynomial set |
71 | | - p7_at_qpts = p7.tabulate(Qpts)[zero_index] |
| 72 | + pk_at_qpts = pk.tabulate(Qpts)[(0,)*sd] |
72 | 73 |
|
73 | | - bubble_coeffs = numpy.zeros((6, dimp7), "d") |
| 74 | + bubble_coeffs = numpy.zeros((6, dimpk), "d") |
74 | 75 |
|
75 | 76 | # first three: bT P1, last three will be bT^2 P1 |
76 | 77 | foo = bT_at_qpts * p1_at_qpts * Qwts |
77 | | - bubble_coeffs[:dimp1, :] = numpy.dot(foo, p7_at_qpts.T) |
| 78 | + bubble_coeffs[:dimp1, :] = numpy.dot(foo, pk_at_qpts.T) |
78 | 79 |
|
79 | | - foo = bT_at_qpts * foo |
80 | | - bubble_coeffs[dimp1:2*dimp1, :] = numpy.dot(foo, p7_at_qpts.T) |
| 80 | + if robust: |
| 81 | + foo = bT_at_qpts * foo |
| 82 | + bubble_coeffs[dimp1:2*dimp1, :] = numpy.dot(foo, pk_at_qpts.T) |
81 | 83 |
|
82 | | - bubbles = polynomial_set.PolynomialSet(ref_el, 3, em_deg, |
83 | | - p7.get_expansion_set(), |
| 84 | + bubbles = polynomial_set.PolynomialSet(ref_el, 3, embedded_degree, |
| 85 | + pk.get_expansion_set(), |
84 | 86 | bubble_coeffs) |
85 | 87 |
|
86 | | - return polynomial_set.polynomial_set_union_normalized(p3fromp7, bubbles) |
87 | | - |
88 | | - |
89 | | -def WuXuH3NCSpace(ref_el): |
90 | | - """Constructs a basis for the the Wu Xu H^3 nonconforming space |
91 | | - P(T) = P_3(T) + b_T P_1(T), |
92 | | - where b_T is the standard cubic bubble.""" |
93 | | - |
94 | | - assert ref_el.get_spatial_dimension() == 2 |
95 | | - |
96 | | - em_deg = 4 |
97 | | - p4 = polynomial_set.ONPolynomialSet(ref_el, em_deg) |
98 | | - |
99 | | - # Here's the first bit we'll work with. It's already expressed in terms |
100 | | - # of the ON basis for P4, so we're golden. |
101 | | - dimp3 = polydim(ref_el, 3) |
102 | | - p3fromp4 = p4.take(list(range(dimp3))) |
103 | | - |
104 | | - # Rather than creating the barycentric coordinates ourself, let's |
105 | | - # reuse the existing bubble functionality |
106 | | - bT = Bubble(ref_el, 4) |
107 | | - |
108 | | - return polynomial_set.polynomial_set_union_normalized(p3fromp4, bT.get_nodal_basis()) |
| 88 | + return polynomial_set.polynomial_set_union_normalized(p3frompk, bubbles) |
109 | 89 |
|
110 | 90 |
|
111 | 91 | class WuXuRobustH3NCDualSet(dual_set.DualSet): |
@@ -176,7 +156,7 @@ def __init__(self, ref_el, degree): |
176 | 156 | class WuXuRobustH3NC(finite_element.CiarletElement): |
177 | 157 | """The Wu-Xu robust H3 nonconforming finite element""" |
178 | 158 | def __init__(self, ref_el, degree=7): |
179 | | - poly_set = WuXuRobustH3NCSpace(ref_el) |
| 159 | + poly_set = WuXuH3NCSpace(ref_el, robust=True) |
180 | 160 | assert degree == poly_set.degree |
181 | 161 | dual = WuXuRobustH3NCDualSet(ref_el, degree) |
182 | 162 | super().__init__(poly_set, dual, degree) |
|
0 commit comments