From 21f4a780335a13fe25efddcd340953e44aaff873 Mon Sep 17 00:00:00 2001
From: JM Etancelin <jean-matthieu.etancelin@univ-pau.fr>
Date: Mon, 30 Nov 2020 15:21:59 +0100
Subject: [PATCH] Fix convergence operator with custom field for previous 
 values

---
 .../host/python/operator/convergence.py       | 11 ++++----
 hysop/operator/base/convergence.py            | 27 +++++++++++++++----
 hysop/operator/convergence.py                 | 19 ++++++-------
 3 files changed, 37 insertions(+), 20 deletions(-)

diff --git a/hysop/backend/host/python/operator/convergence.py b/hysop/backend/host/python/operator/convergence.py
index 7a2c3651f..309ea9595 100644
--- a/hysop/backend/host/python/operator/convergence.py
+++ b/hysop/backend/host/python/operator/convergence.py
@@ -29,12 +29,11 @@ class PythonConvergence(ConvergenceBase, HostOperator):
                                           dtype=self.convergence.dtype)
         self._tmp_reduce = npw.zeros((1+self.field.nb_components),
                                      dtype=self.convergence.dtype)
-        old = [npw.zeros(_.shape) for _ in self.field_buffers]
-        self.dField_old = tuple(old)
 
-        self.__compute_error_absolute = lambda ui, ui_old: npw.max(npw.abs(ui - ui_old))
-        self.__compute_error_relative = lambda ui, ui_old, max_ui: npw.max(
-            npw.abs(ui - ui_old))/max_ui
+        self.__compute_error_absolute = \
+            lambda ui, ui_old: npw.max(npw.abs(ui - ui_old))
+        self.__compute_error_relative = \
+            lambda ui, ui_old, max_ui: npw.max(npw.abs(ui - ui_old))/max_ui
         if self._residual_computation == ResidualError.ABSOLUTE:
             self.__compute_error = self.__compute_error_absolute
         elif self._residual_computation == ResidualError.RELATIVE:
@@ -47,7 +46,7 @@ class PythonConvergence(ConvergenceBase, HostOperator):
 
     @op_apply
     def apply(self, **kwds):
-        u = self.field_buffers
+        u = self.dField.compute_buffers
         u_old = self.dField_old
 
         self._tmp_convergence[...] = 0.
diff --git a/hysop/operator/base/convergence.py b/hysop/operator/base/convergence.py
index eeca70420..9ca58e0d5 100644
--- a/hysop/operator/base/convergence.py
+++ b/hysop/operator/base/convergence.py
@@ -1,13 +1,15 @@
 from abc import ABCMeta
 import numpy as np
 
-from hysop.tools.types       import check_instance, first_not_None, InstanceOf
-from hysop.tools.decorators  import debug
+from hysop.tools.types import check_instance, first_not_None, InstanceOf
+from hysop.tools.decorators import debug
 from hysop.fields.continuous_field import Field
 from hysop.parameters.tensor_parameter import TensorParameter
 from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors
 from hysop.core.memory.memory_request import MemoryRequest
 from hysop.constants import ResidualError
+from hysop.tools.numpywrappers import npw
+
 
 class ConvergenceBase(object):
     """Common implementation interface for Convergence operator"""
@@ -25,6 +27,7 @@ class ConvergenceBase(object):
         dm = super(ConvergenceBase, cls).default_method()
         dm.update(cls.__default_method)
         return dm
+
     @classmethod
     def available_methods(cls):
         am = super(ConvergenceBase, cls).available_methods()
@@ -32,11 +35,12 @@ class ConvergenceBase(object):
         return am
 
     @debug
-    def __init__(self, variables, convergence=None,
+    def __init__(self, variables, convergence=None, u_old=None,
                  implementation=None, **kwds):
         """
         variables: dict
             dictionary of fields as keys and topologies as values.
+
         convergence: TensorParameter (optional)
             Parameter to store the components of ||u-u_old||_\infty or ||u-u_old||_\infty/||u||_\infty
         implementation: Implementation, optional, defaults to None
@@ -48,19 +52,24 @@ class ConvergenceBase(object):
         """
         check_instance(convergence, TensorParameter, allow_none=True)
         check_instance(variables, dict, keys=Field, values=CartesianTopologyDescriptors)
+        check_instance(u_old, Field, allow_none=True)
 
         field = variables.keys()[0]
         if convergence is None:
             convergence = TensorParameter(name="|residual|", dtype=field.dtype,
                                           shape=(field.nb_components, ),
                                           is_read_only=False, quiet=False,
-                                          initial_value=np.asarray([np.finfo(field.dtype).max,]*field.nb_components))
+                                          initial_value=np.asarray([np.finfo(field.dtype).max, ]*field.nb_components))
 
