示例#1
0
文件: editing.py 项目: crosvera/ProDy
def sliceVector(vector, atoms, selstr):
    """Return a slice of *vector* matching *atoms* specified by *selstr*.
    
    Note that returned :class:`Vector` instance is not normalized.
    
    :arg vector: vector instance to be sliced
    :type vector: :class:`VectorBase`
    
    :arg atoms: atoms for which *vector* describes a deformation, motion, etc.
    :type atoms: :class:`~prody.atomic.Atomic`
    
    :arg selstr: selection string
    :type selstr: str 
    
    :returns: (:class:`Vector`, :class:`~prody.atomic.Selection`)"""

    if not isinstance(vector, VectorBase):
        raise TypeError("vector must be a VectorBase instance, not {0:s}".format(type(vector)))
    if not isinstance(atoms, Atomic):
        raise TypeError("atoms must be an Atomic instance, not {0:s}".format(type(atoms)))
    if atoms.numAtoms() != vector.numAtoms():
        raise ValueError("number of atoms in *vector* and *atoms* must be " "equal")
    if isinstance(atoms, AtomGroup):
        sel = atoms.select(selstr)
        which = sel.getIndices()
    else:
        which = SELECT.getIndices(atoms, selstr)
        sel = Selection(atoms.getAtomGroup(), atoms.getIndices()[which], selstr, atoms.getACSIndex())
    vec = Vector(
        vector.getArrayNx3()[which, :].flatten(), '{0:s} slice "{1:s}"'.format(str(vector), selstr), vector.is3d()
    )
    return (vec, sel)
示例#2
0
def sliceVector(vector, atoms, select):
    """Return part of the *vector* for *atoms* matching *select*.  Note that 
    returned :class:`.Vector` instance is not normalized.
    
    :arg vector: vector instance to be sliced
    :type vector: :class:`.VectorBase`
    
    :arg atoms: atoms for which *vector* describes a deformation, motion, etc.
    :type atoms: :class:`.Atomic`
    
    :arg select: an atom selection or a selection string 
    :type select: :class:`.Selection`, str 
    
    :returns: (:class:`.Vector`, :class:`.Selection`)"""
    
    if not isinstance(vector, VectorBase):
        raise TypeError('vector must be a VectorBase instance, not {0:s}'
                        .format(type(vector)))
    if not isinstance(atoms, Atomic):
        raise TypeError('atoms must be an Atomic instance, not {0:s}'
                        .format(type(atoms)))
    if atoms.numAtoms() != vector.numAtoms(): 
        raise ValueError('number of atoms in model and atoms must be equal')
    
    if isinstance(select, str):
        selstr = select
        if isinstance(atoms, AtomGroup):
            sel = atoms.select(selstr)
            which = sel._getIndices()
        else:
            which = SELECT.getIndices(atoms, selstr)
            sel = Selection(atoms.getAtomGroup(), atoms.getIndices()[which],
                            selstr, atoms.getACSIndex())
            
    elif isinstance(select, AtomSubset):
        sel = select
        if isinstance(atoms, AtomGroup):
            if sel.getAtomGroup() != atoms:
                raise ValueError('select and atoms do not match')
            which = sel._getIndices()
        else:
            if atoms.getAtomGroup() != sel.getAtomGroup():
                raise ValueError('select and atoms do not match')
            elif not sel in atoms:
                raise ValueError('select is not a subset of atoms')
            idxset = set(atoms._getIndices())
            which = np.array([idx in idxset for idx in sel._getIndices()])
            which = which.nonzero()[0]
        selstr = sel.getSelstr()
    
    else:
        raise TypeError('select must be a string or a Selection instance')
        
    vec = Vector(vector.getArrayNx3()[
                 which, :].flatten(),
                 '{0:s} slice {1:s}'.format(str(vector), repr(selstr)), 
                 vector.is3d())
    return (vec, sel)
