From d52d27d4bbaee38d4610b43a621edadd789fd0b7 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste Keck <Jean-Baptiste.Keck@imag.fr>
Date: Mon, 23 Jul 2018 22:09:54 +0200
Subject: [PATCH] added assertions for symbolic names

---
 examples/scalar_advection/scalar_advection.py |  1 -
 examples/scalar_diffusion/scalar_diffusion.py |  3 +-
 examples/shear_layer/shear_layer.py           |  7 ++---
 .../backend/device/opencl/opencl_symbolic.py  | 31 +++++++++++--------
 hysop/core/graph/computational_graph.py       | 18 -----------
 hysop/core/graph/computational_node.py        | 31 +++++++++++++------
 hysop/defaults.py                             |  2 +-
 hysop/fields/discrete_field.py                |  4 +++
 hysop/operator/adapt_timestep.py              |  5 ++-
 hysop/operator/base/min_max.py                |  2 +-
 .../tests/test_directional_advection.py       | 11 ++++---
 hysop/parameters/default_parameters.py        |  9 ++++++
 hysop/parameters/parameter.py                 |  4 +++
 hysop/parameters/tensor_parameter.py          | 23 +++++++++-----
 hysop/problem.py                              | 19 +++++++-----
 hysop/symbolic/__init__.py                    | 16 +++++++---
 hysop/symbolic/base.py                        | 12 +++++--
 hysop/symbolic/parameter.py                   | 14 ++++-----
 hysop/tools/sympy_utils.py                    | 13 ++++++--
 hysop/tools/types.py                          |  2 ++
 20 files changed, 141 insertions(+), 86 deletions(-)

diff --git a/examples/scalar_advection/scalar_advection.py b/examples/scalar_advection/scalar_advection.py
index 534759ec2..25d99934b 100644
--- a/examples/scalar_advection/scalar_advection.py
+++ b/examples/scalar_advection/scalar_advection.py
@@ -12,7 +12,6 @@ def compute(args):
 
     ## Function to compute initial velocity values
     def init_velocity(data, coords, component):
-        print len(data), len(coords), component
         assert len(data)==1
         i, = component
         data[0][...] = args.velocity[::-1][i]
diff --git a/examples/scalar_diffusion/scalar_diffusion.py b/examples/scalar_diffusion/scalar_diffusion.py
index 1bd86ac93..62ea8c52d 100755
--- a/examples/scalar_diffusion/scalar_diffusion.py
+++ b/examples/scalar_diffusion/scalar_diffusion.py
@@ -89,8 +89,7 @@ def compute(args):
         problem.display(args.visu_rank)
     
     # Initialize discrete scalar field
-    dfields = problem.input_discrete_fields
-    dfields[scalar].initialize(formula=init_scalar)
+    problem.initialize_field(scalar, formula=init_scalar)
     
     # Create a simulation and solve the problem 
     # (do not forget to specify the dt parameter here)
diff --git a/examples/shear_layer/shear_layer.py b/examples/shear_layer/shear_layer.py
index 92f307bd8..52d924c31 100644
--- a/examples/shear_layer/shear_layer.py
+++ b/examples/shear_layer/shear_layer.py
@@ -10,7 +10,7 @@ def compute(args):
                       ScalarParameter
     from hysop.tools.debug_utils import ImshowDebugger
     from hysop.defaults import VelocityField, VorticityField, \
-                               TimeParameters
+                               TimeParameters, ViscosityParameter
     from hysop.constants import Implementation, AdvectionCriteria
 
     from hysop.operators import DirectionalAdvection, DirectionalDiffusion, \
@@ -78,7 +78,7 @@ def compute(args):
     t, dt = TimeParameters(dtype=args.dtype)
     velo  = VelocityField(domain=box, dtype=args.dtype)
     vorti = VorticityField(domain=box, dtype=args.dtype)
-    nu    = ScalarParameter('nu', initial_value=args.nu, const=True, dtype=args.dtype)
+    nu    = ViscosityParameter(initial_value=args.nu, const=True, dtype=args.dtype)
     
     ### Build the directional operators
     #> Directional advection 
@@ -157,8 +157,7 @@ def compute(args):
     simu.write_parameters(t, dt, filename='parameters.txt', precision=4)
     
     # Initialize only the vorticity
