Package hedge :: Package backends :: Package jit :: Module flux
[hide private]
[frames] | no frames]

Source Code for Module hedge.backends.jit.flux

  1  """Just-in-time compiling backend: Flux code generation.""" 
  2   
  3  from __future__ import division 
  4   
  5  __copyright__ = "Copyright (C) 2008 Andreas Kloeckner" 
  6   
  7  __license__ = """ 
  8  This program is free software: you can redistribute it and/or modify 
  9  it under the terms of the GNU General Public License as published by 
 10  the Free Software Foundation, either version 3 of the License, or 
 11  (at your option) any later version. 
 12   
 13  This program is distributed in the hope that it will be useful, 
 14  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  GNU General Public License for more details. 
 17   
 18  You should have received a copy of the GNU General Public License 
 19  along with this program.  If not, see U{http://www.gnu.org/licenses/}. 
 20  """ 
 21   
 22   
 23   
 24   
 25  from pymbolic.mapper.c_code import CCodeMapper 
 26  from hedge.flux import FluxIdentityMapper 
 27   
 28   
 29   
 30   
 31  # flux to code mapper --------------------------------------------------------- 
32 -class FluxConcretizer(FluxIdentityMapper):
33 - def __init__(self, flux_idx, fvi):
34 self.flux_idx = flux_idx 35 self.flux_var_info = fvi
36
37 - def map_field_component(self, expr):
38 if expr.is_local: 39 where = "loc" 40 else: 41 where = "opp" 42 43 arg_name = self.flux_var_info.flux_idx_and_dep_to_arg_name[ 44 self.flux_idx, expr] 45 46 if not arg_name: 47 return 0 48 else: 49 from pymbolic import var 50 return var(arg_name+"_it")[var(where+"_idx")]
51
52 - def map_scalar_parameter(self, expr):
53 from pymbolic import var 54 return var("args._scalar_arg_%d" 55 % self.flux_var_info.scalar_parameters.index(expr))
56 57 58 59
60 -class FluxToCodeMapper(CCodeMapper):
61 - def map_normal(self, expr, enclosing_prec):
62 return "uncomplex_type(fp.loc.normal[%d])" % (expr.axis)
63
64 - def map_penalty_term(self, expr, enclosing_prec):
65 return ("uncomplex_type(pow(fp.loc.order*fp.loc.order/fp.loc.h, %(pwr)r))" 66 % {"pwr": expr.power})
67
68 - def map_function_symbol(self, expr, enclosing_prec):
69 from hedge.flux import FluxFunctionSymbol, \ 70 flux_abs, flux_min, flux_max 71 72 assert isinstance(expr, FluxFunctionSymbol) 73 74 return { 75 flux_abs: "std::abs", 76 flux_max: "std::max", 77 flux_min: "std::min", 78 }[expr]
79
80 - def map_constant(self, x, enclosing_prec):
81 import numpy 82 if isinstance(x, complex): 83 return "std::complex<uncomplex_type>(%s, %s)" % ( 84 repr(x.real), repr(x.imag)) 85 else: 86 return "uncomplex_type(%s)" % repr(x)
87 88 89 90 91
92 -def flux_to_code(f2c, is_flipped, flux_idx, fvi, flux, prec):
93 if is_flipped: 94 from hedge.flux import FluxFlipper 95 flux = FluxFlipper()(flux) 96 97 return f2c(FluxConcretizer(flux_idx, fvi)(flux), prec)
98 99 100 101 102 # flux variable info ----------------------------------------------------------
103 -def get_flux_var_info(fluxes):
104 from pytools import Record 105 class FluxVariableInfo(Record): 106 pass
107 108 scalar_parameters = set() 109 110 fvi = FluxVariableInfo( 111 scalar_parameters=None, 112 arg_specs=[], 113 arg_names=[], 114 flux_idx_and_dep_to_arg_name={}, # or 0 if zero 115 ) 116 117 field_expr_to_arg_name = {} 118 119 from hedge.flux import \ 120 FieldComponent, FluxDependencyMapper, \ 121 FluxScalarParameter 122 123 from hedge.optemplate import BoundaryPair 124 125 for flux_idx, flux_binding in enumerate(fluxes): 126 for dep in FluxDependencyMapper(include_calls=False)(flux_binding.op.flux): 127 if isinstance(dep, FluxScalarParameter): 128 scalar_parameters.add(dep) 129 elif isinstance(dep, FieldComponent): 130 is_bdry = isinstance(flux_binding.field, BoundaryPair) 131 if is_bdry: 132 if dep.is_local: 133 this_field_expr = flux_binding.field.field 134 else: 135 this_field_expr = flux_binding.field.bfield 136 else: 137 this_field_expr = flux_binding.field 138 139 from hedge.tools import is_obj_array 140 if is_obj_array(this_field_expr): 141 fc_field_expr = this_field_expr[dep.index] 142 else: 143 assert dep.index == 0 144 fc_field_expr = this_field_expr 145 146 def set_or_check(dict_instance, key, value): 147 try: 148 existing_value = dict_instance[key] 149 except KeyError: 150 dict_instance[key] = value 151 else: 152 assert existing_value == value 153 154 from pymbolic.primitives import is_zero 155 if is_zero(fc_field_expr): 156 fvi.flux_idx_and_dep_to_arg_name[flux_idx, dep] = 0 157 else: 158 if fc_field_expr not in field_expr_to_arg_name: 159 arg_name = "arg%d" % len(fvi.arg_specs) 160 field_expr_to_arg_name[fc_field_expr] = arg_name 161 162 fvi.arg_names.append(arg_name) 163 fvi.arg_specs.append((fc_field_expr, dep.is_local)) 164 else: 165 arg_name = field_expr_to_arg_name[fc_field_expr] 166 167 set_or_check( 168 fvi.flux_idx_and_dep_to_arg_name, 169 (flux_idx, dep), 170 arg_name) 171 172 if not is_bdry: 173 # Interior fluxes are used flipped as well. 174 # Make sure we have assigned arg names for the 175 # flipped case as well. 176 set_or_check( 177 fvi.flux_idx_and_dep_to_arg_name, 178 (flux_idx, 179 FieldComponent(dep.index, not dep.is_local)), 180 arg_name) 181 else: 182 raise ValueError("unknown flux dependency type: %s" % dep) 183 184 fvi.scalar_parameters = list(scalar_parameters) 185 186 return fvi 187 188 189 190
191 -def get_flux_toolchain(discr, fluxes):
192 from hedge.flux import FluxFlopCounter 193 flop_count = sum(FluxFlopCounter()(flux.op.flux) for flux in fluxes) 194 195 toolchain = discr.toolchain 196 if flop_count > 250: 197 if "jit_dont_optimize_large_exprs" in discr.debug: 198 toolchain = toolchain.with_optimization_level(0) 199 else: 200 toolchain = toolchain.with_optimization_level(1) 201 202 return toolchain
203 204 205 206
207 -def get_interior_flux_mod(fluxes, fvi, discr, dtype):
208 from codepy.cgen import \ 209 FunctionDeclaration, FunctionBody, \ 210 Const, Reference, Value, MaybeUnused, Typedef, POD, \ 211 Statement, Include, Line, Block, Initializer, Assign, \ 212 CustomLoop, For, Struct 213 214 from codepy.bpl import BoostPythonModule 215 mod = BoostPythonModule() 216 217 from pytools import to_uncomplex_dtype, flatten 218 219 S = Statement 220 mod.add_to_preamble([ 221 Include("cstdlib"), 222 Include("algorithm"), 223 Line(), 224 Include("boost/foreach.hpp"), 225 Line(), 226 Include("hedge/face_operators.hpp"), 227 ]) 228 229 mod.add_to_module([ 230 S("using namespace hedge"), 231 S("using namespace pyublas"), 232 Line(), 233 Typedef(POD(dtype, "value_type")), 234 Typedef(POD(to_uncomplex_dtype(dtype), "uncomplex_type")), 235 Line(), 236 ]) 237 238 arg_struct = Struct("arg_struct", [ 239 Value("numpy_array<value_type>", "flux%d_on_faces" % i) 240 for i in range(len(fluxes)) 241 ]+[ 242 Value("numpy_array<value_type>", arg_name) 243 for arg_name in fvi.arg_names 244 ]+[ 245 Value("value_type" if scalar_par.is_complex else "uncomplex_type", 246 "_scalar_arg_%d" % i) 247 for i, scalar_par in enumerate(fvi.scalar_parameters) 248 ]) 249 250 mod.add_struct(arg_struct, "ArgStruct") 251 mod.add_to_module([Line()]) 252 253 fdecl = FunctionDeclaration( 254 Value("void", "gather_flux"), 255 [ 256 Const(Reference(Value("face_group", "fg"))), 257 Reference(Value("arg_struct", "args")) 258 ]) 259 260 from pymbolic.mapper.stringifier import PREC_PRODUCT 261 262 def gen_flux_code(): 263 f2cm = FluxToCodeMapper(repr, reverse=False) 264 265 result = [ 266 Assign("fof%d_it[%s_fof_base+%s]" % (flux_idx, where, tgt_idx), 267 "uncomplex_type(fp.loc.face_jacobian) * " + 268 flux_to_code(f2cm, is_flipped, flux_idx, fvi, flux.op.flux, PREC_PRODUCT)) 269 for flux_idx, flux in enumerate(fluxes) 270 for where, is_flipped, tgt_idx in [ 271 ("loc", False, "i"), 272 ("opp", True, "opp_write_map[i]") 273 ]] 274 275 return [ 276 Initializer(Value("value_type", f2cm.cse_prefix+str(i)), cse) 277 for i, cse in f2cm.cses] + result
278 279 fbody = Block([ 280 Initializer( 281 Const(Value("numpy_array<value_type>::iterator", "fof%d_it" % i)), 282 "args.flux%d_on_faces.begin()" % i) 283 for i in range(len(fluxes)) 284 ]+[ 285 Initializer( 286 Const(Value("numpy_array<value_type>::const_iterator", "%s_it" % arg_name)), 287 "args.%s.begin()" % arg_name) 288 for arg_name in fvi.arg_names 289 ]+[ 290 Line(), 291 CustomLoop("BOOST_FOREACH(const face_pair &fp, fg.face_pairs)", Block( 292 list(flatten([ 293 Initializer(Value("node_number_t", "%s_ebi" % where), 294 "fp.%s.el_base_index" % where), 295 Initializer(Value("index_lists_t::const_iterator", "%s_idx_list" % where), 296 "fg.index_list(fp.%s.face_index_list_number)" % where), 297 Initializer(Value("node_number_t", "%s_fof_base" % where), 298 "fg.face_length()*(fp.%(where)s.local_el_number*fg.face_count" 299 " + fp.%(where)s.face_id)" % {"where": where}), 300 Line(), 301 ] 302 for where in ["loc", "opp"] 303 ))+[ 304 Initializer(Value("index_lists_t::const_iterator", "opp_write_map"), 305 "fg.index_list(fp.opp_native_write_map)"), 306 Line(), 307 For( 308 "unsigned i = 0", 309 "i < fg.face_length()", 310 "++i", 311 Block( 312 [ 313 Initializer(MaybeUnused(Value("node_number_t", "%s_idx" % where)), 314 "%(where)s_ebi + %(where)s_idx_list[i]" 315 % {"where": where}) 316 for where in ["loc", "opp"] 317 ]+gen_flux_code() 318 ) 319 ) 320 ])) 321 ]) 322 mod.add_function(FunctionBody(fdecl, fbody)) 323 324 #print "----------------------------------------------------------------" 325 #print mod.generate() 326 #raw_input("[Enter]") 327 328 return mod.compile(get_flux_toolchain(discr, fluxes), 329 wait_on_error="jit_wait_on_compile_error" in discr.debug) 330 331 332 333
334 -def get_boundary_flux_mod(fluxes, fvi, discr, dtype):
335 from codepy.cgen import \ 336 FunctionDeclaration, FunctionBody, Typedef, Struct, \ 337 Const, Reference, Value, POD, MaybeUnused, \ 338 Statement, Include, Line, Block, Initializer, Assign, \ 339 CustomLoop, For 340 341 from pytools import to_uncomplex_dtype, flatten 342 343 from codepy.bpl import BoostPythonModule 344 mod = BoostPythonModule() 345 346 mod.add_to_preamble([ 347 Include("cstdlib"), 348 Include("algorithm"), 349 Line(), 350 Include("boost/foreach.hpp"), 351 Line(), 352 Include("hedge/face_operators.hpp"), 353 ]) 354 355 S = Statement 356 mod.add_to_module([ 357 S("using namespace hedge"), 358 S("using namespace pyublas"), 359 Line(), 360 Typedef(POD(dtype, "value_type")), 361 Typedef(POD(to_uncomplex_dtype(dtype), "uncomplex_type")), 362 ]) 363 364 arg_struct = Struct("arg_struct", [ 365 Value("numpy_array<value_type>", "flux%d_on_faces" % i) 366 for i in range(len(fluxes)) 367 ]+[ 368 Value("numpy_array<value_type>", arg_name) 369 for arg_name in fvi.arg_names 370 ]) 371 372 mod.add_struct(arg_struct, "ArgStruct") 373 mod.add_to_module([Line()]) 374 375 fdecl = FunctionDeclaration( 376 Value("void", "gather_flux"), 377 [ 378 Const(Reference(Value("face_group", "fg"))), 379 Reference(Value("arg_struct", "args")) 380 ]) 381 382 from pymbolic.mapper.stringifier import PREC_PRODUCT 383 384 def gen_flux_code(): 385 f2cm = FluxToCodeMapper(repr, reverse=False) 386 387 result = [ 388 Assign("fof%d_it[loc_fof_base+i]" % flux_idx, 389 "uncomplex_type(fp.loc.face_jacobian) * " + 390 flux_to_code(f2cm, False, flux_idx, fvi, flux.op.flux, PREC_PRODUCT)) 391 for flux_idx, flux in enumerate(fluxes) 392 ] 393 394 return [ 395 Initializer(Value("value_type", f2cm.cse_prefix+str(i)), cse) 396 for i, cse in enumerate(f2cm.cses)] + result
397 398 fbody = Block([ 399 Initializer( 400 Const(Value("numpy_array<value_type>::iterator", "fof%d_it" % i)), 401 "args.flux%d_on_faces.begin()" % i) 402 for i in range(len(fluxes)) 403 ]+[ 404 Initializer( 405 Const(Value("numpy_array<value_type>::const_iterator", 406 "%s_it" % arg_name)), 407 "args.%s.begin()" % arg_name) 408 for arg_name in fvi.arg_names 409 ]+[ 410 Line(), 411 CustomLoop("BOOST_FOREACH(const face_pair &fp, fg.face_pairs)", Block( 412 list(flatten([ 413 Initializer(Value("node_number_t", "%s_ebi" % where), 414 "fp.%s.el_base_index" % where), 415 Initializer(Value("index_lists_t::const_iterator", "%s_idx_list" % where), 416 "fg.index_list(fp.%s.face_index_list_number)" % where), 417 Line(), 418 ] 419 for where in ["loc", "opp"] 420 ))+[ 421 Line(), 422 Initializer(Value("node_number_t", "loc_fof_base"), 423 "fg.face_length()*(fp.%(where)s.local_el_number*fg.face_count" 424 " + fp.%(where)s.face_id)" % {"where": "loc"}), 425 Line(), 426 For( 427 "unsigned i = 0", 428 "i < fg.face_length()", 429 "++i", 430 Block( 431 [ 432 Initializer(MaybeUnused( 433 Value("node_number_t", "%s_idx" % where)), 434 "%(where)s_ebi + %(where)s_idx_list[i]" 435 % {"where": where}) 436 for where in ["loc", "opp"] 437 ]+gen_flux_code() 438 ) 439 ) 440 ])) 441 ]) 442 443 mod.add_function(FunctionBody(fdecl, fbody)) 444 445 #print "----------------------------------------------------------------" 446 #print mod.generate() 447 #raw_input("[Enter]") 448 449 return mod.compile(get_flux_toolchain(discr, fluxes), 450 wait_on_error="jit_wait_on_compile_error" in discr.debug) 451