From 3283f73d4a3b3facc4871668266ad4ff7d62bc61 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Mon, 27 Aug 2018 08:33:49 -0500 Subject: [PATCH 1/7] Add default value to position args of __new__ --- pytential/symbolic/primitives.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pytential/symbolic/primitives.py b/pytential/symbolic/primitives.py index 3a297fd1..ee893ce7 100644 --- a/pytential/symbolic/primitives.py +++ b/pytential/symbolic/primitives.py @@ -378,12 +378,12 @@ class NumReferenceDerivative(DiscretizationProperty): reference coordinates. """ - def __new__(cls, ref_axes, operand, where=None): + def __new__(cls, ref_axes=None, operand=None, where=None): # If the constructor is handed a multivector object, return an # object array of the operator applied to each of the # coefficients in the multivector. - if isinstance(operand, (np.ndarray)): + if isinstance(operand, np.ndarray): def make_op(operand_i): return cls(ref_axes, operand_i, where=where) @@ -750,7 +750,7 @@ def _scaled_max_curvature(ambient_dim, dim=None, where=None): # {{{ operators class SingleScalarOperandExpression(Expression): - def __new__(cls, operand): + def __new__(cls, operand=None): # If the constructor is handed a multivector object, return an # object array of the operator applied to each of the # coefficients in the multivector. @@ -792,7 +792,7 @@ def integral(ambient_dim, dim, operand, where=None): class SingleScalarOperandExpressionWithWhere(Expression): - def __new__(cls, operand, where=None): + def __new__(cls, operand=None, where=None): # If the constructor is handed a multivector object, return an # object array of the operator applied to each of the # coefficients in the multivector. @@ -982,7 +982,7 @@ class IntG(Expression): where :math:`\sigma` is *density*. """ - def __new__(cls, kernel, density, *args, **kwargs): + def __new__(cls, kernel=None, density=None, *args, **kwargs): # If the constructor is handed a multivector object, return an # object array of the operator applied to each of the # coefficients in the multivector. -- GitLab From 0c82577817018841f36c77db82018f37d3c6bca7 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Mon, 27 Aug 2018 08:52:25 -0500 Subject: [PATCH 2/7] Add init_arg_names to subclasses of Expression --- pytential/symbolic/primitives.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pytential/symbolic/primitives.py b/pytential/symbolic/primitives.py index ee893ce7..8c566a50 100644 --- a/pytential/symbolic/primitives.py +++ b/pytential/symbolic/primitives.py @@ -328,6 +328,8 @@ class DiscretizationProperty(Expression): further arguments. """ + init_arg_names = ("where",) + def __init__(self, where=None): """ :arg where: |where-blurb| @@ -348,6 +350,9 @@ class QWeight(DiscretizationProperty): class NodeCoordinateComponent(DiscretizationProperty): + + init_arg_names = ("ambient_axis", "where") + def __init__(self, ambient_axis, where=None): """ :arg where: |where-blurb| @@ -378,6 +383,8 @@ class NumReferenceDerivative(DiscretizationProperty): reference coordinates. """ + init_arg_names = ("ref_axes", "operand", "where") + def __new__(cls, ref_axes=None, operand=None, where=None): # If the constructor is handed a multivector object, return an # object array of the operator applied to each of the @@ -750,6 +757,9 @@ def _scaled_max_curvature(ambient_dim, dim=None, where=None): # {{{ operators class SingleScalarOperandExpression(Expression): + + init_arg_names = ("operand",) + def __new__(cls, operand=None): # If the constructor is handed a multivector object, return an # object array of the operator applied to each of the @@ -792,6 +802,9 @@ def integral(ambient_dim, dim, operand, where=None): class SingleScalarOperandExpressionWithWhere(Expression): + + init_arg_names = ("operand", "where") + def __new__(cls, operand=None, where=None): # If the constructor is handed a multivector object, return an # object array of the operator applied to each of the @@ -842,6 +855,8 @@ class Ones(Expression): discretization. """ + init_arg_names = ("where",) + def __init__(self, where=None): self.where = where @@ -870,6 +885,9 @@ def mean(ambient_dim, dim, operand, where=None): class IterativeInverse(Expression): + + init_arg_names = ("expression", "rhs", "variable_name", "extra_vars", "where") + def __init__(self, expression, rhs, variable_name, extra_vars={}, where=None): self.expression = expression @@ -982,6 +1000,9 @@ class IntG(Expression): where :math:`\sigma` is *density*. """ + init_arg_names = ("kernel", "density", "qbx_forced_limit", "source", "target", + "kernel_arguments") + def __new__(cls, kernel=None, density=None, *args, **kwargs): # If the constructor is handed a multivector object, return an # object array of the operator applied to each of the -- GitLab From 26091ddb1429dbf5073607efcfb652c014320e3d Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Mon, 27 Aug 2018 09:49:03 -0500 Subject: [PATCH 3/7] Convert IntG.kernel_arguments back to dict upon unpickling --- pytential/symbolic/primitives.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pytential/symbolic/primitives.py b/pytential/symbolic/primitives.py index 8c566a50..ea7b1fc0 100644 --- a/pytential/symbolic/primitives.py +++ b/pytential/symbolic/primitives.py @@ -1045,8 +1045,8 @@ class IntG(Expression): :arg kernel_arguments: A dictionary mapping named :class:`sumpy.kernel.Kernel` arguments (see :meth:`sumpy.kernel.Kernel.get_args` - and :meth:`sumpy.kernel.Kernel.get_source_args` - to expressions that determine them) + and :meth:`sumpy.kernel.Kernel.get_source_args`) + to expressions that determine them :arg source: The symbolic name of the source discretization. This name is bound to a concrete :class:`pytential.source.LayerPotentialSourceBase` @@ -1135,6 +1135,17 @@ class IntG(Expression): self.source, self.target, hashable_kernel_args(self.kernel_arguments)) + def __setstate__(self, state): + # Overwrite pymbolic.Expression.__setstate__ + assert len(self.init_arg_names) == len(state), type(self) + for name, value in zip(self.init_arg_names, state): + if name == 'kernel_arguments': + value = dict(value) + for dict_name in value: + value[dict_name] = np.array(value[dict_name], dtype=object) + + setattr(self, name, value) + mapper_method = intern("map_int_g") -- GitLab From af12f31a9450f1d57e09464287f81c18ced7b83b Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Mon, 27 Aug 2018 09:53:51 -0500 Subject: [PATCH 4/7] Add a test case for pickling expressions --- test/test_symbolic.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/test/test_symbolic.py b/test/test_symbolic.py index 8b2e7cb4..c0a35ffa 100644 --- a/test/test_symbolic.py +++ b/test/test_symbolic.py @@ -169,8 +169,27 @@ def test_tangential_onb(ctx_factory): # }}} +# {{{ test_expr_picking + +def test_expr_picking(): + from sumpy.kernel import LaplaceKernel + import pickle + import pytential + + op = pytential.sym.D( + LaplaceKernel(2), pytential.sym.var("sigma"), qbx_forced_limit=-2 + ) + + pickled_op = pickle.dumps(op) + after_pickle_op = pickle.loads(pickled_op) + + assert op == after_pickle_op + +# }}} + + # You can test individual routines by typing -# $ python test_tools.py 'test_routine()' +# $ python test_symbolic.py 'test_routine()' if __name__ == "__main__": import sys -- GitLab From 5e82132ec1826382a251aeced8328d518fa8c823 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Sat, 1 Sep 2018 21:16:33 -0500 Subject: [PATCH 5/7] Call __init__ upon unpickling for IntG --- pytential/symbolic/primitives.py | 8 +------- test/test_symbolic.py | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/pytential/symbolic/primitives.py b/pytential/symbolic/primitives.py index ea7b1fc0..1a5f0f1f 100644 --- a/pytential/symbolic/primitives.py +++ b/pytential/symbolic/primitives.py @@ -1138,13 +1138,7 @@ class IntG(Expression): def __setstate__(self, state): # Overwrite pymbolic.Expression.__setstate__ assert len(self.init_arg_names) == len(state), type(self) - for name, value in zip(self.init_arg_names, state): - if name == 'kernel_arguments': - value = dict(value) - for dict_name in value: - value[dict_name] = np.array(value[dict_name], dtype=object) - - setattr(self, name, value) + self.__init__(*state) mapper_method = intern("map_int_g") diff --git a/test/test_symbolic.py b/test/test_symbolic.py index c0a35ffa..0c140d04 100644 --- a/test/test_symbolic.py +++ b/test/test_symbolic.py @@ -169,9 +169,9 @@ def test_tangential_onb(ctx_factory): # }}} -# {{{ test_expr_picking +# {{{ test_expr_pickling -def test_expr_picking(): +def test_expr_pickling(): from sumpy.kernel import LaplaceKernel import pickle import pytential -- GitLab From 481eb6543b4bea63c360b436257eaf4b5431a2f0 Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Mon, 3 Sep 2018 23:48:42 -0500 Subject: [PATCH 6/7] Test pickling kernel wrappers. [ci skip] because it contains bug. --- test/test_symbolic.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/test/test_symbolic.py b/test/test_symbolic.py index 0c140d04..2f5633d3 100644 --- a/test/test_symbolic.py +++ b/test/test_symbolic.py @@ -172,18 +172,29 @@ def test_tangential_onb(ctx_factory): # {{{ test_expr_pickling def test_expr_pickling(): - from sumpy.kernel import LaplaceKernel + from sumpy.kernel import LaplaceKernel, AxisTargetDerivative import pickle import pytential - op = pytential.sym.D( - LaplaceKernel(2), pytential.sym.var("sigma"), qbx_forced_limit=-2 - ) - - pickled_op = pickle.dumps(op) - after_pickle_op = pickle.loads(pickled_op) - - assert op == after_pickle_op + ops_for_testing = [ + pytential.sym.d_dx( + 2, + pytential.sym.D( + LaplaceKernel(2), pytential.sym.var("sigma"), qbx_forced_limit=-2 + ) + ), + pytential.sym.D( + AxisTargetDerivative(0, LaplaceKernel(2)), + pytential.sym.var("sigma"), + qbx_forced_limit=-2 + ) + ] + + for op in ops_for_testing: + pickled_op = pickle.dumps(op) + after_pickle_op = pickle.loads(pickled_op) + + assert op == after_pickle_op # }}} -- GitLab From 8c78372ab38772a5f8b1cdc829f6b4ca4e72b26c Mon Sep 17 00:00:00 2001 From: Hao Gao Date: Sat, 8 Sep 2018 23:36:46 -0500 Subject: [PATCH 7/7] Bug fix --- pytential/symbolic/primitives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytential/symbolic/primitives.py b/pytential/symbolic/primitives.py index 1a5f0f1f..94a8b125 100644 --- a/pytential/symbolic/primitives.py +++ b/pytential/symbolic/primitives.py @@ -1156,7 +1156,7 @@ def _insert_source_derivative_into_kernel(kernel): kernel, dir_vec_name=_DIR_VEC_NAME) else: return kernel.replace_inner_kernel( - _insert_source_derivative_into_kernel(kernel.kernel)) + _insert_source_derivative_into_kernel(kernel.inner_kernel)) def _get_dir_vec(dsource, ambient_dim): -- GitLab