Skip to content

Commit

Permalink
add a test
Browse files Browse the repository at this point in the history
  • Loading branch information
pbrubeck committed Oct 21, 2024
1 parent f4fdbb8 commit de93ebc
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 16 deletions.
30 changes: 14 additions & 16 deletions firedrake/mg/ufl_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,23 +268,21 @@ def coarsen_snescontext(context, self, coefficient_mapping=None):
coarse._fine = context
context._coarse = coarse

solution = context._problem.u
solutiondm = solution.function_space().dm
solutiondm = context._problem.u.function_space().dm
parentdm = get_parent(solutiondm)
if parentdm != solutiondm:
# Now that we have the coarse snescontext, push it to the coarsened DMs
# Otherwise they won't have the right transfer manager when they are
# coarsened in turn
for val in chain(coefficient_mapping.values(), (bc.function_arg for bc in problem.bcs)):
if isinstance(val, (firedrake.Function, firedrake.Cofunction)):
V = val.function_space()
coarseneddm = V.dm

# Now attach the hook to the parent DM
if get_appctx(coarseneddm) is None:
push_appctx(coarseneddm, coarse)
teardown = partial(pop_appctx, coarseneddm, coarse)
add_hook(parentdm, teardown=teardown)
# Now that we have the coarse snescontext, push it to the coarsened DMs
# Otherwise they won't have the right transfer manager when they are
# coarsened in turn
for val in chain(coefficient_mapping.values(), (bc.function_arg for bc in problem.bcs)):
if isinstance(val, (firedrake.Function, firedrake.Cofunction)):
V = val.function_space()
coarseneddm = V.dm

# Now attach the hook to the parent DM
if get_appctx(coarseneddm) is None:
push_appctx(coarseneddm, coarse)
if parentdm.getAttr("__setup_hooks__"):
add_hook(parentdm, teardown=partial(pop_appctx, coarseneddm, coarse))

ises = problem.J.arguments()[0].function_space()._ises
coarse._nullspace = self(context._nullspace, self, coefficient_mapping=coefficient_mapping)
Expand Down
23 changes: 23 additions & 0 deletions tests/multigrid/test_transfer_manager.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest
import numpy
import warnings
from firedrake import *
from firedrake.mg.ufl_utils import coarsen
from firedrake.utils import complex_mode
Expand Down Expand Up @@ -131,3 +132,25 @@ def test_transfer_manager_dat_version_cache(action, transfer_op, spaces):

else:
raise ValueError(f"Unrecognized action {action}")


@pytest.mark.parametrize("family", ("CG", "R"))
def test_cached_transfer(family):
# Test that we can properly reuse transfers within solve
sp = {"mat_type": "matfree",
"pc_type": "mg",
"mg_coarse_pc_type": "none",
"mg_levels_pc_type": "none"}

base = UnitSquareMesh(1, 1)
hierarchy = MeshHierarchy(base, 3)
mesh = hierarchy[-1]

V = FunctionSpace(mesh, family, 0)

Check failure on line 149 in tests/multigrid/test_transfer_manager.py

View workflow job for this annotation

GitHub Actions / Firedrake complex

test_transfer_manager.test_cached_transfer[CG]

ValueError: Order 0 invalid for 'Lagrange' finite element.
Raw output
family = 'CG'

    @pytest.mark.parametrize("family", ("CG", "R"))
    def test_cached_transfer(family):
        # Test that we can properly reuse transfers within solve
        sp = {"mat_type": "matfree",
              "pc_type": "mg",
              "mg_coarse_pc_type": "none",
              "mg_levels_pc_type": "none"}
    
        base = UnitSquareMesh(1, 1)
        hierarchy = MeshHierarchy(base, 3)
        mesh = hierarchy[-1]
    
>       V = FunctionSpace(mesh, family, 0)

tests/multigrid/test_transfer_manager.py:149: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
petsc4py/PETSc/Log.pyx:188: in petsc4py.PETSc.Log.EventDecorator.decorator.wrapped_func
    ???
petsc4py/PETSc/Log.pyx:189: in petsc4py.PETSc.Log.EventDecorator.decorator.wrapped_func
    ???
firedrake/functionspace.py:104: in FunctionSpace
    element = make_scalar_element(mesh, family, degree, vfamily, vdegree, variant)
