Index: modlib/modeller/sequence.py
===================================================================
--- modlib/modeller/sequence.py	(revision 5981)
+++ modlib/modeller/sequence.py	(working copy)
@@ -25,9 +25,31 @@
         _modeller.mod_sequence_rng_set(self.__seq.seqpt, indx, val)
 
 
+class SequenceResidue(residue.residue):
+    """A single residue in a sequence"""
+
+    def __get_type(self):
+        irestyp = _modeller.mod_sequence_irestyp_get(self.mdl.seqpt)
+        return _modeller.mod_int1_get(irestyp, self._num)
+    def __set_type(self, val):
+        irestyp = _modeller.mod_sequence_irestyp_get(self.mdl.seqpt)
+        _modeller.mod_int1_set(irestyp, self._num, val)
+    def __get_chain(self):
+        ichain = _modeller.mod_sequence_chain_for_res(self.mdl.seqpt, self._num)
+        return self.mdl.chains[ichain]
+    type = property(__get_type, __set_type, doc="Integer residue type")
+    chain = property(__get_chain, doc="Chain containing this residue")
+
+
 class sequence(modobject):
     """A residue sequence"""
 
+    #: class for residues in this sequence
+    _residue_class = SequenceResidue
+
+    #: class for chains in this sequence
+    _chain_class = None
+
     def __get_nseg(self):
         return _modeller.mod_sequence_nseg_get(self.seqpt)
     def __get_nres(self):
@@ -67,19 +89,3 @@
                        doc="Protein sequence type")
     resolution = property(__get_resol, __set_resol, doc="Resolution")
     rfactor = property(__get_rfactr, __set_rfactr, doc="R factor")
-
-
-class SequenceResidue(residue.residue):
-    """A single residue in a sequence"""
-
-    def __get_type(self):
-        irestyp = _modeller.mod_sequence_irestyp_get(self.mdl.seqpt)
-        return _modeller.mod_int1_get(irestyp, self._num)
-    def __set_type(self, val):
-        irestyp = _modeller.mod_sequence_irestyp_get(self.mdl.seqpt)
-        _modeller.mod_int1_set(irestyp, self._num, val)
-    def __get_chain(self):
-        ichain = _modeller.mod_sequence_chain_for_res(self.mdl.seqpt, self._num)
-        return self.mdl.chains[ichain]
-    type = property(__get_type, __set_type, doc="Integer residue type")
-    chain = property(__get_chain, doc="Chain containing this residue")
Index: modlib/modeller/coordinates.py
===================================================================
--- modlib/modeller/coordinates.py	(revision 5981)
+++ modlib/modeller/coordinates.py	(working copy)
@@ -9,9 +9,275 @@
 
 __docformat__ = "epytext en"
 
