Skip to content

Commit 8839f87

Browse files
authored
Extend PolySet coefficients (#130)
* Add extension of coefficients to allow union of polysets with different degrees * remove orthonormal as seems to be no longer necessary * Remove further orthonormals
1 parent 15ae324 commit 8839f87

File tree

4 files changed

+83
-6
lines changed

4 files changed

+83
-6
lines changed

FIAT/nedelec.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ def NedelecSpace2D(ref_el, degree):
4343

4444
CrossX = numpy.dot(numpy.array([[0.0, 1.0], [-1.0, 0.0]]), Qpts.T)
4545
PkHCrossX_at_Qpts = PkH_at_Qpts[:, None, :] * CrossX[None, :, :]
46-
PkHCrossX_coeffs = numpy.dot(numpy.multiply(PkHCrossX_at_Qpts, Qwts), Pkp1_at_Qpts.T)
47-
46+
PkHCrossX_coeffs = numpy.dot(numpy.multiply(PkHCrossX_at_Qpts, Qwts),
47+
Pkp1_at_Qpts.T)
4848
PkHcrossX = polynomial_set.PolynomialSet(ref_el,
4949
k + 1,
5050
k + 1,

FIAT/polynomial_set.py

+37-3
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,49 @@ def polynomial_set_union_normalized(A, B):
176176
not contain any of the same members of the set, as we construct a
177177
span via SVD.
178178
"""
179-
new_coeffs = numpy.concatenate((A.coeffs, B.coeffs), axis=0)
179+
assert A.get_reference_element() == B.get_reference_element()
180+
new_coeffs = construct_new_coeffs(A.get_reference_element(), A, B)
181+
182+
deg = max(A.get_degree(), B.get_degree())
183+
em_deg = max(A.get_embedded_degree(), B.get_embedded_degree())
180184
coeffs = spanning_basis(new_coeffs)
181185
return PolynomialSet(A.get_reference_element(),
182-
A.get_degree(),
183-
A.get_embedded_degree(),
186+
deg,
187+
em_deg,
184188
A.get_expansion_set(),
185189
coeffs)
186190

187191

192+
def construct_new_coeffs(ref_el, A, B):
193+
"""
194+
Constructs new coefficients for the set union of A and B
195+
If A and B are discontinuous and do not have the same degree the smaller one
196+
is extended to match the larger.
197+
198+
This does not handle the case that A and B have continuity but not the same degree.
199+
"""
200+
201+
if A.get_expansion_set().continuity != B.get_expansion_set().continuity:
202+
raise ValueError("Continuity of expansion sets does not match.")
203+
204+
if A.get_embedded_degree() != B.get_embedded_degree() and A.get_expansion_set().continuity is None:
205+
higher = A if A.get_embedded_degree() > B.get_embedded_degree() else B
206+
lower = B if A.get_embedded_degree() > B.get_embedded_degree() else A
207+
208+
diff = higher.coeffs.shape[-1] - lower.coeffs.shape[-1]
209+
210+
# pad only the 0th axis with the difference in size
211+
padding = [(0, 0) for i in range(len(lower.coeffs.shape) - 1)] + [(0, diff)]
212+
embedded_coeffs = numpy.pad(lower.coeffs, padding)
213+
214+
new_coeffs = numpy.concatenate((embedded_coeffs, higher.coeffs), axis=0)
215+
elif A.get_embedded_degree() == B.get_embedded_degree():
216+
new_coeffs = numpy.concatenate((A.coeffs, B.coeffs), axis=0)
217+
else:
218+
raise NotImplementedError("Extending of coefficients is not implemented for PolynomialSets with continuity and different degrees")
219+
return new_coeffs
220+
221+
188222
class ONSymTensorPolynomialSet(PolynomialSet):
189223
"""Constructs an orthonormal basis for symmetric-tensor-valued
190224
polynomials on a reference element.

FIAT/raviart_thomas.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ def RTSpace(ref_el, degree):
3939
# have to work on this through "tabulate" interface
4040
# first, tabulate PkH at quadrature points
4141
PkH_at_Qpts = PkH.tabulate(Qpts)[(0,) * sd]
42+
4243
Pkp1_at_Qpts = Pkp1.tabulate(Qpts)[(0,) * sd]
4344

4445
x = Qpts.T
4546
PkHx_at_Qpts = PkH_at_Qpts[:, None, :] * x[None, :, :]
4647
PkHx_coeffs = numpy.dot(numpy.multiply(PkHx_at_Qpts, Qwts), Pkp1_at_Qpts.T)
47-
4848
PkHx = polynomial_set.PolynomialSet(ref_el,
4949
k,
5050
k + 1,

test/FIAT/unit/test_polynomial.py

+43
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from FIAT import expansions, polynomial_set, reference_element
2323
from FIAT.quadrature_schemes import create_quadrature
24+
from itertools import chain
2425

2526

2627
@pytest.fixture(params=(1, 2, 3))
@@ -107,3 +108,45 @@ def test_bubble_duality(cell, degree):
107108
results = scale * numpy.dot(numpy.multiply(phi_dual, qwts), phi.T)
108109
assert numpy.allclose(results, numpy.diag(numpy.diag(results)))
109110
assert numpy.allclose(numpy.diag(results), 1.0)
111+
112+
113+
@pytest.mark.parametrize("degree", [10])
114+
def test_union_of_polysets(cell, degree):
115+
""" demonstrates that polysets don't need to have the same degree for union
116+
using RT space as an example"""
117+
118+
sd = cell.get_spatial_dimension()
119+
k = degree
120+
vecPk = polynomial_set.ONPolynomialSet(cell, degree, (sd,))
121+
122+
vec_Pkp1 = polynomial_set.ONPolynomialSet(cell, k + 1, (sd,), scale="orthonormal")
123+
124+
dimPkp1 = expansions.polynomial_dimension(cell, k + 1)
125+
dimPk = expansions.polynomial_dimension(cell, k)
126+
dimPkm1 = expansions.polynomial_dimension(cell, k - 1)
127+
128+
vec_Pk_indices = list(chain(*(range(i * dimPkp1, i * dimPkp1 + dimPk)
129+
for i in range(sd))))
130+
vec_Pk_from_Pkp1 = vec_Pkp1.take(vec_Pk_indices)
131+
132+
Pkp1 = polynomial_set.ONPolynomialSet(cell, k + 1, scale="orthonormal")
133+
PkH = Pkp1.take(list(range(dimPkm1, dimPk)))
134+
135+
Q = create_quadrature(cell, 2 * (k + 1))
136+
Qpts, Qwts = Q.get_points(), Q.get_weights()
137+
138+
PkH_at_Qpts = PkH.tabulate(Qpts)[(0,) * sd]
139+
Pkp1_at_Qpts = Pkp1.tabulate(Qpts)[(0,) * sd]
140+
x = Qpts.T
141+
PkHx_at_Qpts = PkH_at_Qpts[:, None, :] * x[None, :, :]
142+
PkHx_coeffs = numpy.dot(numpy.multiply(PkHx_at_Qpts, Qwts), Pkp1_at_Qpts.T)
143+
PkHx = polynomial_set.PolynomialSet(cell, k, k + 1, vec_Pkp1.get_expansion_set(), PkHx_coeffs)
144+
145+
same_deg = polynomial_set.polynomial_set_union_normalized(vec_Pk_from_Pkp1, PkHx)
146+
different_deg = polynomial_set.polynomial_set_union_normalized(vecPk, PkHx)
147+
148+
Q = create_quadrature(cell, 2*(degree))
149+
Qpts, _ = Q.get_points(), Q.get_weights()
150+
same_vals = same_deg.tabulate(Qpts)[(0,) * sd]
151+
diff_vals = different_deg.tabulate(Qpts)[(0,) * sd]
152+
assert numpy.allclose(same_vals - diff_vals, 0)

0 commit comments

Comments
 (0)