Skip to content

Commit

Permalink
Merge pull request #77 from inducer/dofarray-not-ndarray-subclass
Browse files Browse the repository at this point in the history
Stop subclassing DOFArray from numpy.ndarray
  • Loading branch information
inducer authored Nov 12, 2020
2 parents 78db6c3 + 6b4b20b commit 0457463
Show file tree
Hide file tree
Showing 10 changed files with 426 additions and 235 deletions.
104 changes: 54 additions & 50 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os
import sys # noqa: F401
import os # noqa: F401

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
Expand All @@ -23,42 +23,45 @@
# -- General configuration ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
#needs_sphinx = "1.0"

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# extensions coming with Sphinx (named "sphinx.ext.*") or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.mathjax',
'sphinx.ext.graphviz',
"sphinx.ext.autodoc",
"sphinx.ext.doctest",
"sphinx.ext.intersphinx",
"sphinx.ext.mathjax",
"sphinx.ext.graphviz",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]

# The suffix of source filenames.
source_suffix = '.rst'
source_suffix = ".rst"

# The encoding of source files.
#source_encoding = 'utf-8-sig'
#source_encoding = "utf-8-sig"

# The master toctree document.
master_doc = 'index'
master_doc = "index"

# General information about the project.
project = u'meshmode'
copyright = u'2014, Andreas Klöckner'
project = u"meshmode"
copyright = u"2014, Andreas Klöckner"

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
ver_dic = {}
exec(compile(open("../meshmode/version.py").read(), "../meshmode/version.py", 'exec'), ver_dic)
exec(
compile(
open("../meshmode/version.py").read(), "../meshmode/version.py", "exec"),
ver_dic)
version = ".".join(str(x) for x in ver_dic["VERSION"])
# The full version, including alpha/beta/rc tags.
release = ver_dic["VERSION_TEXT"]
Expand All @@ -75,7 +78,7 @@

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
exclude_patterns = ["_build"]

# The reST default role (used for this markup: `text`) to use for all
# documents.
Expand All @@ -93,7 +96,7 @@
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
Expand All @@ -114,11 +117,11 @@
}

html_sidebars = {
'**': [
'about.html',
'navigation.html',
'relations.html',
'searchbox.html',
"**": [
"about.html",
"navigation.html",
"relations.html",
"searchbox.html",
]
}

Expand Down Expand Up @@ -194,28 +197,28 @@
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'meshmodedoc'
htmlhelp_basename = "meshmodedoc"


# -- Options for LaTeX output ---------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The paper size ("letterpaper" or "a4paper").
#"papersize": "letterpaper",

# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# The font size ("10pt", "11pt" or "12pt").
#"pointsize": "10pt",

# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Additional stuff for the LaTeX preamble.
#"preamble": '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'meshmode.tex', u'meshmode Documentation',
u'Andreas Klöckner', 'manual'),
("index", "meshmode.tex", u"meshmode Documentation",
u"Andreas Klöckner", "manual"),
]

# The name of an image file (relative to this directory) to place at the top of
Expand Down Expand Up @@ -244,8 +247,8 @@
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'meshmode', u'meshmode Documentation',
[u'Andreas Klöckner'], 1)
("index", "meshmode", u"meshmode Documentation",
[u"Andreas Klöckner"], 1)
]

# If true, show URL addresses after external links.
Expand All @@ -258,9 +261,9 @@
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'meshmode', u'meshmode Documentation',
u'Andreas Klöckner', 'meshmode', 'One line description of project.',
'Miscellaneous'),
("index", "meshmode", u"meshmode Documentation",
u"Andreas Klöckner", "meshmode", "One line description of project.",
"Miscellaneous"),
]

# Documents to append as an appendix to all manuals.
Expand All @@ -269,24 +272,25 @@
# If false, no module index is generated.
#texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# How to display URL addresses: "footnote", "no", or "inline".
#texinfo_show_urls = "footnote"

# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

