Source code for ffc.backends.dolfin.wrappers

# -*- coding: utf-8 -*-
# Copyright (C) 2011 Marie E. Rognes
#
# This file is part of DOLFIN.
#
# DOLFIN 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.
#
# DOLFIN 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 DOLFIN. If not, see <http://www.gnu.org/licenses/>.
#
# Based on original implementation by Martin Alnes and Anders Logg
#
# Modified by Anders Logg 2015
#
# Last changed: 2015-11-05

from . import includes as incl
from .functionspace import *
from .form import generate_form
from .capsules import UFCElementNames

__all__ = ["generate_dolfin_code"]

# NB: generate_dolfin_namespace(...) assumes that if a coefficient has
# the same name in multiple forms, it is indeed the same coefficient:
parameters = {"use_common_coefficient_names": True}


[docs]def generate_dolfin_code(prefix, header, forms, common_function_space=False, add_guards=False, error_control=False): """Generate complete dolfin wrapper code with given generated names. @param prefix: String, prefix for all form names. @param header: Code that will be inserted at the top of the file. @param forms: List of UFCFormNames instances or single UFCElementNames. @param common_function_space: True if common function space, otherwise False @param add_guards: True iff guards (ifdefs) should be added @param error_control: True iff adaptivity typedefs (ifdefs) should be added """ # Generate dolfin namespace namespace = generate_dolfin_namespace(prefix, forms, common_function_space, error_control) # Collect pieces of code code = [incl.dolfin_tag, header, incl.stl_includes, incl.dolfin_includes, namespace] # Add ifdefs/endifs if specified if add_guards: guard_name = ("%s_h" % prefix).upper() preguard = "#ifndef %s\n#define %s\n" % (guard_name, guard_name) postguard = "\n#endif\n\n" code = [preguard] + code + [postguard] # Return code
return "\n".join(code) def generate_dolfin_namespace(prefix, forms, common_function_space=False, error_control=False): # Allow forms to represent a single space, and treat separately if isinstance(forms, UFCElementNames): return generate_single_function_space(prefix, forms) # Extract (common) coefficient spaces assert(parameters["use_common_coefficient_names"]) spaces = extract_coefficient_spaces(forms) # Generate code for common coefficient spaces code = [apply_function_space_template(*space) for space in spaces] # Generate code for forms code += [generate_form(form, "Form_%s" % form.name, error_control) for form in forms] # Generate namespace typedefs (Bilinear/Linear & Test/Trial/Function) code += [generate_namespace_typedefs(forms, common_function_space, error_control)] # Wrap code in namespace block code = "\nnamespace %s\n{\n\n%s\n}" % (prefix, "\n".join(code)) # Return code return code def generate_single_function_space(prefix, space): code = apply_function_space_template("FunctionSpace", space.ufc_finite_element_classnames[0], space.ufc_dofmap_classnames[0]) code = "\nnamespace %s\n{\n\n%s\n}" % (prefix, code) return code def generate_namespace_typedefs(forms, common_function_space, error_control): # Generate typedefs as (fro, to) pairs of strings pairs = [] # Add typedef for Functional/LinearForm/BilinearForm if only one # is present of each aliases = ["Functional", "LinearForm", "BilinearForm"] extra_aliases = {"LinearForm": "ResidualForm", "BilinearForm": "JacobianForm"} for rank in sorted(range(len(aliases)), reverse=True): forms_of_rank = [form for form in forms if form.rank == rank] if len(forms_of_rank) == 1: pairs += [("Form_%s" % forms_of_rank[0].name, aliases[rank])] if not error_control: # FIXME: Issue #91 pairs += [("MultiMeshForm_%s" % forms_of_rank[0].name, "MultiMesh" + aliases[rank])] if aliases[rank] in extra_aliases: extra_alias = extra_aliases[aliases[rank]] pairs += [("Form_%s" % forms_of_rank[0].name, extra_alias)] if not error_control: # FIXME: Issue #91 pairs += [("MultiMeshForm_%s" % forms_of_rank[0].name, "MultiMesh" + extra_alias)] # Keepin' it simple: Add typedef for FunctionSpace if term applies if common_function_space: for i, form in enumerate(forms): if form.rank: pairs += [("Form_%s::TestSpace" % form.name, "FunctionSpace")] if not error_control: # FIXME: Issue #91 pairs += [("Form_%s::MultiMeshTestSpace" % form.name, "MultiMeshFunctionSpace")] break # Add specialized typedefs when adding error control wrapppers if error_control: pairs += error_control_pairs(forms) # Combine data to typedef code typedefs = "\n".join("typedef %s %s;" % (to, fro) for (to, fro) in pairs) # Return typedefs or "" if not typedefs: return "" return "// Class typedefs\n" + typedefs + "\n" def error_control_pairs(forms): assert (len(forms) == 11), "Expecting 11 error control forms" return [("Form_%s" % forms[8].name, "BilinearForm"), ("Form_%s" % forms[9].name, "LinearForm"), ("Form_%s" % forms[10].name, "GoalFunctional")]