+class point(object):
+    """An arbitary point in the Cartesian space of a model"""
+    def __init__(self, mdl, x, y, z):
+        self.mdl = mdl
+        self.x = x
+        self.y = y
+        self.z = z
+
+    def __repr__(self):
+        return "<Point (%.2f, %.2f, %.2f)>" % (self.x, self.y, self.z)
+
+    def select_sphere(self, radius):
+        """Returns a selection of all atoms within the given distance"""
+        inds = _modeller.mod_selection_sphere(self.mdl.modpt, self.x, self.y,
+                                              self.z, radius)
+        return selection.selection(AtomIndices(inds, self.mdl))
+
+
+class atom(point):
+    """A single atom in a protein structure"""
+
+    def __init__(self, mdl, num):
+        self.mdl = mdl
+        self._num = num
+
+    def get_atom_indices(self):
+        return [self._num + 1], self.mdl
+
+    def __repr__(self):
+        chainid = self.residue.get_chain_suffix()
+        return "<Atom %s:%s%s>" % (self.name, self.residue.num, chainid)
+
+    def __get_x(self):
+        x = _modeller.mod_coordinates_x_get(self.mdl.cdpt)
+        return _modeller.mod_float1_get(x, self._num)
+    def __set_x(self, val):
+        x = _modeller.mod_coordinates_x_get(self.mdl.cdpt)
+        _modeller.mod_float1_set(x, self._num, val)
+    def __get_y(self):
+        y = _modeller.mod_coordinates_y_get(self.mdl.cdpt)
+        return _modeller.mod_float1_get(y, self._num)
+    def __set_y(self, val):
+        y = _modeller.mod_coordinates_y_get(self.mdl.cdpt)
+        _modeller.mod_float1_set(y, self._num, val)
+    def __get_z(self):
+        z = _modeller.mod_coordinates_z_get(self.mdl.cdpt)
+        return _modeller.mod_float1_get(z, self._num)
+    def __set_z(self, val):
+        z = _modeller.mod_coordinates_z_get(self.mdl.cdpt)
+        _modeller.mod_float1_set(z, self._num, val)
+    def __get_dvx(self):
+        dvx = _modeller.mod_model_dvx_get(self.mdl.modpt)
+        return _modeller.mod_float1_get(dvx, self._num)
+    def __get_dvy(self):
+        dvy = _modeller.mod_model_dvy_get(self.mdl.modpt)
+        return _modeller.mod_float1_get(dvy, self._num)
+    def __get_dvz(self):
+        dvz = _modeller.mod_model_dvz_get(self.mdl.modpt)
+        return _modeller.mod_float1_get(dvz, self._num)
+    def __get_vx(self):
+        vx = _modeller.mod_model_vx_get(self.mdl.modpt)
+        return _modeller.mod_float1_get(vx, self._num)
+    def __get_vy(self):
+        vy = _modeller.mod_model_vy_get(self.mdl.modpt)
+        return _modeller.mod_float1_get(vy, self._num)
+    def __get_vz(self):
+        vz = _modeller.mod_model_vz_get(self.mdl.modpt)
+        return _modeller.mod_float1_get(vz, self._num)
+    def __get_mass(self):
+        return self.type.mass
+    def __get_biso(self):
+        biso = _modeller.mod_coordinates_biso_get(self.mdl.cdpt)
+        return _modeller.mod_float1_get(biso, self._num)
+    def __set_biso(self, val):
+        biso = _modeller.mod_coordinates_biso_get(self.mdl.cdpt)
+        _modeller.mod_float1_set(biso, self._num, val)
+    def __get_occ(self):
+        occ = _modeller.mod_coordinates_occ_get(self.mdl.cdpt)
+        return _modeller.mod_float1_get(occ, self._num)
+    def __set_occ(self, val):
+        occ = _modeller.mod_coordinates_occ_get(self.mdl.cdpt)
+        _modeller.mod_float1_set(occ, self._num, val)
+    def __get_charge(self):
+        charge = _modeller.mod_model_charge_get(self.mdl.modpt)
+        return _modeller.mod_float1_get(charge, self._num)
+    def __set_charge(self, val):
+        charge = _modeller.mod_model_charge_get(self.mdl.modpt)
+        _modeller.mod_float1_set(charge, self._num, val)
+    def __get_name(self):
+        return _modeller.mod_coordinates_atmnam_get(self.mdl.cdpt, self._num)
+    def __get_type(self):
+        iattyp = _modeller.mod_model_iattyp_get(self.mdl.modpt)
+        return AtomType(self.mdl, _modeller.mod_int1_get(iattyp, self._num)-1)
+    def __get_gprsr_class(self):
+        iatta = _modeller.mod_model_iatta_get(self.mdl.modpt)
+        return _modeller.mod_int1_get(iatta, self._num)
+    def __get_residue(self):
+        iresatm = _modeller.mod_coordinates_iresatm_get(self.mdl.cdpt)
+        resind = _modeller.mod_int1_get(iresatm, self._num) - 1
+        return self.mdl.residues[resind]
+    def __get_index(self):
+        return self._num + 1
+
+    x = property(__get_x, __set_x, doc="x coordinate")
+    y = property(__get_y, __set_y, doc="y coordinate")
+    z = property(__get_z, __set_z, doc="z coordinate")
+    dvx = property(__get_dvx, doc="Objective function derivative, dF/dx")
+    dvy = property(__get_dvy, doc="Objective function derivative, dF/dy")
+    dvz = property(__get_dvz, doc="Objective function derivative, dF/dz")
+    vx = property(__get_vx, doc="x component of velocity")
+    vy = property(__get_vy, doc="y component of velocity")
+    vz = property(__get_vz, doc="z component of velocity")
+    mass = property(__get_mass, doc="Atomic mass")
+    biso = property(__get_biso, __set_biso, doc="Isotropic temperature factor")
+    occ = property(__get_occ, __set_occ, doc="Occupancy")
+    charge = property(__get_charge, __set_charge, doc="Electrostatic charge")
+    name = property(__get_name, doc="PDB name")
+    type = property(__get_type, doc="Atom type")
+    gprsr_class = property(__get_gprsr_class, doc="group_restraints class")
+    residue = property(__get_residue, doc="Residue object containing this atom")
+    index = property(__get_index, doc="Internal atom index")
+
+
+class chain(object):
+    """A single chain/segment in a protein structure."""
+
+    def __init__(self, mdl, num):
+        self.mdl = mdl
+        self.num = num
+
+    def __repr__(self):
+        return "<Chain %s>" % repr(self.name)
+
+    def filter(self, structure_types='structure', minimal_resolution=99.0,
+               minimal_chain_length=30, max_nonstdres=10,
+               chop_nonstd_termini=True, minimal_stdres=30):
+        """Does this chain pass all filter criteria?"""
+        f = _modeller.mod_chain_filter
+        return f(self.mdl.seqpt, self.num, structure_types, minimal_resolution,
+                 minimal_chain_length, max_nonstdres, chop_nonstd_termini,
+                 minimal_stdres)
+
+    def write(self, file, atom_file, align_code, comment='', format='PIR',
+              chop_nonstd_termini=True):
+        """Write this chain out to an alignment file"""
+        f = _modeller.mod_chain_write
+        return f(self.mdl.seqpt, self.mdl.cdpt, self.num, file, atom_file,
+                 align_code, comment, format, chop_nonstd_termini,
+                 self.mdl.env.libs.modpt)
+
+    def atom_file_and_code(self, filename):
+        """Return suitable atom_file and align_codes for this chain, given
+           a model filename."""
+        return _modeller.mod_chain_atom_file_and_code(self.mdl.seqpt, self.num,
+                                                      filename)
+
+    def __get_resind(self):
+        iress1 = _modeller.mod_sequence_iress1_get(self.mdl.seqpt)
+        iress2 = _modeller.mod_sequence_iress2_get(self.mdl.seqpt)
+        return (_modeller.mod_int1_get(iress1, self.num) - 1,
+                _modeller.mod_int1_get(iress2, self.num))
+
+    def __get_residues(self):
+        (startres, endres) = self.__get_resind()
+        suffix = ":%s" % self.name
+        return ResidueList(self.mdl, startres, endres - startres, suffix)
+
+    def __get_atoms(self):
+        (startres, endres) = self.__get_resind()
+        (startatm, endatm) = get_residue_atom_indices(self.mdl, startres,
+                                                      endres)
+        suffix = ":%s" % self.name
+        return AtomList(self.mdl, startatm, endatm - startatm, suffix)
+
+    def get_atom_indices(self):
+        (startres, endres) = self.__get_resind()
+        (startatm, endatm) = get_residue_atom_indices(self.mdl, startres,
+                                                      endres)
+        return (range(startatm+1, endatm+1), self.mdl)
+
+    def __get_name(self):
+        return _modeller.mod_sequence_segid_get(self.mdl.seqpt, self.num)
+    def __set_name(self, val):
+        return _modeller.mod_sequence_segid_set(self.mdl.seqpt, self.num, val)
+
+    residues = property(__get_residues,
+                        doc="List of all residues in this chain")
+    atoms = property(__get_atoms, doc="List of all atoms in this chain")
+    name = property(__get_name, __set_name, doc="Chain ID")
+
+
+class residue(sequence.SequenceResidue):
+    """A single residue in a protein structure"""
+
+    def get_atom_indices(self):
+        (startind, endind) = get_residue_atom_indices(self.mdl, self._num,
+                                                      self._num + 1)
+        return range(startind + 1, endind + 1), self.mdl
+
+    def __repr__(self):
+        chainid = self.get_chain_suffix()
+        return "Residue %s%s (type %s)" % (self.num, chainid, self.name)
+
+    def __str__(self):
+        return "<%s>" % repr(self)
+
+    def get_chain_suffix(self):
+        """Returns a suffix - e.g. ':A' - to identify the chain this residue
+           is in. If the chain has no ID, returns a blank string."""
+        chainid = self.chain.name
+        if chainid == ' ':
+            return ''
+        else:
+            return ':' + chainid
+
+    def __get_num(self):
+        return _modeller.mod_coordinates_resnum_get(self.mdl.cdpt,
+                                                    self._num).strip()
+    def __set_num(self, val):
+        _modeller.mod_coordinates_resnum_set(self.mdl.cdpt, self._num, val)
+    def __get_atoms(self):
+        (startind, endind) = get_residue_atom_indices(self.mdl, self._num,
+                                                      self._num + 1)
+        suffix = ":%s%s" % (self.num, self.get_chain_suffix())
+        return AtomList(self.mdl, startind, endind - startind, suffix)
+
+    def __get_alpha(self):
+        return get_dihedral("alpha", 1, self._num, self.mdl)
+    def __get_phi(self):
+        return get_dihedral("phi", 2, self._num, self.mdl)
+    def __get_psi(self):
+        return get_dihedral("psi", 3, self._num, self.mdl)
+    def __get_omega(self):
+        return get_dihedral("omega", 4, self._num, self.mdl)
+    def __get_chi1(self):
+        return get_dihedral("chi1", 5, self._num, self.mdl)
+    def __get_chi2(self):
+        return get_dihedral("chi2", 6, self._num, self.mdl)
+    def __get_chi3(self):
+        return get_dihedral("chi3", 7, self._num, self.mdl)
+    def __get_chi4(self):
+        return get_dihedral("chi4", 8, self._num, self.mdl)
+    def __get_chi5(self):
+        return get_dihedral("chi5", 9, self._num, self.mdl)
+    def __get_index(self):
+        return self._num + 1
+
+    num = property(__get_num, __set_num, doc="PDB-style residue number")
+    atoms = property(__get_atoms, doc="All atoms in this residue")
+    alpha = property(__get_alpha, doc="Alpha dihedral angle")
+    phi = property(__get_phi, doc="Phi dihedral angle")
+    psi = property(__get_psi, doc="Psi dihedral angle")
+    omega = property(__get_omega, doc="Omega dihedral angle")
+    chi1 = property(__get_chi1, doc="Chi1 dihedral angle")
+    chi2 = property(__get_chi2, doc="Chi2 dihedral angle")
+    chi3 = property(__get_chi3, doc="Chi3 dihedral angle")
+    chi4 = property(__get_chi4, doc="Chi4 dihedral angle")
+    chi5 = property(__get_chi5, doc="Chi5 dihedral angle")
+    index = property(__get_index, doc="Internal residue index")
+
+
 class coordinates(sequence.sequence):
     """Holds protein coordinates"""
 
