diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index eb3a2e4aff06ef799b5a2018685b07e5d149646f..1d877ddbb97c6feec650d7b6648474017eb2e837 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,6 +9,8 @@ Python 2.7 POCL:
- python2.7
- pocl
- mpi
+ # https://github.com/pocl/pocl/issues/757
+ allow_failure: true
except:
- tags
artifacts:
@@ -26,6 +28,26 @@ Python 3 POCL:
- python3
- pocl
- mpi
+ # https://github.com/pocl/pocl/issues/757
+ allow_failure: true
+ except:
+ - tags
+ artifacts:
+ reports:
+ junit: test/pytest.xml
+
+Python 3 Intel:
+ script:
+ - export PY_EXE=python3
+ - export EXTRA_INSTALL="pybind11 numpy mako"
+ - source /opt/enable-intel-cl.sh
+ - export PYOPENCL_TEST="intel(r):pu"
+ - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh
+ - ". ./build-and-test-py-project.sh"
+ tags:
+ - python3
+ - pocl
+ - mpi
except:
- tags
artifacts:
@@ -44,6 +66,8 @@ Python 2.7 POCL MPI:
- python2.7
- pocl
- mpi
+ # https://github.com/pocl/pocl/issues/757
+ allow_failure: true
except:
- tags
artifacts:
@@ -62,6 +86,27 @@ Python 3 POCL MPI:
- python3
- pocl
- mpi
+ # https://github.com/pocl/pocl/issues/757
+ allow_failure: true
+ except:
+ - tags
+ artifacts:
+ reports:
+ junit: test/pytest.xml
+
+Python 3 Intel MPI:
+ script:
+ - export PY_EXE=python3
+ - source /opt/enable-intel-cl.sh
+ - export PYOPENCL_TEST="intel(r):pu"
+ - export EXTRA_INSTALL="pybind11 numpy mako mpi4py pymetis"
+ - export PYTEST_ADDOPTS="-k mpi"
+ - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh
+ - ". ./build-and-test-py-project.sh"
+ tags:
+ - python3
+ - pocl
+ - mpi
except:
- tags
artifacts:
@@ -79,6 +124,23 @@ Python 3 POCL Examples:
- python3
- pocl
- large-node
+ # https://github.com/pocl/pocl/issues/757
+ allow_failure: true
+ except:
+ - tags
+
+Python 3 Intel Examples:
+ script:
+ - export PY_EXE=python3
+ - source /opt/enable-intel-cl.sh
+ - export PYOPENCL_TEST="intel(r):pu"
+ - export EXTRA_INSTALL="pybind11 numpy mako mpi4py pyvisfile pymetis"
+ - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-py-project-and-run-examples.sh
+ - ". ./build-py-project-and-run-examples.sh"
+ tags:
+ - python3
+ - pocl
+ - large-node
except:
- tags
diff --git a/doc/conf.py b/doc/conf.py
index 3becabe61a7206322542e48a615be62742af0dae..560efec5951aa5de9a4b732e304a121c0c0c8baa 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -320,11 +320,11 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
'http://docs.python.org/': None,
- 'http://documen.tician.de/boxtree/': None,
'http://docs.scipy.org/doc/numpy/': None,
- 'http://documen.tician.de/modepy/': None,
'http://documen.tician.de/pyopencl/': None,
+ 'http://documen.tician.de/modepy/': None,
'http://documen.tician.de/pymbolic/': None,
+ 'http://documen.tician.de/meshmode/': None,
#'http://documen.tician.de/loopy/': None,
}
autoclass_content = "both"
diff --git a/doc/index.rst b/doc/index.rst
index a20ec5093527240204a0da00b19b4188f08317c2..b996c470ffc998618b118e815b05b1c42ff7e9be 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -1,9 +1,4 @@
-.. grudge documentation master file, created by
- sphinx-quickstart on Sun Sep 27 13:08:30 2015.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-Welcome to grudge's documentation!
+Welcome to grudge's Documentation!
==================================
Contents:
@@ -12,10 +7,10 @@ Contents:
:maxdepth: 2
misc
+ symbolic
-
-Indices and tables
+Indices and Tables
==================
* :ref:`genindex`
diff --git a/doc/symbolic.rst b/doc/symbolic.rst
new file mode 100644
index 0000000000000000000000000000000000000000..632b1f861beaa80c3f3c26e93b08272ec4a31259
--- /dev/null
+++ b/doc/symbolic.rst
@@ -0,0 +1,14 @@
+Symbolic Operator Representation
+================================
+
+Based on :mod:`pymbolic`.
+
+Basic Objects
+-------------
+
+.. automodule:: grudge.symbolic.primitives
+
+Operators
+---------
+
+.. automodule:: grudge.symbolic.operators
diff --git a/examples/advection/weak.py b/examples/advection/weak.py
index 9b880ba8952761514c91743e5078794b346b7c4b..6e30094d080033f225a9dbc45227e0d0c7665ad0 100644
--- a/examples/advection/weak.py
+++ b/examples/advection/weak.py
@@ -13,88 +13,135 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see
residual": sym.make_sym_array( + "
residual": sym.make_sym_array(
"input_residual", field_components),
}
@@ -245,7 +246,6 @@ class RK4TimeStepperBase(object):
self.component_getter = component_getter
def get_initial_context(self, fields, t_start, dt):
- from pytools.obj_array import join_fields
# Flatten fields.
flattened_fields = []
@@ -286,7 +286,6 @@ class RK4TimeStepperBase(object):
assert len(output_states) == num_fields
assert len(output_states) == len(output_residuals)
- from pytools.obj_array import join_fields
flattened_results = join_fields(output_t, output_dt, *output_states)
self.bound_op = bind(
@@ -354,8 +353,6 @@ class RK4TimeStepper(RK4TimeStepperBase):
+ tuple(
Variable(field_var_name, dd=sym.DD_VOLUME)[i]
for i in range(num_fields)))))
-
- from pytools.obj_array import join_fields
sym_rhs = join_fields(*(call[i] for i in range(num_fields)))
self.queue = queue
@@ -377,7 +374,6 @@ class RK4TimeStepper(RK4TimeStepperBase):
self.component_getter = component_getter
def _bound_op(self, queue, t, *args, profile_data=None):
- from pytools.obj_array import join_fields
context = {
"t": t,
self.field_var_name: join_fields(*args)}
@@ -452,16 +448,15 @@ def dg_flux(c, tpair):
dims = len(v)
normal = sym.normal(tpair.dd, dims)
-
- flux_weak = sym.join_fields(
+ flux_weak = join_fields(
np.dot(v.avg, normal),
u.avg * normal)
- flux_weak -= (1 if c > 0 else -1)*sym.join_fields(
+ flux_weak -= (1 if c > 0 else -1)*join_fields(
0.5*(u.int-u.ext),
0.5*(normal * np.dot(normal, v.int-v.ext)))
- flux_strong = sym.join_fields(
+ flux_strong = join_fields(
np.dot(v.int, normal),
u.int * normal) - flux_weak
@@ -507,13 +502,13 @@ def get_strong_wave_op_with_discr_direct(cl_ctx, dims=2, order=4):
rad_u = sym.cse(sym.interp("vol", BTAG_ALL)(u))
rad_v = sym.cse(sym.interp("vol", BTAG_ALL)(v))
- rad_bc = sym.cse(sym.join_fields(
+ rad_bc = sym.cse(join_fields(
0.5*(rad_u - sign*np.dot(rad_normal, rad_v)),
0.5*rad_normal*(np.dot(rad_normal, rad_v) - sign*rad_u)
), "rad_bc")
sym_operator = (
- - sym.join_fields(
+ - join_fields(
-c*np.dot(sym.nabla(dims), v) - source_f,
-c*(sym.nabla(dims)*u)
)
@@ -550,7 +545,6 @@ def test_stepper_equivalence(ctx_factory, order=4):
elif dims == 3:
dt = 0.02
- from pytools.obj_array import join_fields
ic = join_fields(discr.zeros(queue),
[discr.zeros(queue) for i in range(discr.dim)])
@@ -804,7 +798,6 @@ def test_stepper_mem_ops(ctx_factory, use_fusion):
dt = 0.04
t_end = 0.2
- from pytools.obj_array import join_fields
ic = join_fields(discr.zeros(queue),
[discr.zeros(queue) for i in range(discr.dim)])
@@ -975,7 +968,6 @@ def test_stepper_timing(ctx_factory, use_fusion):
dt = 0.04
t_end = 0.1
- from pytools.obj_array import join_fields
ic = join_fields(discr.zeros(queue),
[discr.zeros(queue) for i in range(discr.dim)])
@@ -1040,7 +1032,6 @@ def get_example_stepper(queue, dims=2, order=3, use_fusion=True,
exec_mapper_factory=exec_mapper_factory)
if return_ic:
- from pytools.obj_array import join_fields
ic = join_fields(discr.zeros(queue),
[discr.zeros(queue) for i in range(discr.dim)])
return stepper, ic
diff --git a/grudge/__init__.py b/grudge/__init__.py
index b854007a48c227d58541a13a972a3a7e25c4e062..17358dd474304bec731bedb58a98cd692ec69935 100644
--- a/grudge/__init__.py
+++ b/grudge/__init__.py
@@ -22,6 +22,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
-import grudge.sym # noqa
-from grudge.execution import bind # noqa
-from grudge.discretization import DGDiscretizationWithBoundaries # noqa
+import grudge.symbolic as sym
+from grudge.execution import bind
+
+from grudge.discretization import DGDiscretizationWithBoundaries
+
+__all__ = [
+ "sym", "bind", "DGDiscretizationWithBoundaries"
+]
diff --git a/grudge/execution.py b/grudge/execution.py
index 948be131205034a2d0ddb597a11d2c8ad8f42327..761b14729c330e5d1ebcdaf203dea1c437259a4f 100644
--- a/grudge/execution.py
+++ b/grudge/execution.py
@@ -132,7 +132,7 @@ class ExecutionMapper(mappers.Evaluator,
if isinstance(else_, pyopencl.array.Array):
sym_else = var("b")[i]
- elif isinstance(then, np.number):
+ elif isinstance(else_, np.number):
sym_else = var("b")
else:
raise TypeError(
@@ -174,6 +174,7 @@ class ExecutionMapper(mappers.Evaluator,
default_offset=lp.auto, name="diff")
knl = lp.split_iname(knl, "i", 16, inner_tag="l.0")
+ knl = lp.tag_array_axes(knl, "mat", "stride:auto,stride:auto")
return lp.tag_inames(knl, dict(k="g.0"))
in_discr = self.discrwb.discr_from_dd(op.dd_in)
@@ -283,6 +284,29 @@ class ExecutionMapper(mappers.Evaluator,
# }}}
+ def map_signed_face_ones(self, expr):
+ assert expr.dd.is_trace()
+ face_discr = self.discrwb.discr_from_dd(expr.dd)
+ assert face_discr.dim == 0
+
+ # NOTE: ignore quadrature_tags on expr.dd, since we only care about
+ # the face_id here
+ all_faces_conn = self.discrwb.connection_from_dds(
+ sym.DD_VOLUME,
+ sym.DOFDesc(expr.dd.domain_tag))
+
+ field = face_discr.empty(self.queue,
+ dtype=self.discrwb.real_dtype,
+ allocator=self.bound_op.allocator)
+ field.fill(1)
+
+ for grp in all_faces_conn.groups:
+ for batch in grp.batches:
+ i = batch.to_element_indices.with_queue(self.queue)
+ field[i] = (2.0 * (batch.to_element_face % 2) - 1.0) * field[i]
+
+ return field
+
# }}}
# {{{ instruction execution functions
diff --git a/grudge/function_registry.py b/grudge/function_registry.py
index 111443c41a7c12f155222bb06bb0ac636c0bde87..4d521560d8e6c83a8e9fa238b3c46955dc62e7a7 100644
--- a/grudge/function_registry.py
+++ b/grudge/function_registry.py
@@ -33,6 +33,24 @@ from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_1 # noqa
from pytools import RecordWithoutPickling, memoize_in
+# {{{ helpers
+
+def should_use_numpy(arg):
+ from numbers import Number
+ if isinstance(arg, Number) or \
+ isinstance(arg, np.ndarray) and arg.shape == ():
+ return True
+ return False
+
+
+def cl_to_numpy_function_name(name):
+ return {
+ "atan2": "arctan2",
+ }.get(name, name)
+
+# }}}
+
+
# {{{ function
class FunctionNotFound(KeyError):
@@ -74,12 +92,7 @@ class CElementwiseUnaryFunction(Function):
def __call__(self, queue, arg):
func_name = self.identifier
-
- from numbers import Number
- if (
- isinstance(arg, Number)
- or (isinstance(arg, np.ndarray)
- and arg.shape == ())):
+ if should_use_numpy(arg):
func = getattr(np, func_name)
return func(arg)
@@ -108,6 +121,39 @@ class CElementwiseUnaryFunction(Function):
return out
+class CElementwiseBinaryFunction(Function):
+ supports_codegen = True
+
+ def get_result_dofdesc(self, arg_dds):
+ assert len(arg_dds) == 2
+ from pytools import single_valued
+ return single_valued(arg_dds)
+
+ def __call__(self, queue, arg0, arg1):
+ func_name = self.identifier
+ if should_use_numpy(arg0) and should_use_numpy(arg1):
+ func = getattr(np, cl_to_numpy_function_name(func_name))
+ return func(arg0, arg1)
+
+ from pymbolic.primitives import Variable
+
+ @memoize_in(self, "map_call_knl_%s" % func_name)
+ def knl():
+ i = Variable("i")
+ knl = lp.make_kernel(
+ "{[i]: 0<=i