1
# Copyright (C) 2011 Marie E. Rognes
3
# This file is part of DOLFIN.
5
# DOLFIN is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU Lesser General Public License as published by
7
# the Free Software Foundation, either version 3 of the License, or
8
# (at your option) any later version.
10
# DOLFIN is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU Lesser General Public License for more details.
15
# You should have received a copy of the GNU Lesser General Public License
16
# along with DOLFIN. If not, see <http://www.gnu.org/licenses/>.
18
# Based on original implementation by Martin Alnes and Anders Logg
20
# Modified by Anders Logg 2011
22
# Last changed: 2011-11-15
24
from includes import snippets
25
from functionspace import *
26
from goalfunctional import generate_update_ec
28
__all__ = ["generate_form"]
30
#-------------------------------------------------------------------------------
31
def generate_form(form, classname):
32
"""Generate dolfin wrapper code associated with a form including
33
code for function spaces used in form and typedefs
36
A UFCFormNames instance
41
# Generate code for Form_x_FunctionSpace_y subclasses
42
wrap = apply_function_space_template
43
blocks = [wrap("%s_FunctionSpace_%d" % (classname, i),
44
form.ufc_finite_element_classnames[i],
45
form.ufc_dofmap_classnames[i]) for i in range(form.rank)]
47
# Add typedefs CoefficientSpace_z -> Form_x_FunctionSpace_y
48
blocks += ["typedef CoefficientSpace_%s %s_FunctionSpace_%d;\n"
49
% (form.coefficient_names[i], classname, form.rank + i)
50
for i in range(form.num_coefficients)]
52
# Generate Form subclass
53
blocks += [generate_form_class(form, classname)]
56
return "\n".join(blocks)
57
#-------------------------------------------------------------------------------
58
def generate_form_class(form, classname):
59
"Generate dolfin wrapper code for a single Form class."
61
# Generate constructors
62
constructors = generate_form_constructors(form, classname)
64
# Generate data for coefficient assignments
65
(number, name) = generate_coefficient_map_data(form)
67
# Generate typedefs for FunctionSpace subclasses for Coefficients
68
typedefs = [" // Typedefs", generate_typedefs(form, classname), ""]
70
# Member variables for coefficients
71
members = [" dolfin::CoefficientAssigner %s;" % coefficient
72
for coefficient in form.coefficient_names]
73
if form.superclassname == "GoalFunctional":
74
members += [generate_update_ec(form)]
76
# Group typedefs and members together for inserting into template
77
additionals = "\n".join(typedefs + [" // Coefficients"] + members)
79
# Wrap functions in class body
80
code = apply_form_template(classname, constructors, number, name,
81
additionals, form.superclassname)
85
#-------------------------------------------------------------------------------
86
def generate_coefficient_map_data(form):
87
"""Generate data for code for the functions
88
Form::coefficient_number and Form::coefficient_name."""
90
# Write error if no coefficients
91
if form.num_coefficients == 0:
93
dolfin::dolfin_error("generated code for class %s",
94
"access coefficient data",
95
"There are no coefficients");''' % form.superclassname
96
num = "\n %s\n return 0;" % message
97
name = '\n %s\n return "unnamed";' % message
100
# Otherwise create switch
103
name = ' switch (i)\n {\n'
104
for i, coeff in enumerate(form.coefficient_names):
105
num += ' %s(name == "%s")\n return %d;\n' % (ifstr, coeff, i)
106
name += ' case %d:\n return "%s";\n' % (i, coeff)
109
# Create final return
111
dolfin::dolfin_error("generated code for class %s",
112
"access coefficient data",
113
"Invalid coefficient");''' % form.superclassname
114
num += "\n %s\n return 0;" % message
115
name += ' }\n\n %s\n return "unnamed";' % message
118
#-------------------------------------------------------------------------------
119
def generate_form_constructors(form, classname):
120
"""Generate the dolfin::Form constructors for different
121
combinations of references/shared pointers etc."""
123
coeffs = ("referenced_coefficient", "shared_ptr_coefficient")
124
spaces = ("referenced_space", "shared_ptr_space")
126
# Treat functionals a little special
128
spaces = ("referenced_mesh", "shared_ptr_mesh")
130
# Generate permutations of constructors
133
constructors += [generate_constructor(form, classname, space)]
134
if form.num_coefficients > 0:
135
constructors += [generate_constructor(form, classname, space, coeff)
138
# Return joint constructor code
139
return "\n\n".join(constructors)
141
#-------------------------------------------------------------------------------
142
def generate_constructor(form, classname, space_tag, coefficient_tag=None):
143
"Generate a single Form constructor according to the given parameters."
145
# Extract correct code snippets
146
(argument, assign) = snippets[space_tag]
148
# Construct list of arguments and function space assignments
151
arguments = [argument % (name % i) for i in reversed(range(form.rank))]
152
assignments = [assign % (i, name % i) for i in range(form.rank)]
154
arguments = [argument]
155
assignments = [assign]
157
# Add coefficients to argument/assignment lists if specified
158
if coefficient_tag is not None:
159
(argument, assign) = snippets[coefficient_tag]
160
arguments += [argument % name for name in form.coefficient_names]
161
if form.rank > 0: # FIXME: To match old generated code only
163
assignments += [assign %(name, name) for name in form.coefficient_names]
165
# Add assignment of _ufc_form variable
166
line = "\n _ufc_form = boost::shared_ptr<const ufc::form>(new %s());"
167
# FIXME: To match old generated code only
168
if form.rank == 0 and coefficient_tag is None:
169
line = " _ufc_form = boost::shared_ptr<const ufc::form>(new %s());"
170
assignments += [line % form.ufc_form_classname]
172
# Construct list for initialization of Coefficient references
173
initializers = ["%s(*this, %d)" % (name, number)
174
for (number, name) in enumerate(form.coefficient_names)]
176
# Join lists together
177
arguments = ", ".join(arguments)
178
initializers = ", " + ", ".join(initializers) if initializers else ""
179
body = "\n".join(assignments)
181
# Wrap code into template
182
args = {"classname": classname,
184
"num_coefficients": form.num_coefficients,
185
"arguments": arguments,
186
"initializers": initializers,
188
"superclass": form.superclassname
190
code = form_constructor_template % args
192
#-------------------------------------------------------------------------------
193
form_class_template = """\
194
class %(classname)s: public dolfin::%(superclass)s
204
/// Return the number of the coefficient with this name
205
virtual std::size_t coefficient_number(const std::string& name) const
207
%(coefficient_number)s
210
/// Return the name of the coefficient with this number
211
virtual std::string coefficient_name(std::size_t i) const
219
#-------------------------------------------------------------------------------
220
# Template code for Form constructor
221
form_constructor_template = """\
223
%(classname)s(%(arguments)s):
224
dolfin::%(superclass)s(%(rank)d, %(num_coefficients)d)%(initializers)s
228
#-------------------------------------------------------------------------------
229
def apply_form_template(classname, constructors, number, name, members,
231
args = {"classname": classname,
232
"superclass": superclass,
233
"constructors": constructors,
234
"coefficient_number": number,
235
"coefficient_name": name,
237
return form_class_template % args
238
#-------------------------------------------------------------------------------