+    #: class for atoms in this structure
+    _atom_class = atom
+    _residue_class = residue
+    _chain_class = chain
+
     def __init__(self):
         sequence.sequence.__init__(self)
 
@@ -151,7 +417,7 @@
         ret = modutil.handle_seq_indx(self, indx, self.mdl._indxatm,
                                       (self.offset, self.length, self.suffix))
         if isinstance(ret, int):
-            return atom(self.mdl, ret + self.offset)
+            return self.mdl._atom_class(self.mdl, ret + self.offset)
         else:
             return [self[ind] for ind in ret]
 
@@ -197,7 +463,7 @@
         ret = modutil.handle_seq_indx(self, indx, self.mdl._indxres,
                                       (self.offset, self.length, self.suffix))
         if isinstance(ret, int):
-            return residue(self.mdl, ret + self.offset)
+            return self.mdl._residue_class(self.mdl, ret + self.offset)
         else:
             return [self[ind] for ind in ret]
 
@@ -211,199 +477,6 @@
         return self.inds, self.mdl
 
 
-class point(object):
-    """An arbitary point in the Cartesian space of a model"""
-    def __init__(self, mdl, x, y, z):
-        self.mdl = mdl
-        self.x = x
-        self.y = y
-        self.z = z
-
-    def __repr__(self):
-        return "<Point (%.2f, %.2f, %.2f)>" % (self.x, self.y, self.z)
-
-    def select_sphere(self, radius):
-        """Returns a selection of all atoms within the given distance"""
-        inds = _modeller.mod_selection_sphere(self.mdl.modpt, self.x, self.y,
-                                              self.z, radius)
-        return selection.selection(AtomIndices(inds, self.mdl))
-
-
-class atom(point):
-    """A single atom in a protein structure"""
-
-    def __init__(self, mdl, num):
-        self.mdl = mdl
-        self._num = num
-
-    def get_atom_indices(self):
-        return [self._num + 1], self.mdl
-
-    def __repr__(self):
-        chainid = self.residue.get_chain_suffix()
-        return "<Atom %s:%s%s>" % (self.name, self.residue.num, chainid)
-
-    def __get_x(self):
-        x = _modeller.mod_coordinates_x_get(self.mdl.cdpt)
-        return _modeller.mod_float1_get(x, self._num)
-    def __set_x(self, val):
-        x = _modeller.mod_coordinates_x_get(self.mdl.cdpt)
-        _modeller.mod_float1_set(x, self._num, val)
-    def __get_y(self):
-        y = _modeller.mod_coordinates_y_get(self.mdl.cdpt)
-        return _modeller.mod_float1_get(y, self._num)
-    def __set_y(self, val):
-        y = _modeller.mod_coordinates_y_get(self.mdl.cdpt)
-        _modeller.mod_float1_set(y, self._num, val)
-    def __get_z(self):
-        z = _modeller.mod_coordinates_z_get(self.mdl.cdpt)
-        return _modeller.mod_float1_get(z, self._num)
-    def __set_z(self, val):
-        z = _modeller.mod_coordinates_z_get(self.mdl.cdpt)
-        _modeller.mod_float1_set(z, self._num, val)
-    def __get_dvx(self):
-        dvx = _modeller.mod_model_dvx_get(self.mdl.modpt)
-        return _modeller.mod_float1_get(dvx, self._num)
-    def __get_dvy(self):
-        dvy = _modeller.mod_model_dvy_get(self.mdl.modpt)
-        return _modeller.mod_float1_get(dvy, self._num)
-    def __get_dvz(self):
-        dvz = _modeller.mod_model_dvz_get(self.mdl.modpt)
-        return _modeller.mod_float1_get(dvz, self._num)
-    def __get_vx(self):
-        vx = _modeller.mod_model_vx_get(self.mdl.modpt)
-        return _modeller.mod_float1_get(vx, self._num)
-    def __get_vy(self):
-        vy = _modeller.mod_model_vy_get(self.mdl.modpt)
-        return _modeller.mod_float1_get(vy, self._num)
-    def __get_vz(self):
-        vz = _modeller.mod_model_vz_get(self.mdl.modpt)
-        return _modeller.mod_float1_get(vz, self._num)
-    def __get_mass(self):
-        return self.type.mass
-    def __get_biso(self):
-        biso = _modeller.mod_coordinates_biso_get(self.mdl.cdpt)
-        return _modeller.mod_float1_get(biso, self._num)
-    def __set_biso(self, val):
-        biso = _modeller.mod_coordinates_biso_get(self.mdl.cdpt)
-        _modeller.mod_float1_set(biso, self._num, val)
-    def __get_occ(self):
-        occ = _modeller.mod_coordinates_occ_get(self.mdl.cdpt)
-        return _modeller.mod_float1_get(occ, self._num)
-    def __set_occ(self, val):
-        occ = _modeller.mod_coordinates_occ_get(self.mdl.cdpt)
-        _modeller.mod_float1_set(occ, self._num, val)
-    def __get_charge(self):
-        charge = _modeller.mod_model_charge_get(self.mdl.modpt)
-        return _modeller.mod_float1_get(charge, self._num)
-    def __set_charge(self, val):
-        charge = _modeller.mod_model_charge_get(self.mdl.modpt)
-        _modeller.mod_float1_set(charge, self._num, val)
-    def __get_name(self):
-        return _modeller.mod_coordinates_atmnam_get(self.mdl.cdpt, self._num)
-    def __get_type(self):
-        iattyp = _modeller.mod_model_iattyp_get(self.mdl.modpt)
-        return AtomType(self.mdl, _modeller.mod_int1_get(iattyp, self._num)-1)
-    def __get_gprsr_class(self):
-        iatta = _modeller.mod_model_iatta_get(self.mdl.modpt)
-        return _modeller.mod_int1_get(iatta, self._num)
-    def __get_residue(self):
-        iresatm = _modeller.mod_coordinates_iresatm_get(self.mdl.cdpt)
-        resind = _modeller.mod_int1_get(iresatm, self._num) - 1
-        return residue(self.mdl, resind)
-    def __get_index(self):
-        return self._num + 1
-
-    x = property(__get_x, __set_x, doc="x coordinate")
-    y = property(__get_y, __set_y, doc="y coordinate")
-    z = property(__get_z, __set_z, doc="z coordinate")
-    dvx = property(__get_dvx, doc="Objective function derivative, dF/dx")
-    dvy = property(__get_dvy, doc="Objective function derivative, dF/dy")
-    dvz = property(__get_dvz, doc="Objective function derivative, dF/dz")
-    vx = property(__get_vx, doc="x component of velocity")
-    vy = property(__get_vy, doc="y component of velocity")
-    vz = property(__get_vz, doc="z component of velocity")
-    mass = property(__get_mass, doc="Atomic mass")
-    biso = property(__get_biso, __set_biso, doc="Isotropic temperature factor")
-    occ = property(__get_occ, __set_occ, doc="Occupancy")
-    charge = property(__get_charge, __set_charge, doc="Electrostatic charge")
-    name = property(__get_name, doc="PDB name")
-    type = property(__get_type, doc="Atom type")
-    gprsr_class = property(__get_gprsr_class, doc="group_restraints class")
-    residue = property(__get_residue, doc="Residue object containing this atom")
-    index = property(__get_index, doc="Internal atom index")
-
-
-class residue(sequence.SequenceResidue):
-    """A single residue in a protein structure"""
-
-    def get_atom_indices(self):
-        (startind, endind) = get_residue_atom_indices(self.mdl, self._num,
-                                                      self._num + 1)
-        return range(startind + 1, endind + 1), self.mdl
-
-    def __repr__(self):
-        chainid = self.get_chain_suffix()
-        return "Residue %s%s (type %s)" % (self.num, chainid, self.name)
-
-    def __str__(self):
-        return "<%s>" % repr(self)
-
-    def get_chain_suffix(self):
-        """Returns a suffix - e.g. ':A' - to identify the chain this residue
-           is in. If the chain has no ID, returns a blank string."""
-        chainid = self.chain.name
-        if chainid == ' ':
-            return ''
-        else:
-            return ':' + chainid
-
-    def __get_num(self):
-        return _modeller.mod_coordinates_resnum_get(self.mdl.cdpt,
-                                                    self._num).strip()
-    def __set_num(self, val):
-        _modeller.mod_coordinates_resnum_set(self.mdl.cdpt, self._num, val)
-    def __get_atoms(self):
-        (startind, endind) = get_residue_atom_indices(self.mdl, self._num,
-                                                      self._num + 1)
-        suffix = ":%s%s" % (self.num, self.get_chain_suffix())
-        return AtomList(self.mdl, startind, endind - startind, suffix)
-
-    def __get_alpha(self):
-        return get_dihedral("alpha", 1, self._num, self.mdl)
-    def __get_phi(self):
-        return get_dihedral("phi", 2, self._num, self.mdl)
-    def __get_psi(self):
-        return get_dihedral("psi", 3, self._num, self.mdl)
-    def __get_omega(self):
-        return get_dihedral("omega", 4, self._num, self.mdl)
-    def __get_chi1(self):
-        return get_dihedral("chi1", 5, self._num, self.mdl)
-    def __get_chi2(self):
-        return get_dihedral("chi2", 6, self._num, self.mdl)
-    def __get_chi3(self):
-        return get_dihedral("chi3", 7, self._num, self.mdl)
-    def __get_chi4(self):
-        return get_dihedral("chi4", 8, self._num, self.mdl)
-    def __get_chi5(self):
-        return get_dihedral("chi5", 9, self._num, self.mdl)
-    def __get_index(self):
-        return self._num + 1
-
-    num = property(__get_num, __set_num, doc="PDB-style residue number")
-    atoms = property(__get_atoms, doc="All atoms in this residue")
-    alpha = property(__get_alpha, doc="Alpha dihedral angle")
-    phi = property(__get_phi, doc="Phi dihedral angle")
-    psi = property(__get_psi, doc="Psi dihedral angle")
-    omega = property(__get_omega, doc="Omega dihedral angle")
-    chi1 = property(__get_chi1, doc="Chi1 dihedral angle")
-    chi2 = property(__get_chi2, doc="Chi2 dihedral angle")
-    chi3 = property(__get_chi3, doc="Chi3 dihedral angle")
-    chi4 = property(__get_chi4, doc="Chi4 dihedral angle")
-    chi5 = property(__get_chi5, doc="Chi5 dihedral angle")
-    index = property(__get_index, doc="Internal residue index")
-
-
 def get_residue_atom_indices(mdl, start, end):
     iatmr1 = _modeller.mod_coordinates_iatmr1_get(mdl.cdpt)
     startind = _modeller.mod_int1_get(iatmr1, start) - 1