示例#3
0
文件: editing.py 项目: npabon/ProDy
def sliceVector(vector, atoms, select):
    """Return part of the *vector* for *atoms* matching *select*.  Note that
    returned :class:`.Vector` instance is not normalized.

    :arg vector: vector instance to be sliced
    :type vector: :class:`.VectorBase`

    :arg atoms: atoms for which *vector* describes a deformation, motion, etc.
    :type atoms: :class:`.Atomic`

    :arg select: an atom selection or a selection string
    :type select: :class:`.Selection`, str

    :returns: (:class:`.Vector`, :class:`.Selection`)"""

    if not isinstance(vector, VectorBase):
        raise TypeError('vector must be a VectorBase instance, not {0}'
                        .format(type(vector)))
    if not isinstance(atoms, Atomic):
        raise TypeError('atoms must be an Atomic instance, not {0}'
                        .format(type(atoms)))
    if atoms.numAtoms() != vector.numAtoms():
        raise ValueError('number of atoms in model and atoms must be equal')

    if isinstance(select, str):
        selstr = select
        if isinstance(atoms, AtomGroup):
            sel = atoms.select(selstr)
            which = sel._getIndices()
        else:
            which = SELECT.getIndices(atoms, selstr)
            sel = Selection(atoms.getAtomGroup(), atoms.getIndices()[which],
                            selstr, atoms.getACSIndex())

    elif isinstance(select, AtomSubset):
        sel = select
        if isinstance(atoms, AtomGroup):
            if sel.getAtomGroup() != atoms:
                raise ValueError('select and atoms do not match')
            which = sel._getIndices()
        else:
            if atoms.getAtomGroup() != sel.getAtomGroup():
                raise ValueError('select and atoms do not match')
            elif not sel in atoms:
                raise ValueError('select is not a subset of atoms')
            idxset = set(atoms._getIndices())
            which = np.array([idx in idxset for idx in sel._getIndices()])
            which = which.nonzero()[0]
        selstr = sel.getSelstr()

    else:
        raise TypeError('select must be a string or a Selection instance')

    vec = Vector(vector.getArrayNx3()[
                 which, :].flatten(),
                 '{0} slice {1}'.format(str(vector), repr(selstr)),
                 vector.is3d())
    return (vec, sel)
示例#4
0
文件: editing.py 项目: crosvera/ProDy
def sliceModel(model, atoms, selstr):
    """Return a slice of *model* matching *atoms* specified by *selstr*.
    
    Note that sliced normal modes (eigenvectors) are not normalized.
    
    :arg mode: NMA model instance to be sliced
    :type mode: :class:`NMA`
    
    :arg atoms: atoms for which the *model* was built
    :type atoms: :class:`~prody.atomic.Atomic`
    
    :arg selstr: selection string
    :type selstr: str 
    
    :returns: (:class:`NMA`, :class:`~prody.atomic.Selection`)"""

    if not isinstance(model, NMA):
        raise TypeError("mode must be a NMA instance, not {0:s}".format(type(model)))
    if not isinstance(atoms, Atomic):
        raise TypeError("atoms must be an Atomic instance, not {0:s}".format(type(atoms)))
    if atoms.numAtoms() != model.numAtoms():
        raise ValueError("number of atoms in *model* and *atoms* must be " "equal")

    array = model._getArray()
    if isinstance(atoms, AtomGroup):
        sel = atoms.select(selstr)
        which = sel.getIndices()
    else:
        which = SELECT.getIndices(atoms, selstr)
        sel = Selection(atoms.getAtomGroup(), atoms.getIndices()[which], selstr, atoms.getACSIndex())

    nma = type(model)('{0:s} slice "{1:s}"'.format(model.getTitle(), selstr))
    if model.is3d():
        which = [which.reshape((len(which), 1)) * 3]
        which.append(which[0] + 1)
        which.append(which[0] + 2)
        which = np.concatenate(which, 1).flatten()
    nma.setEigens(array[which, :], model.getEigenvalues())
    return (nma, sel)
示例#5
0
文件: editing.py 项目: crosvera/ProDy
def sliceMode(mode, atoms, selstr):
    """Return a slice of *mode* matching *atoms* specified by *selstr*.
    
    This works slightly difference from :func:`sliceVector`. Mode array 
    (eigenvector) is multiplied by square-root of the variance along the mode.
    If mode is from an elastic network model, variance is defined as the 
    inverse of the eigenvalue.
    
    Note that returned :class:`Vector` instance is not normalized.
    
    :arg mode: mode instance to be sliced
    :type mode: :class:`Mode`
    
    :arg atoms: atoms for which *mode* describes a deformation, motion, etc.
    :type atoms: :class:`~prody.atomic.Atomic`
    
    :arg selstr: selection string
    :type selstr: str 
    
    :returns: (:class:`Vector`, :class:`~prody.atomic.Selection`)"""

    if not isinstance(mode, Mode):
        raise TypeError("mode must be a Mode instance, not {0:s}".format(type(mode)))
    if not isinstance(atoms, Atomic):
        raise TypeError("atoms must be an Atomic instance, not {0:s}".format(type(atoms)))
    if atoms.numAtoms() != mode.numAtoms():
        raise ValueError("number of atoms in *mode* and *atoms* must be equal")
    if isinstance(atoms, AtomGroup):
        sel = atoms.select(selstr)
        which = sel.getIndices()
    else:
        which = SELECT.getIndices(atoms, selstr)
        sel = Selection(atoms.getAtomGroup(), atoms.getIndices()[which], selstr, atoms.getACSIndex())
    vec = Vector(
        mode.getArrayNx3()[which, :].flatten() * mode.getVariance() ** 0.5,
        '{0:s} slice "{1:s}"'.format(str(mode), selstr),
        mode.is3d(),
    )
    return (vec, sel)