-    dfields = problem.input_discrete_fields
-    dfields[vorti].initialize(formula=init_vorticity)
+    problem.initialize_field(vorti, formula=init_vorticity)
     
     # Setup vorticity plotter if required
     if args.plot_vorticity:
diff --git a/hysop/backend/device/opencl/opencl_symbolic.py b/hysop/backend/device/opencl/opencl_symbolic.py
index 3d33256ed..18adca261 100644
--- a/hysop/backend/device/opencl/opencl_symbolic.py
+++ b/hysop/backend/device/opencl/opencl_symbolic.py
@@ -83,18 +83,21 @@ class OpenClSymbolic(OpenClOperator):
         if ('count' in kwds):
             count = kwds.pop('count')
             assert len(names)==1
-            snames      = tuple(names[0]+subscript(i)           for i in xrange(count))         
+            snames     = tuple(names[0]+subscript(i)           for i in xrange(count))         
             var_names   = tuple('{}{}'.format(names[0], i)      for i in xrange(count))         
             latex_names = tuple('{}_{{{}}}'.format(names[0], i) for i in xrange(count))
         else:
             snames     = names
             varnames   = names
             latexnames = names
-        for (name, var_name, latex_name) in zip(snames, var_names, latex_names):
+        for (name, pname, var_name, latex_name) in zip(var_names, snames, var_names, latex_names):
             assert ',' not in name
-            check_instance(name, (str,unicode))
-            buf = OpenClSymbolicBuffer(name=name, var_name=var_name, latex_name=latex_name,
-                                                                    memory_object=None, **kwds)
+            check_instance(name, str)
+            buf = OpenClSymbolicBuffer(name=name, 
+                                       pretty_name=pname,
+                                       var_name=var_name, 
+                                       latex_name=latex_name,
+                                       memory_object=None, **kwds)
             buffers += (buf,)
         return buffers
 
@@ -112,11 +115,12 @@ class OpenClSymbolic(OpenClOperator):
             snames      = names
             var_names   = names
             latex_names = names
-        for (name, var_name, latex_name) in zip(snames, var_names, latex_names):
+        for (name, pname, var_name, latex_name) in zip(var_names, snames, var_names, latex_names):
             assert ',' not in name
-            check_instance(name, (str,unicode))
-            arr = OpenClSymbolicArray(name=name, var_name=var_name, latex_name=latex_name,
-                                                                    memory_object=None, **kwds)
+            check_instance(name, str)
+            arr = OpenClSymbolicArray(name=name, pretty_name=pname,
+                                      var_name=var_name, latex_name=latex_name,
+                                      memory_object=None, **kwds)
             arrays += (arr,)
         return arrays
         
@@ -134,11 +138,12 @@ class OpenClSymbolic(OpenClOperator):
             snames      = names
             var_names   = names
             latex_names = names
-        for (name, var_name, latex_name) in zip(snames, var_names, latex_names):
+        for (name, pname, var_name, latex_name) in zip(var_names, snames, var_names, latex_names):
             assert ',' not in name
-            check_instance(name, (str,unicode))
-            tmp = TmpScalar(name=name, var_name=var_name, latex_name=latex_name,
-                                **kwds)
+            check_instance(name, str)
+            tmp = TmpScalar(name=name, pretty_name=pname,
+                            var_name=var_name, latex_name=latex_name,
+                            **kwds)
             scalars += (tmp,)
         return scalars
 
diff --git a/hysop/core/graph/computational_graph.py b/hysop/core/graph/computational_graph.py
index 6d2e7b093..7c7919548 100644
--- a/hysop/core/graph/computational_graph.py
+++ b/hysop/core/graph/computational_graph.py
@@ -62,9 +62,6 @@ class ComputationalGraph(ComputationalGraphNode):
         self.graph_is_rendering = False
         self.candidate_input_tensors  = set(first_not_None(candidate_input_tensors, ()))
         self.candidate_output_tensors = set(first_not_None(candidate_output_tensors, ()))
-        print self.name
-        print self.candidate_input_tensors
-        print self.candidate_output_tensors
     
     @graph_built
     def _get_profiling_info(self):
@@ -386,10 +383,6 @@ class ComputationalGraph(ComputationalGraphNode):
             else:
                 msg = 'Given node is not an instance of ComputationalGraphNode (got a {}).'
                 raise ValueError(msg.format(node.__class__))
-            print 'PUSH NODE {}'.format(node.name)
-            print self.name
-            print self.candidate_input_tensors
-            print self.candidate_output_tensors
         return self
     
     def available_methods(self):