petsc4py/PETSc/Log.pyx:188: in petsc4py.PETSc.Log.EventDecorator.decorator.wrapped_func
    ???
petsc4py/PETSc/Log.pyx:189: in petsc4py.PETSc.Log.EventDecorator.decorator.wrapped_func
    ???
firedrake/functionspace.py:70: in make_scalar_element
    return finat.ufl.FiniteElement(family, cell=cell, degree=degree, variant=variant)
../firedrake_venv/src/FInAT/finat/ufl/finiteelement.py:145: in __init__
    ) = canonical_element_description(family, cell, degree, form_degree)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

family = 'Lagrange', cell = triangle, order = 0, form_degree = None

    def canonical_element_description(family, cell, order, form_degree):
        """Given basic element information, return corresponding element information on canonical form.
    
        Input: family, cell, (polynomial) order, form_degree
        Output: family (canonical), short_name (for printing), order, value shape,
        reference value shape, sobolev_space.
    
        This is used by the FiniteElement constructor to ved input
        data against the element list and aliases defined in ufl.
        """
        # Get domain dimensions
        if cell is not None:
            tdim = cell.topological_dimension()
            gdim = cell.geometric_dimension()
            if isinstance(cell, Cell):
                cellname = cell.cellname()
            else:
                cellname = None
        else:
            tdim = None
            gdim = None
            cellname = None
    
        # Catch general FEEC notation "P" and "S"
        if form_degree is not None and family in ("P", "S"):
            family, order = feec_element(family, tdim, order, form_degree)
    
        if form_degree is not None and family in ("P L2", "S L2"):
            family, order = feec_element_l2(family, tdim, order, form_degree)
    
        # Check whether this family is an alias for something else
        while family in aliases:
            if tdim is None:
                raise ValueError("Need dimension to handle element aliases.")
            (family, order) = aliases[family](family, tdim, order, form_degree)
    
        # Check that the element family exists
        if family not in ufl_elements:
            raise ValueError(f"Unknown finite element '{family}'.")
    
        # Check that element data is valid (and also get common family
        # name)
        (family, short_name, value_rank, sobolev_space, mapping, krange, cellnames) = ufl_elements[family]
    
        # Accept CG/DG on all kind of cells, but use Q/DQ on "product" cells
        if cellname in set(cubes) - set(simplices) or isinstance(cell, TensorProductCell):
            if family == "Lagrange":
                family = "Q"
            elif family == "Discontinuous Lagrange":
                if order >= 1:
                    warnings.warn("Discontinuous Lagrange element requested on %s, creating DQ element." % cell.cellname())
                family = "DQ"
            elif family == "Discontinuous Lagrange L2":
                if order >= 1:
                    warnings.warn(f"Discontinuous Lagrange L2 element requested on {cell.cellname()}, "
                                  "creating DQ L2 element.")
                family = "DQ L2"
    
        # Validate cellname if a valid cell is specified
        if not (cellname is None or cellname in cellnames):
            raise ValueError(f"Cellname '{cellname}' invalid for '{family}' finite element.")
    
        # Validate order if specified
        if order is not None:
            if krange is None:
                raise ValueError(f"Order {order} invalid for '{family}' finite element, should be None.")
            kmin, kmax = krange
            if not (kmin is None or (asarray(order) >= kmin).all()):
>               raise ValueError(f"Order {order} invalid for '{family}' finite element.")
E               ValueError: Order 0 invalid for 'Lagrange' finite element.

../firedrake_venv/src/FInAT/finat/ufl/elementlist.py:478: ValueError

Check failure on line 149 in tests/multigrid/test_transfer_manager.py

View workflow job for this annotation

GitHub Actions / Firedrake real

test_transfer_manager.test_cached_transfer[CG]

ValueError: Order 0 invalid for 'Lagrange' finite element.
Raw output
family = 'CG'

    @pytest.mark.parametrize("family", ("CG", "R"))
    def test_cached_transfer(family):
        # Test that we can properly reuse transfers within solve
        sp = {"mat_type": "matfree",
              "pc_type": "mg",
              "mg_coarse_pc_type": "none",
              "mg_levels_pc_type": "none"}
    
        base = UnitSquareMesh(1, 1)
        hierarchy = MeshHierarchy(base, 3)
        mesh = hierarchy[-1]
    
>       V = FunctionSpace(mesh, family, 0)

