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 import sfc
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
45 from sfc.representation import GeometryRepresentation
46 from sfc.representation import ElementRepresentation
47 from sfc.representation import FormRepresentation
48
49 from sfc.codegeneration.formcg import FormCG
50 from sfc.codegeneration.dofmapcg import DofMapCG
51 from sfc.codegeneration.finiteelementcg import FiniteElementCG
52
53
73
74
75
76 _header_template = r"""/*
77 * %(name)s.h
78 *
79 * This file was automatically generated by SFC.
80 *
81 * http://www.fenics.org/syfi/
82 *
83 */
84
85 #ifndef GENERATED_SFC_CODE_%(name)s
86 #define GENERATED_SFC_CODE_%(name)s
87
88 #include "ufc.h"
89
90 %(hincludes)s
91
92 //namespace sfc
93 //{
94 %(hbody)s
95 //}
96
97 #endif
98 """
99
100
101 _implementation_template = r"""/*
102 * %(name)s.cpp
103 *
104 * This file was automatically generated by SFC.
105 *
106 * http://www.fenics.org/syfi/
107 *
108 */
109
110 #include "ufc.h"
111
112 #include "%(name)s.h"
113
114 %(cincludes)s
115
116 //namespace // Anonymous namespace
117 //{
118 %(supportcode)s
119 //}
120
121 //namespace sfc
122 //{
123 %(cbody)s
124 //}
125 """
126
128 return ("iostream", "cmath", "stdexcept", "cstring")
129
131 "Template formatting with improved checking for template argument mismatch."
132 expected_keys = set(re.findall('%\((\w+)\)', format_string))
133 actual_keys = set(code_dict.keys())
134
135 missing_keys = expected_keys.difference(actual_keys)
136 if missing_keys:
137 print "When formatting code using template, missing keys:"
138 print "\n".join(sorted(missing_keys))
139 print
140
141
142
143
144
145
146
147 return format_string % code_dict
148
150 sfc_debug("Entering generate_class_files")
151
152 code_dict = cg.generate_code_dict()
153 classname = code_dict["classname"]
154
155 hbody = apply_code_dict(cg.header_template(), code_dict)
156 supportcode = cg.generate_support_code()
157 cbody = apply_code_dict(cg.impl_template(), code_dict)
158
159
160 system_includes = common_system_includes()
161
162 hincludes = "\n".join('#include "%s"' % inc for inc in cg.hincludes())
163
164 cincludes = "\n".join('#include <%s>' % f for f in system_includes)
165 cincludes += "\n"
166 cincludes += "\n".join('#include "%s"' % inc
167 for inc in chain(cg.cincludes(), cg.local_includes()))
168
169 hdict = { "name": classname,
170 "hbody": hbody,
171 "hincludes": hincludes }
172 cdict = { "name": classname,
173 "supportcode": supportcode,
174 "cbody": cbody,
175 "cincludes": cincludes }
176
177 hcode = _header_template % hdict
178 ccode = _implementation_template % cdict
179
180
181 includes = cg.hincludes() + cg.cincludes()
182
183 sfc_debug("Leaving generate_class_files")
184 return classname, (hcode, ccode), includes
185
187 "Write contents to a file."
188
189
190 f = open(filename, "w")
191 f.write(contents)
192 f.close()
193
195 "Write code for a class to a header file or header + impl file."
196 sfc_debug("Entering write_code")
197 if isinstance(code, tuple):
198
199 hcode, ccode = code
200 hname = classname + ".h"
201 cname = classname + ".cpp"
202 write_file(hname, hcode)
203 write_file(cname, ccode)
204 ret = (hname, cname)
205 else:
206
207 name = classname + ".h"
208 write_file(name, code)
209 ret = (name,)
210 sfc_debug("Leaving write_code")
211 return ret
212
256
257 dolfin_header_template = """/*
258 * DOLFIN wrapper code generated by the SyFi Form Compiler.
259 */
260
261 %s
262 """
264 if formnames:
265 sfc_info("Generating DOLFIN wrapper code, formnames are %s." %\
266 "\n".join(map(str,formnames)))
267
268 header = dolfin_header_template % "\n".join('#include "%s"' % h
269 for h in hfilenames)
270 dolfin_code = generate_dolfin_code(prefix, header, formnames)
271
272 dolfin_filename = "%s.h" % prefix
273 write_file(dolfin_filename, dolfin_code)
274 return dolfin_filename
275 else:
276
277 sfc_info("NOT generating dolfin wrappers, no forms to wrap!")
278 return None
279
286 update_global_syfi_nsd.last_nsd = None
287
289
290 if e in element_reps:
291 return []
292
293
294 quad_rule = None
295 assert not "Quadrature" in e.family()
296
297
298 erep = ElementRepresentation(e, geomrep, quad_rule=quad_rule,
299 options=options, cache=element_reps)
300 element_reps[e] = erep
301
302
303 todo = [erep]
304 ereps = []
305 while todo:
306 erep = todo.pop()
307
308 if not erep.ufl_element in generated_elements:
309 generated_elements.add(erep.ufl_element)
310 ereps.append(erep)
311
312 for subrep in erep.sub_elements:
313 todo.append(subrep)
314
315 return ereps
316
329
359
373
374 -def generate_code(input, objects, options=None, common_cell=None):
375 """Generate code from input and options.
376
377 @param input:
378 TODO
379 @param options:
380 TODO
381 """
382 sfc_debug("Entering generate_code")
383 sfc_assert(input, "Got no input!")
384
385 if options is None:
386 options = default_parameters()
387
388 DEBUG = 0
389 if DEBUG: print "Calling compiler_input"
390 ufl_elements, formdatas = compiler_input(input, objects, common_cell=common_cell)
391
392 generated_classes = []
393 geometry_reps = {}
394 element_reps = {}
395 generated_elements = set()
396
397
398 if DEBUG: print "Making element representations"
399 for e in ufl_elements:
400
401
402 geomrep = create_geometry_rep(e.cell().domain(), geometry_reps)
403
404
405 element_reps_list = update_element_representations(e,
406 geomrep,
407 element_reps,
408 generated_elements,
409 options)
410
411
412 gc = generate_element_ufc_code(element_reps_list, options)
413 generated_classes.extend(gc)
414
415
416 formnames = []
417 for formdata in formdatas:
418 if DEBUG: print "Starting processing another form."
419
420
421
422 geomrep = create_geometry_rep(formdata.cell.domain(), geometry_reps)
423
424
425 if DEBUG: print "Making form representation"
426 formrep = FormRepresentation(formdata, element_reps, geomrep, options)
427
428
429 if DEBUG: print "Generating form code"
430 gc = generate_form_ufc_code(formrep, options)
431 generated_classes.extend(gc)
432
433
434 namespace = ""
435 fn = UFCFormNames(formdata.name,
436 formdata.coefficient_names,
437 namespace + formrep.classname,
438 [namespace + name for name in formrep.fe_names],
439 [namespace + name for name in formrep.dm_names])
440 formnames.append(fn)
441
442 if DEBUG: print "Done with this form."
443
444
445 filenames = []
446 needed_files = []
447 for classname, code, includes in generated_classes:
448 fn = write_code(classname, code)
449 filenames.extend(fn)
450 needed_files.extend(includes)
451
452
453 if needed_files:
454 raise NotImplementedError("FIXME: Implement fetching non-ufc-class "+\
455 "files like DofPtv and quadrature rule files.")
456
457 filenames = list(unique(chain(filenames, needed_files)))
458 hfilenames = [f for f in filenames if f.endswith(".h")]
459 cfilenames = [f for f in filenames if f.endswith(".cpp")]
460
461
462 if options.code.dolfin_wrappers:
463 hfn = generate_dolfin_header_file(options.code.prefix, formnames, hfilenames)
464 if hfn: hfilenames.append(hfn)
465
466 sfc_debug("Leaving generate_code")
467 return hfilenames, cfilenames
468