@@ -514,12 +507,6 @@ class ComputationalGraph(ComputationalGraphNode):
         output_fields = builder.output_fields
         candidate_input_tensors  = self.candidate_input_tensors
         candidate_output_tensors = self.candidate_output_tensors
-        print
-        print 'BUILD GRAPH {}'.format(self.name)
-        print 'CANDIDATE_INPUT_TENSORS: {}'.format(tuple(f.name for f in candidate_input_tensors))
-        print 'CANDIDATE_OUTPUT_TENSORS: {}'.format(tuple(f.name for f in candidate_output_tensors))
-        print 'INPUT_FIELDS: {}'.format(tuple(f.name for f in input_fields))
-        print 'OUTPUT_FIELDS: {}'.format(tuple(f.name for f in output_fields))
         
         input_tensor_fields = ()
         output_tensor_fields = ()
@@ -530,9 +517,6 @@ class ComputationalGraph(ComputationalGraphNode):
             if all((f in output_fields) for f in otfield):
                 output_tensor_fields += (otfield,)
 
-        print 'INPUT_TENSORS: {}'.format( tuple(f.name for f in input_tensor_fields))
-        print 'OUTPUT_TENSORS: {}'.format(tuple(f.name for f in output_tensor_fields))
-
         # keep variables
         self._init_base(input_fields=input_fields, 
                         output_fields=output_fields,
@@ -624,7 +608,6 @@ class ComputationalGraph(ComputationalGraphNode):
     def discretize(self):
         if self.discretized:
             return
-        print 'DISCRETIZE {}'.format(self.name)
         reduced_graph = self.reduced_graph
         operators     = reduced_graph.vertex_properties['operators']
         for vid in self.sorted_nodes:
@@ -688,7 +671,6 @@ class ComputationalGraph(ComputationalGraphNode):
         self.discrete_fields = discrete_fields
         self.discrete_tensor_fields = discrete_tensor_fields
 
-        print 'INPUT DISCRETE TENSOR FIELD:',tuple(f.name for f in self.input_discrete_tensor_fields)
         
         self.discretized = True
 
diff --git a/hysop/core/graph/computational_node.py b/hysop/core/graph/computational_node.py
index bb3d60164..c60ba7a04 100644
--- a/hysop/core/graph/computational_node.py
+++ b/hysop/core/graph/computational_node.py
@@ -188,7 +188,7 @@ class ComputationalGraphNode(OperatorBase):
                                            for  sfield in tfield.fields }
         else:
             output_tensor_fields = ()
-        
+
         # Check input values
         input_fields  = first_not_None(input_fields,  {})
         output_fields = first_not_None(output_fields, {})
@@ -306,6 +306,17 @@ class ComputationalGraphNode(OperatorBase):
         """
         Initialize base class and check everything.
         """
+        # Merge scalar and tensor fields
+        all_input_fields = tuple(input_tensor_fields)
+        for ofield in input_fields.keys():
+            if not any (ofield in tf for tf in input_tensor_fields):
+                all_input_fields += (ofield,)
+
+        all_output_fields = tuple(output_tensor_fields)
+        for ofield in output_fields.keys():
+            if not any (ofield in tf for tf in output_tensor_fields):
+                all_output_fields += (ofield,)
+        
         assert not self._base_initialized
         check_instance(input_fields,  dict, keys=ScalarField)
         check_instance(output_fields, dict, keys=ScalarField)
@@ -313,6 +324,8 @@ class ComputationalGraphNode(OperatorBase):
         check_instance(output_params, dict, keys=str, values=Parameter)
         check_instance(input_tensor_fields,  tuple, values=TensorField)
         check_instance(output_tensor_fields, tuple, values=TensorField)
+        check_instance(all_input_fields, tuple, values=Field)
+        check_instance(all_output_fields, tuple, values=Field)
 
         self.input_fields  = input_fields
         self.output_fields = output_fields
@@ -321,10 +334,6 @@ class ComputationalGraphNode(OperatorBase):
         self.input_tensor_fields = input_tensor_fields
         self.output_tensor_fields = output_tensor_fields
         
-        print
-        print 'INIT BASE {}'.format(self.name)
-        print 'INPUT TENSOR FIELDS:', tuple(f.name for f in self.input_tensor_fields)
-        
         ifields = set(self.input_fields.keys())
         ofields = set(self.output_fields.keys())
         fields  = tuple(ifields.union(ofields))
