Index: src/sas/sascalc/realspace/VolumeCanvas.py
===================================================================
--- src/sas/sascalc/realspace/VolumeCanvas.py	(revision 235f514ba93b57fa63e44309f182acef0b98bb55)
+++ src/sas/sascalc/realspace/VolumeCanvas.py	(revision 98e3f24eb417c960360e014aae48605345a05266)
@@ -4,12 +4,12 @@
     Simulation canvas for real-space simulation of SAS scattering intensity.
     The user can create an arrangement of basic shapes and estimate I(q) and
-    I(q_x, q_y). Error estimates on the simulation are also available. 
-    
+    I(q_x, q_y). Error estimates on the simulation are also available.
+
     Example:
-    
+
     import sas.sascalc.realspace.VolumeCanvas as VolumeCanvas
     canvas = VolumeCanvas.VolumeCanvas()
     canvas.setParam('lores_density', 0.01)
-    
+
     sphere = SphereDescriptor()
     handle = canvas.addObject(sphere)
@@ -17,12 +17,12 @@
     output, error = canvas.getIqError(q=0.1)
     output, error = canvas.getIq2DError(0.1, 0.1)
-    
+
     or alternatively:
     iq = canvas.run(0.1)
     i2_2D = canvas.run([0.1, 1.57])
-    
+
 """
 
-from sas.models.BaseComponent import BaseComponent
+from sas.sascalc.calculator.BaseComponent import BaseComponent
 from sas.sascalc.simulation.pointsmodelpy import pointsmodelpy
 from sas.sascalc.simulation.geoshapespy import geoshapespy
@@ -31,13 +31,13 @@
 import os.path, math
 
-class ShapeDescriptor:
+class ShapeDescriptor(object):
     """
         Class to hold the information about a shape
         The descriptor holds a dictionary of parameters.
-        
+
         Note: if shape parameters are accessed directly
         from outside VolumeCanvas. The getPr method
         should be called before evaluating I(q).
-                
+
     """
     def __init__(self):
@@ -55,5 +55,5 @@
         self.params['is_lores'] = True
         self.params['order'] = 0
-            
+
     def create(self):
         """
@@ -65,5 +65,5 @@
         z0 = self.params["center"][2]
         geoshapespy.set_center(self.shapeObject, x0, y0, z0)
-        
+
         # Set orientation
         x0 = self.params["orientation"][0]
@@ -71,21 +71,21 @@
         z0 = self.params["orientation"][2]
         geoshapespy.set_orientation(self.shapeObject, x0, y0, z0)
-               
+
 class SphereDescriptor(ShapeDescriptor):
     """
         Descriptor for a sphere
-        
+
         The parameters are:
             - radius [Angstroem] [default = 20 A]
             - Contrast [A-2] [default = 1 A-2]
-            
+
     """
     def __init__(self):
         """
             Initialization
-        """ 
+        """
         ShapeDescriptor.__init__(self)
         # Default parameters
-        self.params["type"]   = "sphere"
+        self.params["type"] = "sphere"
         # Radius of the sphere
         self.params["radius"] = 20.0
@@ -100,13 +100,13 @@
         self.shapeObject = geoshapespy.new_sphere(\
             self.params["radius"])
-        
-        ShapeDescriptor.create(self)   
+
+        ShapeDescriptor.create(self)
         return self.shapeObject
-    
+
 class CylinderDescriptor(ShapeDescriptor):
     """
         Descriptor for a cylinder
         Orientation: Default cylinder is along Y
-        
+
         Parameters:
             - Length [default = 40 A]
@@ -117,8 +117,8 @@
         """
             Initialization
-        """ 
+        """
         ShapeDescriptor.__init__(self)
         # Default parameters
-        self.params["type"]   = "cylinder"
+        self.params["type"] = "cylinder"
         # Length of the cylinder
         self.params["length"] = 40.0
@@ -127,5 +127,5 @@
         # Constrast parameter
         self.params["contrast"] = 1.0
-        
+
     def create(self):
         """
