Skip to content
Snippets Groups Projects

Reimplement create_staggered_kernel

Merged Michael Kuron requested to merge staggered_kernel into master
Compare and
3 files
+ 162
2
Compare changes
  • Side-by-side
  • Inline
Files
3
@@ -6,8 +6,10 @@ import sympy as sp
@@ -6,8 +6,10 @@ import sympy as sp
from pystencils.assignment import Assignment
from pystencils.assignment import Assignment
from pystencils.astnodes import Block, Conditional, LoopOverCoordinate, SympyAssignment
from pystencils.astnodes import Block, Conditional, LoopOverCoordinate, SympyAssignment
from pystencils.cpu.vectorization import vectorize
from pystencils.cpu.vectorization import vectorize
 
from pystencils.field import Field
from pystencils.gpucuda.indexing import indexing_creator_from_params
from pystencils.gpucuda.indexing import indexing_creator_from_params
from pystencils.simp.assignment_collection import AssignmentCollection
from pystencils.simp.assignment_collection import AssignmentCollection
 
from pystencils.stencil import direction_string_to_offset, inverse_direction_string
from pystencils.transformations import (
from pystencils.transformations import (
loop_blocking, move_constants_before_loop, remove_conditionals_in_staggered_kernel)
loop_blocking, move_constants_before_loop, remove_conditionals_in_staggered_kernel)
@@ -186,8 +188,18 @@ def create_indexed_kernel(assignments,
@@ -186,8 +188,18 @@ def create_indexed_kernel(assignments,
raise ValueError("Unknown target %s. Has to be either 'cpu' or 'gpu'" % (target,))
raise ValueError("Unknown target %s. Has to be either 'cpu' or 'gpu'" % (target,))
def create_staggered_kernel(staggered_field, expressions, subexpressions=(), target='cpu',
def create_staggered_kernel(*args, **kwargs):
gpu_exclusive_conditions=False, **kwargs):
"""Kernel that updates a staggered field. Dispatches to either create_staggered_kernel_1 or
 
create_staggered_kernel_2 depending on the argument types.
 
"""
 
if 'staggered_field' in kwargs or type(args[0]) is Field:
 
return create_staggered_kernel_1(*args, **kwargs)
 
else:
 
return create_staggered_kernel_2(*args, **kwargs)
 
 
 
def create_staggered_kernel_1(staggered_field, expressions, subexpressions=(), target='cpu',
 
gpu_exclusive_conditions=False, **kwargs):
"""Kernel that updates a staggered field.
"""Kernel that updates a staggered field.
.. image:: /img/staggered_grid.svg
.. image:: /img/staggered_grid.svg
@@ -287,3 +299,79 @@ def create_staggered_kernel(staggered_field, expressions, subexpressions=(), tar
@@ -287,3 +299,79 @@ def create_staggered_kernel(staggered_field, expressions, subexpressions=(), tar
elif isinstance(cpu_vectorize_info, dict):
elif isinstance(cpu_vectorize_info, dict):
vectorize(ast, **cpu_vectorize_info)
vectorize(ast, **cpu_vectorize_info)
return ast
return ast
 
 
 
def create_staggered_kernel_2(assignments, **kwargs):
 
"""Kernel that updates a staggered field.
 
 
.. image:: /img/staggered_grid.svg
 
 
For a staggered field, the first index coordinate defines the location of the staggered value.
 
Further index coordinates can be used to store vectors/tensors at each point.
 
 
Args:
 
assignments: a sequence of assignments or AssignmentCollection with one item for each staggered grid point.
 
When storing vectors/tensors, the number of items expected is multiplied with the number of
 
components.
 
kwargs: passed directly to create_kernel
 
"""
 
assert 'ghost_layers' not in kwargs
 
 
subexpressions = ()
 
if isinstance(assignments, AssignmentCollection):
 
assignments = assignments.main_assignments
 
subexpressions = assignments.subexpressions
 
if len(set([a.lhs.field for a in assignments])) != 1:
 
raise ValueError("All assignments need to be made to the same staggered field")
 
staggered_field = assignments[0].lhs.field
 
dim = staggered_field.spatial_dimensions
 
points = staggered_field.index_shape[0]
 
values_per_point = sp.Mul(*staggered_field.index_shape[1:])
 
assert len(assignments) == points * values_per_point
 
 
counters = [LoopOverCoordinate.get_loop_counter_symbol(i) for i in range(dim)]
 
 
final_assignments = []
 
 
# find out whether any of the ghost layers is not needed
 
common_exclusions = set(["E", "W", "N", "S", "T", "B"][:2 * dim])
 
for direction in staggered_field.staggered_stencil:
 
exclusions = set(["E", "W", "N", "S", "T", "B"][:2 * dim])
 
for elementary_direction in direction:
 
exclusions.remove(inverse_direction_string(elementary_direction))
 
common_exclusions.intersection_update(exclusions)
 
ghost_layers = [[1, 1] for d in range(dim)]
 
for direction in common_exclusions:
 
direction = direction_string_to_offset(direction)
 
for d, s in enumerate(direction):
 
if s == 1:
 
ghost_layers[d][1] = 0
 
elif s == -1:
 
ghost_layers[d][0] = 0
 
 
def condition(direction):
 
"""exclude those staggered points that correspond to fluxes between ghost cells"""
 
exclusions = set(["E", "W", "N", "S", "T", "B"][:2 * dim])
 
 
for elementary_direction in direction:
 
exclusions.remove(inverse_direction_string(elementary_direction))
 
conditions = []
 
for e in exclusions:
 
if e in common_exclusions:
 
continue
 
offset = direction_string_to_offset(e)
 
for i, o in enumerate(offset):
 
if o == 1:
 
conditions.append(counters[i] < staggered_field.shape[i] - 1)
 
elif o == -1:
 
conditions.append(counters[i] > 0)
 
return sp.And(*conditions)
 
 
for d, direction in zip(range(points), staggered_field.staggered_stencil):
 
sp_assignments = [SympyAssignment(assignments[d].lhs, assignments[d].rhs)] + \
 
[SympyAssignment(s.lhs, s.rhs) for s in subexpressions]
 
last_conditional = Conditional(condition(direction), Block(sp_assignments))
 
final_assignments.append(last_conditional)
 
 
ast = create_kernel(final_assignments, ghost_layers=ghost_layers, **kwargs)
 
return ast
Loading