intersphinx_mapping = {
'https://docs.python.org/': None,
'https://docs.scipy.org/doc/numpy/': None,
'https://documen.tician.de/pyopencl': None,
'https://documen.tician.de/meshpy': None,
'https://documen.tician.de/modepy': None,
'https://documen.tician.de/loopy': None,
'https://documen.tician.de/gmsh_interop': None,
'https://firedrakeproject.org/': None,
'https://tisaac.gitlab.io/recursivenodes/': None,
'https://fenics.readthedocs.io/projects/fiat/en/latest/': None,
'https://finat.github.io/FInAT/': None,
"https://docs.python.org/3/": None,
"https://numpy.org/doc/stable/": None,
"https://documen.tician.de/pytools": None,
"https://documen.tician.de/pyopencl": None,
"https://documen.tician.de/meshpy": None,
"https://documen.tician.de/modepy": None,
"https://documen.tician.de/loopy": None,
"https://documen.tician.de/gmsh_interop": None,
"https://firedrakeproject.org/": None,
"https://tisaac.gitlab.io/recursivenodes/": None,
"https://fenics.readthedocs.io/projects/fiat/en/latest/": None,
"https://finat.github.io/FInAT/": None,
}

autoclass_content = "class"
17 changes: 5 additions & 12 deletions examples/simple-dg.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
flat_obj_array, make_obj_array,
obj_array_vectorize)
from meshmode.mesh import BTAG_ALL, BTAG_NONE # noqa
from meshmode.dof_array import DOFArray, freeze, thaw
from meshmode.dof_array import freeze, thaw
from meshmode.array_context import PyOpenCLArrayContext, make_loopy_program


Expand Down Expand Up @@ -146,9 +146,7 @@ def get_connection(self, src, tgt):
raise ValueError(f"locations '{src}'->'{tgt}' not understood")

def interp(self, src, tgt, vec):
if (isinstance(vec, np.ndarray)
and vec.dtype.char == "O"
and not isinstance(vec, DOFArray)):
if isinstance(vec, np.ndarray):
return obj_array_vectorize(
lambda el: self.interp(src, tgt, el), vec)

Expand Down Expand Up @@ -237,9 +235,7 @@ def get_inverse_mass_matrix(self, grp, dtype):
return actx.freeze(actx.from_numpy(matrix))

def inverse_mass(self, vec):
if (isinstance(vec, np.ndarray)
and vec.dtype.char == "O"
and not isinstance(vec, DOFArray)):
if isinstance(vec, np.ndarray):
return obj_array_vectorize(
lambda el: self.inverse_mass(el), vec)

Expand Down Expand Up @@ -291,11 +287,8 @@ def get_local_face_mass_matrix(self, afgrp, volgrp, dtype):
return actx.freeze(actx.from_numpy(matrix))

def face_mass(self, vec):
if (isinstance(vec, np.ndarray)
and vec.dtype.char == "O"
and not isinstance(vec, DOFArray)):
return obj_array_vectorize(
lambda el: self.face_mass(el), vec)
if isinstance(vec, np.ndarray):
return obj_array_vectorize(lambda el: self.face_mass(el), vec)

@memoize_in(self, "face_mass_knl")
def knl():
Expand Down
23 changes: 12 additions & 11 deletions meshmode/array_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import loopy as lp
from loopy.version import MOST_RECENT_LANGUAGE_VERSION
from pytools import memoize_method
from pytools.obj_array import obj_array_vectorized_n_args

