3
"""Unit tests for error control"""
5
# Copyright (C) 2011 Marie E. Rognes
7
# This file is part of DOLFIN.
9
# DOLFIN is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU Lesser General Public License as published by
11
# the Free Software Foundation, either version 3 of the License, or
12
# (at your option) any later version.
14
# DOLFIN is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# GNU Lesser General Public License for more details.
19
# You should have received a copy of the GNU Lesser General Public License
20
# along with DOLFIN. If not, see <http://www.gnu.org/licenses/>.
23
from ufl.algorithms import replace
26
from dolfin.fem.adaptivesolving import *
27
from dolfin_utils.test import skip_in_parallel
29
# FIXME: Move this to dolfin for user access?
30
def reconstruct_refined_form(form, functions, mesh):
33
w = Function(u.leaf_node().function_space())
34
w.assign(u.leaf_node())
35
function_mapping[u] = w
36
domain = mesh.leaf_node().ufl_domain()
37
newform = replace_integral_domains(replace(form, function_mapping), domain)
38
return newform, function_mapping
41
# This must be scope function, because the tests will modify some of the objects,
42
# including the mesh which gets its hierarchial adapted submeshes attached.
43
fixt = pytest.fixture(scope="function")
47
return UnitSquareMesh(8, 8)
51
return FunctionSpace(mesh, "Lagrange", 1)
61
return inner(grad(u), grad(v))*dx()
66
f = Expression("10*exp(-(pow(x[0] - 0.5, 2) + pow(x[1] - 0.5, 2)) / 0.02)", degree=1)
67
g = Expression("sin(5*x[0])", degree=1)
68
return f*v*dx() + g*v*ds()
71
def problem(a, L, u, V):
72
bc = [DirichletBC(V, 0.0, "x[0] < DOLFIN_EPS || x[0] > 1.0 - DOLFIN_EPS")]
73
return LinearVariationalProblem(a, L, u, bc)
80
def ec(problem, goal):
81
return generate_error_control(problem, goal)
85
def test_check_domains(goal, mesh, a, L):
86
# Asserting that domains are ok before trying error control generation
87
msg = "Expecting only the domain from the mesh to get here through u."
88
assert len(goal.domains()) == 1, msg
89
assert goal.domains()[0] == mesh.ufl_domain(), msg
90
assert len(a.domains()) == 1, msg
91
assert a.domains()[0] == mesh.ufl_domain(), msg
92
assert len(L.domains()) == 1, msg
93
assert L.domains()[0] == mesh.ufl_domain(), msg
97
def test_error_estimation(problem, u, ec):
99
# Solve variational problem once
100
solver = LinearVariationalSolver(problem)
103
# Compute error estimate
104
error_estimate = ec.estimate_error(u, problem.bcs())
106
# Compare estimate with defined reference
107
reference = 0.0011789985750808342
108
assert round(error_estimate - reference, 7) == 0
112
def test_error_indicators(problem, u, mesh):
114
# Solve variational problem once
115
solver = LinearVariationalSolver(problem)
118
# Compute error indicators
119
indicators = Vector(mesh.mpi_comm(), u.function_space().mesh().num_cells())
121
#ec.compute_indicators(indicators, u) #
123
reference = 1.0 # FIXME
124
assert round(indicators.sum() - reference, 7) == 0
128
def _test_adaptive_solve(problem, goal, u, mesh):
130
# Solve problem adaptively
131
solver = AdaptiveLinearVariationalSolver(problem, goal)
135
# Note: This old approach is now broken, as it doesn't change the integration domain:
136
#M = replace(goal, {u: w})
137
# This new approach handles the integration domain properly:
138
M, fm = reconstruct_refined_form(goal, [u], mesh)
140
# Compare computed goal with reference
141
reference = 0.12583303389560166
142
assert round(assemble(M) - reference, 7) == 0