示例#6
0
def reduceModel(model, atoms, select):
    """Return reduced NMA model.  Reduces a :class:`.NMA` model to a subset of
    *atoms* matching *select*.  This function behaves differently depending on
    the type of the *model* argument.  For :class:`.ANM` and :class:`.GNM` or
    other :class:`.NMA` models, force constant matrix for system of interest
    (specified by the *select*) is derived from the force constant matrix for
    the *model* by assuming that for any given displacement of the system of
    interest, other atoms move along in such a way as to minimize the potential
    energy.  This is based on the formulation in [KH00]_.  For :class:`.PCA`
    models, this function simply takes the sub-covariance matrix for selection.

    .. [KH00] Konrad H, Andrei-Jose P, Serge D, Marie-Claire BF, Gerald RK.
       Harmonicity in slow protein dynamics. *Chem Phys* **2000** 261:25-37.

    :arg model: dynamics model
    :type model: :class:`.ANM`, :class:`.GNM`, or :class:`.PCA`

    :arg atoms: atoms that were used to build the model
    :type atoms: :class:`.Atomic`

    :arg select: an atom selection or a selection string
    :type select: :class:`.Selection`, str

    :returns: (:class:`.NMA`, :class:`.Selection`)"""

    linalg = importLA()

    if not isinstance(model, NMA):
        raise TypeError('model must be an NMA instance, not {0}'
                        .format(type(model)))
    if not isinstance(atoms, (AtomGroup, AtomSubset, AtomMap)):
        raise TypeError('atoms type is not valid')
    if len(atoms) <= 1:
        raise TypeError('atoms must contain more than 1 atoms')

    if isinstance(model, GNM):
        matrix = model._kirchhoff
    elif isinstance(model, ANM):
        matrix = model._hessian
    elif isinstance(model, PCA):
        matrix = model._cov
    else:
        raise TypeError('model does not have a valid type derived from NMA')
    if matrix is None:
        raise ValueError('model matrix (Hessian/Kirchhoff/Covariance) is not '
                         'built')

    if isinstance(select, str):
        system = SELECT.getBoolArray(atoms, select)
        n_sel = sum(system)
        if n_sel == 0:
            raise ValueError('select matches 0 atoms')
        if len(atoms) == n_sel:
            raise ValueError('select matches all atoms')

        if isinstance(atoms, AtomGroup):
            ag = atoms
            which = np.arange(len(atoms))[system]
        else:
            ag = atoms.getAtomGroup()
            which = atoms._getIndices()[system]
        sel = Selection(ag, which, select, atoms.getACSIndex())

    elif isinstance(select, AtomSubset):
        sel = select
        if isinstance(atoms, AtomGroup):
            if sel.getAtomGroup() != atoms:
                raise ValueError('select and atoms do not match')
            system = np.zeros(len(atoms), bool)
            system[sel._getIndices()] = True
        else:
            if atoms.getAtomGroup() != sel.getAtomGroup():
                raise ValueError('select and atoms do not match')
            elif not sel in atoms:
                raise ValueError('select is not a subset of atoms')
            idxset = set(atoms._getIndices())
            system = np.array([idx in idxset for idx in sel._getIndices()])

    else:
        raise TypeError('select must be a string or a Selection instance')

    other = np.invert(system)

    if model.is3d():
        system = np.tile(system, (3, 1)).transpose().flatten()
        other = np.tile(other, (3, 1)).transpose().flatten()
    ss = matrix[system, :][:, system]
    if isinstance(model, PCA):
        eda = PCA(model.getTitle() + ' reduced')
        eda.setCovariance(ss)
        return eda, system
    so = matrix[system, :][:, other]
    os = matrix[other, :][:, system]
    oo = matrix[other, :][:, other]
    matrix = ss - np.dot(so, np.dot(linalg.inv(oo), os))

    if isinstance(model, GNM):
        gnm = GNM(model.getTitle() + ' reduced')
        gnm.setKirchhoff(matrix)
        return gnm, sel
    elif isinstance(model, ANM):
        anm = ANM(model.getTitle() + ' reduced')
        anm.setHessian(matrix)
        return anm, sel
    elif isinstance(model, PCA):
        eda = PCA(model.getTitle() + ' reduced')
        eda.setCovariance(matrix)
        return eda, sel
