Skip to content

Commit

Permalink
tests: Check that interpolation sum factorises for simple cases
Browse files Browse the repository at this point in the history
On tensor product cells, interpolation of Q/DQ elements should sum
factorise to give an operation count that is O(p^{d+1}). Check this
works. Additionally check that interpolation of Vector/TensorElement
costs only the product of the value_shape more flops than the
equivalent scalar element.
  • Loading branch information
wence- committed Aug 26, 2021
1 parent 6a78fac commit a32ddc0
Showing 1 changed file with 64 additions and 0 deletions.
64 changes: 64 additions & 0 deletions tests/test_interpolation_factorisation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from functools import partial
import numpy
import pytest

from ufl import (Mesh, FunctionSpace, FiniteElement, VectorElement,
TensorElement, Coefficient,
interval, quadrilateral, hexahedron)

from tsfc.driver import compile_expression_dual_evaluation
from tsfc.finatinterface import create_element


@pytest.fixture(params=[interval, quadrilateral, hexahedron],
ids=lambda x: x.cellname())
def mesh(request):
return Mesh(VectorElement("P", request.param, 1))


@pytest.fixture(params=[FiniteElement, VectorElement, TensorElement],
ids=lambda x: x.__name__)
def element(request, mesh):
if mesh.ufl_cell() == interval:
family = "DP"
else:
family = "DQ"
return partial(request.param, family, mesh.ufl_cell())


def flop_count(mesh, source, target):
Vtarget = FunctionSpace(mesh, target)
Vsource = FunctionSpace(mesh, source)
to_element = create_element(Vtarget.ufl_element())
expr = Coefficient(Vsource)
kernel = compile_expression_dual_evaluation(expr, to_element)
return kernel.flop_count


def test_sum_factorisation(mesh, element):
# Interpolation between sum factorisable elements should cost
# O(p^{d+1})
degrees = numpy.asarray([2**n - 1 for n in range(2, 9)])
flops = []
for lo, hi in zip(degrees - 1, degrees):
flops.append(flop_count(mesh, element(int(lo)), element(int(hi))))
flops = numpy.asarray(flops)
rates = numpy.diff(numpy.log(flops)) / numpy.diff(numpy.log(degrees))
assert (rates < (mesh.topological_dimension()+1)).all()


def test_sum_factorisation_scalar_tensor(mesh, element):
# Interpolation into tensor elements should cost value_shape
# more than the equivalent scalar element.
degree = 2**7 - 1
source = element(degree - 1)
target = element(degree)
tensor_flops = flop_count(mesh, source, target)
expect = numpy.prod(target.value_shape())
if isinstance(target, FiniteElement):
scalar_flops = tensor_flops
else:
target = target.sub_elements()[0]
source = source.sub_elements()[0]
scalar_flops = flop_count(mesh, source, target)
assert numpy.allclose(tensor_flops / scalar_flops, expect, rtol=1e-2)

0 comments on commit a32ddc0

Please sign in to comment.