From f05790813a0855ffbece4243b0e766cbbd364f85 Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Fri, 25 Jun 2021 10:11:01 +0100 Subject: [PATCH 01/14] Add recreate to Arg --- pyop2/base.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pyop2/base.py b/pyop2/base.py index 01097d6ae..15d3163eb 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -169,6 +169,27 @@ def __init__(self, data=None, map=None, access=None, lgmaps=None, unroll_map=Fal raise MapValueError( "To set of %s doesn't match the set of %s." % (map, data)) + def recreate(self, data=None, map=None, access=None, lgmaps=None, unroll_map=False): + """:param data: A data-carrying object, either :class:`Dat` or class:`Mat` + :param map: A :class:`Map` to access this :class:`Arg` or the default + if the identity map is to be used. + :param access: An access descriptor of type :class:`Access` + :param lgmaps: For :class:`Mat` objects, a tuple of 2-tuples of local to + global maps used during assembly. + + Takes all arguments from _init_ and returns new args.""" + if data is None: + data = self.data + + if map is None: + map = self.map + + if access is None: + data = self.access + + if lgmaps is None: + data = self.lgmaps + @cached_property def _kernel_args_(self): return self.data._kernel_args_ From 3442f0681d2e40a8df4bbe520693a41718eef6a2 Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Fri, 25 Jun 2021 10:19:38 +0100 Subject: [PATCH 02/14] Recreate method of Arg --- pyop2/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyop2/base.py b/pyop2/base.py index 15d3163eb..1badb4eed 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -177,7 +177,7 @@ def recreate(self, data=None, map=None, access=None, lgmaps=None, unroll_map=Fal :param lgmaps: For :class:`Mat` objects, a tuple of 2-tuples of local to global maps used during assembly. - Takes all arguments from _init_ and returns new args.""" + Takes all the same arguments as _init_ overwriting them if necessary.""" if data is None: data = self.data From 92184de3317fe1b13151642ee4573d03c4a030ba Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Fri, 25 Jun 2021 12:32:12 +0100 Subject: [PATCH 03/14] Fix cache problem --- pyop2/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyop2/base.py b/pyop2/base.py index 1badb4eed..94b0256e2 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -177,7 +177,7 @@ def recreate(self, data=None, map=None, access=None, lgmaps=None, unroll_map=Fal :param lgmaps: For :class:`Mat` objects, a tuple of 2-tuples of local to global maps used during assembly. - Takes all the same arguments as _init_ overwriting them if necessary.""" + Takes all the same arguments as _init_ overriding them if necessary.""" if data is None: data = self.data From e9b73ab1391eb8f1fc4e791368b0940f823aebe4 Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Fri, 25 Jun 2021 12:48:07 +0100 Subject: [PATCH 04/14] Fix cache problem --- pyop2/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyop2/base.py b/pyop2/base.py index 94b0256e2..6029a50e5 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -185,10 +185,10 @@ def recreate(self, data=None, map=None, access=None, lgmaps=None, unroll_map=Fal map = self.map if access is None: - data = self.access + access = self.access if lgmaps is None: - data = self.lgmaps + lgmaps = self.lgmaps @cached_property def _kernel_args_(self): From f24478a6960a2ff1a126f074916738b55e5167d0 Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Fri, 25 Jun 2021 12:57:19 +0100 Subject: [PATCH 05/14] Fix cache problem --- pyop2/base.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pyop2/base.py b/pyop2/base.py index 6029a50e5..888425ff9 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -177,18 +177,20 @@ def recreate(self, data=None, map=None, access=None, lgmaps=None, unroll_map=Fal :param lgmaps: For :class:`Mat` objects, a tuple of 2-tuples of local to global maps used during assembly. - Takes all the same arguments as _init_ overriding them if necessary.""" - if data is None: - data = self.data + Takes all the same arguments as _init_ overriding them, if necessary.""" + if data is not None: + self.data = data - if map is None: - map = self.map + if map is not None: + self.map = map + + if access is not None: + self.access = access - if access is None: - access = self.access + if lgmaps is not None: + self.lgmaps = lgmaps - if lgmaps is None: - lgmaps = self.lgmaps + # self.unroll_map = unroll_map @cached_property def _kernel_args_(self): From 899a5439b6c5c762d75d588d0e61afedaefb021f Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Thu, 1 Jul 2021 14:12:11 +0100 Subject: [PATCH 06/14] Updated changes --- pyop2/base.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/pyop2/base.py b/pyop2/base.py index 888425ff9..e946f8525 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -169,7 +169,7 @@ def __init__(self, data=None, map=None, access=None, lgmaps=None, unroll_map=Fal raise MapValueError( "To set of %s doesn't match the set of %s." % (map, data)) - def recreate(self, data=None, map=None, access=None, lgmaps=None, unroll_map=False): + def recreate(self, data=None, map=None, access=None, lgmaps=None, unroll_map=None): """:param data: A data-carrying object, either :class:`Dat` or class:`Mat` :param map: A :class:`Map` to access this :class:`Arg` or the default if the identity map is to be used. @@ -178,19 +178,11 @@ def recreate(self, data=None, map=None, access=None, lgmaps=None, unroll_map=Fal global maps used during assembly. Takes all the same arguments as _init_ overriding them, if necessary.""" - if data is not None: - self.data = data - - if map is not None: - self.map = map - - if access is not None: - self.access = access - - if lgmaps is not None: - self.lgmaps = lgmaps - - # self.unroll_map = unroll_map + return type(self)(data = data or self.data, + map = map or self.map, + access = access or self.access, + lgmaps = lgmaps or self.lgmaps, + unroll_map = False if unroll_map is None else unroll_map) @cached_property def _kernel_args_(self): From 70c4b390a030a3b53644ca03be1b36ddb850b0e5 Mon Sep 17 00:00:00 2001 From: "David A. Ham" Date: Tue, 13 Jul 2021 16:10:30 +0100 Subject: [PATCH 07/14] Don't use a parloop when not needed --- pyop2/base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyop2/base.py b/pyop2/base.py index 01097d6ae..f27daf0bc 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -1579,6 +1579,9 @@ def copy(self, other, subset=None): :arg subset: A :class:`Subset` of elements to copy (optional)""" if other is self: return + if subset is None: + other.data[:] = self.data + return self._copy_parloop(other, subset=subset).compute() @collective From 58f89efdf2e7b38bac902a6a1a85c9813d724a9b Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Tue, 13 Jul 2021 17:18:32 +0100 Subject: [PATCH 08/14] added subset case for copy --- pyop2/base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyop2/base.py b/pyop2/base.py index e946f8525..9f9d1db54 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -1594,6 +1594,9 @@ def copy(self, other, subset=None): :arg subset: A :class:`Subset` of elements to copy (optional)""" if other is self: return + if subset is None: + other.data[:] = self.data + return self._copy_parloop(other, subset=subset).compute() @collective From 2460b37f5d0181a3a056eecd384e123d7f6cd1af Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Thu, 15 Jul 2021 12:20:53 +0100 Subject: [PATCH 09/14] @dham --- pyop2/base.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyop2/base.py b/pyop2/base.py index f27daf0bc..8f089badb 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -1580,8 +1580,9 @@ def copy(self, other, subset=None): if other is self: return if subset is None: - other.data[:] = self.data - return + other.data[:] = self.data_ro + else: + other.data[subset.indices] = self.data_ro[subset.indices] self._copy_parloop(other, subset=subset).compute() @collective From 3ddc70a557330287504eb719ee794c3af74ca742 Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Thu, 15 Jul 2021 12:24:32 +0100 Subject: [PATCH 10/14] Don't use a parloop when not needed --- pyop2/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyop2/base.py b/pyop2/base.py index 8f089badb..0eb002c4e 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -1580,7 +1580,7 @@ def copy(self, other, subset=None): if other is self: return if subset is None: - other.data[:] = self.data_ro + other.data[:] = self.data_ro else: other.data[subset.indices] = self.data_ro[subset.indices] self._copy_parloop(other, subset=subset).compute() From 5b053ccc12a30a6dc7baf9241715e02e4212b843 Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Fri, 16 Jul 2021 09:09:33 +0100 Subject: [PATCH 11/14] faster dat copy --- pyop2/base.py | 82 +++++++++++++++------------------------------------ 1 file changed, 24 insertions(+), 58 deletions(-) diff --git a/pyop2/base.py b/pyop2/base.py index a3dab313c..20713079e 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -1553,38 +1553,10 @@ def zero(self, subset=None): """Zero the data associated with this :class:`Dat` :arg subset: A :class:`Subset` of entries to zero (optional).""" - if hasattr(self, "_zero_parloops"): - loops = self._zero_parloops + if subset is None: + self.data[:] = 0 else: - loops = {} - self._zero_parloops = loops - - iterset = subset or self.dataset.set - - loop = loops.get(iterset, None) - - if loop is None: - try: - knl = self._zero_kernels[(self.dtype, self.cdim)] - except KeyError: - import islpy as isl - import pymbolic.primitives as p - - inames = isl.make_zero_and_vars(["i"]) - domain = (inames[0].le_set(inames["i"])) & (inames["i"].lt_set(inames[0] + self.cdim)) - x = p.Variable("dat") - i = p.Variable("i") - insn = loopy.Assignment(x.index(i), 0, within_inames=frozenset(["i"])) - data = loopy.GlobalArg("dat", dtype=self.dtype, shape=(self.cdim,)) - knl = loopy.make_function([domain], [insn], [data], name="zero", target=loopy.CTarget(), lang_version=(2018, 2)) - - knl = _make_object('Kernel', knl, 'zero') - self._zero_kernels[(self.dtype, self.cdim)] = knl - loop = _make_object('ParLoop', knl, - iterset, - self(WRITE)) - loops[iterset] = loop - loop.compute() + self.data[subset.indices] = 0 @collective def copy(self, other, subset=None): @@ -1595,31 +1567,9 @@ def copy(self, other, subset=None): if other is self: return if subset is None: - other.data[:] = self.data_ro + other.data[:] = self.data_ro else: other.data[subset.indices] = self.data_ro[subset.indices] - self._copy_parloop(other, subset=subset).compute() - - @collective - def _copy_parloop(self, other, subset=None): - """Create the :class:`ParLoop` implementing copy.""" - if not hasattr(self, '_copy_kernel'): - import islpy as isl - import pymbolic.primitives as p - inames = isl.make_zero_and_vars(["i"]) - domain = (inames[0].le_set(inames["i"])) & (inames["i"].lt_set(inames[0] + self.cdim)) - _other = p.Variable("other") - _self = p.Variable("self") - i = p.Variable("i") - insn = loopy.Assignment(_other.index(i), _self.index(i), within_inames=frozenset(["i"])) - data = [loopy.GlobalArg("self", dtype=self.dtype, shape=(self.cdim,)), - loopy.GlobalArg("other", dtype=other.dtype, shape=(other.cdim,))] - knl = loopy.make_function([domain], [insn], data, name="copy", target=loopy.CTarget(), lang_version=(2018, 2)) - - self._copy_kernel = _make_object('Kernel', knl, 'copy') - return _make_object('ParLoop', self._copy_kernel, - subset or self.dataset.set, - self(READ), other(WRITE)) def __iter__(self): """Yield self when iterated over.""" @@ -1842,21 +1792,37 @@ def __truediv__(self, other): __div__ = __truediv__ # Python 2 compatibility - def __iadd__(self, other): + def __iadd__(self, other, subset=None): """Pointwise addition of fields.""" return self._iop(other, operator.iadd) + # if subset is None: + # other.data[:] *= self.data_ro + # else: + # other.data[subset.indices] *= self.data_ro[subset.indices] - def __isub__(self, other): + def __isub__(self, other, subset=None): """Pointwise subtraction of fields.""" return self._iop(other, operator.isub) + # if subset is None: + # other.data[:] *= self.data_ro + # else: + # other.data[subset.indices] *= self.data_ro[subset.indices] - def __imul__(self, other): + def __imul__(self, other, subset=None): """Pointwise multiplication or scaling of fields.""" return self._iop(other, operator.imul) + # if subset is None: + # other.data[:] *= self.data_ro + # else: + # other.data[subset.indices] *= self.data_ro[subset.indices] - def __itruediv__(self, other): + def __itruediv__(self, other, subset=None): """Pointwise division or scaling of fields.""" return self._iop(other, operator.itruediv) + # if subset is None: + # other.data[:] /= self.data_ro + # else: + # other.data[subset.indices] /= self.data_ro[subset.indices] __idiv__ = __itruediv__ # Python 2 compatibility From c048265c5e037da5d1fc4bdfb07423f00739c5c3 Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Fri, 16 Jul 2021 17:25:29 +0100 Subject: [PATCH 12/14] Lint fix --- pyop2/base.py | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/pyop2/base.py b/pyop2/base.py index 20713079e..9a6293463 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -176,13 +176,13 @@ def recreate(self, data=None, map=None, access=None, lgmaps=None, unroll_map=Non :param access: An access descriptor of type :class:`Access` :param lgmaps: For :class:`Mat` objects, a tuple of 2-tuples of local to global maps used during assembly. - + Takes all the same arguments as _init_ overriding them, if necessary.""" - return type(self)(data = data or self.data, - map = map or self.map, - access = access or self.access, - lgmaps = lgmaps or self.lgmaps, - unroll_map = False if unroll_map is None else unroll_map) + return type(self)(data=data or self.data, + map=map or self.map, + access=access or self.access, + lgmaps=lgmaps or self.lgmaps, + unroll_map=False if unroll_map is None else unroll_map) @cached_property def _kernel_args_(self): @@ -1792,37 +1792,25 @@ def __truediv__(self, other): __div__ = __truediv__ # Python 2 compatibility - def __iadd__(self, other, subset=None): + def __iadd__(self, other): """Pointwise addition of fields.""" return self._iop(other, operator.iadd) - # if subset is None: - # other.data[:] *= self.data_ro - # else: - # other.data[subset.indices] *= self.data_ro[subset.indices] + # other.data[:] += self.data_ro - def __isub__(self, other, subset=None): + def __isub__(self, other): """Pointwise subtraction of fields.""" return self._iop(other, operator.isub) - # if subset is None: - # other.data[:] *= self.data_ro - # else: - # other.data[subset.indices] *= self.data_ro[subset.indices] + # other.data[:] -= self.data_ro - def __imul__(self, other, subset=None): + def __imul__(self, other): """Pointwise multiplication or scaling of fields.""" return self._iop(other, operator.imul) - # if subset is None: - # other.data[:] *= self.data_ro - # else: - # other.data[subset.indices] *= self.data_ro[subset.indices] + # other.data[:] *= self.data_ro - def __itruediv__(self, other, subset=None): + def __itruediv__(self, other): """Pointwise division or scaling of fields.""" return self._iop(other, operator.itruediv) - # if subset is None: - # other.data[:] /= self.data_ro - # else: - # other.data[subset.indices] /= self.data_ro[subset.indices] + # other.data[:] /= self.data_ro __idiv__ = __itruediv__ # Python 2 compatibility From 1272f5023f05210ed629da128e210628b0d7610c Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Wed, 21 Jul 2021 16:59:50 +0100 Subject: [PATCH 13/14] Edited iops for Dat --- pyop2/base.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/pyop2/base.py b/pyop2/base.py index 9a6293463..22052a6a0 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -1794,23 +1794,35 @@ def __truediv__(self, other): def __iadd__(self, other): """Pointwise addition of fields.""" - return self._iop(other, operator.iadd) - # other.data[:] += self.data_ro + # return self._iop(other, operator.iadd) + if other is None: + return self + else: + other.data[:] += self.data_ro def __isub__(self, other): """Pointwise subtraction of fields.""" - return self._iop(other, operator.isub) - # other.data[:] -= self.data_ro + # return self._iop(other, operator.isub) + if other is None: + return self + else: + other.data[:] -= self.data_ro def __imul__(self, other): """Pointwise multiplication or scaling of fields.""" - return self._iop(other, operator.imul) - # other.data[:] *= self.data_ro + # return self._iop(other, operator.imul) + if type(other) is float: + other = np.float64(other) + else: + other.data[:] *= self.data_ro def __itruediv__(self, other): """Pointwise division or scaling of fields.""" - return self._iop(other, operator.itruediv) - # other.data[:] /= self.data_ro + # return self._iop(other, operator.itruediv) + if other is None: + return self + else: + other.data[:] /= self.data_ro __idiv__ = __itruediv__ # Python 2 compatibility From 84235370ea0da5ed814a3d7fcd9fcd0c61c083ba Mon Sep 17 00:00:00 2001 From: Melina Giagiozis Date: Thu, 22 Jul 2021 11:50:37 +0100 Subject: [PATCH 14/14] recreate method only --- pyop2/base.py | 92 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 31 deletions(-) diff --git a/pyop2/base.py b/pyop2/base.py index 22052a6a0..082106bce 100644 --- a/pyop2/base.py +++ b/pyop2/base.py @@ -170,14 +170,14 @@ def __init__(self, data=None, map=None, access=None, lgmaps=None, unroll_map=Fal "To set of %s doesn't match the set of %s." % (map, data)) def recreate(self, data=None, map=None, access=None, lgmaps=None, unroll_map=None): - """:param data: A data-carrying object, either :class:`Dat` or class:`Mat` + """Creates a new Dat based on the existing Dat with the changes specified. + + :param data: A data-carrying object, either :class:`Dat` or class:`Mat` :param map: A :class:`Map` to access this :class:`Arg` or the default if the identity map is to be used. :param access: An access descriptor of type :class:`Access` :param lgmaps: For :class:`Mat` objects, a tuple of 2-tuples of local to - global maps used during assembly. - - Takes all the same arguments as _init_ overriding them, if necessary.""" + global maps used during assembly.""" return type(self)(data=data or self.data, map=map or self.map, access=access or self.access, @@ -1553,10 +1553,38 @@ def zero(self, subset=None): """Zero the data associated with this :class:`Dat` :arg subset: A :class:`Subset` of entries to zero (optional).""" - if subset is None: - self.data[:] = 0 + if hasattr(self, "_zero_parloops"): + loops = self._zero_parloops else: - self.data[subset.indices] = 0 + loops = {} + self._zero_parloops = loops + + iterset = subset or self.dataset.set + + loop = loops.get(iterset, None) + + if loop is None: + try: + knl = self._zero_kernels[(self.dtype, self.cdim)] + except KeyError: + import islpy as isl + import pymbolic.primitives as p + + inames = isl.make_zero_and_vars(["i"]) + domain = (inames[0].le_set(inames["i"])) & (inames["i"].lt_set(inames[0] + self.cdim)) + x = p.Variable("dat") + i = p.Variable("i") + insn = loopy.Assignment(x.index(i), 0, within_inames=frozenset(["i"])) + data = loopy.GlobalArg("dat", dtype=self.dtype, shape=(self.cdim,)) + knl = loopy.make_function([domain], [insn], [data], name="zero", target=loopy.CTarget(), lang_version=(2018, 2)) + + knl = _make_object('Kernel', knl, 'zero') + self._zero_kernels[(self.dtype, self.cdim)] = knl + loop = _make_object('ParLoop', knl, + iterset, + self(WRITE)) + loops[iterset] = loop + loop.compute() @collective def copy(self, other, subset=None): @@ -1566,10 +1594,28 @@ def copy(self, other, subset=None): :arg subset: A :class:`Subset` of elements to copy (optional)""" if other is self: return - if subset is None: - other.data[:] = self.data_ro - else: - other.data[subset.indices] = self.data_ro[subset.indices] + self._copy_parloop(other, subset=subset).compute() + + @collective + def _copy_parloop(self, other, subset=None): + """Create the :class:`ParLoop` implementing copy.""" + if not hasattr(self, '_copy_kernel'): + import islpy as isl + import pymbolic.primitives as p + inames = isl.make_zero_and_vars(["i"]) + domain = (inames[0].le_set(inames["i"])) & (inames["i"].lt_set(inames[0] + self.cdim)) + _other = p.Variable("other") + _self = p.Variable("self") + i = p.Variable("i") + insn = loopy.Assignment(_other.index(i), _self.index(i), within_inames=frozenset(["i"])) + data = [loopy.GlobalArg("self", dtype=self.dtype, shape=(self.cdim,)), + loopy.GlobalArg("other", dtype=other.dtype, shape=(other.cdim,))] + knl = loopy.make_function([domain], [insn], data, name="copy", target=loopy.CTarget(), lang_version=(2018, 2)) + + self._copy_kernel = _make_object('Kernel', knl, 'copy') + return _make_object('ParLoop', self._copy_kernel, + subset or self.dataset.set, + self(READ), other(WRITE)) def __iter__(self): """Yield self when iterated over.""" @@ -1794,35 +1840,19 @@ def __truediv__(self, other): def __iadd__(self, other): """Pointwise addition of fields.""" - # return self._iop(other, operator.iadd) - if other is None: - return self - else: - other.data[:] += self.data_ro + return self._iop(other, operator.iadd) def __isub__(self, other): """Pointwise subtraction of fields.""" - # return self._iop(other, operator.isub) - if other is None: - return self - else: - other.data[:] -= self.data_ro + return self._iop(other, operator.isub) def __imul__(self, other): """Pointwise multiplication or scaling of fields.""" - # return self._iop(other, operator.imul) - if type(other) is float: - other = np.float64(other) - else: - other.data[:] *= self.data_ro + return self._iop(other, operator.imul) def __itruediv__(self, other): """Pointwise division or scaling of fields.""" - # return self._iop(other, operator.itruediv) - if other is None: - return self - else: - other.data[:] /= self.data_ro + return self._iop(other, operator.itruediv) __idiv__ = __itruediv__ # Python 2 compatibility