@@ -354,6 +363,8 @@ class ComputationalGraphNode(OperatorBase):
                 parameters=parameters, 
                 **self.__kwds)
         self._base_initialized = True
+        self.all_input_fields = all_input_fields
+        self.all_output_fields = all_output_fields
 
     @debug
     def _check_method(self, user_method):
@@ -943,13 +954,14 @@ class ComputationalGraphNode(OperatorBase):
             check_instance(fields, (set,list,tuple), values=Field)
             if self._base_initialized:
                 for field in fields:
-                    if field not in self.input_fields.keys():
+                    if ((field not in self.input_fields) and \
+                        (field not in self.input_tensor_fields)):
                         msg='Field {} is not an input field of operator {}.'
                         msg=msg.format(field.name, self.name)
                         raise RuntimeError(msg)
         else:
             assert self._base_initialized, self.name
-            fields = self.input_fields.keys()
+            fields = self.all_input_fields
             fields = list(sorted(fields, key=lambda f:f.name))
 
         if (io_params is None):
@@ -994,12 +1006,13 @@ class ComputationalGraphNode(OperatorBase):
             check_instance(fields, (set,list,tuple), values=Field)
             if self._base_initialized:
                 for field in fields:
-                    if field not in self.output_fields.keys():
+                    if ((field not in self.output_fields) and \
+                        (field not in self.output_tensor_fields)):
                         msg='Field {} is not an output field of operator {}.'
                         msg=msg.format(field.name, self.name)
                         raise RuntimeError(msg)
         else:
-            fields = self.output_fields.keys()
+            fields = self.all_output_fields
             fields = list(sorted(fields, key=lambda f:f.name))
         
         if (io_params is None):
diff --git a/hysop/defaults.py b/hysop/defaults.py
index 15423fc3b..7585c2ad3 100644
--- a/hysop/defaults.py
+++ b/hysop/defaults.py
@@ -2,5 +2,5 @@
 from hysop.fields.default_fields import VelocityField, VorticityField, \
                                         DensityField, ViscosityField, \
                                         LevelSetField, PenalizationField
-from hysop.parameters.default_parameters import TimeParameters, \
+from hysop.parameters.default_parameters import TimeParameters, ViscosityParameter, \
         EnstrophyParameter, KineticEnergyParameter, VolumicIntegrationParameter