@@ -138,10 +138,10 @@
         ShapeDescriptor.create(self)
         return self.shapeObject
-        
+
 
 class EllipsoidDescriptor(ShapeDescriptor):
     """
         Descriptor for an ellipsoid
-        
+
         Parameters:
             - Radius_x along the x-axis [default = 30 A]
@@ -153,13 +153,13 @@
         """
             Initialization
-        """ 
+        """
         ShapeDescriptor.__init__(self)
         # Default parameters
-        self.params["type"]   = "ellipsoid"
+        self.params["type"] = "ellipsoid"
         self.params["radius_x"] = 30.0
         self.params["radius_y"] = 20.0
         self.params["radius_z"] = 10.0
         self.params["contrast"] = 1.0
-        
+
     def create(self):
         """
@@ -168,14 +168,14 @@
         """
         self.shapeObject = geoshapespy.new_ellipsoid(\
-            self.params["radius_x"], self.params["radius_y"], 
+            self.params["radius_x"], self.params["radius_y"],
             self.params["radius_z"])
-        
-        ShapeDescriptor.create(self)   
+
+        ShapeDescriptor.create(self)
         return self.shapeObject
-        
+
 class HelixDescriptor(ShapeDescriptor):
     """
         Descriptor for an helix
-        
+
         Parameters:
             -radius_helix: the radius of the helix [default = 10 A]
@@ -188,8 +188,8 @@
         """
             Initialization
-        """ 
+        """
         ShapeDescriptor.__init__(self)
         # Default parameters
-        self.params["type"]   = "singlehelix"
+        self.params["type"] = "singlehelix"
         self.params["radius_helix"] = 10.0
         self.params["radius_tube"] = 3.0
@@ -204,14 +204,14 @@
         """
         self.shapeObject = geoshapespy.new_singlehelix(\
-            self.params["radius_helix"], self.params["radius_tube"], 
+            self.params["radius_helix"], self.params["radius_tube"],
             self.params["pitch"], self.params["turns"])
-        
-        ShapeDescriptor.create(self)   
+
+        ShapeDescriptor.create(self)
         return self.shapeObject
-        
+
 class PDBDescriptor(ShapeDescriptor):
     """
         Descriptor for a PDB set of points
-        
+
         Parameter:
             - file = name of the PDB file
@@ -221,8 +221,8 @@
             Initialization
             @param filename: name of the PDB file to load
-        """ 
+        """
         ShapeDescriptor.__init__(self)
         # Default parameters
-        self.params["type"]   = "pdb"
+        self.params["type"] = "pdb"
         self.params["file"] = filename
         self.params['is_lores'] = False
@@ -234,9 +234,9 @@
         """
         self.shapeObject = pointsmodelpy.new_pdbmodel()
-        pointsmodelpy.pdbmodel_add(self.shapeObject, self.params['file'])       
-        
-        #ShapeDescriptor.create(self)   
+        pointsmodelpy.pdbmodel_add(self.shapeObject, self.params['file'])
+
+        #ShapeDescriptor.create(self)
         return self.shapeObject
-        
+
 # Define a dictionary for the shape until we find
 # a better way to create them
@@ -245,15 +245,15 @@
               'ellipsoid':EllipsoidDescriptor,
               'singlehelix':HelixDescriptor}
-        
+
 class VolumeCanvas(BaseComponent):
     """
-        Class representing an empty space volume to add 
+        Class representing an empty space volume to add
         geometrical object to.
-        
+
         For 1D I(q) simulation, getPr() is called internally for the
         first call to getIq().
-        
-    """
-    
+
+    """
+
     def __init__(self):
         """
@@ -261,5 +261,5 @@
         """
         BaseComponent.__init__(self)
-        
+
         ## Maximum value of q reachable
         self.params['q_max'] = 0.1
