Index: sanscalculator/src/sans/calculator/sans_gen.py
===================================================================
--- sanscalculator/src/sans/calculator/sans_gen.py	(revision 318b5bbbcb046db18a8e953dccae04fc7b8a71e0)
+++ sanscalculator/src/sans/calculator/sans_gen.py	(revision dbc5dc9b21e953e43e7d6a054b2231a04fd6ae84)
@@ -234,4 +234,6 @@
                              self.pos_z[mask], self.sld_n[mask], 
                              self.mx[mask], self.my[mask], self.mz[mask])
+        self.output.set_pix_type('pixel')
+        self.output.set_pixel_symbols('pixel')
         
     def get_omfdata(self):
@@ -429,4 +431,98 @@
             raise RuntimeError, msg
 
+class PDBReader:
+    """
+    PDB reader class: limited for reading the lines starting with 'ATOM'
+    """
+    type_name = "PDB"
+    ## Wildcards
+    type = ["pdb files (*.PDB, *.pdb)|*.pdb"]
+    ## List of allowed extensions
+    ext = ['.pdb', '.PDB']
+
+    def read(self, path):
+        """
+        Load data file
+        
+        :param path: file path
+        
+        :return: MagSLD
+        
+        :raise RuntimeError: when the file can't be opened
+        """
+        pos_x = numpy.zeros(0)
+        pos_y = numpy.zeros(0)
+        pos_z = numpy.zeros(0)
+        sld_n = numpy.zeros(0)
+        sld_mx = numpy.zeros(0)
+        sld_my = numpy.zeros(0)
+        sld_mz = numpy.zeros(0)
+        pix_symbol = numpy.zeros(0)#numpy.array([])
+        try:
+            input_f = open(path, 'rb')
+            buff = input_f.read()
+            #buff.replace(' ', '')
+            lines = buff.split('\n')
+            input_f.close()
+            for line in lines:
+                try:
+                    toks = line.split()
+                    # check if line starts with "ATOM"
+                    if toks[0].count('ATM') > 0 or toks[0] == 'ATOM':
+                        # define fields of interest
+                        atom_id = toks[1]
+                        atom_name = toks[2]
+                        atom_name = atom_name[0].upper() + atom_name[1:].lower()
+                        try:
+                            float(toks[3])
+                            ind = 3
+                        except:
+                            ind = 4
+                        res_name = toks[ind]
+                        #chain_name = toks[3].strip()
+                        #residue_id = toks[4].strip()
+                        try:
+                            float(toks[4])
+                        except:
+                            ind += 1
+                        ind += 1
+                        _pos_x = float(toks[ind])
+                        ind += 1
+                        _pos_y = float(toks[ind])
+                        ind += 1
+                        _pos_z = float(toks[ind])
+                        pos_x = numpy.append(pos_x, _pos_x)
+                        pos_y = numpy.append(pos_y, _pos_y)
+                        pos_z = numpy.append(pos_z, _pos_z)
+                        sld_n = numpy.append(sld_n, 7e-06)
+                        sld_mx = numpy.append(sld_mx, 0)
+                        sld_my = numpy.append(sld_my, 0)
+                        sld_mz = numpy.append(sld_mz, 0)
+                        pix_symbol = numpy.append(pix_symbol, atom_name)
+                except:
+                    pass
+            #print pix_symbol, pos_x
+            pos_x -= (min(pos_x) + max(pos_x)) / 2.0
+            pos_y -= (min(pos_y) + max(pos_y)) / 2.0
+            pos_z -= (min(pos_z) + max(pos_z)) / 2.0
+
+            output = MagSLD(pos_x, pos_y, pos_z, sld_n, sld_mx, sld_my, sld_mz)
+            #output.set_sldms(0, 0, 0)
+            output.filename = os.path.basename(path)
+            output.set_pix_type('atom')
+            output.set_pixel_symbols(pix_symbol)
+            output.set_nodes()
+            output.sld_unit = 'A'
+            return output
+        except:
+            RuntimeError, "%s is not a sld file" % path
+
+    def write(self, path, data):
+        """
+        Write
+        """
+        #Not implemented 
+        print "Not implemented... "
+
 class SLDReader:
     """
@@ -448,5 +544,5 @@
         :param path: file path
         
-        :return: x, y, z, sld_n, sld_mx, sld_my, sld_mz
+        :return MagSLD: x, y, z, sld_n, sld_mx, sld_my, sld_mz
         
         :raise RuntimeError: when the file can't be opened
@@ -492,4 +588,6 @@
             output = MagSLD(pos_x, pos_y, pos_z, sld_n, sld_mx, sld_my, sld_mz)
             output.filename = os.path.basename(path)
+            output.set_pix_type('pixel')
+            output.set_pixel_symbols('pixel')
             return output
         except:
@@ -636,4 +734,5 @@
     _pos_unit = 'A'
     _sld_unit = '1/A^(2)'
+    _pix_type = 'pixel'
     
     def __init__(self, pos_x, pos_y, pos_z, sld_n=None, 
@@ -654,4 +753,5 @@
         self.pos_unit = self._pos_unit
         self.sld_unit = self._sld_unit
+        self.pix_type = 'pixel'
         self.pos_x = pos_x
         self.pos_y = pos_y
@@ -664,4 +764,5 @@
         self.sld_phi = None
         self.sld_theta = None
+        self.pix_symbol = None
         if sld_mx != None and sld_my != None and sld_mz != None:
             self.set_sldms(sld_mx, sld_my, sld_mz)
@@ -678,4 +779,11 @@
         return _str
     
+    def set_pix_type(self, pix_type):
+        """
+        Set pixel type
+        :Param pix_type: string, 'pixel' or 'atom'
+        """
+        self.pix_type = pix_type
+        
     def set_sldn(self, sld_n):
         """