-        input_fields  = {field: variables[field]}
+        input_fields = {field: variables[field]}
         output_params = {convergence.name: convergence}
 
         self.field = field
         self.convergence = convergence
+        self.u_old = u_old
+
+        if not u_old is None:
+            input_fields.update({u_old: variables[u_old]})
 
         super(ConvergenceBase, self).__init__(input_fields=input_fields,
                                               output_params=output_params, **kwds)
@@ -76,3 +85,11 @@ class ConvergenceBase(object):
             return
         super(ConvergenceBase, self).discretize()
         self.dField = self.get_input_discrete_field(self.field)
+        if not self.u_old is None:
+            self.dField_old = self.get_input_discrete_field(self.u_old).compute_buffers
+
+    @debug
+    def setup(self, work):
+        super(ConvergenceBase, self).setup(work)
+        if self.u_old is None:
+            self.dField_old = tuple([npw.zeros(_.shape) for _ in self.dField.compute_buffers])
diff --git a/hysop/operator/convergence.py b/hysop/operator/convergence.py
index 3abcd47e3..1f31631b8 100644
--- a/hysop/operator/convergence.py
+++ b/hysop/operator/convergence.py
@@ -3,14 +3,15 @@
 Convergence operator.
 """
 
-from hysop.tools.decorators  import debug
-from hysop.constants         import Implementation
-from hysop.tools.types       import check_instance
+from hysop.tools.decorators import debug
+from hysop.constants import Implementation
+from hysop.tools.types import check_instance
 from hysop.fields.continuous_field import Field
 from hysop.parameters.tensor_parameter import TensorParameter
 from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors
 from hysop.core.graph.computational_node_frontend import ComputationalGraphNodeFrontend
 
+
 class Convergence(ComputationalGraphNodeFrontend):
     """
     Computes the convergence citeria for a given field.
@@ -24,7 +25,7 @@ class Convergence(ComputationalGraphNodeFrontend):
     def implementations(cls):
         from hysop.backend.host.python.operator.convergence import PythonConvergence
         implementations = {
-                Implementation.PYTHON: PythonConvergence
+            Implementation.PYTHON: PythonConvergence
         }
         return implementations
 
@@ -33,7 +34,7 @@ class Convergence(ComputationalGraphNodeFrontend):
         return Implementation.PYTHON
 
     @debug
-    def __init__(self, variables, error=None, convergence=None,
+    def __init__(self, variables, u_old=None, convergence=None,
                  implementation=None, **kwds):
         """Initialize a convergence operator.
 
@@ -43,8 +44,8 @@ class Convergence(ComputationalGraphNodeFrontend):
 
         variables: dict
             dictionary of fields as keys and topologies as values.
-        error: Field (optional)
-            Field to compute u-u_old. This field is created if not given.
+        u_old: Field (optional)
+            Field to store u_old. This field is created if not given.
         convergence: TensorParameter (optional)
             Parameter to store the components of ||u-u_old||_\infty or ||u-u_old||_\infty/||u||_\infty
         implementation: Implementation, optional, defaults to None
@@ -54,11 +55,11 @@ class Convergence(ComputationalGraphNodeFrontend):
             Extra keywords arguments that will be passed towards implementation
             enstrophy operator __init__.
         """
-        check_instance(error, Field, allow_none=True)
+        check_instance(u_old, Field, allow_none=True)
         check_instance(convergence, TensorParameter, allow_none=True)
         check_instance(variables, dict, keys=Field, values=CartesianTopologyDescriptors)
 
         super(Convergence, self).__init__(
-            error=error, convergence=convergence,
+            u_old=u_old, convergence=convergence,
             variables=variables,
             implementation=implementation, **kwds)
-- 
GitLab