@@ -267,25 +267,25 @@
         self.params['scale'] = 1.0
         self.params['background'] = 0.0
-        
+
         self.lores_model = pointsmodelpy.new_loresmodel(self.params['lores_density'])
         self.complex_model = pointsmodelpy.new_complexmodel()
         self.shapes = {}
-        self.shapecount = 0        
+        self.shapecount = 0
         self.points = None
         self.npts = 0
-        self.hasPr = False        
-        
+        self.hasPr = False
+
     def _model_changed(self):
         """
-            Reset internal data members to reflect the fact that the 
+            Reset internal data members to reflect the fact that the
             real-space model has changed
         """
-        self.hasPr  = False
+        self.hasPr = False
         self.points = None
-        
-    def addObject(self, shapeDesc, id = None):
+
+    def addObject(self, shapeDesc, id=None):
         """
             Adds a real-space object to the canvas.
-        
+
             @param shapeDesc: object to add to the canvas [ShapeDescriptor]
             @param id: string handle for the object [string] [optional]
@@ -295,5 +295,5 @@
         if id is None:
             id = shapeDesc.params["type"]+str(self.shapecount)
-         
+
         # Self the order number
         shapeDesc.params['order'] = self.shapecount
@@ -307,7 +307,7 @@
 
         return id
-            
-    
-    def add(self, shape, id = None):
+
+
+    def add(self, shape, id=None):
         """
             The intend of this method is to eventually be able to use it
@@ -315,9 +315,9 @@
             analytical solutions. For instance, if one adds a cylinder and
             it is the only shape on the canvas, the analytical solution
-            could be called. If multiple shapes are involved, then 
+            could be called. If multiple shapes are involved, then
             simulation has to be performed.
-            
+
             This function is deprecated, use addObject().
-        
+
             @param shape: name of the object to add to the canvas [string]
             @param id: string handle for the object [string] [optional]
@@ -327,5 +327,5 @@
         if id is None:
             id = "shape"+str(self.shapecount)
- 
+
         # shapeDesc = ShapeDescriptor(shape.lower())
         if shape.lower() in shape_dict:
@@ -336,5 +336,5 @@
         else:
             raise ValueError("VolumeCanvas.add: Unknown shape %s" % shape)
-        
+
         return self.addObject(shapeDesc, id)
 
@@ -354,27 +354,27 @@
 
 
-    def setParam(self, name, value):    
-        """
-            Function to set the value of a parameter. 
+    def setParam(self, name, value):
+        """
+            Function to set the value of a parameter.
             Both VolumeCanvas parameters and shape parameters
-            are accessible. 
-            
+            are accessible.
+
             Note: if shape parameters are accessed directly
             from outside VolumeCanvas. The getPr method
             should be called before evaluating I(q).
-        
+
             TODO: implemented a check method to protect
             against that.
-        
+
             @param name: name of the parameter to change
             @param value: value to give the parameter
         """
-        
+
         # Lowercase for case insensitivity
         name = name.lower()
-        
+
         # Look for shape access
         toks = name.split('.')
-        
+
         # If a shape identifier was given, look the shape up
         # in the dictionary
@@ -390,20 +390,20 @@
             else:
                 raise ValueError("Could not find shape %s" % toks[0])
-        
+
         else:
-            # If we are not accessing the parameters of a 
+            # If we are not accessing the parameters of a
             # shape, see if the parameter is part of this object
             BaseComponent.setParam(self, name, value)
             self._model_changed()
 
-    def getParam(self, name):    
+    def getParam(self, name):
         """
             @param name: name of the parameter to change
         """
         #TODO: clean this up
-        
+
         # Lowercase for case insensitivity
         name = name.lower()
-        
+
         # Look for sub-model access
         toks = name.split('.')
@@ -435,10 +435,10 @@
         else:
             raise ValueError("VolumeCanvas.getParam: Could not find %s" % name)
-            
+
     def getParamList(self, shapeid=None):
         """