__doc__ = """
.. autofunction:: make_loopy_program
Expand Down Expand Up @@ -58,7 +57,7 @@ def __init__(self, array_context):
self._array_context = array_context

def __getattr__(self, name):
def f(*args):
def loopy_implemented_elwise_func(*args):
actx = self._array_context
# FIXME: Maybe involve loopy type inference?
result = actx.empty(args[0].shape, args[0].dtype)
Expand All @@ -68,14 +67,15 @@ def f(*args):
**{"inp%d" % i: arg for i, arg in enumerate(args)})
return result

return obj_array_vectorized_n_args(f)
from meshmode.dof_array import obj_or_dof_array_vectorized_n_args
return obj_or_dof_array_vectorized_n_args(loopy_implemented_elwise_func)

@obj_array_vectorized_n_args
def conjugate(self, x):
# NOTE: conjugate distribute over object arrays, but it looks for a
# `conjugate` ufunc, while some implementations only have the shorter
# `conj` (e.g. cl.array.Array), so this should work for everybody
return x.conj()
from meshmode.dof_array import obj_or_dof_array_vectorize
return obj_or_dof_array_vectorize(lambda obj: obj.conj(), x)

conj = conjugate

Expand Down Expand Up @@ -225,20 +225,21 @@ def thaw(self, array):
# {{{ PyOpenCLArrayContext

class _PyOpenCLFakeNumpyNamespace(_BaseFakeNumpyNamespace):
@obj_array_vectorized_n_args
def maximum(self, x, y):
import pyopencl.array as cl_array
return cl_array.maximum(x, y)
from meshmode.dof_array import obj_or_dof_array_vectorize_n_args
return obj_or_dof_array_vectorize_n_args(cl_array.maximum, x, y)

@obj_array_vectorized_n_args
def minimum(self, x, y):
import pyopencl.array as cl_array
return cl_array.minimum(x, y)
from meshmode.dof_array import obj_or_dof_array_vectorize_n_args
return obj_or_dof_array_vectorize_n_args(cl_array.minimum, x, y)

@obj_array_vectorized_n_args
def where(self, criterion, then, else_):
import pyopencl.array as cl_array
return cl_array.if_positive(criterion != 0, then, else_)
from meshmode.dof_array import obj_or_dof_array_vectorize_n_args
return obj_or_dof_array_vectorize_n_args(
cl_array.if_positive, criterion != 0, then, else_)


class PyOpenCLArrayContext(ArrayContext):
Expand Down
16 changes: 8 additions & 8 deletions meshmode/discretization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,9 @@ def _new_array(self, actx, creation_func, dtype=None):
else:
dtype = np.dtype(dtype)

return _DOFArray.from_list(actx, [
return _DOFArray(actx, tuple(
creation_func(shape=(grp.nelements, grp.nunit_dofs), dtype=dtype)
for grp in self.groups])
for grp in self.groups))

def empty(self, actx: ArrayContext, dtype=None):
"""Return an empty :class:`~meshmode.dof_array.DOFArray`.
Expand Down Expand Up @@ -297,11 +297,11 @@ def get_mat(grp):

return mat

return _DOFArray.from_list(actx, [
return _DOFArray(actx, tuple(
actx.call_loopy(
prg(), diff_mat=actx.from_numpy(get_mat(grp)), vec=vec[grp.index]
)["result"]
for grp in self.groups])
for grp in self.groups))

@memoize_method
def quad_weights(self):
Expand All @@ -316,14 +316,14 @@ def prg():
"result[iel,idof] = weights[idof]",
name="quad_weights")

return _DOFArray.from_list(None, [
return _DOFArray(None, tuple(
actx.freeze(
actx.call_loopy(
prg(),
weights=actx.from_numpy(grp.weights),
nelements=grp.nelements,
)["result"])
for grp in self.groups])
for grp in self.groups))

@memoize_method
def nodes(self):
Expand All @@ -348,15 +348,15 @@ def prg():
name="nodes")

return make_obj_array([
_DOFArray.from_list(None, [
_DOFArray(None, tuple(
actx.freeze(
actx.call_loopy(
prg(),
resampling_mat=actx.from_numpy(
grp.from_mesh_interp_matrix()),
nodes=actx.from_numpy(grp.mesh_el_group.nodes[iaxis])
)["result"])
for grp in self.groups])
for grp in self.groups))
for iaxis in range(self.ambient_dim)])

# vim: fdm=marker
6 changes: 2 additions & 4 deletions meshmode/discretization/visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import numpy as np
from pytools import memoize_method, Record
from meshmode.dof_array import DOFArray, flatten, thaw
from meshmode.dof_array import flatten, thaw


__doc__ = """
Expand Down Expand Up @@ -73,9 +73,7 @@ def separate_by_real_and_imag(names_and_fields, real_only):


def resample_to_numpy(conn, vec):
if (isinstance(vec, np.ndarray)
and vec.dtype.char == "O"
and not isinstance(vec, DOFArray)):
if isinstance(vec, np.ndarray):
from pytools.obj_array import obj_array_vectorize
return obj_array_vectorize(lambda x: resample_to_numpy(conn, x), vec)

Expand Down
Loading

0 comments on commit 0457463

Please sign in to comment.