# -*- 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")]