1
2
3 """
4 Codegeneration utilities.
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 from itertools import chain
30 import re
31 import ufl
32 import ufc_utils
33 import SyFi
34
35 from ufl.classes import Measure
36 from ufl.algorithms import FormData, preprocess
37
38 from dolfin_utils.wrappers import generate_dolfin_code, UFCFormNames
39
40 from sfc.common.utilities import unique
41 from sfc.common.output import sfc_assert, sfc_error, sfc_info, sfc_debug
42
43 from sfc.common.options import default_parameters
44 from sfc.representation import ElementRepresentation, FormRepresentation, \
45 CellIntegralRepresentation, ExteriorFacetIntegralRepresentation, \
46 InteriorFacetIntegralRepresentation
47 from sfc.codegeneration.formcg import FormCG
48 from sfc.codegeneration.dofmapcg import DofMapCG
49 from sfc.codegeneration.finiteelementcg import FiniteElementCG
50 from sfc.codegeneration.cellintegralcg import CellIntegralCG
51 from sfc.codegeneration.exteriorfacetintegralcg import ExteriorFacetIntegralCG
52 from sfc.codegeneration.interiorfacetintegralcg import InteriorFacetIntegralCG
53
54
55 _header_template = r"""/*
56 * %(name)s.h
57 *
58 * This file was automatically generated by SFC.
59 *
60 * http://www.fenics.org/syfi/
61 *
62 */
63
64 #ifndef GENERATED_SFC_CODE_%(name)s
65 #define GENERATED_SFC_CODE_%(name)s
66
67 #include "ufc.h"
68
69 %(includes)s
70
71 //namespace sfc
72 //{
73 %(body)s
74 //}
75
76 #endif
77 """
78
79
80 _implementation_template = r"""/*
81 * %(name)s.cpp
82 *
83 * This file was automatically generated by SFC.
84 *
85 * http://www.fenics.org/syfi/
86 *
87 */
88
89 #include "ufc.h"
90
91 #include "%(name)s.h"
92
93 %(includes)s
94
95 //namespace sfc
96 //{
97 %(body)s
98 //}
99 """
100
102 return ("iostream", "cmath", "stdexcept", "cstring")
103
105 "Template formatting with improved checking for template argument mismatch."
106 expected_keys = set(re.findall('%\((\w+)\)', format_string))
107 actual_keys = set(code_dict.keys())
108
109 missing_keys = expected_keys.difference(actual_keys)
110 if missing_keys:
111 print "When formatting code using template, missing keys:"
112 print "\n".join(sorted(missing_keys))
113 print
114
115
116
117
118
119
120
121 return format_string % code_dict
122
124 sfc_debug("Entering generate_finite_element_code")
125 classname = ferep.finite_element_classname
126 cg = FiniteElementCG(ferep)
127 code_dict = cg.generate_code_dict()
128 supportcode = cg.generate_support_code()
129
130 hcode = apply_code_dict(ufc_utils.finite_element_header, code_dict)
131 ccode = supportcode + "\n"*3
132 ccode += apply_code_dict(ufc_utils.finite_element_implementation, code_dict)
133
134 includes = cg.hincludes() + cg.cincludes()
135
136 system_headers = common_system_headers()
137 local_headers = unique("%s.h" % e.finite_element_classname for e in ferep.sub_elements)
138
139 hincludes = "\n".join('#include "%s"' % inc for inc in cg.hincludes())
140 cincludes = "\n".join('#include <%s>' % f for f in system_headers)
141 cincludes += "\n"
142 cincludes += "\n".join('#include "%s"' % inc for inc in chain(cg.cincludes(), local_headers))
143
144 hcode = _header_template % { "body": hcode, "name": classname, "includes": hincludes }
145 ccode = _implementation_template % { "body": ccode, "name": classname, "includes": cincludes }
146 sfc_debug("Leaving generate_finite_element_code")
147 return classname, (hcode, ccode), includes
148
150 sfc_debug("Entering generate_dof_map_code")
151 classname = ferep.dof_map_classname
152 cg = DofMapCG(ferep)
153 code_dict = cg.generate_code_dict()
154 supportcode = cg.generate_support_code()
155
156 hcode = apply_code_dict(ufc_utils.dofmap_header, code_dict)
157 ccode = supportcode + "\n"*3
158 ccode += apply_code_dict(ufc_utils.dofmap_implementation, code_dict)
159
160 includes = cg.hincludes() + cg.cincludes()
161
162 system_headers = common_system_headers()
163 local_headers = unique("%s.h" % e.dof_map_classname for e in ferep.sub_elements)
164
165 hincludes = "\n".join('#include "%s"' % inc for inc in cg.hincludes())
166 cincludes = "\n".join('#include <%s>' % f for f in system_headers)
167 cincludes += "\n"
168 cincludes += "\n".join('#include "%s"' % inc for inc in chain(cg.cincludes(), local_headers))
169
170 hcode = _header_template % { "body": hcode, "name": classname, "includes": hincludes }
171 ccode = _implementation_template % { "body": ccode, "name": classname, "includes": cincludes }
172 sfc_debug("Leaving generate_dof_map_code")
173 return classname, (hcode, ccode), includes
174
176 sfc_debug("Entering generate_cell_integral_code")
177 itgrep = CellIntegralRepresentation(integrals, formrep)
178
179 cg = CellIntegralCG(itgrep)
180 code_dict = cg.generate_code_dict()
181 supportcode = cg.generate_support_code()
182
183
184 hcode = apply_code_dict(ufc_utils.cell_integral_header, code_dict)
185 ccode = supportcode + "\n"*3 + apply_code_dict(ufc_utils.cell_integral_implementation, code_dict)
186
187 includes = cg.hincludes() + cg.cincludes()
188
189 system_headers = common_system_headers()
190
191 hincludes = "\n".join('#include "%s"' % inc for inc in cg.hincludes())
192 cincludes = "\n".join('#include <%s>' % f for f in system_headers)
193 cincludes += "\n"
194 cincludes += "\n".join('#include "%s"' % inc for inc in cg.cincludes())
195
196 hcode = _header_template % { "body": hcode, "name": itgrep.classname, "includes": hincludes }
197 ccode = _implementation_template % { "body": ccode, "name": itgrep.classname, "includes": cincludes }
198 sfc_debug("Leaving generate_cell_integral_code")
199 return itgrep.classname, (hcode, ccode), includes
200
202 sfc_debug("Entering generate_exterior_facet_integral_code")
203 itgrep = ExteriorFacetIntegralRepresentation(integrals, formrep)
204
205 cg = ExteriorFacetIntegralCG(itgrep)
206 code_dict = cg.generate_code_dict()
207 supportcode = cg.generate_support_code()
208
209
210 hcode = apply_code_dict(ufc_utils.exterior_facet_integral_header, code_dict)
211 ccode = supportcode + "\n"*3 + apply_code_dict(ufc_utils.exterior_facet_integral_implementation, code_dict)
212
213 includes = cg.hincludes() + cg.cincludes()
214
215 system_headers = common_system_headers()
216
217 hincludes = "\n".join('#include "%s"' % inc for inc in cg.hincludes())
218 cincludes = "\n".join('#include <%s>' % f for f in system_headers)
219 cincludes += "\n"
220 cincludes += "\n".join('#include "%s"' % inc for inc in cg.cincludes())
221
222 hcode = _header_template % { "body": hcode, "name": itgrep.classname, "includes": hincludes }
223 ccode = _implementation_template % { "body": ccode, "name": itgrep.classname, "includes": cincludes }
224 sfc_debug("Leaving generate_exterior_facet_integral_code")
225 return itgrep.classname, (hcode, ccode), includes
226
228 sfc_debug("Entering generate_interior_facet_integral_code")
229 itgrep = InteriorFacetIntegralRepresentation(integrals, formrep)
230
231 cg = InteriorFacetIntegralCG(itgrep)
232 code_dict = cg.generate_code_dict()
233 supportcode = cg.generate_support_code()
234
235 hcode = apply_code_dict(ufc_utils.interior_facet_integral_header, code_dict)
236 ccode = supportcode + "\n"*3 + apply_code_dict(ufc_utils.interior_facet_integral_implementation, code_dict)
237
238 includes = cg.hincludes() + cg.cincludes()
239
240 system_headers = common_system_headers()
241
242 hincludes = "\n".join('#include "%s"' % inc for inc in cg.hincludes())
243 cincludes = "\n".join('#include <%s>' % f for f in system_headers)
244 cincludes += "\n"
245 cincludes += "\n".join('#include "%s"' % inc for inc in cg.cincludes())
246
247 hcode = _header_template % { "body": hcode, "name": itgrep.classname, "includes": hincludes }
248 ccode = _implementation_template % { "body": ccode, "name": itgrep.classname, "includes": cincludes }
249 sfc_debug("Leaving generate_interior_facet_integral_code")
250 return itgrep.classname, (hcode, ccode), includes
251
276
278 f = open(filename, "w")
279 f.write(text)
280 f.close()
281
283 sfc_debug("Entering write_code")
284 if isinstance(code, tuple):
285
286 hcode, ccode = code
287 hname = classname + ".h"
288 cname = classname + ".cpp"
289 open(hname, "w").write(hcode)
290 open(cname, "w").write(ccode)
291 ret = (hname, cname)
292 else:
293
294 name = classname + ".h"
295 open(name, "w").write(code)
296 ret = (name,)
297 sfc_debug("Leaving write_code")
298 return ret
299
341
342 dolfin_header_template = """/*
343 * DOLFIN wrapper code generated by the SyFi Form Compiler.
344 */
345
346 %s
347 """
348
349 -def generate_code(input, objects, options = None, common_cell=None):
350 """Generate code from input and options.
351
352 @param input:
353 TODO
354 @param options:
355 TODO
356 """
357 sfc_debug("Entering generate_code")
358
359 if options is None:
360 options = default_parameters()
361
362 ufl_elements, formdatas = compiler_input(input, objects, common_cell=common_cell)
363
364 filenames = []
365 needed_files = []
366 formnames = []
367
368
369 element_reps = {}
370 last_nsd = None
371 generated_elements = set()
372 for e in ufl_elements:
373
374 nsd = e.cell().geometric_dimension()
375 if not nsd == last_nsd and isinstance(nsd, int):
376 SyFi.initSyFi(nsd)
377 last_nsd = nsd
378
379
380 quad_rule = None
381 assert not "Quadrature" in e.family()
382 if e in element_reps:
383 continue
384
385 erep = ElementRepresentation(e, quad_rule, options, element_reps)
386 element_reps[e] = erep
387
388
389 todo = [erep]
390 ereps = []
391 while todo:
392 erep = todo.pop()
393
394 if not erep.ufl_element in generated_elements:
395 generated_elements.add(erep.ufl_element)
396 ereps.append(erep)
397
398 for subrep in erep.sub_elements:
399 todo.append(subrep)
400
401 for erep in ereps:
402
403 classname, code, includes = generate_finite_element_code(erep)
404 filenames.extend( write_code(classname, code) )
405 needed_files.extend(includes)
406
407
408 classname, code, includes = generate_dof_map_code(erep)
409 filenames.extend( write_code(classname, code) )
410 needed_files.extend(includes)
411
412
413 for formdata in formdatas:
414
415 nsd = formdata.geometric_dimension
416 if not nsd == last_nsd:
417 SyFi.initSyFi(nsd)
418 last_nsd = nsd
419
420
421 formrep = FormRepresentation(formdata, element_reps, options)
422
423 pf = formdata.preprocessed_form
424
425
426 ig = pf.integral_groups()
427
428
429 for domain in pf.domains(Measure.CELL):
430 integrals = ig[domain]
431 classname, code, includes = generate_cell_integral_code(integrals, formrep)
432 filenames.extend( write_code(classname, code) )
433 needed_files.extend(includes)
434
435
436 for domain in pf.domains(Measure.EXTERIOR_FACET):
437 integrals = ig[domain]
438 classname, code, includes = generate_exterior_facet_integral_code(integrals, formrep)
439 filenames.extend( write_code(classname, code) )
440 needed_files.extend(includes)
441
442
443 for domain in pf.domains(Measure.INTERIOR_FACET):
444 integrals = ig[domain]
445 classname, code, includes = generate_interior_facet_integral_code(integrals, formrep)
446 filenames.extend( write_code(classname, code) )
447 needed_files.extend(includes)
448
449
450 code, includes = generate_form_code(formrep)
451 filenames.extend( write_code(formrep.classname, code) )
452 needed_files.extend(includes)
453
454
455 namespace = ""
456 ufc_form_classname = namespace + formrep.classname
457 ufc_finite_element_classnames = [namespace + name for name in formrep.fe_names]
458 ufc_dof_map_classnames = [namespace + name for name in formrep.dm_names]
459
460 fn = UFCFormNames(formdata.name, formdata.coefficient_names,
461 ufc_form_classname, ufc_finite_element_classnames, ufc_dof_map_classnames)
462 formnames.append(fn)
463
464
465 if needed_files:
466 raise NotImplementedError("FIXME: Implement fetching non-ufc-class files like DofPtv and quadrature rule files.")
467
468 filenames = list(unique(chain(filenames, needed_files)))
469 hfilenames = [f for f in filenames if f.endswith(".h")]
470 cfilenames = [f for f in filenames if f.endswith(".cpp")]
471
472
473 if options.code.dolfin_wrappers:
474 if not formnames:
475 print "NOT generating dolfin wrappers, missing forms!"
476 else:
477 prefix = options.code.prefix
478 header = dolfin_header_template % "\n".join('#include "%s"' % h for h in hfilenames)
479 sfc_info("Generating DOLFIN wrapper code, formnames are %s." % "\n".join(map(str,formnames)))
480 dolfin_code = generate_dolfin_code(prefix, header, formnames)
481 dolfin_filename = "%s.h" % prefix
482 write_file(dolfin_filename, dolfin_code)
483 hfilenames.append(dolfin_filename)
484
485 sfc_debug("Leaving generate_code")
486 return hfilenames, cfilenames
487