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. :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: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') 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
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