diff --git a/hysop/fields/discrete_field.py b/hysop/fields/discrete_field.py
index 379f9a147..f87cb7a0b 100644
--- a/hysop/fields/discrete_field.py
+++ b/hysop/fields/discrete_field.py
@@ -387,6 +387,9 @@ class DiscreteScalarFieldView(DiscreteScalarFieldViewContainerI, TaggedObjectVie
     def _get_dfield(self):
         """Get the discrete field on which the view is."""
         return self._dfield
+    def _get_field(self):
+        """Get the continuous field on which the view is."""
+        return self._dfield._field
     def _get_topology_state(self):
         """Get the topology state of this view."""
         return self._topology_state
@@ -505,6 +508,7 @@ class DiscreteScalarFieldView(DiscreteScalarFieldViewContainerI, TaggedObjectVie
         return self._dfield._symbol
 
     dfield = property(_get_dfield)
+    field = property(_get_field)
     topology_state = property(_get_topology_state)
     is_read_only = property(_get_is_read_only)
     
diff --git a/hysop/operator/adapt_timestep.py b/hysop/operator/adapt_timestep.py
index 5a67b23d7..9b52f3555 100755
--- a/hysop/operator/adapt_timestep.py
+++ b/hysop/operator/adapt_timestep.py
@@ -339,7 +339,10 @@ class AdaptiveTimeStep(ComputationalGraphNodeGenerator):
         * This operator has no effect on input variables.
         """
         base_kwds = first_not_None(base_kwds, {})
-        super(AdaptiveTimeStep, self).__init__(**base_kwds)
+        super(AdaptiveTimeStep, self).__init__(
+                candidate_input_tensors=(),
+                candidate_output_tensors=(),
+                **base_kwds)
         
         # tuple of criterias used to compute dt
         self.criterias = {}
diff --git a/hysop/operator/base/min_max.py b/hysop/operator/base/min_max.py
index ac3c3a308..826e72ea0 100644
--- a/hysop/operator/base/min_max.py
+++ b/hysop/operator/base/min_max.py
@@ -43,7 +43,7 @@ class MinMaxFieldStatisticsBase(object):
         def make_param(k, quiet):
             return TensorParameter(name=names[k], pretty_name=pretty_names[k],
                     dtype=field.dtype, shape=(nb_components,), quiet=quiet)
-        
+
         names = {
             'Fmin': '{}min'.format(pbasename),
             'Fmax': '{}max'.format(pbasename),
diff --git a/hysop/operator/tests/test_directional_advection.py b/hysop/operator/tests/test_directional_advection.py
index c969f237a..3fc8723d2 100644
--- a/hysop/operator/tests/test_directional_advection.py
+++ b/hysop/operator/tests/test_directional_advection.py
@@ -58,7 +58,7 @@ class TestDirectionalAdvectionOperator(object):
             velocity_cfls = (0.62, 1.89)
         else:
             flt_types = (npw.float,)
-            time_integrators = (RK2,)
+            time_integrators = (Euler,)
             remesh_kernels = (Remesh.L4_2,)
             velocity_cfls = (1.89,)
         
@@ -180,6 +180,8 @@ class TestDirectionalAdvectionOperator(object):
                     try:
                         dvin.initialize(self.__velocity_init, axes=axes)
                         dsin.initialize(self.__scalar_init)
+                        print dvin[0].data
+                        print dvin[1].data
                         _input = tuple(dsin.data[i].get().handle.copy() 
                                 for i in xrange(dsin.nb_components))
                         S0 = dsin.integrate()
@@ -203,6 +205,7 @@ class TestDirectionalAdvectionOperator(object):
                                 dxk = -Vi*(k+0)*dt()
                                 dsref.initialize(self.__scalar_init, offsets=dxk.tolist())
                                 d = dsout.distance(dsref, p=2)
+                                print d
                                 if npw.any(d > 1e-2):
                                     print
                                     dsout.print_with_ghosts()
@@ -271,9 +274,9 @@ class TestDirectionalAdvectionOperator(object):
         self._test(dim=3, is_inplace=True)
     
     def perform_tests(self):
-        self.test_advec_1D_inplace()
+        #self.test_advec_1D_inplace()
         self.test_advec_2D_inplace()
-        self.test_advec_3D_inplace()
+        #self.test_advec_3D_inplace()
         
         #self.test_advec_1D_out_of_place()
         #self.test_advec_2D_out_of_place()
@@ -284,7 +287,7 @@ class TestDirectionalAdvectionOperator(object):
 if __name__ == '__main__':
     import hysop
     TestDirectionalAdvectionOperator.setup_class(enable_extra_tests=False, 
-                                      enable_debug_mode=False)
+                                      enable_debug_mode=True)
     
     test = TestDirectionalAdvectionOperator()
     
diff --git a/hysop/parameters/default_parameters.py b/hysop/parameters/default_parameters.py
index b6776362a..2e920f0c5 100644
--- a/hysop/parameters/default_parameters.py
+++ b/hysop/parameters/default_parameters.py
@@ -10,6 +10,15 @@ def TimeParameters(dtype=None, **kwds):
     dt = ScalarParameter('dt', dtype=dtype, **kwds)
     return (t, dt)
 
+def ViscosityParameter(name=None, pretty_name=None, mu=False, **kwds):
+    if mu:
+        name = first_not_None(name, 'mu')
+        pretty_name = first_not_None(pretty_name, greak[11])
+    else:
+        name = first_not_None(name, 'nu')
+        pretty_name = first_not_None(pretty_name, greak[12])
+    return ScalarParameter(name=name, pretty_name=pretty_name, **kwds)
+
 def EnstrophyParameter(name=None, pretty_name=None, **kwds):
     name        = first_not_None(name, 'enstrophy')
     pretty_name = first_not_None(pretty_name, greak[5])
diff --git a/hysop/parameters/parameter.py b/hysop/parameters/parameter.py
index 968c2889f..a27f41605 100644
--- a/hysop/parameters/parameter.py
+++ b/hysop/parameters/parameter.py
@@ -29,6 +29,8 @@ class Parameter(TaggedObject, VariableTag):
         name : string
             A name for the parameter.
             A parameter is uniquely identified by its name.
+        pretty_name : string
+            A pretty name for the parameter.
         parameter_types: type of array like of types
             Allowed types for the parameter.
             None is accepted only if allow_none is set to True.
@@ -55,6 +57,8 @@ class Parameter(TaggedObject, VariableTag):
         parameter_types:
             Return allowed parameter types for this parameter.
         """
+        check_instance(name, str)
+        check_instance(pretty_name, (str, unicode), allow_none=True)
         check_instance(allow_None, bool)
         check_instance(const, bool)
         if not isinstance(parameter_types, type):
diff --git a/hysop/parameters/tensor_parameter.py b/hysop/parameters/tensor_parameter.py
index b878721df..8ffdd2d0d 100644
--- a/hysop/parameters/tensor_parameter.py
+++ b/hysop/parameters/tensor_parameter.py
@@ -3,7 +3,7 @@ from hysop.deps import np, sm
 from hysop.constants import HYSOP_REAL
 from hysop.tools.types import check_instance, first_not_None
 from hysop.tools.numerics import is_signed, is_unsigned, is_fp, is_complex
-from hysop.tools.sympy_utils import subscripts
+from hysop.tools.sympy_utils import subscripts, SymbolicBase
 from hysop.parameters.parameter import Parameter
 
 class TensorParameter(Parameter):
@@ -12,7 +12,8 @@ class TensorParameter(Parameter):
     that may change value as simulation advances.
     """
 
-    def __new__(cls, name, shape, dtype=HYSOP_REAL, initial_value=None, 
+    def __new__(cls, name, shape, dtype=HYSOP_REAL, 
+            pretty_name=None, initial_value=None, 
             min_value=None, max_value=None, ignore_nans=False, **kwds):
         """
         Create or get an existing TensorParameter with a specific name
@@ -22,6 +23,8 @@ class TensorParameter(Parameter):
         ----------
         name: string
             A name for the parameter that uniquely identifies it.
+        pretty_name: string
+            A pretty name for the parameter.
         shape: array like of ints 
             Shape of this TensorParameter.
         dtype: type convertible to np.dtype, optional
@@ -56,13 +59,18 @@ class TensorParameter(Parameter):
         if ('allow_None' in kwds) and (kwds['allow_None'] is True):
             msg='A TensorParameter cannot be allowed to be set to None.'
             raise ValueError(msg)
+
+        check_instance(name, (str, SymbolicBase))
         
-        if not isinstance(name, (str, unicode)):
-            symbol = name
-            name = symbol.name
+        if isinstance(name, SymbolicBase):
+            symbol      = name
+            name        = symbol._name
+            pretty_name = symbol._pretty_name
         else:
             symbol = None
-        check_instance(name, (str, unicode))
+            pretty_name = first_not_None(pretty_name, name)
+        check_instance(name, str)
+        check_instance(pretty_name, (str, unicode))
         check_instance(shape, (list,tuple), values=(int,long,np.integer))
         check_instance(ignore_nans, bool)
         assert (min_value is None) or (max_value is None) or (min_value <= max_value)
@@ -99,7 +107,8 @@ class TensorParameter(Parameter):
         elif is_complex(dtype):
             parameter_types += ( np.complex64, np.complex128, np.clongdouble, complex )
 
-        obj = super(TensorParameter,cls).__new__(cls, name=name, 
+        obj = super(TensorParameter,cls).__new__(cls, 
+                name=name, pretty_name=pretty_name,
                 parameter_types=parameter_types, allow_None=False,
                 initial_value=initial_value, **kwds)
 
diff --git a/hysop/problem.py b/hysop/problem.py
index e9974db30..cf27415a6 100644
--- a/hysop/problem.py
+++ b/hysop/problem.py
@@ -47,25 +47,28 @@ class Problem(ComputationalGraph):
                               op.output_discrete_fields, op.output_discrete_tensor_fields):
                 if (field in op_fields):
                     dfield = op_fields[field]
-                    if dfield.has_unique_topology():
+                    if all((df in initialized) for df in dfield.discrete_fields()):
+                        continue
+                    elif dfield.has_unique_topology() and \
+                            all((df not in initialized) for df in dfield.discrete_fields()):
                         topo_view = dfield.topology
-                        topo      = topo_view.topology
-                        wstate    = topo_view.topology_state.copy(is_read_only=False) # get a writtable state
+                        topo   = topo_view.topology
+                        wstate = topo_view.topology_state.copy(is_read_only=False) # get a writtable state
                         dfield = field.discretize(topo, wstate)
                         dfield.initialize(**kwds)
-                        initialized.add(*dfield.discrete_fields)
+                        initialized.update(dfield.discrete_fields())
                     else:
-                        print dfield
                         for (component, dfield_i) in dfield.nd_iter():
-                            print dfield_i, type(dfield_i)
+                            if (dfield_i._dfield in initialized):
+                                continue
                             topo_view = dfield_i.topology
                             topo      = topo_view.topology
                             wstate    = topo_view.topology_state.copy(is_read_only=False) # get a writtable state
-                            dfield_i  = field.discretize(topo, wstate)
+                            dfield_i  = dfield_i.field.discretize(topo, wstate)
                             dfield_i.initialize(component=component, **kwds)
                             initialized.add(dfield_i._dfield)
         if not initialized:
-            msg='Could not initialize field {}.'.format(field.name)
+            msg='FATAL ERROR: Could not initialize field {}.'.format(field.name)
             raise RuntimeError(msg)
 
     @debug
diff --git a/hysop/symbolic/__init__.py b/hysop/symbolic/__init__.py
index 1f004bdaa..33001022f 100644
--- a/hysop/symbolic/__init__.py
+++ b/hysop/symbolic/__init__.py
@@ -17,25 +17,33 @@ time_symbol = TimeSymbol('t')
 dtime_symbol = TimeSymbol('dt')
 """Dummy symbol representing infinitesimal time."""
 
-space_symbols = tuple(SpaceSymbol(name=u'x'+subscript(i), 
+space_symbols = tuple(SpaceSymbol(
+    name='x{}'.format(i),
+    pretty_name=u'x'+subscript(i), 
     var_name='x{}'.format(i),
     latex_name='x_{{{}}}'.format(i))
         for i in xrange(16))
 """Dummy symbols representing space."""
 
-dspace_symbols = tuple(SpaceSymbol(name=u'dx'+subscript(i), 
+dspace_symbols = tuple(SpaceSymbol(
+    name='dx_{}'.format(i),
+    pretty_name=u'dx'+subscript(i), 
     var_name='dx_{}'.format(i),
     latex_name='dx_{{{}}}'.format(i))
         for i in xrange(16))
 """Dummy symbols representing space infinitesimals."""
 
-local_indices_symbols = tuple(SpaceSymbol(name=u'i'+subscript(i), 
+local_indices_symbols = tuple(SpaceSymbol(
+    name = 'i{}'.format(i),
+    pretty_name=u'i'+subscript(i), 
     var_name='i{}'.format(i),
     latex_name='i_{{{}}}'.format(i))
         for i in xrange(16))
 """Dummy symbols local array indices."""
 
-global_indices_symbols = tuple(SpaceSymbol(name=u'i'+subscript(i), 
+global_indices_symbols = tuple(SpaceSymbol(
+    name = 'I{}'.format(i),
+    pretty_name=u'I'+subscript(i), 
     var_name='I{}'.format(i),
     latex_name='I_{{{}}}'.format(i))
         for i in xrange(16))
diff --git a/hysop/symbolic/base.py b/hysop/symbolic/base.py
index 05a4e7e53..2e8f9a30c 100644
--- a/hysop/symbolic/base.py
+++ b/hysop/symbolic/base.py
@@ -135,7 +135,9 @@ class TensorBase(npw.ndarray):
             vsep = '_'
             with obj.write_context():
                 for idx in npw.ndindex(*shape):
-                    pname = u'{}{}'.format(pretty_name, u''.join(subscript(i) 
+                    name = '{}_{}'.format(name, vsep.join(str(i) 
+                        for i in idx))
+                    pname = u'{}{}'.format(pretty_name.decode('utf-8'), u''.join(subscript(i) 
                         for i in idx))
                     vname = '{}_{}'.format(name, vsep.join(str(i) 
                         for i in idx))
@@ -151,8 +153,12 @@ class TensorBase(npw.ndarray):
                             assert k not in scalar_kwds, msg
                         idx_kwds.update(scalar_kwds)
                         skwds = idx_kwds
-                    obj[idx] = scalar_cls(name=pname, var_name=vname, latex_name=lname,
-                            value=value, idx=idx, **skwds)
+                    obj[idx] = scalar_cls(name=name, 
+                                          pretty_name=pname, 
+                                          var_name=vname, 
+                                          latex_name=lname,
+                                          value=value, idx=idx, 
+                                          **skwds)
         else:
             obj[...] = init
         return obj
diff --git a/hysop/symbolic/parameter.py b/hysop/symbolic/parameter.py
index ab24726da..68a45ddcc 100644
--- a/hysop/symbolic/parameter.py
+++ b/hysop/symbolic/parameter.py
@@ -4,14 +4,14 @@ from hysop.tools.types import check_instance, to_tuple, first_not_None
 from hysop.tools.numpywrappers import npw
 
 class SymbolicTensorParameter(SymbolicTensor):
-    def __new__(cls, parameter, name=None, value=None, 
-            shape=None, scalar_cls=None, **kwds):
+    def __new__(cls, parameter, name=None, pretty_name=None, 
+            value=None, shape=None, scalar_cls=None, **kwds):
         from hysop.parameters.tensor_parameter import TensorParameter
         check_instance(parameter, TensorParameter)
         value = first_not_None(value, parameter)
         shape = first_not_None(shape, parameter.shape)
-        name  = first_not_None(name, parameter.name)
-        pname  = parameter.pretty_name.decode('utf-8')
+        name  = first_not_None(name,  parameter.name)
+        pname = first_not_None(pretty_name, parameter.pretty_name)
         scalar_cls = first_not_None(scalar_cls, SymbolicScalarParameter)
         scalar_kwds = dict(parameter=parameter)
         def make_scalar_kwds(idx): 
@@ -23,15 +23,15 @@ class SymbolicTensorParameter(SymbolicTensor):
                 scalar_kwds=scalar_kwds, **kwds)
 
 class SymbolicScalarParameter(SymbolicScalar):
-    def __new__(cls, parameter, name=None, value=None, **kwds):
+    def __new__(cls, parameter, name=None, pretty_name=None, value=None, **kwds):
         from hysop.parameters.tensor_parameter import TensorParameter
         check_instance(parameter, TensorParameter)
         value = first_not_None(value, parameter._value)
         name   = first_not_None(name, parameter.name)
-        pname  = parameter.pretty_name.decode('utf-8')
+        pname  = first_not_None(pretty_name, parameter.pretty_name)
         obj = super(SymbolicScalarParameter, cls).__new__(cls,
                 name=name, pretty_name=pname,
-                value=value,**kwds)
+                value=value, **kwds)
         obj.parameter = parameter
         return obj
 
diff --git a/hysop/tools/sympy_utils.py b/hysop/tools/sympy_utils.py
index 9813d6576..d01814214 100644
--- a/hysop/tools/sympy_utils.py
+++ b/hysop/tools/sympy_utils.py
@@ -1,6 +1,6 @@
 
 from hysop.deps import np, sm, copy
-from hysop.tools.types import first_not_None
+from hysop.tools.types import first_not_None, check_instance
 
 from sympy.utilities import group
 from sympy.printing.str import StrPrinter, StrReprPrinter
@@ -58,9 +58,16 @@ def enable_pretty_printing():
 class SymbolicBase(object):
     def __new__(cls, name, var_name=None, latex_name=None, 
             pretty_name=None, **kwds):
-        name = name.encode('utf-8')
+        if isinstance(pretty_name, unicode):
+            pretty_name = pretty_name.encode('utf-8')
+        if isinstance(latex_name, unicode):
+            latex_name = latex_name.encode('utf-8')
+        check_instance(name, str)
+        check_instance(var_name, str, allow_none=True)
+        check_instance(latex_name, str, allow_none=True)
+        check_instance(pretty_name, str, allow_none=True)
         obj = super(SymbolicBase, cls).__new__(cls, name=name, **kwds)
-        obj._name = name
+        obj._name =  name
         obj._var_name    = first_not_None(var_name, name)
         obj._latex_name  = first_not_None(latex_name, name)
         obj._pretty_name = first_not_None(pretty_name, name)
diff --git a/hysop/tools/types.py b/hysop/tools/types.py
index 4a4a1c55d..3236cb00c 100644
--- a/hysop/tools/types.py
+++ b/hysop/tools/types.py
@@ -68,6 +68,8 @@ def check_instance(val, cls, allow_none=False, **kargs):
                     ', ...' if (len(val)>5) else '')
         except:
             types = type(val)
+        if isinstance(val, unicode):
+            val = val.encode('utf-8')
         msg='\nFATAL ERROR: Type did not match any of types {} for the following value:\n{}\n'
         msg+='which is of type {}.\n'
         msg=msg.format(all_cls, val, types)
-- 
GitLab