-	       return a full list of all available parameters from 
+	       return a full list of all available parameters from
            self.params.keys(). If a key in self.params is a instance
-           of ShapeDescriptor, extend the return list to: 
+           of ShapeDescriptor, extend the return list to:
            [param1,param2,shapeid.param1,shapeid.param2.......]
 
@@ -456,7 +456,7 @@
                 header = key2 + '.'
                 for key3 in value2.params:
-                    fullname = header + key3                 
+                    fullname = header + key3
                     param_list.append(fullname)
-     
+
         else:
             if not shapeid in self.shapes:
@@ -470,5 +470,5 @@
     def getShapeList(self):
         """
-            Return a list of the shapes 
+            Return a list of the shapes
         """
         return self.shapes.keys()
@@ -481,9 +481,10 @@
         # Create the object model
         shapeDesc.create()
-                    
+
         if shapeDesc.params['is_lores']:
             # Add the shape to the lores_model
-            pointsmodelpy.lores_add(self.lores_model, 
-                shapeDesc.shapeObject, shapeDesc.params['contrast'])  
+            pointsmodelpy.lores_add(self.lores_model,
+                                    shapeDesc.shapeObject,
+                                    shapeDesc.params['contrast'])
 
     def _createVolumeFromList(self):
@@ -492,15 +493,15 @@
             Whenever we change a parameter of a shape, we have to re-create
             the whole thing.
-            
+
             Items with higher 'order' number take precedence for regions
-            of space that are shared with other objects. Points in the 
+            of space that are shared with other objects. Points in the
             overlapping region belonging to objects with lower 'order'
             will be ignored.
-            
+
             Items are added in decreasing 'order' number.
             The item with the highest 'order' will be added *first*.
             [That conventions is prescribed by the realSpaceModeling module]
         """
-        
+
         # Create empty model
         self.lores_model = \
@@ -509,13 +510,13 @@
         # Create empty complex model
         self.complex_model = pointsmodelpy.new_complexmodel()
-       
+
         # Order the object first
         obj_list = []
-    
+
         for shape in self.shapes:
             order = self.shapes[shape].params['order']
             # find where to place it in the list
             stored = False
-            
+
             for i in range(len(obj_list)):
                 if obj_list[i][0] > order:
@@ -523,8 +524,8 @@
                     stored = True
                     break
-            
+
             if not stored:
                 obj_list.append([order, shape])
-                
+
         # Add each shape
         len_list = len(obj_list)
@@ -533,6 +534,6 @@
             self._addSingleShape(shapedesc)
 
-        return 0     
-    
+        return 0
+
     def getPr(self):
         """
@@ -540,15 +541,15 @@
             This method should always be called after the shapes
             on the VolumeCanvas have changed.
-            
-            @return: calculation output flag 
+
+            @return: calculation output flag
         """
         # To find a complete example of the correct call order:
         # In LORES2, in actionclass.py, method CalculateAction._get_iq()
-        
+
         # If there are not shapes, do nothing
         if len(self.shapes) == 0:
             self._model_changed()
             return 0
-        
+
         # generate space filling points from shape list
         self._createVolumeFromList()
@@ -556,23 +557,23 @@
         self.points = pointsmodelpy.new_point3dvec()
 
-        pointsmodelpy.complexmodel_add(self.complex_model, 
-                                        self.lores_model, "LORES")
+        pointsmodelpy.complexmodel_add(self.complex_model,
+                                       self.lores_model, "LORES")
         for shape in self.shapes:
-            if self.shapes[shape].params['is_lores'] == False:
-                pointsmodelpy.complexmodel_add(self.complex_model, 
+            if not self.shapes[shape].params['is_lores']:
+                pointsmodelpy.complexmodel_add(self.complex_model,
                     self.shapes[shape].shapeObject, "PDB")
-        
+
         #pointsmodelpy.get_lorespoints(self.lores_model, self.points)
         self.npts = pointsmodelpy.get_complexpoints(self.complex_model, self.points)
-        
+
         # expecting the rmax is a positive float or 0. The maximum distance.
-        #rmax = pointsmodelpy.get_lores_pr(self.lores_model, self.points)   
-         
-        rmax = pointsmodelpy.get_complex_pr(self.complex_model, self.points) 
-        self.hasPr = True   
+        #rmax = pointsmodelpy.get_lores_pr(self.lores_model, self.points)
+
+        rmax = pointsmodelpy.get_complex_pr(self.complex_model, self.points)
+        self.hasPr = True
 
         return rmax
-        
-    def run(self, q = 0):
+
+    def run(self, q=0):
         """
             Returns the value of I(q) for a given q-value
