Index: /issm/trunk-jpl/src/m/classes/qmu/normal_uncertain.py
===================================================================
--- /issm/trunk-jpl/src/m/classes/qmu/normal_uncertain.py	(revision 24848)
+++ /issm/trunk-jpl/src/m/classes/qmu/normal_uncertain.py	(revision 24849)
@@ -1,157 +1,161 @@
 import numpy as np
-from pairoptions import pairoptions
+from MatlabArray import *
 
 
 class normal_uncertain(object):
     '''
-    NORMAL_UNCERTAIN class definition
+  definition for the normal_uncertain class.
 
-        Usage:
-            nuv = normal_uncertain('descriptor',descriptor,'mean',mean,'stddev',stddev,'partition',partition)
-            where nuv is the normal_uncertain object returned by the constructor, mean and stddev are self
-            explanatory.  partition is the partition vector for distributed variables. Can be a partition
-            vector over elements or vertices.
+  [nuv] = normal_uncertain.normal_uncertain(args)
+   nuv = normal_uncertain()
 
-        Example:
-            md.qmu.variables.rheology=normal_uncertain('descriptor','RheologyBBar','mean',1,'stddev',.05);
-            md.qmu.variables.rheology=normal_uncertain('descriptor','scaled_RheologyBBar','mean',1,'stddev',.05,'partition',vpartition);
-    '''
-    def __init__(self, *args): #{{{
+  where the required args are:
+    descriptor    (str, description, '')
+    mean          (float, mean, float('NaN'))
+    stddev        (float, standard deviation, float('NaN'))
+  and the optional args and defaults are:
+    lower         (float, lower bound, -np.Inf)
+    upper         (float, upper bound, np.Inf)
+
+  note that zero arguments constructs a default instance, one
+  argument of the class copies the instance, and three or more
+  arguments constructs a new instance from the arguments.
+'''
+    def __init__(self):
         self.descriptor = ''
         self.mean = float('NaN')
         self.stddev = float('NaN')
-        self.partition = []
+        self.lower = -np.Inf
+        self.upper = np.Inf
 
-        #recover options:
-        options = pairoptions(*args)
+    @staticmethod
+    def normal_uncertain(*args):
+        nargin = len(args)
 
-        #initialize fields:
-        self.descriptor = getfieldvalue(options, 'descriptor')
-        self.mean = getfieldvalue(options, 'mean')
-        self.stddev = getfieldvalue(options, 'stddev')
+        # create a default object
+        if nargin == 0:
+            return normal_uncertain()
 
-        #if the variable is scales, a partition vector should have been supplied, and
-        #that partition vector should have as many partitions as the mean and stddev
-        #vectors:
-        if self.isscaled():
-            self.partition = getfieldvalue(options, 'partition')
-            npart = partition_npart(self.partition)
-            if npart != len(self.mean):
-                error("normal_uncertain constructor: for the scaled variable %s the mean field is not currently a vector of values for all the partitions described in the partition vector" % self.descriptor)
-            if npart != len(self.stddev):
-                error("normal_uncertain constructor: for the scaled variable %s the stddev field is not cureently a vector of values for all the partitions described in the partition vector" % self.descriptor)
-    #}}}
+        # copy the object
+        elif nargin == 1:
+            if isinstance(args[0], normal_uncertain):
+                nuv = args[0]
+            else:
+                raise RuntimeError('Object ' + str(args[0]) + ' is a ' + str(type(args[0])) + ' class object, not "normal_uncertain".')
+
+        # not enough arguments
+        elif nargin == 2:
+            raise RuntimeError('Construction of "normal_uncertain" class object requires at least 3 inputs.')
+
+    # create the object from the input
+        else:
+            # lines differ here in other classes / tests; see asizec problem in notes
+            nuv = normal_uncertain()
+            nuv.descriptor = str(args[0])
+            nuv.mean = args[1]
+            nuv.stddev = args[2]
+            if nargin >= 4:
+                nuv.lower = args[3]
+            if nargin >= 5:
+                nuv.upper = args[4]
+            if nargin > 5:
+                print('WARNING: normal_uncertain:extra_arg: Extra arguments for object of class ' + str(type(nuv)) + '.')
+
+        return [nuv]
 
     def __repr__(self):
+        # display an individual object
         string = '\n'
-        string += 'normal uncertain variable: '
-        string += "%s\n%s" % (string, fielddisplay(self, 'descriptor', 'name tag'))
-        string += "%s\n%s" % (string, fielddisplay(self, 'mean', 'pdf mean'))
-        string += "%s\n%s" % (string, fielddisplay(self, 'stddev', 'pdf standard deviation'))
-        if self.partition:
-            string += "%s\n%s" % (string, fielddisplay(self, 'partition', 'partitionb vector defining where sampling will occur'))
+        string += 'class "normal_uncertain" object = \n'
+        string += '    descriptor: ' + str(self.descriptor) + '\n'
+        string += '          mean: ' + str(self.mean) + '\n'
+        string += '        stddev: ' + str(self.stddev) + '\n'
+        string += '         lower: ' + str(self.lower) + '\n'
+        string += '         upper: ' + str(self.upper) + '\n'
+
         return string
-    #}}}
 
-    def checkconsistency(self, md, solution, analyses): #{{{
-        md = checkfield(md, 'field', self.mean, 'fieldname', 'normal_uncertain.mean', 'NaN', 1, 'Inf', 1, '>=', 0)
-        md = checkfield(md, 'field', self.stddev, 'fieldname', 'normal_uncertain.stddev', 'NaN', 1, 'Inf', 1, '>=', 0, 'numel', len(self.mean))
-        if self.isscaled():
-            if not self.partition:
-                error("normal_uncertain is a scaled variable, but it's missing a partition vector")
-            #better have a partition vector that has as many partitions as stddev's size:
-            if len(self.stddev) != partition_npart(self.partititon):
-                error("normal_uncertain error message: stddev and partition should be vectors of identical size")
-            if len(self.mean) != partition_npart(self.partition):
-                error("normal_uncertain error message: mean and partition should be vectors of identical size")
-            md = checkfield(md, 'field', self.partition, 'fieldname', 'normal_uncertain.partition', 'NaN', 1, 'Inf', 1, '>=', -1, 'numel', [md.mesh.numberofvertices, md.mesh.numberofvertices])
-            if self.partition.shape[1] > 1:
-                error("normal_uncertain error message: partition should be a column vector")
-            partcheck = np.unique(self.partition)
-            partmin = min(partcheck)
-            partmax = max(partcheck)
-            if partmax < -1:
-                error("normal_uncertain error message: partition vector's min value should be -1 (for no partition), or start at 0")
-            nmax = max(md.mesh.numberofelements, md.mesh.numberofvertices)
-            if partmax > nmax:
-                error("normal_uncertain error message: partition vector's values cannot go over the number of vertices or elements")
-    #}}}
-
-    #virtual functions needed by qmu processing algorithms
-    #implemented:
+    # from here on, nuv is either a single, or a 1d vector of, normal_uncertain
 
     @staticmethod
-    def prop_desc(nuv, dstr): #{{{
+    def prop_desc(nuv, dstr):
+        if type(nuv) not in [list, np.ndarray]:
+            if nuv.descriptor != '' or type(nuv.descriptor) != str:
+                desc = str(nuv.descriptor)
+            elif dstr != '':
+                desc = str(dstr)
+            else:
+                desc = 'nuv'
+            return desc
+
         desc = ['' for i in range(np.size(nuv))]
         for i in range(np.size(nuv)):
-            if nuv[i].descriptor:
+            if nuv[i].descriptor != '' or type(nuv[i].descriptor) != str:
                 desc[i] = str(nuv[i].descriptor)
-            elif dstr:
+            elif dstr != '':
                 desc[i] = str(dstr) + str(string_dim(nuv, i, 'vector'))
             else:
                 desc[i] = 'nuv' + str(string_dim(nuv, i, 'vector'))
+
         desc = allempty(desc)
 
         return desc
-    #}}}
 
     @staticmethod
-    def prop_mean(nuv): #{{{
+    def prop_initpt(nuv):
+        initpt = []
+        return initpt
+
+    @staticmethod
+    def prop_lower(nuv):
+        if type(nuv) not in [list, np.ndarray]:
+            return nuv.lower
+
+        lower = np.zeros(np.size(nuv))
+        for i in range(np.size(nuv)):
+            lower[i] = nuv[i].lower
+
+        lower = allequal(lower, -np.inf)
+
+        return lower
+
+    @staticmethod
+    def prop_upper(nuv):
+        if type(nuv) not in [list, np.ndarray]:
+            return nuv.upper
+
+        upper = np.zeros(np.size(nuv))
+        for i in range(np.size(nuv)):
+            upper[i] = nuv[i].upper
+
+        upper = allequal(upper, -np.inf)
+        return upper
+
+    @staticmethod
+    def prop_mean(nuv):
+        if type(nuv) not in [list, np.ndarray]:
+            return nuv.mean
+
         mean = np.zeros(np.size(nuv))
         for i in range(np.size(nuv)):
             mean[i] = nuv[i].mean
+
         return mean
-    #}}}
 
     @staticmethod
-    def prop_stddev(nuv): #{{{
+    def prop_stddev(nuv):
+        if type(nuv) not in [list, np.ndarray]:
+            return nuv.stddev
+
         stddev = np.zeros(np.size(nuv))
         for i in range(np.size(nuv)):
             stddev[i] = nuv[i].stddev
+
         return stddev
-    #}}}
-
-    #default
-    @staticmethod
-    def prop_abscissas(nbu): #{{{
-        abscissas = []
-        return abscissas
-    #}}}
-
-    @staticmethod
-    def prop_counts(nbu): #{{{
-        counts = []
-        return counts
-    #}}}
-
-    @staticmethod
-    def prop_pairs_per_variable(nbu): #{{{
-        pairs_per_variable = []
-        return pairs_per_variable
-    #}}}
-
-    @staticmethod
-    def prop_initpt(nuv): #{{{
-        initpt = []
-        return initpt
-    #}}}
-
-    @staticmethod
-    def prop_lower(nuv): #{{{
-        lower = []
-        return lower
-    #}}}
-
-    @staticmethod
-    def prop_upper(nuv):
-        upper = []
-        return upper
-    #}}}
 
     @staticmethod
     def prop_initst(nuv):
-        inist = []
-        return inist
-    #}}}
+        initst = []
+        return initst
 
     @staticmethod
@@ -159,5 +163,4 @@
         stype = []
         return stype
-    #}}}
 
     @staticmethod
@@ -165,23 +168,12 @@
         scale = []
         return scale
-    #}}}
-
-    #new methods:
-    def isscaled(self): #{{{
-        if self.descriptor[:7] == 'scaled_':
-            return 1
-        else:
-            return 0
-    #}}}
 
     @staticmethod
-    def dakota_write(fidi, dvar): #{{{
+    def dakota_write(fidi, dvar):
         # collect only the variables of the appropriate class
         nuv = [struc_class(i, 'normal_uncertain', 'nuv') for i in dvar]
 
-        # # possible namespace pollution, the above import seems not to work
-        # from vlist_write import vlist_write
-
-        # write variables
+    # possible namespace pollution, the above import seems not to work
+        from vlist_write import vlist_write
+    # write variables
         vlist_write(fidi, 'normal_uncertain', 'nuv', nuv)
-    #}}}