tests/multigrid/test_transfer_manager.py:149: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
petsc4py/PETSc/Log.pyx:188: in petsc4py.PETSc.Log.EventDecorator.decorator.wrapped_func
    ???
petsc4py/PETSc/Log.pyx:189: in petsc4py.PETSc.Log.EventDecorator.decorator.wrapped_func
    ???
firedrake/functionspace.py:104: in FunctionSpace
    element = make_scalar_element(mesh, family, degree, vfamily, vdegree, variant)
petsc4py/PETSc/Log.pyx:188: in petsc4py.PETSc.Log.EventDecorator.decorator.wrapped_func
    ???
petsc4py/PETSc/Log.pyx:189: in petsc4py.PETSc.Log.EventDecorator.decorator.wrapped_func
    ???
firedrake/functionspace.py:70: in make_scalar_element
    return finat.ufl.FiniteElement(family, cell=cell, degree=degree, variant=variant)
../firedrake_venv/src/FInAT/finat/ufl/finiteelement.py:145: in __init__
    ) = canonical_element_description(family, cell, degree, form_degree)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

family = 'Lagrange', cell = triangle, order = 0, form_degree = None

    def canonical_element_description(family, cell, order, form_degree):
        """Given basic element information, return corresponding element information on canonical form.
    
        Input: family, cell, (polynomial) order, form_degree
        Output: family (canonical), short_name (for printing), order, value shape,
        reference value shape, sobolev_space.
    
        This is used by the FiniteElement constructor to ved input
        data against the element list and aliases defined in ufl.
        """
        # Get domain dimensions
        if cell is not None:
            tdim = cell.topological_dimension()
            gdim = cell.geometric_dimension()
            if isinstance(cell, Cell):
                cellname = cell.cellname()
            else:
                cellname = None
        else:
            tdim = None
            gdim = None
            cellname = None
    
        # Catch general FEEC notation "P" and "S"
        if form_degree is not None and family in ("P", "S"):
            family, order = feec_element(family, tdim, order, form_degree)
    
        if form_degree is not None and family in ("P L2", "S L2"):
            family, order = feec_element_l2(family, tdim, order, form_degree)
    
        # Check whether this family is an alias for something else
        while family in aliases:
            if tdim is None:
                raise ValueError("Need dimension to handle element aliases.")
            (family, order) = aliases[family](family, tdim, order, form_degree)
    
        # Check that the element family exists
        if family not in ufl_elements:
            raise ValueError(f"Unknown finite element '{family}'.")
    
        # Check that element data is valid (and also get common family
        # name)
        (family, short_name, value_rank, sobolev_space, mapping, krange, cellnames) = ufl_elements[family]
    
        # Accept CG/DG on all kind of cells, but use Q/DQ on "product" cells
        if cellname in set(cubes) - set(simplices) or isinstance(cell, TensorProductCell):
            if family == "Lagrange":
                family = "Q"
            elif family == "Discontinuous Lagrange":
                if order >= 1:
                    warnings.warn("Discontinuous Lagrange element requested on %s, creating DQ element." % cell.cellname())
                family = "DQ"
            elif family == "Discontinuous Lagrange L2":
                if order >= 1:
                    warnings.warn(f"Discontinuous Lagrange L2 element requested on {cell.cellname()}, "
                                  "creating DQ L2 element.")
                family = "DQ L2"
    
        # Validate cellname if a valid cell is specified
        if not (cellname is None or cellname in cellnames):
            raise ValueError(f"Cellname '{cellname}' invalid for '{family}' finite element.")
    
        # Validate order if specified
        if order is not None:
            if krange is None:
                raise ValueError(f"Order {order} invalid for '{family}' finite element, should be None.")
            kmin, kmax = krange
            if not (kmin is None or (asarray(order) >= kmin).all()):
>               raise ValueError(f"Order {order} invalid for '{family}' finite element.")
E               ValueError: Order 0 invalid for 'Lagrange' finite element.

../firedrake_venv/src/FInAT/finat/ufl/elementlist.py:478: ValueError
u = Function(V)
F = inner(u - 1, TestFunction(V)) * dx

# This test will fail if we raise this warning
with warnings.catch_warnings():
warnings.filterwarnings("error", "Creating new TransferManager", RuntimeWarning)
solve(F == 0, u, solver_parameters=sp)

0 comments on commit de93ebc

Please sign in to comment.