@@ -595,9 +596,9 @@
         else:
             raise ValueError("run(q): bad type for q")
-    
-    def runXY(self, q = 0):
+
+    def runXY(self, q=0):
         """
             Standard run command for the canvas.
-            Redirects to the correct method 
+            Redirects to the correct method
             according to the input type.
             @param q: q-value [float] or [list] [A-1]
@@ -615,26 +616,26 @@
         else:
             raise ValueError("runXY(q): bad type for q")
-    
+
     def _create_modelObject(self):
         """
             Create the simulation model obejct from the list
             of shapes.
-            
+
             This method needs to be called each time a parameter
             changes because of the way the underlying library
-            was (badly) written. It is impossible to change a 
-            parameter, or remove a shape without having to 
+            was (badly) written. It is impossible to change a
+            parameter, or remove a shape without having to
             refill the space points.
-            
+
             TODO: improve that.
         """
         # To find a complete example of the correct call order:
         # In LORES2, in actionclass.py, method CalculateAction._get_iq()
-        
+
         # If there are not shapes, do nothing
         if len(self.shapes) == 0:
             self._model_changed()
             return 0
-        
+
         # generate space filling points from shape list
         self._createVolumeFromList()
@@ -642,15 +643,15 @@
         self.points = pointsmodelpy.new_point3dvec()
 
-        pointsmodelpy.complexmodel_add(self.complex_model, 
-                                        self.lores_model, "LORES")
+        pointsmodelpy.complexmodel_add(self.complex_model,
+                                       self.lores_model, "LORES")
         for shape in self.shapes:
-            if self.shapes[shape].params['is_lores'] == False:
-                pointsmodelpy.complexmodel_add(self.complex_model, 
+            if not self.shapes[shape].params['is_lores']:
+                pointsmodelpy.complexmodel_add(self.complex_model,
                     self.shapes[shape].shapeObject, "PDB")
-        
+
         #pointsmodelpy.get_lorespoints(self.lores_model, self.points)
         self.npts = pointsmodelpy.get_complexpoints(self.complex_model, self.points)
-        
-        
+
+
     def getIq2D(self, qx, qy):
         """
@@ -660,55 +661,55 @@
             @return: I(q) [cm-1]
         """
-        
+
         # If this is the first simulation call, we need to generate the
         # space points
         if self.points is None:
             self._create_modelObject()
-            
+
             # Protect against empty model
             if self.points is None:
                 return 0
-               
-        # Evalute I(q) 
-        norm =  1.0e8/self.params['lores_density']*self.params['scale']
+
+        # Evalute I(q)
+        norm = 1.0e8/self.params['lores_density']*self.params['scale']
         return norm*pointsmodelpy.get_complex_iq_2D(self.complex_model, self.points, qx, qy)\
             + self.params['background']
-                
+
     def write_pr(self, filename):
         """
             Write P(r) to an output file
             @param filename: file name for P(r) output
-        """   
-        if self.hasPr == False:
+        """
+        if not self.hasPr:
             self.getPr()
-     
+
         pointsmodelpy.outputPR(self.complex_model, filename)
