1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
# -*- coding: utf-8 -*-
"""
This module provides compilation of forms required for goal-oriented
error control
"""
# Copyright (C) 2010 Marie E. Rognes
#
# This file is part of FFC.
#
# FFC is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# FFC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with FFC. If not, see <http://www.gnu.org/licenses/>.
from ufl.utils.sorting import sorted_by_key
from ufl import Coefficient
from ffc.log import error
from ffc.compiler import compile_form
__all__ = ["compile_with_error_control"]
def compile_with_error_control(forms, object_names, reserved_objects,
prefix, parameters):
"""
Compile forms and additionally generate and compile forms required
for performing goal-oriented error control
For linear problems, the input forms should be a bilinear form (a)
and a linear form (L) specifying the variational problem and
additionally a linear form (M) specifying the goal functional.
For nonlinear problems, the input should be linear form (F) and a
functional (M) specifying the goal functional.
*Arguments*
forms (tuple)
Three (linear case) or two (nonlinear case) forms
specifying the primal problem and the goal
object_names (dict)
Map from object ids to object names
reserved_names (dict)
Map from reserved object names to object ids
prefix (string)
Basename of header file
parameters (dict)
Parameters for form compilation
"""
# Check input arguments
F, M, u = prepare_input_arguments(forms, object_names, reserved_objects)
# Generate forms to be used for the error control
from ffc.errorcontrol.errorcontrolgenerators import UFLErrorControlGenerator
generator = UFLErrorControlGenerator(F, M, u)
ec_forms = generator.generate_all_error_control_forms()
# Check that there are no conflicts between user defined and
# generated names
ec_names = generator.ec_names
if set(object_names.values()) & set(ec_names.values()):
comment = "%s are reserved error control names." % str(sorted(ec_names.values()))
error("Conflict between user defined and generated names: %s" % comment)
# Add names generated for error control to object_names
for (objid, name) in sorted_by_key(ec_names):
object_names[objid] = name
# Compile error control and input (pde + goal) forms as normal
forms = generator.primal_forms()
code_h, code_c = compile_form(ec_forms + forms, object_names, prefix, parameters)
return code_h, code_c
def prepare_input_arguments(forms, object_names, reserved_objects):
"""
Extract required input arguments to UFLErrorControlGenerator.
*Arguments*
forms (tuple)
Three (linear case) or two (nonlinear case) forms
specifying the primal problem and the goal
object_names (dict)
Map from object ids to object names
reserved_names (dict)
Map from reserved object names to object ids
*Returns*
tuple (of length 3) containing
Form or tuple
A single linear form or a tuple of a bilinear and a linear
form
Form
A linear form or a functional for the goal functional
Coefficient
The coefficient considered as the unknown
"""
# Check that we get a tuple of forms
if not isinstance(forms, (list, tuple)):
error("Expecting tuple of forms, got %s" % str(forms))
def __is_nonlinear(forms):
return len(forms) == 2
def __is_linear(forms):
return len(forms) == 3
# Extract Coefficient labelled as 'unknown'
u = reserved_objects.get("unknown", None)
if __is_nonlinear(forms):
# Check that unknown is defined
if u is None:
error("Can't extract 'unknown'. The Coefficient representing the unknown must be labelled by 'unknown' for nonlinear problems.")
(F, M) = forms
# Check that forms have the expected rank
assert len(F.arguments()) == 1
assert len(M.arguments()) == 0
# Return primal, goal and unknown
return (F, M, u)
elif __is_linear(forms):
# Throw error if unknown is given, don't quite know what to do
# with this case yet
if u is not None:
error("'unknown' defined: not implemented for linear problems")
(a, L, M) = forms
# Check that forms have the expected rank
arguments = a.arguments()
assert len(arguments) == 2
assert len(L.arguments()) == 1
assert len(M.arguments()) == 1
# Standard case: create default Coefficient in trial space and
# label it __discrete_primal_solution
V = arguments[1].ufl_function_space()
u = Coefficient(V)
object_names[id(u)] = "__discrete_primal_solution"
return ((a, L), M, u)
else:
error("Wrong input tuple length: got %s, expected 2 or 3-tuple"
% str(forms))
|