示例#7
0
def sliceModel(model, atoms, select):
    """Return a part of the *model* for *atoms* matching *select*.  Note that 
    normal modes (eigenvectors) are not normalized.
    
    :arg mode: NMA model instance to be sliced
    :type mode: :class:`.NMA`
    
    :arg atoms: atoms for which the *model* was built
    :type atoms: :class:`.Atomic`
    
    :arg select: an atom selection or a selection string 
    :type select: :class:`.Selection`, str 
    
    :returns: (:class:`.NMA`, :class:`.Selection`)"""
    
    if not isinstance(model, NMA):
        raise TypeError('mode must be a NMA instance, not {0:s}'
                        .format(type(model)))
    if not isinstance(atoms, Atomic):
        raise TypeError('atoms must be an Atomic instance, not {0:s}'
                        .format(type(atoms)))
    if atoms.numAtoms() != model.numAtoms(): 
        raise ValueError('number of atoms in model and atoms must be equal')
    
    array = model._getArray()
    
    if isinstance(select, str):
        selstr = select
        if isinstance(atoms, AtomGroup):
            sel = atoms.select(selstr)
            which = sel.getIndices()
        else:
            which = SELECT.getIndices(atoms, selstr)
            sel = Selection(atoms.getAtomGroup(), atoms.getIndices()[which],
                            selstr, atoms.getACSIndex())
        
    elif isinstance(select, AtomSubset):
        sel = select
        if isinstance(atoms, AtomGroup):
            if sel.getAtomGroup() != atoms:
                raise ValueError('select and atoms do not match')
            which = sel._getIndices()
        else:
            if atoms.getAtomGroup() != sel.getAtomGroup():
                raise ValueError('select and atoms do not match')
            elif not sel in atoms:
                raise ValueError('select is not a subset of atoms')
            idxset = set(atoms._getIndices())
            which = np.array([idx in idxset for idx in sel._getIndices()])
            which = which.nonzero()[0]
        selstr = sel.getSelstr()
    
    else:
        raise TypeError('select must be a string or a Selection instance')
        
    nma = type(model)('{0:s} slice {1:s}'
                      .format(model.getTitle(), repr(selstr)))
    if model.is3d():
        which = [which.reshape((len(which),1))*3]
        which.append(which[0]+1)
        which.append(which[0]+2)
        which = np.concatenate(which, 1).flatten()
    nma.setEigens( array[which, :], model.getEigvals() )
    return (nma, sel)
示例#8
0
def sliceMode(mode, atoms, select):
    """Return part of the *mode* for *atoms* matching *select*.  This works 
    slightly different from :func:`.sliceVector`. Mode array (eigenvector) is 
    multiplied by square-root of the variance along the mode.  If mode is from
    an elastic network model, variance is defined as the inverse of the 
    eigenvalue.  Note that returned :class:`~.Vector` instance is not 
    normalized.
    
    :arg mode: mode instance to be sliced
    :type mode: :class:`.Mode`
    
    :arg atoms: atoms for which *mode* describes a deformation, motion, etc.
    :type atoms: :class:`.Atomic`
    
    :arg select: an atom selection or a selection string 
    :type select: :class:`.Selection`, str 
    
    :returns: (:class:`~.Vector`, :class:`~.Selection`)"""
    
    if not isinstance(mode, Mode):
        raise TypeError('mode must be a Mode instance, not {0:s}'
                        .format(type(mode)))
    if not isinstance(atoms, Atomic):
        raise TypeError('atoms must be an Atomic instance, not {0:s}'
                        .format(type(atoms)))
    if atoms.numAtoms() != mode.numAtoms(): 
        raise ValueError('number of atoms in model and atoms must be equal')
    
    if isinstance(select, str):
        selstr = select
        if isinstance(atoms, AtomGroup):
            sel = atoms.select(selstr)
            which = sel._getIndices()
        else:
            which = SELECT.getIndices(atoms, selstr)
            sel = Selection(atoms.getAtomGroup(), atoms.getIndices()[which],
                            selstr, atoms.getACSIndex())
        
    elif isinstance(select, AtomSubset):
        sel = select
        if isinstance(atoms, AtomGroup):
            if sel.getAtomGroup() != atoms:
                raise ValueError('select and atoms do not match')
            which = sel._getIndices()
        else:
            if atoms.getAtomGroup() != sel.getAtomGroup():
                raise ValueError('select and atoms do not match')
            elif not sel in atoms:
                raise ValueError('select is not a subset of atoms')
            idxset = set(atoms._getIndices())
            which = np.array([idx in idxset for idx in sel._getIndices()])
            which = which.nonzero()[0]
        selstr = sel.getSelstr()
    
    else:
        raise TypeError('select must be a string or a Selection instance')
    
    vec = Vector(mode.getArrayNx3()[
                 which,:].flatten() * mode.getVariance()**0.5,
                 '{0:s} slice {1:s}'.format(str(mode), repr(selstr)), 
                 mode.is3d()) 
    return (vec, sel)