-     
+
     def getPrData(self):
         """
             Write P(r) to an output file
             @param filename: file name for P(r) output
-        """   
-        if self.hasPr == False:
+        """
+        if not self.hasPr:
             self.getPr()
-     
+
         return pointsmodelpy.get_pr(self.complex_model)
-     
+
     def getIq(self, q):
         """
             Returns the value of I(q) for a given q-value
-            
+
             This method should remain internal to the class
             and the run() method should be used instead.
-            
+
             @param q: q-value [float]
             @return: I(q) [float]
         """
-        
-        if self.hasPr == False:
+
+        if not self.hasPr:
             self.getPr()
 
-        # By dividing by the density instead of the actuall V/N, 
-        # we have an uncertainty of +-1 on N because the number 
+        # By dividing by the density instead of the actuall V/N,
+        # we have an uncertainty of +-1 on N because the number
         # of points chosen for the simulation is int(density*volume).
         # Propagation of error gives:
@@ -716,9 +717,9 @@
         # where N is stored in self.npts
 
-        norm =  1.0e8/self.params['lores_density']*self.params['scale']
+        norm = 1.0e8/self.params['lores_density']*self.params['scale']
         #return norm*pointsmodelpy.get_lores_i(self.lores_model, q)
         return norm*pointsmodelpy.get_complex_i(self.complex_model, q)\
             + self.params['background']
-    
+
     def getError(self, q):
         """
@@ -727,10 +728,10 @@
             @return: I(q) [float]
         """
-        
-        if self.hasPr == False:
+
+        if not self.hasPr:
             self.getPr()
 
-        # By dividing by the density instead of the actual V/N, 
-        # we have an uncertainty of +-1 on N because the number 
+        # By dividing by the density instead of the actual V/N,
+        # we have an uncertainty of +-1 on N because the number
         # of points chosen for the simulation is int(density*volume).
         # Propagation of error gives:
@@ -738,17 +739,17 @@
         # where N is stored in self.npts
 
-        norm =  1.0e8/self.params['lores_density']*self.params['scale']
+        norm = 1.0e8/self.params['lores_density']*self.params['scale']
         #return norm*pointsmodelpy.get_lores_i(self.lores_model, q)
         return norm*pointsmodelpy.get_complex_i_error(self.complex_model, q)\
             + self.params['background']
-    
+
     def getIqError(self, q):
         """
             Return the simulated value along with its estimated
             error for a given q-value
-            
+
             Propagation of errors is used to evaluate the
             uncertainty.
-            
+
             @param q: q-value [float]
             @return: mean, error [float, float]
@@ -765,8 +766,8 @@
             Return the simulated value along with its estimated
             error for a given q-value
-            
+
             Propagation of errors is used to evaluate the
             uncertainty.
-            
+
             @param qx: qx-value [float]
             @param qy: qy-value [float]
@@ -774,19 +775,18 @@
         """
         self._create_modelObject()
-                
-        norm =  1.0e8/self.params['lores_density']*self.params['scale']
+
+        norm = 1.0e8/self.params['lores_density']*self.params['scale']
         val = norm*pointsmodelpy.get_complex_iq_2D(self.complex_model, self.points, qx, qy)\
             + self.params['background']
-        
+
         # Simulation error (statistical)
-        norm =  1.0e8/self.params['lores_density']*self.params['scale'] \
-                * math.pow(self.npts/self.params['lores_density'], 1.0/3.0)/self.npts
+        norm = 1.0e8/self.params['lores_density']*self.params['scale'] \
+               * math.pow(self.npts/self.params['lores_density'], 1.0/3.0)/self.npts
         err = norm*pointsmodelpy.get_complex_iq_2D_err(self.complex_model, self.points, qx, qy)
         # Error on V/N
         simerr = 2*val/self.npts
-        
+
         # The error used for the position is over-simplified.
         # The actual error was empirically found to be about
         # an order of magnitude larger.
         return val, 10.0*err+simerr
-        