@@ -436,79 +509,11 @@
     def __getitem__(self, indx):
         ret = modutil.handle_seq_indx(self, indx, self.mdl._indxseg, (0, None))
         if isinstance(ret, int):
-            return chain(self.mdl, ret)
+            return self.mdl._chain_class(self.mdl, ret)
         else:
             return [self[ind] for ind in ret]
 
 
-class chain(object):
-    """A single chain/segment in a protein structure."""
-
-    def __init__(self, mdl, num):
-        self.mdl = mdl
-        self.num = num
-
-    def __repr__(self):
-        return "<Chain %s>" % repr(self.name)
-
-    def filter(self, structure_types='structure', minimal_resolution=99.0,
-               minimal_chain_length=30, max_nonstdres=10,
-               chop_nonstd_termini=True, minimal_stdres=30):
-        """Does this chain pass all filter criteria?"""
-        f = _modeller.mod_chain_filter
-        return f(self.mdl.seqpt, self.num, structure_types, minimal_resolution,
-                 minimal_chain_length, max_nonstdres, chop_nonstd_termini,
-                 minimal_stdres)
-
-    def write(self, file, atom_file, align_code, comment='', format='PIR',
-              chop_nonstd_termini=True):
-        """Write this chain out to an alignment file"""
-        f = _modeller.mod_chain_write
-        return f(self.mdl.seqpt, self.mdl.cdpt, self.num, file, atom_file,
-                 align_code, comment, format, chop_nonstd_termini,
-                 self.mdl.env.libs.modpt)
-
-    def atom_file_and_code(self, filename):
-        """Return suitable atom_file and align_codes for this chain, given
-           a model filename."""
-        return _modeller.mod_chain_atom_file_and_code(self.mdl.seqpt, self.num,
-                                                      filename)
-
-    def __get_resind(self):
-        iress1 = _modeller.mod_sequence_iress1_get(self.mdl.seqpt)
-        iress2 = _modeller.mod_sequence_iress2_get(self.mdl.seqpt)
-        return (_modeller.mod_int1_get(iress1, self.num) - 1,
-                _modeller.mod_int1_get(iress2, self.num))
-
-    def __get_residues(self):
-        (startres, endres) = self.__get_resind()
-        suffix = ":%s" % self.name
-        return ResidueList(self.mdl, startres, endres - startres, suffix)
-
-    def __get_atoms(self):
-        (startres, endres) = self.__get_resind()
-        (startatm, endatm) = get_residue_atom_indices(self.mdl, startres,
-                                                      endres)
-        suffix = ":%s" % self.name
-        return AtomList(self.mdl, startatm, endatm - startatm, suffix)
-
-    def get_atom_indices(self):
-        (startres, endres) = self.__get_resind()
-        (startatm, endatm) = get_residue_atom_indices(self.mdl, startres,
-                                                      endres)
-        return (range(startatm+1, endatm+1), self.mdl)
-
-    def __get_name(self):
-        return _modeller.mod_sequence_segid_get(self.mdl.seqpt, self.num)
-    def __set_name(self, val):
-        return _modeller.mod_sequence_segid_set(self.mdl.seqpt, self.num, val)
-
-    residues = property(__get_residues,
-                        doc="List of all residues in this chain")
-    atoms = property(__get_atoms, doc="List of all atoms in this chain")
-    name = property(__get_name, __set_name, doc="Chain ID")
-
-
 def get_dihedral(type, idihtyp, num, mdl):
     """Get a residue dihedral angle, or None if not defined for this residue"""
     if _modeller.mod_coordinates_has_dihedral(mdl.cdpt, mdl.seqpt,
Index: modlib/modeller/alignment.py
===================================================================
--- modlib/modeller/alignment.py	(revision 6006)
+++ modlib/modeller/alignment.py	(working copy)
@@ -4,8 +4,7 @@
 import util.modutil as modutil
 import util.modlist as modlist
 from modeller.util.modobject import modobject
-from modeller.coordinates import coordinates
-from modeller import sequence
+from modeller import sequence, coordinates
 
 __docformat__ = "epytext en"
 
@@ -413,11 +412,72 @@
     positions = property(__get_positions, doc="Alignment positions")
 
 
+class AlignmentResidue(sequence.SequenceResidue):
+    """A single residue in an aligned sequence"""
+
+    def get_position(self):
+        """Get the position in the alignment of this residue"""
+        invaln = _modeller.mod_alignment_invaln_get(self.mdl.aln.modpt)
+        num = _modeller.mod_int2_get(invaln, self._num, self.mdl._num)
+        return self.mdl.aln.positions[num - 1]
+
+    def get_aligned_residue(self, seq):
+        """Get the residue in C{seq} that is aligned with this one, or None"""
+        alnpos = self.get_position()
+        return alnpos.get_residue(seq)
+
+    def add_leading_gaps(self, ngap=1):
+        """Add gaps immediately before this residue."""
+        return _modeller.mod_alnresidue_add_gaps(self.mdl.aln.modpt, self._num,
+                                                 self.mdl._num + 1, ngap)
+
+    def add_trailing_gaps(self, ngap=1):
+        """Add gaps immediately after this residue."""
+        return _modeller.mod_alnresidue_add_gaps(self.mdl.aln.modpt,
+                                                 self._num + 1,
+                                                 self.mdl._num + 1, ngap)
+
+    def remove_leading_gaps(self, ngap=1):
+        """Remove gaps immediately before this residue."""
+        return _modeller.mod_alnresidue_remove_gaps(self.mdl.aln.modpt,
+                                                    self._num,
+                                                    self.mdl._num + 1, ngap)
+
+    def remove_trailing_gaps(self, ngap=1):
+        """Remove gaps immediately after this residue."""
+        return _modeller.mod_alnresidue_remove_gaps(self.mdl.aln.modpt,
+                                                    self._num + 1,
+                                                    self.mdl._num + 1, ngap)
+
+    def get_leading_gaps(self):
+        """Get the number of gaps in the alignment immediately preceding this
+           residue."""
+        mypos = self.get_position().num
+        if self._num > 0:
+            prepos = self.mdl.residues[self._num - 1].get_position()
+            prepos = prepos.num
+            return mypos - prepos - 1
+        else:
+            return mypos
+
+    def get_trailing_gaps(self):
+        """Get the number of gaps in the alignment immediately following this
+           residue."""
+        mypos = self.get_position().num
+        try:
+            postpos = self.mdl.residues[self._num + 1].get_position()
+            postpos = postpos.num
+        except IndexError:
+            postpos = self.mdl.naln
+        return postpos - mypos - 1
+
+
 class alnsequence(sequence.sequence):
     """A single sequence within an alignment"""
     aln = None
     _num = None
     env = None
+    _residue_class = AlignmentResidue
 
     def __init__(self, aln, num):
         self.aln = aln
@@ -480,16 +540,22 @@
     seqpt = property(__get_seqpt)
 
 
-class structure(alnsequence, coordinates):
+class _StructureResidue(coordinates.residue, AlignmentResidue):
+    """A single residue in a template structure"""
+    pass
+
+
+class structure(alnsequence, coordinates.coordinates):
     """A single template structure within an alignment"""
 
     __num = None
     __read_coord = False
+    _residue_class = _StructureResidue
 
     def __init__(self, aln, num):
         self.__num = num
         alnsequence.__init__(self, aln, num)
-        coordinates.__init__(self)
+        coordinates.coordinates.__init__(self)
 
     def __repr__(self):
         return "Structure %s" % repr(self.code)
@@ -522,7 +588,7 @@
 
 
 class ResidueList(object):
-    """A list of L{AlignmentResidue} objects."""
+    """A list of residue objects."""
 
     def __init__(self, seq, offset=0, length=None):
         self.seq = seq
@@ -538,71 +604,11 @@
     def __getitem__(self, indx):
         ret = modutil.handle_seq_indx(self, indx)
         if isinstance(ret, int):
-            return AlignmentResidue(self.seq, ret + self.offset)
+            return self.seq._residue_class(self.seq, ret + self.offset)
         else:
             return [self[ind] for ind in ret]
 
 
-class AlignmentResidue(sequence.SequenceResidue):
-    """A single residue in an aligned sequence"""
-
-    def get_position(self):
-        """Get the position in the alignment of this residue"""
-        invaln = _modeller.mod_alignment_invaln_get(self.mdl.aln.modpt)
-        num = _modeller.mod_int2_get(invaln, self._num, self.mdl._num)
-        return self.mdl.aln.positions[num - 1]
-
-    def get_aligned_residue(self, seq):
-        """Get the residue in C{seq} that is aligned with this one, or None"""
-        alnpos = self.get_position()
-        return alnpos.get_residue(seq)
-
-    def add_leading_gaps(self, ngap=1):
-        """Add gaps immediately before this residue."""
-        return _modeller.mod_alnresidue_add_gaps(self.mdl.aln.modpt, self._num,
-                                                 self.mdl._num + 1, ngap)
-
-    def add_trailing_gaps(self, ngap=1):
-        """Add gaps immediately after this residue."""
-        return _modeller.mod_alnresidue_add_gaps(self.mdl.aln.modpt,
-                                                 self._num + 1,
-                                                 self.mdl._num + 1, ngap)
-
-    def remove_leading_gaps(self, ngap=1):
-        """Remove gaps immediately before this residue."""
-        return _modeller.mod_alnresidue_remove_gaps(self.mdl.aln.modpt,
-                                                    self._num,
-                                                    self.mdl._num + 1, ngap)
-
-    def remove_trailing_gaps(self, ngap=1):
-        """Remove gaps immediately after this residue."""
-        return _modeller.mod_alnresidue_remove_gaps(self.mdl.aln.modpt,
-                                                    self._num + 1,
-                                                    self.mdl._num + 1, ngap)
-
-    def get_leading_gaps(self):
-        """Get the number of gaps in the alignment immediately preceding this
-           residue."""
-        mypos = self.get_position().num
-        if self._num > 0:
-            prepos = self.mdl.residues[self._num - 1].get_position()
-            prepos = prepos.num
-            return mypos - prepos - 1
-        else:
-            return mypos
-
-    def get_trailing_gaps(self):
-        """Get the number of gaps in the alignment immediately following this
-           residue."""
-        mypos = self.get_position().num
-        try:
-            postpos = self.mdl.residues[self._num + 1].get_position()
-            postpos = postpos.num
-        except IndexError:
-            postpos = self.mdl.naln
-        return postpos - mypos - 1
-
-
 class AlnPosition(object):
     """An alignment position"""
 