示例#9
0
文件: editing.py 项目: npabon/ProDy
def sliceModel(model, atoms, select):
    """Return a part of the *model* for *atoms* matching *select*.  Note that
    normal modes (eigenvectors) are not normalized.

    :arg mode: NMA model instance to be sliced
    :type mode: :class:`.NMA`

    :arg atoms: atoms for which the *model* was built
    :type atoms: :class:`.Atomic`

    :arg select: an atom selection or a selection string
    :type select: :class:`.Selection`, str

    :returns: (:class:`.NMA`, :class:`.Selection`)"""

    if not isinstance(model, NMA):
        raise TypeError('mode must be a NMA instance, not {0}'
                        .format(type(model)))
    if not isinstance(atoms, Atomic):
        raise TypeError('atoms must be an Atomic instance, not {0}'
                        .format(type(atoms)))
    if atoms.numAtoms() != model.numAtoms():
        raise ValueError('number of atoms in model and atoms must be equal')

    array = model._getArray()

    if isinstance(select, str):
        selstr = select
        if isinstance(atoms, AtomGroup):
            sel = atoms.select(selstr)
            which = sel.getIndices()
        else:
            which = SELECT.getIndices(atoms, selstr)
            sel = Selection(atoms.getAtomGroup(), atoms.getIndices()[which],
                            selstr, atoms.getACSIndex())

    elif isinstance(select, AtomSubset):
        sel = select
        if isinstance(atoms, AtomGroup):
            if sel.getAtomGroup() != atoms:
                raise ValueError('select and atoms do not match')
            which = sel._getIndices()
        else:
            if atoms.getAtomGroup() != sel.getAtomGroup():
                raise ValueError('select and atoms do not match')
            elif not sel in atoms:
                raise ValueError('select is not a subset of atoms')
            idxset = set(atoms._getIndices())
            which = np.array([idx in idxset for idx in sel._getIndices()])
            which = which.nonzero()[0]
        selstr = sel.getSelstr()

    else:
        raise TypeError('select must be a string or a Selection instance')

    nma = type(model)('{0} slice {1}'
                      .format(model.getTitle(), repr(selstr)))
    if model.is3d():
        which = [which.reshape((len(which), 1))*3]
        which.append(which[0]+1)
        which.append(which[0]+2)
        which = np.concatenate(which, 1).flatten()
    nma.setEigens(array[which, :], model.getEigvals())
    return (nma, sel)