@@ -685,9 +793,12 @@
             if self.is_data:
                 # For data, put the value to only the pixels w non-zero M 
+                is_nonzero = (numpy.fabs(self.sld_mx) + 
+                                  numpy.fabs(self.sld_my) + 
+                                  numpy.fabs(self.sld_mz)).nonzero() 
                 self.sld_n = numpy.zeros(len(self.pos_x))
-                is_nonzero = (numpy.fabs(self.sld_mx) + 
-                              numpy.fabs(self.sld_my) + 
-                              numpy.fabs(self.sld_mz)).nonzero()  
-                self.sld_n[is_nonzero] = sld_n
+                if len(self.sld_n[is_nonzero]) > 0:
+                    self.sld_n[is_nonzero] = sld_n
+                else:
+                    self.sld_n.fill(sld_n)
             else:
                 # For non-data, put the value to all the pixels
@@ -716,5 +827,17 @@
                                 sld_mz * sld_mz)  
         self.sld_m = sld_m
-        
+    
+    def set_pixel_symbols(self, symbol='pixel'):  
+        """
+        Set pixel
+        :Params pixel: str; pixel or atomic symbol, or array of strings
+        """
+        if self.sld_n == None:
+            return
+        if symbol.__class__.__name__ == 'str':
+            self.pix_symbol = numpy.repeat(symbol, len(self.sld_n))
+        else:
+            self.pix_symbol = symbol
+
     def get_sldn(self):
         """
@@ -739,14 +862,18 @@
         Set xnodes, ynodes, and znodes
         """
-        if not self.has_stepsize:
-            self.set_stepsize()
-        try:
-            xdist = (max(self.pos_x) - min(self.pos_x)) / self.xstepsize
-            ydist = (max(self.pos_y) - min(self.pos_y)) / self.ystepsize
-            zdist = (max(self.pos_z) - min(self.pos_z)) / self.zstepsize
-            self.xnodes = int(xdist) + 1
-            self.ynodes = int(ydist) + 1
-            self.znodes = int(zdist) + 1
-        except:
+        self.set_stepsize()
+        if self.pix_type == 'pixel':
+            try:
+                xdist = (max(self.pos_x) - min(self.pos_x)) / self.xstepsize
+                ydist = (max(self.pos_y) - min(self.pos_y)) / self.ystepsize
+                zdist = (max(self.pos_z) - min(self.pos_z)) / self.zstepsize
+                self.xnodes = int(xdist) + 1
+                self.ynodes = int(ydist) + 1
+                self.znodes = int(zdist) + 1
+            except:
+                self.xnodes = None
+                self.ynodes = None
+                self.znodes = None
+        else:
             self.xnodes = None
             self.ynodes = None
@@ -757,26 +884,32 @@
         Set xtepsize, ystepsize, and zstepsize
         """
-        try:
-            xpos_pre = self.pos_x[0]
-            ypos_pre = self.pos_y[0]
-            zpos_pre = self.pos_z[0]
-            for x_pos in self.pos_x:
-                if xpos_pre != x_pos:
-                    self.xstepsize = numpy.fabs(x_pos - xpos_pre)
-                    break
-            for y_pos in self.pos_y:
-                if ypos_pre != y_pos:
-                    self.ystepsize = numpy.fabs(y_pos - ypos_pre)
-                    break
-            for z_pos in self.pos_z:
-                if zpos_pre != z_pos:
-                    self.zstepsize = numpy.fabs(z_pos - zpos_pre)
-                    break
-            self.has_stepsize = True
-        except:
+        if self.pix_type == 'pixel':
+            try:
+                xpos_pre = self.pos_x[0]
+                ypos_pre = self.pos_y[0]
+                zpos_pre = self.pos_z[0]
+                for x_pos in self.pos_x:
+                    if xpos_pre != x_pos:
+                        self.xstepsize = numpy.fabs(x_pos - xpos_pre)
+                        break
+                for y_pos in self.pos_y:
+                    if ypos_pre != y_pos:
+                        self.ystepsize = numpy.fabs(y_pos - ypos_pre)
+                        break
+                for z_pos in self.pos_z:
+                    if zpos_pre != z_pos:
+                        self.zstepsize = numpy.fabs(z_pos - zpos_pre)
+                        break
+                self.has_stepsize = True
+            except:
+                self.xstepsize = None
+                self.ystepsize = None
+                self.zstepsize = None
+                self.has_stepsize = False
+        else:
             self.xstepsize = None
             self.ystepsize = None
             self.zstepsize = None
-            self.has_stepsize = False
+            self.has_stepsize = True
         return self.xstepsize, self.ystepsize, self.zstepsize
 