示例#10
0
文件: editing.py 项目: npabon/ProDy
def sliceMode(mode, atoms, select):
    """Return part of the *mode* for *atoms* matching *select*.  This works
    slightly different from :func:`.sliceVector`. Mode array (eigenvector) is
    multiplied by square-root of the variance along the mode.  If mode is from
    an elastic network model, variance is defined as the inverse of the
    eigenvalue.  Note that returned :class:`.Vector` instance is not
    normalized.

    :arg mode: mode instance to be sliced
    :type mode: :class:`.Mode`

    :arg atoms: atoms for which *mode* describes a deformation, motion, etc.
    :type atoms: :class:`.Atomic`

    :arg select: an atom selection or a selection string
    :type select: :class:`.Selection`, str

    :returns: (:class:`.Vector`, :class:`.Selection`)"""

    if not isinstance(mode, Mode):
        raise TypeError('mode must be a Mode instance, not {0}'
                        .format(type(mode)))
    if not isinstance(atoms, Atomic):
        raise TypeError('atoms must be an Atomic instance, not {0}'
                        .format(type(atoms)))
    if atoms.numAtoms() != mode.numAtoms():
        raise ValueError('number of atoms in model and atoms must be equal')

    if isinstance(select, str):
        selstr = select
        if isinstance(atoms, AtomGroup):
            sel = atoms.select(selstr)
            which = sel._getIndices()
        else:
            which = SELECT.getIndices(atoms, selstr)
            sel = Selection(atoms.getAtomGroup(), atoms.getIndices()[which],
                            selstr, atoms.getACSIndex())

    elif isinstance(select, AtomSubset):
        sel = select
        if isinstance(atoms, AtomGroup):
            if sel.getAtomGroup() != atoms:
                raise ValueError('select and atoms do not match')
            which = sel._getIndices()
        else:
            if atoms.getAtomGroup() != sel.getAtomGroup():
                raise ValueError('select and atoms do not match')
            elif not sel in atoms:
                raise ValueError('select is not a subset of atoms')
            idxset = set(atoms._getIndices())
            which = np.array([idx in idxset for idx in sel._getIndices()])
            which = which.nonzero()[0]
        selstr = sel.getSelstr()

    else:
        raise TypeError('select must be a string or a Selection instance')

    vec = Vector(mode.getArrayNx3()[which, :].flatten() *
                 mode.getVariance()**0.5,
                 '{0} slice {1}'.format(str(mode), repr(selstr)), mode.is3d())
    return (vec, sel)
示例#11
0
文件: editing.py 项目: crosvera/ProDy
def reduceModel(model, atoms, selstr):
    """Return reduced NMA model.
    
    Reduces a :class:`NMA` model to a subset of *atoms* matching a selection 
    *selstr*.  This function behaves differently depending on the type of the 
    *model* argument.  For ANM and GNM or other NMA models, this functions 
    derives the force constant matrix for system of interest (specified by the 
    *selstr*) from the force constant matrix for the *model* by assuming that 
    for any given displacement of the system of interest, the other atoms move 
    along in such a way as to minimize the potential energy.  This is based on 
    the formulation in in [KH00]_.  For PCA models, this function simply takes 
    the sub-covariance matrix for the selected atoms.

    :arg model: dynamics model
    :type model: :class:`ANM`, :class:`GNM`, or :class:`PCA`
    :arg atoms: atoms that were used to build the model
    :arg selstr: a selection string specifying subset of atoms"""

    linalg = importLA()

    if not isinstance(model, NMA):
        raise TypeError("model must be an NMA instance, not {0:s}".format(type(model)))
    if not isinstance(atoms, (AtomGroup, AtomSubset, AtomMap)):
        raise TypeError("atoms type is not valid")
    if len(atoms) <= 1:
        raise TypeError("atoms must contain more than 1 atoms")

    if isinstance(model, GNM):
        matrix = model._kirchhoff
    elif isinstance(model, ANM):
        matrix = model._hessian
    elif isinstance(model, PCA):
        matrix = model._cov
    else:
        raise TypeError("model does not have a valid type derived from NMA")
    if matrix is None:
        raise ValueError("model matrix (Hessian/Kirchhoff/Covariance) is not " "built")

    system = SELECT.getBoolArray(atoms, selstr)
    other = np.invert(system)
    n_sel = sum(system)
    if n_sel == 0:
        LOGGER.warning("selection has 0 atoms")
        return None
    if len(atoms) == n_sel:
        LOGGER.warning("selection results in same number of atoms, " "model is not reduced")
        return None

    if model.is3d():
        system = np.tile(system, (3, 1)).transpose().flatten()
        other = np.tile(other, (3, 1)).transpose().flatten()
    ss = matrix[system, :][:, system]
    if isinstance(model, PCA):
        eda = PCA(model.getTitle() + " reduced")
        eda.setCovariance(ss)
        return eda, system
    so = matrix[system, :][:, other]
    os = matrix[other, :][:, system]
    oo = matrix[other, :][:, other]
    matrix = ss - np.dot(so, np.dot(linalg.inv(oo), os))

    if isinstance(model, GNM):
        gnm = GNM(model.getTitle() + " reduced")
        gnm.setKirchhoff(matrix)
        return gnm, system
    elif isinstance(model, ANM):
        anm = ANM(model.getTitle() + " reduced")
        anm.setHessian(matrix)
        return anm, system
    elif isinstance(model, PCA):
        eda = PCA(model.getTitle() + " reduced")
        eda.setCovariance(matrix)
        return eda, system