diff --git a/.github/workflows/publish_and_tag.yml b/.github/workflows/publish_and_tag.yml index 6d9867a..2c9ca08 100644 --- a/.github/workflows/publish_and_tag.yml +++ b/.github/workflows/publish_and_tag.yml @@ -32,6 +32,7 @@ jobs: pip install setuptools wheel twine pip install scipion-pyworkflow pip install scipion-em + pip install scipion-app - name: Build and publish env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} diff --git a/MANIFEST.in b/MANIFEST.in index 7f9b27a..73b2109 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,4 +2,5 @@ include *.txt include MANIFEST.in include *.rst recursive-include continuousflex/protocols * - +include continuousflex/*.yaml +recursive-include continuousflex/templates * diff --git a/README.rst b/README.rst index ad39aa8..98fab45 100644 --- a/README.rst +++ b/README.rst @@ -5,17 +5,20 @@ ContinuousFlex plugin This plugin provides the latest Scipion protocols for cryo-EM continuous conformational flexibility/heterogeneity analysis of biomolecular complexes. -Installation +Requirements ------------ -You will need to use `3.0 `_ version of Scipion to be able to run these protocols. To install the plugin, you have two options: -We you need help installing Scipion3, please refer to the Scipion Documentation `here `__ +- You will need to use `3.0 `_ version of Scipion to be able to run these protocols. If you need help installing Scipion3, please refer to the Scipion Documentation `here `__ +- GCC >= 8 +- GFORTRAN = 9.X + +Note: you can set GFORTRAN version on Ubuntu using "sudo update-alternatives --install /usr/bin/gfortran gfortran /usr/bin/gfortran-9 1000" -Make sure that you have cmake installed on your Linux system. For example, if you are using Ubuntu - .. code-block:: - sudo apt install cmake +Installation +------------ +To install the plugin, you have two options: a) Stable version @@ -44,29 +47,40 @@ You should also consider having VMD on your system for visualization. We assume that VMD is installed on your system in "/usr/local/lib/vmd". If VMD is installed but does not work, you may run the command "scipion3 config" and look for VMD_HOME in the config file (the config file is usually at ~/scipion3/config/scipion.conf) +Note: Matlab with its image processing toolbox is optional. It will only be needed if missing-wedge correction using Monte Carlo or volume denoising using BM4D are to be used +We assume that Matlab is installed on your system in "~/programs/Matlab". +If Matlab is installed but does not work, you may run the command "scipion3 config" and look for MATLAB_HOME in the config file (the config file is usually at ~/scipion3/config/scipion.conf) + Supported versions ------------------ -versions > 3.0.15 +versions > 3.3.0 Protocols --------- -* HEMNMA: Hybrid Electron Microscopy Normal Mode Analysis method to interpret heterogeneity of a set of single particle cryo-EM images in terms of continuous macromolecular conformational transitions [1-3] -* StructMap: Structural Mapping method to interpret heterogeneity of a set of single particle cryo-EM maps in terms of continuous conformational transitions [4] -* HEMNMA-3D: Extension of HEMNMA to continuous conformational variability analysis of macromolecules from in situ cryo-ET subtomograms [5] -* TomoFlow: Method for analyzing continuous conformational variability of macromolecules in in vitro and in situ cryogenic subtomograms based on 3D dense optical flow [7] +* **HEMNMA**: Hybrid Electron Microscopy Normal Mode Analysis method to interpret heterogeneity of a set of single particle cryo-EM images in terms of continuous macromolecular conformational transitions, based on normal mode analysis [1-3] +* **StructMap**: Structural Mapping method to interpret heterogeneity of a set of single particle cryo-EM maps in terms of continuous conformational transitions, based on normal mode analysis [4] +* **HEMNMA-3D**: Extension of HEMNMA to continuous conformational variability analysis of macromolecules in cryo-ET subtomograms (in vitro and in situ) [5] +* **TomoFlow**: Method for analyzing continuous conformational variability of macromolecules in cryo-ET subtomograms (in vitro and in situ) based on 3D dense optical flow [6] +* **NMMD**: Software to perform cryo-EM flexible fitting using a combination of Normal Mode (NM) analysis and Molecular Dynamics (MD) simulations implemented in GENESIS [7] +* **DeepHEMNMA**: A deep learning extension of HEMNMA [8] +* **MDSPACE** `[Tutorial] `_: Approach for extracting atomic-resolution landscapes of continuous conformational variability of biomolecular complexes from cryo electron microscopy (cryo-EM) single particle images based on a new 3D-to-2D flexible fitting method, which uses molecular dynamics (MD) simulation and is embedded in an iterative conformational-landscape refinement scheme. [11] +* **MDTOMO**: Approach for extracting continuous conformational atomic-resolution landscapes of biomolecular complexes from cryo electron subtomograms using Molecular Dynamics simulations. [12] Notes: -* The plugin additionally provides the test data and automated tests of the protocols in Scipion 3. The following two types of tests of HEMNMA and HEMNMA-3D can be produced by running, in the terminal, "scipion3 tests continuousflex.tests.test_workflow_HEMNMA" and “scipion3 tests continuousflex.tests.test_workflow_HEMNMA3D”, respectively: (1) tests of the entire protocol with the flexible references coming from an atomic structure and from an EM map; and (2) test of the alignment module (test run using 5 MPI threads). The automated tests of the TomoFlow method are also available and can be run using scipion3 tests continuousflex.tests.test_workflow_TomoFlow. -* HEMNMA additionally provides tools for synthesizing noisy and CTF-affected single particle cryo-EM images with flexible or rigid biomolecular conformations, for several types of conformational distributions, from a given atomic structure or an EM map. One part of the noise is applied on the ideal projections before and the other after the CTF, as described in [6]. -* HEMNMA-3D additionally provides tools for synthesizing noisy, CTF and missing wedge affected cryo-ET tomograms and single particle subtomograms with flexible or rigid biomolecular conformations, for several types of conformational distributions, from a given atomic structure or an EM map. One part of the noise is applied on the ideal projections before and the other after the CTF, as described in [6]. +* The plugin additionally provides the test data and automated tests of the protocols in Scipion 3. The following two types of tests of HEMNMA and HEMNMA-3D can be produced by running, in the terminal, "scipion3 tests continuousflex.tests.test_workflow_HEMNMA" and “scipion3 tests continuousflex.tests.test_workflow_HEMNMA3D”, respectively: (1) tests of the entire protocol with the flexible references coming from an atomic structure and from an EM map; and (2) test of the alignment module (test run using 5 MPI threads). The automated tests of the TomoFlow method are also available and can be run using scipion3 tests continuousflex.tests.test_workflow_TomoFlow. +* The automated tests of GENESIS provide an example of cryo-EM flexible fitting of an atomic model into a 3D density map using NMMD for CHARMM and C-Alpha Go model. The tests can be produced by running "scipion3 tests continuousflex.tests.test_workflow_GENESIS" (you need at least 2 MPI cores for these tests). +* HEMNMA additionally provides tools for synthesizing noisy and CTF-affected single particle cryo-EM images with flexible or rigid biomolecular conformations, for several types of conformational distributions, from a given atomic structure or an EM map. One part of the noise is applied on the ideal projections before and the other after the CTF, as described in [9-10]. +* HEMNMA-3D additionally provides tools for synthesizing noisy, CTF and missing wedge affected cryo-ET tomograms and single particle subtomograms with flexible or rigid biomolecular conformations, for several types of conformational distributions, from a given atomic structure or an EM map. One part of the noise is applied on the ideal projections before and the other after the CTF, as described in [9-10]. * A reproduction of some utility codes with their corresponding licenses are contained in this plugin for subtomogram averaging, missing wedge correction, denoising and data reading. These codes are not used in the methods above, but they are made optional for data preprocessing and visualization. +* DeepHEMNMA automated test generates a small set of images; then, it runs HEMNMA to prepare data for the neural network training; finally, it trains the network and performs the inference. The test can be run using "scipion3 tests continuousflex.tests.test_workflow_Deep_HEMNMA.TestDeepHEMNMA1". References ---------- + [1] Jin Q, Sorzano CO, de la Rosa-Trevin JM, Bilbao-Castro JR, Nunez-Ramirez R, Llorca O, Tama F, Jonic S: Iterative elastic 3D-to-2D alignment method using normal modes for studying structural dynamics of large macromolecular complexes. Structure 2014, 22:496-506. `[Open-access] `__ [2] Jonic S: Computational methods for analyzing conformational variability of macromolecular complexes from cryo-electron microscopy images. Curr Opin Struct Biol 2017, 43:114-121. `[Link] `__ `[Author’s version] `__ @@ -77,8 +91,27 @@ References [5] Harastani M, Eltsov M, Leforestier A, Jonic S: HEMNMA-3D: Cryo Electron Tomography Method Based on Normal Mode Analysis to Study Continuous Conformational Variability of Macromolecular Complexes. Front Mol Biosci 2021, 8:663121. `[Open-access] `__ -[6] Jonic S, Sorzano CO, Thevenaz P, El-Bez C, De Carlo S, Unser M: Spline-based image-to-volume registration for three-dimensional electron microscopy. Ultramicroscopy 2005, 103:303-317. `[Author’s version] `__ +[6] Harastani M, Eltsov M, Leforestier A, Jonic S: TomoFlow: Analysis of continuous conformational variability of macromolecules in cryogenic subtomograms based on 3D dense optical flow. J Mol Biol 2021,167381. `[Author’s version] `__ `[Journal] `__ + +[7] Vuillemot R, Miyashita O, Tama F, Rouiller I, Jonic S, NMMD: Efficient Cryo-EM Flexible Fitting Based on Simultaneous Normal Mode and Molecular Dynamics atomic displacements. J Mol Biol 2022, 167483. `[Author’s version] `__ `[Journal] `__ + +[8] Hamitouche I and Jonic S (2022), DeepHEMNMA: ResNet-based hybrid analysis of continuous conformational heterogeneity in cryo-EM single particle images. Front. Mol. Biosci. 9:965645. `[Author’s version] `__ `[Journal] `__ + +[9] C.O.S. Sorzano, S. Jonic, R. Núñez-Ramírez, N. Boisset, J.M. Carazo: Fast, robust, and accurate determination of transmission electron microscopy contrast transfer function. Journal of Structural Biology 2007, 160: 249-262. `[Journal] `__ + +[10] Jonic S, Sorzano CO, Thevenaz P, El-Bez C, De Carlo S, Unser M: Spline-based image-to-volume registration for three-dimensional electron microscopy. Ultramicroscopy 2005, 103:303-317. `[Journal] `__ + +[11] Vuillemot R, Mirzaei A, Harastani M, Hamitouche I, Fréchin L, Klaholz BP, Miyashita O, Tama F, Rouiller I, Jonic S. MDSPACE: Extracting continuous conformational landscapes from cryo-EM single particle datasets using 3D-to-2D flexible fitting based on Molecular Dynamics simulation. Journal of Molecular Biology. 2023 Jan 10:167951. `[Journal] `__ + +[12] Vuillemot, R., Rouiller, I., & Jonić, S. MDTOMO method for continuous conformational variability analysis in cryo electron subtomograms based on molecular dynamics simulations. Scientific Reports, 2023, 13(1), 10596. `[Journal] `__ + +Citation +---------- +Harastani, M., Vuillemot, R., Hamitouche, I., Moghadam, N. B., & Jonic, S. (2022). ContinuousFlex: Software package for analyzing continuous conformational variability of macromolecules in cryo electron microscopy and tomography data. Journal of Structural Biology, 214(4), 107906. `[Journal] `__ + +Contact: +---------- -[7] Harastani M, Eltsov M, Leforestier A, Jonic S: TomoFlow: Analysis of continuous conformational variability of macromolecules in cryogenic subtomograms based on 3D dense optical flow. J Mol Biol 2021,167381. `[Author’s version] `__ `[Journal] `__ +All questions regarding the software can be sent through submitting an issue on the Github page or addressed to `[Contact] `__ # scipion-em-continuousflex diff --git a/continuousflex/__init__.py b/continuousflex/__init__.py index 8ecd994..f34e3df 100644 --- a/continuousflex/__init__.py +++ b/continuousflex/__init__.py @@ -1,7 +1,9 @@ # ************************************************************************** # * # * Authors: -# * Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Mohamad Harastani (mohamad.harastani@igbmc.fr) +# * Remi Vuillemot (remi.vuillemot@upmc.fr) +# * Ilyes Hamitouche (ilyes.hamitouche@upmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -20,115 +22,143 @@ # * 02111-1307 USA # * # * All comments concerning this program package may be sent to the -# * e-mail address 'scipion@cnb.csic.es' -# * +# * e-mail address 'scipion@cnb.csic.es' (if scipion related) +# * e-mail address 'slavica.jonic@upmc.fr' (for methods issues) # ************************************************************************** import os - import pwem from continuousflex.constants import * +import datetime +from scipion.install.funcs import VOID_TGZ +import continuousflex +import subprocess +import re import pyworkflow.utils as pwutils -getXmippPath = pwem.Domain.importFromPlugin("xmipp3.base", 'getXmippPath') -from pyworkflow.tests import DataSet + _logo = "logo.png" -__version__ = "3.1.2" + +MD_NMMD_GENESIS_VERSION = "2.1" +# Use this variable to activate an environment from the Scipion conda +MODEL_CONTINUOUSFLEX_ENV_ACTIVATION_VAR = "MODEL_CONTINUOUSFLEX_ENV_ACTIVATION" +# Use this general activation variable when installed outside Scipion +MODEL_CONTINUOUSFLEX_ACTIVATION_VAR = "MODEL_CONTINUOUSFLEX_ACTIVATION" + +__version__ = "3.4.2" + class Plugin(pwem.Plugin): _homeVar = CONTINUOUSFLEX_HOME _pathVars = [CONTINUOUSFLEX_HOME] - _supportedVersions = [VV] + # We only support our latest release, we can't afford supporting previous releases + _supportedVersions = [__version__] + _url = CONTINUOUSFLEX_URL @classmethod def _defineVariables(cls): - cls._defineEmVar(CONTINUOUSFLEX_HOME, 'xmipp') - cls._defineEmVar(NMA_HOME,'nma') - cls._defineVar(VMD_HOME,'/usr/local/lib/vmd') - - # @classmethod - # def getEnviron(cls): - # """ Setup the environment variables needed to launch the program. """ - # environ = Environ(os.environ) - # environ.update({ - # 'PATH': Plugin.getHome(), - # }, position=Environ.BEGIN) - # - # return environ + cls._defineVar(MODEL_CONTINUOUSFLEX_ACTIVATION_VAR, '') + cls._defineEmVar(CONTINUOUSFLEX_HOME, 'ContinuousFlex-' + __version__) + cls._defineVar(MODEL_CONTINUOUSFLEX_ENV_ACTIVATION_VAR, cls.getActivationCmd(__version__)) + cls._defineEmVar(NMA_HOME, 'nma') + cls._defineEmVar(GENESIS_HOME, 'MDTools-' + MD_NMMD_GENESIS_VERSION) + cls._defineEmVar(SMOG_HOME, 'smog-2.4.5') + cls._defineVar(VMD_HOME, '/usr/local/lib/vmd') + cls._defineVar(MATLAB_HOME, '~/programs/Matlab') @classmethod - def getEnviron(cls, xmippFirst=True): - """ Create the needed environment for Xmipp programs. """ + def getEnviron(cls): environ = pwutils.Environ(os.environ) - pos = pwutils.Environ.BEGIN if xmippFirst else pwutils.Environ.END - environ.update({ - 'PATH': getXmippPath('bin'), - 'LD_LIBRARY_PATH': getXmippPath('lib'), - 'PYTHONPATH': getXmippPath('pylib') - }, position=pos) - - # environ variables are strings not booleans - if os.environ.get('CUDA', 'False') != 'False': - environ.update({ - 'PATH': os.environ.get('CUDA_BIN', ''), - 'LD_LIBRARY_PATH': os.environ.get('NVCC_LIBDIR', '') - }, position=pos) - return environ + @classmethod + def getContinuousFlexCmd(cls, args): + cmd = cls.getVar(MODEL_CONTINUOUSFLEX_ACTIVATION_VAR) + if not cmd: + cmd = cls.getCondaActivationCmd() + cmd += cls.getVar(MODEL_CONTINUOUSFLEX_ENV_ACTIVATION_VAR) + cmd += " && " + cmd += args + return cmd + + @classmethod + def getActivationCmd(cls, version): + return 'conda activate {}'.format(cls.getVar(CONTINUOUSFLEX_HOME)) @classmethod def isVersionActive(cls): - return cls.getActiveVersion().startswith(VV) + return cls.getActiveVersion().startswith(__version__) + + @classmethod + def getCondaLibPath(cls): + return cls.getVar(CONTINUOUSFLEX_HOME) + '/lib' @classmethod def defineBinaries(cls, env): os.environ['PATH'] += os.pathsep + env.getBinFolder() - lapack = env.addLibrary( - 'lapack', - tar='lapack-3.5.0.tgz', - flags=['-DBUILD_SHARED_LIBS:BOOL=ON', - '-DLAPACKE:BOOL=ON'], - cmake=True, - neededProgs=['gfortran'], - default=False) - - arpack = env.addLibrary( - 'arpack', - tar='arpack-96.tgz', - neededProgs=['gfortran'], - commands=[('cd ' + env.getBinFolder() + '; ln -s $(which gfortran) f77', - env.getBinFolder() + '/f77'), - ('cd ' + env.getTmpFolder() + '/arpack-96; make all', - env.getLibFolder() + '/libarpack.a')]) - # See http://modb.oce.ulg.ac.be/mediawiki/index.php/How_to_compile_ARPACK - - # Cleaning the nma binaries files and folder before expanding - if os.path.exists(env.getEmFolder() + '/nma-2.0.tgz'): - os.system('rm ' + env.getEmFolder() + '/nma-2.0.tgz') - - # env.addPackage('nma', version='3.0', deps=[arpack, lapack], - env.addPackage('nma', version='3.1', deps=[arpack, lapack], - # url='https://github.com/slajo/NMA_basic_code/raw/master/nma_v3.tar', - # url='https://github.com/MohamadHarastani/nma_basic_codes/raw/main/nma_v4.tar', - # url='https://github.com/MohamadHarastani/nma_basic_codes/raw/main/nma_v5.tar', - url='https://github.com/slajo/NMA_basic_code/raw/master/nma_v5.tar', + + def defineCondaInstallation(version): + installed = "last-pull-%s.txt" % __version__ + + cf_commands = [] + cf_commands.append((getCondaInstallation(version, installed), installed)) + + env.addPackage('ContinuousFlex', version=version, + commands=cf_commands, + tar=VOID_TGZ, + default=True) + + def getCondaInstallation(version, txtfile): + installationCmd = cls.getCondaActivationCmd() + config_path = continuousflex.__path__[0] + '/conda_noCuda.yaml' + installationCmd += 'conda env create -f {} --prefix . --yes'.format(config_path) + # If nvcc is in the path, install Optical Flow and DeepLearning Libraries + if os.popen('which nvcc').read() is not None: + config_path = continuousflex.__path__[0] + '/conda.yaml' + installationCmd += "&& conda env update --prefix . --file={}".format(config_path) + installationCmd += ' && touch {}'.format(txtfile) + return installationCmd + + # Install the conda environment followed by the binaries + defineCondaInstallation(__version__) + env.addPackage('nma', version='3.1', + url='https://github.com/continuousflex-org/NMA_basic_code/raw/master/nma_v5.tar', createBuildDir=False, buildDir='nma', target="nma", - commands=[('cd ElNemo; make; mv nma_* ..', - 'nma_elnemo_pdbmat'), + commands=[('cd ElNemo; make; mv nma_* ..', 'nma_elnemo_pdbmat'), ('cd NMA_cart; LDFLAGS=-L%s make; mv nma_* ..' - % env.getLibFolder(), 'nma_diag_arpack')], + % cls.getCondaLibPath() , 'nma_diag_arpack')], neededProgs=['gfortran'], default=True) - -files_dictionary = {'pdb': 'pdb/AK.pdb', 'particles': 'particles/img.stk', 'vol': 'volumes/AK_LP10.vol', - 'precomputed_atomic': 'gold/images_WS_atoms.xmd', - 'precomputed_pseudoatomic': 'gold/images_WS_pseudoatoms.xmd', - 'small_stk': 'test_alignment_10images/particles/smallstack_img.stk', - 'subtomograms':'HEMNMA_3D/subtomograms/*.vol', - 'precomputed_HEMNMA3D_atoms':'HEMNMA_3D/gold/precomputed_atomic.xmd', - 'precomputed_HEMNMA3D_pseudo':'HEMNMA_3D/gold/precomputed_pseudo.xmd'} -DataSet(name='nma_V2.0', folder='nma_V2.0', files=files_dictionary, - url='https://raw.githubusercontent.com/MohamadHarastani/nma_V2.0/main/') - + target_branch = "master" + output = subprocess.getoutput("gfortran --version") + gfotran_version = int(re.search(r'\d+', output).group()) + if gfotran_version >= 10: + FFLAGS = "-fallow-argument-mismatch -ffree-line-length-none" + else: + FFLAGS = "-ffree-line-length-none" + + env.addPackage('MDTools', version=MD_NMMD_GENESIS_VERSION, + buildDir='MDTools', tar="void.tgz", + commands=[( + 'git clone -b %s https://github.com/continuousflex-org/MDTools.git . &&' + 'mkdir lib && cp %s/libopenblas* lib && cp %s/libblas* lib && cp %s/liblapack* lib &&' + ' autoreconf -fi && ./configure LDFLAGS=-L%s/lib FFLAGS=\"%s\" && make install;' + % (target_branch, cls.getCondaLibPath(), + cls.getCondaLibPath(),cls.getCondaLibPath(), cls.getVar("GENESIS_HOME"), FFLAGS), ["bin/atdyn"])], + neededProgs=['mpif90'], default=True) + + + env.addPackage('smog', version="2.4.5", + buildDir='smog-2.4.5', url="https://smog-server.org/smog2/code/smog-2.4.5.tgz", + target="smog-2.4.5", + commands=[( "mkdir -p smogenv && cd smogenv && %s conda env create -f %s/smog2.yaml --yes --prefix . " + "&& cd .. && %s/smog-2.4.5//smogenv/bin/perl -MCPAN -e 'install XML::Validator::Schema' &&" + "export perl4smog=\"%s/smog-2.4.5/smogenv/bin/perl\" && " + "echo -n '#!/bin/bash' > configure && " + "echo "" >> configure &&" + "cat configure.smog2 >> configure &&" + "chmod 777 configure &&" + "./configure"% + (cls.getCondaActivationCmd(),continuousflex.__path__[0], env.getEmFolder(), env.getEmFolder()), + ["bin/smog2"])], default=True) diff --git a/continuousflex/bibtex.py b/continuousflex/bibtex.py index b5c849f..45d3d7f 100644 --- a/continuousflex/bibtex.py +++ b/continuousflex/bibtex.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -103,7 +103,6 @@ doi= {https://doi.org/10.1002/pro.3772} } - @article{moebel2020monte, title={A Monte Carlo framework for missing wedge restoration and noise removal in cryo-electron tomography}, author={Moebel, Emmanuel and Kervrann, Charles}, @@ -114,5 +113,95 @@ publisher={Elsevier} } +@article{vuillemot2022NMMD, +title = {NMMD: Efficient Cryo-EM Flexible Fitting Based on Simultaneous Normal Mode and Molecular Dynamics atomic displacements}, +journal = {Journal of Molecular Biology}, +volume = {434}, +number = {7}, +pages = {167483}, +year = {2022}, +issn = {0022-2836}, +doi = {https://doi.org/10.1016/j.jmb.2022.167483}, +url = {https://www.sciencedirect.com/science/article/pii/S0022283622000523}, +author = {Rémi Vuillemot and Osamu Miyashita and Florence Tama and Isabelle Rouiller and Slavica Jonic} +} + +@article{vuillemot2023mdspace, + title={MDSPACE: Extracting continuous conformational landscapes from cryo-EM single particle datasets using 3D-to-2D flexible fitting based on Molecular Dynamics simulation}, + author={Vuillemot, R{\'e}mi and Mirzaei, Alex and Harastani, Mohamad and Hamitouche, Ilyes and Fr{\'e}chin, L{\'e}o and Klaholz, Bruno P and Miyashita, Osamu and Tama, Florence and Rouiller, Isabelle and Jonic, Slavica}, + journal={Journal of Molecular Biology}, + pages={167951}, + year={2023}, + publisher={Elsevier} +} + +@article{kobayashi2017genesis, +author = {Kobayashi, Chigusa and Jung, Jaewoon and Matsunaga, Yasuhiro and Mori, Takaharu and Ando, Tadashi and Tamura, Koichi and Kamiya, Motoshi and Sugita, Yuji}, +title = {GENESIS 1.1: A hybrid-parallel molecular dynamics simulator with enhanced sampling algorithms on multiple computational platforms}, +journal = {Journal of Computational Chemistry}, +volume = {38}, +number = {25}, +pages = {2193-2206}, +keywords = {molecular dynamics, string method, replica exchange molecular dynamics, graphics processing unit, multiple time step integration}, +doi = {https://doi.org/10.1002/jcc.24874}, +url = {https://onlinelibrary.wiley.com/doi/abs/10.1002/jcc.24874}, +eprint = {https://onlinelibrary.wiley.com/doi/pdf/10.1002/jcc.24874}, +abstract = {GENeralized-Ensemble SImulation System (GENESIS) is a software package for molecular dynamics (MD) simulation of biological systems. It is designed to extend limitations in system size and accessible time scale by adopting highly parallelized schemes and enhanced conformational sampling algorithms. In this new version, GENESIS 1.1, new functions and advanced algorithms have been added. The all-atom and coarse-grained potential energy functions used in AMBER and GROMACS packages now become available in addition to CHARMM energy functions. The performance of MD simulations has been greatly improved by further optimization, multiple time-step integration, and hybrid (CPU + GPU) computing. The string method and replica-exchange umbrella sampling with flexible collective variable choice are used for finding the minimum free-energy pathway and obtaining free-energy profiles for conformational changes of a macromolecule. These new features increase the usefulness and power of GENESIS for modeling and simulation in biological research. © 2017 Wiley Periodicals, Inc.}, +year = {2017} +} + +@article{CHEN2013235, +title = {Fast and accurate reference-free alignment of subtomograms}, +journal = {Journal of Structural Biology}, +volume = {182}, +number = {3}, +pages = {235-245}, +year = {2013}, +issn = {1047-8477}, +doi = {https://doi.org/10.1016/j.jsb.2013.03.002}, +url = {https://www.sciencedirect.com/science/article/pii/S1047847713000737}, +author = {Yuxiang Chen and Stefan Pfeffer and Thomas Hrabe and Jan Michael Schuller and Friedrich Förster}, +keywords = {Cryo-electron tomography, Subtomogram averaging, Spherical harmonics}, +abstract = {In cryoelectron tomography alignment and averaging of subtomograms, each dnepicting the same macromolecule, improves the resolution compared to the individual subtomogram. Major challenges of subtomogram alignment are noise enhancement due to overfitting, the bias of an initial reference in the iterative alignment process, and the computational cost of processing increasingly large amounts of data. Here, we propose an efficient and accurate alignment algorithm via a generalized convolution theorem, which allows computation of a constrained correlation function using spherical harmonics. This formulation increases computational speed of rotational matching dramatically compared to rotation search in Cartesian space without sacrificing accuracy in contrast to other spherical harmonic based approaches. Using this sampling method, a reference-free alignment procedure is proposed to tackle reference bias and overfitting, which also includes contrast transfer function correction by Wiener filtering. Application of the method to simulated data allowed us to obtain resolutions near the ground truth. For two experimental datasets, ribosomes from yeast lysate and purified 20S proteasomes, we achieved reconstructions of approximately 20Å and 16Å, respectively. The software is ready-to-use and made public to the community.} +} + +@article{harastani2022continuousflex, + title={ContinuousFlex: Software package for analyzing continuous conformational variability of macromolecules in cryo electron microscopy and tomography data}, + author={Harastani, Mohamad and Vuillemot, R{\'e}mi and Hamitouche, Ilyes and Moghadam, Nima Barati and Jonic, Slavica}, + journal={Journal of Structural Biology}, + volume={214}, + number={4}, + pages={107906}, + year={2022}, + publisher={Elsevier} +} + +@article{harastani2022tomoflow, + title={TomoFlow: Analysis of continuous conformational variability of macromolecules in cryogenic subtomograms based on 3D dense optical flow}, + author={Harastani, Mohamad and Eltsov, Mikhail and Leforestier, Am{\'e}lie and Jonic, Slavica}, + journal={Journal of molecular biology}, + volume={434}, + number={2}, + pages={167381}, + year={2022}, + publisher={Elsevier} +} + +@article{harastani2021hemnma, + title={Hemnma-3d: Cryo electron tomography method based on normal mode analysis to study continuous conformational variability of macromolecular complexes}, + author={Harastani, Mohamad and Eltsov, Mikhail and Leforestier, Am{\'e}lie and Jonic, Slavica}, + journal={Frontiers in molecular biosciences}, + pages={317}, + year={2021}, + publisher={Frontiers} +} + +@article{hamitouche2022deephemnma, + title={DeepHEMNMA: ResNet-based hybrid analysis of continuous conformational heterogeneity in cryo-EM single particle images}, + author={Hamitouche, Ilyes and Jonic, Slavica}, + journal={Frontiers in Molecular Biosciences}, + year={2022} +} + """ diff --git a/continuousflex/conda.yaml b/continuousflex/conda.yaml new file mode 100644 index 0000000..49e63c0 --- /dev/null +++ b/continuousflex/conda.yaml @@ -0,0 +1,21 @@ +dependencies: + - conda-forge::arpack + - conda-forge::lapack + - pip + - python=3.8 + - pip: + - setuptools==59.5.0 + - torch==1.10.1 + - starfile + - matplotlib + - mrcfile + - umap-learn + - torchvision==0.11.2 + - tensorboard==2.8.0 + - tqdm==4.64.0 + - protobuf==3.20.3 + - pycuda==2020.1 + - scipion-pyworkflow==3.1.1 + - scipion-em==3.2.0 + - numpy==1.23.0 + - farneback3d==0.1.4 diff --git a/continuousflex/conda_noCuda.yaml b/continuousflex/conda_noCuda.yaml new file mode 100644 index 0000000..5768d38 --- /dev/null +++ b/continuousflex/conda_noCuda.yaml @@ -0,0 +1,11 @@ +dependencies: + - conda-forge::arpack + - conda-forge::lapack + - pip + - python=3.8 + - pip: + - setuptools==59.5.0 + - umap-learn + - scipion-em + - tqdm==4.64.0 + - protobuf==3.20.3 diff --git a/continuousflex/constants.py b/continuousflex/constants.py index 1044a8d..d40e4bc 100644 --- a/continuousflex/constants.py +++ b/continuousflex/constants.py @@ -2,7 +2,7 @@ # ************************************************************************** # * # * Authors: -# * Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -29,9 +29,7 @@ CONTINUOUSFLEX_HOME = 'CONTINUOUSFLEX_HOME' NMA_HOME = 'NMA_HOME' VMD_HOME = 'VMD_HOME' - -# Supported versions -VV = '0.6' - - - +GENESIS_HOME = 'GENESIS_HOME' +SMOG_HOME = 'SMOG_HOME' +MATLAB_HOME = 'MATLAB_HOME' +CONTINUOUSFLEX_URL = 'https://github.com/scipion-em/scipion-em-continuousflex' diff --git a/continuousflex/protocols.conf b/continuousflex/protocols.conf index 940705b..d55b949 100644 --- a/continuousflex/protocols.conf +++ b/continuousflex/protocols.conf @@ -22,16 +22,20 @@ HEMNMA = [ {"tag": "section", "text": "3. Stop here or continue", "children": []}, {"tag": "section", "text": "4. Images", "children": [ {"tag": "protocol", "value": "ProtImportParticles", "text": "Import particles", "icon": "bookmark.png"}, + {"tag": "protocol", "value": "ProtSubSet", "text": "Create subsets from Particles (optional)", "icon": "bookmark.png"}, {"tag": "protocol", "value": "FlexProtSynthesizeImages", "text": "Synthesize particles (optional)"}, {"tag": "protocol", "value": "XmippProtCropResizeParticles", "text": "Resize particles (optional)"} ]}, {"tag": "section", "text": "5. Conformational distribution", "children": [ - {"tag": "protocol", "value": "FlexProtAlignmentNMA", "text": "Image analysis with normal modes"} + {"tag": "protocol", "value": "FlexProtAlignmentNMA", "text": "Image analysis with normal modes"}, + {"tag": "protocol", "value": "FlexProtDeepHEMNMATrain", "text": "[Train] DeepLearning on HEMNMA (optional)"}, + {"tag": "protocol", "value": "FlexProtDeepHEMNMAInfer", "text": "[Infer] DeepLearning on HEMNMA (optional)"} ]}, {"tag": "section", "text": "6. Dimension reduction, clusters, and trajectories", "children": [ {"tag": "protocol", "value": "FlexProtDimredNMA", "text": "3D reconstructions from image clusters, animated trajectories"} ]}] + HEMNMA_3D = [ {"tag": "section", "text": "1. Reference model", "children": [ {"tag": "protocol", "value": "ProtImportPdb", "text": " a. Import PDB", "icon": "bookmark.png"}, @@ -90,3 +94,42 @@ TomoFlow = [ {"tag": "section", "text": "5. 3D averaging & animations", "children": [ {"tag": "protocol", "value": "FlexProtDimredHeteroFlow", "text": "Clustering and trajectories"} ]}] + +MD-NMMD-Fitting = [ + {"tag": "section", "text": "1. Import atomic model", "children": [ + {"tag": "protocol", "value": "ProtImportPdb", "text": " Input PDB", "icon": "bookmark.png"} + ]}, + {"tag": "section", "text": "2. Import target EM data", "children": [ + {"tag": "protocol", "value": "ProtImportVolumes", "text": "Input volume", "icon": "bookmark.png"} + ]}, + {"tag": "section", "text": "3. Prepare simulation (Optional)", "children": [ + {"tag": "protocol", "value": "ProtGenerateTopology", "text": "Generate topology", "icon": "bookmark.png"} + ]}, + {"tag": "section", "text": "4. Energy Minimization", "children": [ + {"tag": "protocol", "value": "FlexProtGenesis", "text": "MD-NMMD-Genesis", "icon": "bookmark.png"} + ]}, + {"tag": "section", "text": "5. Normal Mode Analysis (Optional)", "children": [ + {"tag": "protocol", "value": "FlexProtNMA", "text": "NMA"} + ]}, + {"tag": "section", "text": "6. Flexible Fitting using MD / NMMD", "children": [ + {"tag": "protocol", "value": "FlexProtGenesis", "text": "MD-NMMD-Genesis", "icon": "bookmark.png"} + ]}] + +MDSPACE = [ + {"tag": "section", "text": "1. Import input data ", "children": [ + {"tag": "protocol", "value": "ProtImportPdb", "text": "Input PDB", "icon": "bookmark.png"}, + {"tag": "protocol", "value": "ProtImportParticles", "text": "Input particles", "icon": "bookmark.png"} + ]}, + {"tag": "section", "text": "2. Prepare simulation", "children": [ + {"tag": "protocol", "value": "ChimeraProtRigidFit", "text": "Chimera rigid body fit"}, + {"tag": "protocol", "value": "ProtGenerateTopology", "text": "Generate topology model", "icon": "bookmark.png"}, + {"tag": "protocol", "value": "FlexProtGenesis", "text": "Energy minimization", "icon": "bookmark.png"}, + {"tag": "protocol", "value": "FlexProtNMA", "text": "Normal mode analysis"} + ]}, + {"tag": "section", "text": "3. Run MDSPACE", "children": [ + {"tag": "protocol", "value": "FlexProtMDSPACE", "text": "MDSPACE", "icon": "bookmark.png"} + ]}, + {"tag": "section", "text": "4. Analyze conformational space", "children": [ + {"tag": "protocol", "value": "FlexProtAlignPdb", "text": "PDB rigid-body alignment", "icon": "bookmark.png"}, + {"tag": "protocol", "value": "FlexProtDimredPdb", "text": "PCA / UMAP", "icon": "bookmark.png"} + ]}] \ No newline at end of file diff --git a/continuousflex/protocols/__init__.py b/continuousflex/protocols/__init__.py index f24d0eb..33a6bdf 100644 --- a/continuousflex/protocols/__init__.py +++ b/continuousflex/protocols/__init__.py @@ -29,22 +29,32 @@ #from .protocol_nma_choose import XmippProtNMAChoose from .protocol_nma_dimred import FlexProtDimredNMA from .protocol_batch_cluster import FlexBatchProtNMACluster +from .protocol_batch_pdb_cluster import FlexBatchProtClusterSet from .protocol_structure_mapping import FlexProtStructureMapping -from .protocol_subtomogrmas_synthesize import FlexProtSynthesizeSubtomo +from .protocol_subtomograms_synthesize import FlexProtSynthesizeSubtomo from .protocol_batch_cluster_vol import FlexBatchProtNMAClusterVol from .protocol_nma_alignment_vol import FlexProtAlignmentNMAVol from .protocol_nma_dimred_vol import FlexProtDimredNMAVol from .protocol_subtomogram_averaging import FlexProtSubtomogramAveraging -from .protocol_missing_wedge_filling import FlexProtMissingWedgeRestoration +from .protocol_mw_restoration import FlexProtMissingWedgeRestoration from .protocol_apply_volumeset_alignment import FlexProtApplyVolSetAlignment -from .protocol_heteroflow import FlexProtHeteroFlow -from .protocol_heteroflow_dimred import FlexProtDimredHeteroFlow -from .protocol_batch_cluster_heteroflow import FlexBatchProtHeteroFlowCluster +from .protocol_tomoflow import FlexProtHeteroFlow +from .protocol_tomoflow_dimred import FlexProtDimredHeteroFlow +from .protocol_batch_cluster_tomoflow import FlexBatchProtTomoFlowCluster from .protocol_denoise_volumes import FlexProtVolumeDenoise from .data import * from .pdb import * from .protocol_pdb_dimred import FlexProtDimredPdb +from .protocol_align_pdbs import FlexProtAlignPdb from .protocol_subtomograms_classify import FlexProtSubtomoClassify from .protocol_image_synthesize import FlexProtSynthesizeImages -from .protocol_subtomogram_refine_alignment import FlexProtRefineSubtomoAlign -from .protocol_histogram_matching import FlexProtHistogramMatch +from .protocol_tomoflow_refine_alignment import FlexProtRefineSubtomoAlign +from .protocol_deep_hemnma_train import FlexProtDeepHEMNMATrain +from .protocol_deep_hemnma_infer import FlexProtDeepHEMNMAInfer +from .protocol_genesis import FlexProtGenesis +from .protocol_mdspace import FlexProtMDSPACE +from .protocol_mdtomo import FlexProtMDTOMO +from .protocol_generate_topology import ProtGenerateTopology +from .protocol_generate_topology import ProtGenerateTopology +from .protocol_pdb_synthesize import FlexProtSynthesizePDBs +from .protocol_ca2aa import FlexProtCA2AA diff --git a/continuousflex/protocols/convert.py b/continuousflex/protocols/convert.py index 0948c19..1c3077b 100644 --- a/continuousflex/protocols/convert.py +++ b/continuousflex/protocols/convert.py @@ -1,11 +1,10 @@ # ************************************************************************** # * -# * Authors: +# * Authors: +# * Mohamad Harastani (mohamad.harastani@igbmc.fr) # * J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es) # * Slavica Jonic (slavica.jonic@upmc.fr) # * -# * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC -# * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by # * the Free Software Foundation; either version 2 of the License, or @@ -26,22 +25,138 @@ # * # ************************************************************************** -import os from collections import OrderedDict - -from pwem.emlib import (MDL_NMA_MODEFILE, MDL_NMA_COLLECTIVITY, MDL_NMA_SCORE, - MDL_ORDER) +from pwem.emlib import (MDL_NMA_MODEFILE, MDL_NMA_COLLECTIVITY, MDL_NMA_SCORE, MDL_ORDER) from pyworkflow.utils import Environ from pwem.objects import NormalMode from xmipp3.convert import rowToObject, objectToRow -from xmipp3.constants import NMA_HOME - -MODE_DICT = OrderedDict([ - ("_modeFile", MDL_NMA_MODEFILE), - ("_collectivity", MDL_NMA_COLLECTIVITY), - ("_score", MDL_NMA_SCORE) - ]) +from continuousflex.constants import NMA_HOME +import numpy as np +import math + +MODE_DICT = OrderedDict([ + ("_modeFile", MDL_NMA_MODEFILE), + ("_collectivity", MDL_NMA_COLLECTIVITY), + ("_score", MDL_NMA_SCORE), +]) + +""" +Represents a point within a multidimensional dataset together with +its associated metadata, including spatial coordinates, weight, and +selection status. The class serves as the fundamental element for +managing geometric, statistical, or visualization-oriented data in +interactive analysis workflows. + +AI Generated: + +Point and Data Management (Point) - User Manual + Overview + + The Point protocol provides a framework for representing, + organizing, and manipulating collections of multidimensional + points. Its primary purpose is to support analytical and + visualization workflows in which individual observations are + associated with spatial coordinates and additional descriptive + properties. + + A point is more than a simple coordinate. In addition to its + position, each element may carry a numerical importance value + and a logical state describing whether it is active, selected, + or excluded from analysis. This design allows the same dataset + to support exploration, filtering, annotation, and interactive + selection without permanently modifying the original data. + + Data Organization + + The framework manages collections of points as coherent datasets. + Each dataset preserves the relationship between individual + elements while providing convenient access to coordinate values, + weights, and selection information. This organization is useful + for applications involving dimensionality reduction, clustering, + trajectory analysis, geometric measurements, or interactive + plotting environments. + + Datasets may contain two-dimensional or three-dimensional + coordinates as well as additional numerical descriptors. The + coordinate system remains consistent across all points, + facilitating comparison and interpretation of spatial patterns. + + Selection and Filtering + + A central feature of the framework is the ability to distinguish + between active, selected, and discarded elements. Selected + points can be used to define regions of interest, identify + representative observations, or support manual curation. + Discarded points remain stored within the dataset but are + excluded from standard analysis operations. + + This approach allows users to explore alternative selections + without losing information. As a result, workflows remain + flexible and reversible throughout the analysis process. + + Mathematical Exploration + + The framework supports evaluation of mathematical relationships + involving point-associated variables. This capability enables + users to derive new measurements, explore custom metrics, or + investigate relationships among dimensions without creating + separate datasets. + + Such flexibility is particularly useful during exploratory + analysis, where researchers often need to test hypotheses and + evaluate different combinations of variables before deciding on + a final interpretation. + + Path-Based Analysis + + In addition to general datasets, the framework supports ordered + collections of points that define trajectories or paths through + a coordinate space. These paths can represent motion, + transitions between states, interpolation routes, or user-defined + exploration trajectories. + + The path representation allows refinement of trajectories by + introducing additional intermediate positions. This capability + helps create smoother paths, improve sampling density, and + support analyses that require continuous transitions between + neighboring states. + + Outputs and Interpretation + + The resulting datasets provide structured access to coordinates, + weights, and selection information while preserving the original + relationships between points. Users can extract coordinate + distributions, analyze subsets of interest, or construct + trajectories for visualization and further computation. + + Because discarded and selected elements remain explicitly + represented, the framework supports transparent and reproducible + analysis decisions throughout the workflow. + + Practical Recommendations + + When working with exploratory datasets, it is often beneficial + to use selection states to identify candidate regions of + interest before performing more detailed analyses. Maintaining + discarded elements within the dataset can also facilitate later + reevaluation of filtering decisions. + + For trajectory-based studies, adding intermediate points may + improve visual continuity and provide a more accurate + representation of gradual transitions between neighboring + states. + + Final Perspective + + The framework provides a flexible foundation for managing + multidimensional point collections and ordered trajectories. + By combining coordinate storage, state management, weighting, + and path handling within a unified structure, it supports a + broad range of visualization, exploration, and analytical + workflows while preserving the integrity and interpretability + of the underlying data. +""" def rowToMode(row): @@ -56,11 +171,80 @@ def modeToRow(mode, row): """ Write the MetaData row from a given NormalMode object. """ row.setValue(MDL_ORDER, int(mode.getObjId())) objectToRow(mode, row, MODE_DICT) - - + + def getNMAEnviron(): """ Create the needed environment for NMA programs. """ - from xmipp3 import Plugin + from continuousflex import Plugin environ = Plugin.getEnviron() environ.update({'PATH': Plugin.getVar(NMA_HOME)}, position=Environ.BEGIN) + environ.update({'LD_LIBRARY_PATH': Plugin.getCondaLibPath()}, position=Environ.BEGIN) return environ + + +def eulerAngles2matrix(alpha, beta, gamma, shiftx, shifty, shiftz): + A = np.empty([4, 4]) + A.fill(2) + A[3, 3] = 1 + A[3, 0:3] = 0 + A[0, 3] = float(shiftx) + A[1, 3] = float(shifty) + A[2, 3] = float(shiftz) + alpha = float(alpha) + beta = float(beta) + gamma = float(gamma) + sa = np.sin(np.deg2rad(alpha)) + ca = np.cos(np.deg2rad(alpha)) + sb = np.sin(np.deg2rad(beta)) + cb = np.cos(np.deg2rad(beta)) + sg = np.sin(np.deg2rad(gamma)) + cg = np.cos(np.deg2rad(gamma)) + cc = cb * ca + cs = cb * sa + sc = sb * ca + ss = sb * sa + A[0, 0] = cg * cc - sg * sa + A[0, 1] = cg * cs + sg * ca + A[0, 2] = -cg * sb + A[1, 0] = -sg * cc - cg * sa + A[1, 1] = -sg * cs + cg * ca + A[1, 2] = sg * sb + A[2, 0] = sc + A[2, 1] = ss + A[2, 2] = cb + return A + + +def matrix2eulerAngles(A): + abs_sb = np.sqrt(A[0, 2] * A[0, 2] + A[1, 2] * A[1, 2]) + if (abs_sb > 16 * np.exp(-5)): + gamma = math.atan2(A[1, 2], -A[0, 2]) + alpha = math.atan2(A[2, 1], A[2, 0]) + if (abs(np.sin(gamma)) < np.exp(-5)): + sign_sb = np.sign(-A[0, 2] / np.cos(gamma)) + else: + if np.sin(gamma) > 0: + sign_sb = np.sign(A[1, 2]) + else: + sign_sb = -np.sign(A[1, 2]) + beta = math.atan2(sign_sb * abs_sb, A[2, 2]) + else: + if (np.sign(A[2, 2]) > 0): + alpha = 0 + beta = 0 + gamma = math.atan2(-A[1, 0], A[0, 0]) + else: + alpha = 0 + beta = np.pi + gamma = math.atan2(A[1, 0], -A[0, 0]) + gamma = np.rad2deg(gamma) + beta = np.rad2deg(beta) + alpha = np.rad2deg(alpha) + return alpha, beta, gamma, A[0, 3], A[1, 3], A[2, 3] + + +def l2(Vec1, Vec2): + Vec1 = np.array(Vec1) + Vec2 = np.array(Vec2) + value = np.inner(Vec1 - Vec2, Vec1 - Vec2) + return np.sqrt(value) diff --git a/continuousflex/protocols/data.py b/continuousflex/protocols/data.py index 3f9186a..a30571c 100644 --- a/continuousflex/protocols/data.py +++ b/continuousflex/protocols/data.py @@ -30,8 +30,121 @@ class Point: - """ Return x, y 2d coordinates and some other properties - such as weight and state. + """ + Represents a point within a multidimensional dataset together with + its associated metadata, including spatial coordinates, weight, and + selection status. The class serves as the fundamental element for + managing geometric, statistical, or visualization-oriented data in + interactive analysis workflows. + + AI Generated: + + Point and Data Management (Point) - User Manual + Overview + + The Point protocol provides a framework for representing, + organizing, and manipulating collections of multidimensional + points. Its primary purpose is to support analytical and + visualization workflows in which individual observations are + associated with spatial coordinates and additional descriptive + properties. + + A point is more than a simple coordinate. In addition to its + position, each element may carry a numerical importance value + and a logical state describing whether it is active, selected, + or excluded from analysis. This design allows the same dataset + to support exploration, filtering, annotation, and interactive + selection without permanently modifying the original data. + + Data Organization + + The framework manages collections of points as coherent datasets. + Each dataset preserves the relationship between individual + elements while providing convenient access to coordinate values, + weights, and selection information. This organization is useful + for applications involving dimensionality reduction, clustering, + trajectory analysis, geometric measurements, or interactive + plotting environments. + + Datasets may contain two-dimensional or three-dimensional + coordinates as well as additional numerical descriptors. The + coordinate system remains consistent across all points, + facilitating comparison and interpretation of spatial patterns. + + Selection and Filtering + + A central feature of the framework is the ability to distinguish + between active, selected, and discarded elements. Selected + points can be used to define regions of interest, identify + representative observations, or support manual curation. + Discarded points remain stored within the dataset but are + excluded from standard analysis operations. + + This approach allows users to explore alternative selections + without losing information. As a result, workflows remain + flexible and reversible throughout the analysis process. + + Mathematical Exploration + + The framework supports evaluation of mathematical relationships + involving point-associated variables. This capability enables + users to derive new measurements, explore custom metrics, or + investigate relationships among dimensions without creating + separate datasets. + + Such flexibility is particularly useful during exploratory + analysis, where researchers often need to test hypotheses and + evaluate different combinations of variables before deciding on + a final interpretation. + + Path-Based Analysis + + In addition to general datasets, the framework supports ordered + collections of points that define trajectories or paths through + a coordinate space. These paths can represent motion, + transitions between states, interpolation routes, or user-defined + exploration trajectories. + + The path representation allows refinement of trajectories by + introducing additional intermediate positions. This capability + helps create smoother paths, improve sampling density, and + support analyses that require continuous transitions between + neighboring states. + + Outputs and Interpretation + + The resulting datasets provide structured access to coordinates, + weights, and selection information while preserving the original + relationships between points. Users can extract coordinate + distributions, analyze subsets of interest, or construct + trajectories for visualization and further computation. + + Because discarded and selected elements remain explicitly + represented, the framework supports transparent and reproducible + analysis decisions throughout the workflow. + + Practical Recommendations + + When working with exploratory datasets, it is often beneficial + to use selection states to identify candidate regions of + interest before performing more detailed analyses. Maintaining + discarded elements within the dataset can also facilitate later + reevaluation of filtering decisions. + + For trajectory-based studies, adding intermediate points may + improve visual continuity and provide a more accurate + representation of gradual transitions between neighboring + states. + + Final Perspective + + The framework provides a flexible foundation for managing + multidimensional point collections and ordered trajectories. + By combining coordinate storage, state management, weighting, + and path handling within a unified structure, it supports a + broad range of visualization, exploration, and analytical + workflows while preserving the integrity and interpretability + of the underlying data. """ # Selection states DISCARDED = -1 diff --git a/continuousflex/protocols/pdb/__init__.py b/continuousflex/protocols/pdb/__init__.py index 8c40192..4a28638 100644 --- a/continuousflex/protocols/pdb/__init__.py +++ b/continuousflex/protocols/pdb/__init__.py @@ -24,8 +24,6 @@ # * # ************************************************************************** -from .protocol_convert_pdb import FlexProtConvertPdb -#from .protocol_combine_pdb import FlexProtCombinePdb from .protocol_pseudoatoms import FlexProtConvertToPseudoAtoms from .protocol_pseudoatoms_base import FlexProtConvertToPseudoAtomsBase diff --git a/continuousflex/protocols/pdb/protocol_convert_pdb.py b/continuousflex/protocols/pdb/protocol_convert_pdb.py deleted file mode 100644 index e829e22..0000000 --- a/continuousflex/protocols/pdb/protocol_convert_pdb.py +++ /dev/null @@ -1,172 +0,0 @@ -# -*- coding: utf-8 -*- -# ************************************************************************** -# * -# * Authors: Jesus Cuenca (jcuenca@cnb.csic.es) -# * Roberto Marabini (rmarabini@cnb.csic.es) -# * Ignacio Foche -# * Slavica Jonic (jonic@impmc.upmc.fr) -# * -# * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC -# * -# * This program is free software; you can redistribute it and/or modify -# * it under the terms of the GNU General Public License as published by -# * the Free Software Foundation; either version 2 of the License, or -# * (at your option) any later version. -# * -# * This program is distributed in the hope that it will be useful, -# * but WITHOUT ANY WARRANTY; without even the implied warranty of -# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# * GNU General Public License for more details. -# * -# * You should have received a copy of the GNU General Public License -# * along with this program; if not, write to the Free Software -# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -# * 02111-1307 USA -# * -# * All comments concerning this program package may be sent to the -# * e-mail address 'scipion@cnb.csic.es' -# * -# ************************************************************************** - -import os, ftplib, gzip -import sys - -import pyworkflow.protocol.params as params -import pyworkflow.protocol.constants as const -import pwem as em -from pwem.convert.atom_struct import cifToPdb -from pyworkflow.utils import replaceBaseExt, removeExt, getExt - - -class FlexProtConvertPdb(em.protocols.ProtInitialVolume): - """ Convert a PDB file into a volume. """ - _label = 'convert a PDB' - IMPORT_FROM_ID = 0 - IMPORT_OBJ = 1 - IMPORT_FROM_FILES = 2 - - #--------------------------- DEFINE param functions -------------------------------------------- - def _defineParams(self, form): - """ Define the parameters that will be input for the Protocol. - This definition is also used to generate automatically the GUI. - """ - form.addSection(label='Input') - form.addParam('inputPdbData', params.EnumParam, choices=['id', 'object', 'file'], - label="Retrieve PDB from", default=self.IMPORT_FROM_ID, - display=params.EnumParam.DISPLAY_HLIST, - help='Retrieve PDB data from server, use a pdb Object, or a local file') - form.addParam('pdbId', params.StringParam, condition='inputPdbData == IMPORT_FROM_ID', - label="Pdb Id ", allowsNull=True, - help='Type a pdb Id (four alphanumeric characters).') - form.addParam('pdbObj', params.PointerParam, pointerClass='AtomStruct', - label="Input pdb ", condition='inputPdbData == IMPORT_OBJ', allowsNull=True, - help='Specify a pdb object.') - form.addParam('pdbFile', params.FileParam, - label="File path", condition='inputPdbData == IMPORT_FROM_FILES', allowsNull=True, - help='Specify a path to desired PDB structure.') - form.addParam('sampling', params.FloatParam, default=1.0, - label="Sampling rate (Å/px)", - help='Sampling rate (Angstroms/pixel)') - form.addParam('setSize', params.BooleanParam, label='Set final size?', default=False) - form.addParam('size', params.IntParam, condition='setSize', allowsNull=True, - label="Final size (px)", - help='Final size in pixels. If no value is provided, protocol will estimate it.') - form.addParam('centerPdb', params.BooleanParam, default=True, - expertLevel=const.LEVEL_ADVANCED, - label="Center PDB", - help='Center PDB with the center of mass') - - #--------------------------- INSERT steps functions -------------------------------------------- - def _insertAllSteps(self): - """ In this function the steps that are going to be executed should - be defined. Two of the most used functions are: _insertFunctionStep or _insertRunJobStep - """ - if self.inputPdbData == self.IMPORT_FROM_ID: - self._insertFunctionStep('pdbDownloadStep') - self._insertFunctionStep('convertPdbStep') - self._insertFunctionStep('createOutput') - - #--------------------------- STEPS functions -------------------------------------------- - def pdbDownloadStep(self): - """Download all pdb files in file_list and unzip them.""" - em.downloadPdb(self.pdbId.get(), self._getPdbFileName(), self._log) - - def convertPdbStep(self): - """ Although is not mandatory, usually is used by the protocol to - register the resulting outputs in the database. - """ - pdbFn = self._getPdbFileName() - outFile = removeExt(self._getVolName()) - if getExt(pdbFn)==".cif": - pdbFn2=replaceBaseExt(pdbFn, 'pdb') - cifToPdb(pdbFn, pdbFn2) - pdbFn = pdbFn2 - - args = '-i %s --sampling %f -o %s' % (pdbFn, self.sampling.get(), outFile) - - if self.centerPdb: - args += ' --centerPDB' - - if self.setSize: - args += ' --size' - - if self.size.hasValue(): - args += ' %d' % self.size.get() - - self.info("Input file: " + pdbFn) - self.info("Output file: " +outFile) - - program = "xmipp_volume_from_pdb" - self.runJob(program, args) - - def createOutput(self): - volume = em.Volume() - volume.setSamplingRate(self.sampling.get()) - volume.setFileName(self._getVolName()) - self._defineOutputs(outputVolume=volume) - if self.inputPdbData == self.IMPORT_OBJ: - self._defineSourceRelation(self.pdbObj, volume) - - #--------------------------- INFO functions -------------------------------------------- - def _summary(self): - """ Even if the full set of parameters is available, this function provides - summary information about an specific run. - """ - summary = [ ] - # Add some lines of summary information - if not hasattr(self, 'outputVolume'): - summary.append("outputVolume not ready yet.") - else: - if self.inputPdbData == self.IMPORT_FROM_ID: - summary.append("Input PDB ID: %s" % self.pdbId.get()) - elif self.inputPdbData == self.IMPORT_OBJ: - summary.append("Input PDB File: %s" % self.pdbObj.get().getFileName()) - else: - summary.append("Input PDB File: %s" % self.pdbFile.get()) - return summary - - def _validate(self): - """ The function of this hook is to add some validation before the protocol - is launched to be executed. It should return a list of errors. If the list is - empty the protocol can be executed. - """ - errors = [] - if self.inputPdbData == self.IMPORT_FROM_ID: - lenStr = len(self.pdbId.get()) - if lenStr != 4: - errors = ["Pdb id is composed only by four alphanumeric characters"] - - return errors - - #--------------------------- UTLIS functions -------------------------------------------- - def _getPdbFileName(self): - if self.inputPdbData == self.IMPORT_FROM_ID: - return self._getExtraPath('%s.cif' % self.pdbId.get()) - elif self.inputPdbData == self.IMPORT_OBJ: - return self.pdbObj.get().getFileName() - else: - return self.pdbFile.get() - - def _getVolName(self): - return self._getExtraPath(replaceBaseExt(self._getPdbFileName(), "vol")) - diff --git a/continuousflex/protocols/pdb/protocol_pseudoatoms_base.py b/continuousflex/protocols/pdb/protocol_pseudoatoms_base.py index ce2b7b6..065423e 100644 --- a/continuousflex/protocols/pdb/protocol_pseudoatoms_base.py +++ b/continuousflex/protocols/pdb/protocol_pseudoatoms_base.py @@ -37,6 +37,7 @@ from pwem.protocols import Prot3D #this is not an error from pwem.viewers.viewer_chimera import Chimera from xmipp3.convert import getImageLocation +from pwem import Domain NMA_MASK_NONE = 0 @@ -85,7 +86,7 @@ def _insertMaskStep(self, fnVol, prefix=''): fnMask = self._getExtraPath('mask%s.vol' % prefix) maskParams = '-i %s -o %s --select below %f --substitute binarize'\ % (fnVol, fnMask, self.maskThreshold.get()) - self._insertRunJobStep('xmipp_transform_threshold', maskParams) + self.runJob("xmipp_transform_threshold", maskParams, env=Domain.importFromPlugin('xmipp3').Plugin.getEnviron()) elif self.maskMode == NMA_MASK_FILE: fnMask = getImageLocation(self.volumeMask.get()) return fnMask @@ -106,17 +107,17 @@ def convertToPseudoAtomsStep(self, inputFn, fnMask, sampling, prefix=''): "-v 2 --intensityColumn Bfactor" if fnMask: params += " --mask binary_file %(fnMask)s" - self.runJob("xmipp_volume_to_pseudoatoms", params % locals()) + self.runJob("xmipp_volume_to_pseudoatoms", params % locals(), env=Domain.importFromPlugin('xmipp3').Plugin.getEnviron()) for suffix in ["_approximation.vol", "_distance.hist"]: moveFile(self._getPath(pseudoatoms + suffix), self._getExtraPath(pseudoatoms + suffix)) self.runJob("xmipp_image_convert", "-i %s_approximation.vol -o %s_approximation.mrc -t vol" % (self._getExtraPath(pseudoatoms), - self._getExtraPath(pseudoatoms))) + self._getExtraPath(pseudoatoms)), env=Domain.importFromPlugin('xmipp3').Plugin.getEnviron()) self.runJob("xmipp_image_header", "-i %s_approximation.mrc --sampling_rate %f" % - (self._getExtraPath(pseudoatoms), sampling)) + (self._getExtraPath(pseudoatoms), sampling),env=Domain.importFromPlugin('xmipp3').Plugin.getEnviron()) cleanPattern(self._getPath(pseudoatoms + '_*')) def createChimeraScript(self, volume, pdb): diff --git a/continuousflex/protocols/protocol_align_pdbs.py b/continuousflex/protocols/protocol_align_pdbs.py new file mode 100644 index 0000000..7c641dd --- /dev/null +++ b/continuousflex/protocols/protocol_align_pdbs.py @@ -0,0 +1,440 @@ +# ************************************************************************** +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) +# * Remi Vuillemot (remi.vuillemot@upmc.fr) +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +from pyworkflow.protocol.params import (PointerParam, EnumParam, IntParam) +from pwem.protocols import ProtAnalysis3D +from pyworkflow.protocol import params +from continuousflex.protocols.utilities.genesis_utilities import numpyArr2dcd, dcd2numpyArr +from .utilities.pdb_handler import ContinuousFlexPDBHandler +from pwem.objects import AtomStruct, SetOfParticles, SetOfVolumes +from xmipp3.convert import writeSetOfVolumes, writeSetOfParticles, readSetOfVolumes, readSetOfParticles +from pwem.constants import ALIGN_PROJ +from continuousflex.protocols.convert import matrix2eulerAngles + +import numpy as np +import glob +import pwem.emlib.metadata as md + +PDB_SOURCE_PATTERN = 0 +PDB_SOURCE_OBJECT = 1 +PDB_SOURCE_TRAJECT = 2 + +MATCHING_PDB_NONE = 0 +MATCHING_PDB_CHAIN = 1 +MATCHING_PDB_SEG = 2 + +class FlexProtAlignPdb(ProtAnalysis3D): + """ + Performs rigid-body alignment of atomic structures represented as + PDB files or molecular dynamics trajectories. The protocol places + multiple structural conformations into a common coordinate system, + enabling direct structural comparison, visualization, variability + analysis, and integration with downstream cryo-EM or structural + biology workflows. + + AI Generated: + + PDB Rigid Body Alignment (FlexProtAlignPdb) - User Manual + Overview + + The PDB Rigid Body Alignment protocol aligns a collection of + atomic structures to a selected reference structure using + rigid-body transformations. Its primary objective is to remove + differences caused by overall rotation and translation so that + biologically meaningful conformational variations can be studied + in a consistent spatial frame. + + In structural biology projects, ensembles of structures may + originate from molecular dynamics simulations, normal mode + analyses, flexible fitting procedures, integrative modeling, or + collections of experimentally determined conformations. Before + these structures can be compared quantitatively, they must be + expressed within a common coordinate system. This protocol + provides that standardization step and facilitates subsequent + analyses focused on molecular flexibility and structural + heterogeneity. + + Inputs and General Workflow + + The protocol accepts structural data from several sources. Users + may provide a collection of PDB files, an existing set of + atomic structures stored within a project, or molecular dynamics + trajectory files accompanied by an appropriate structural + reference. This flexibility allows the protocol to be used both + for static structural ensembles and for large conformational + trajectories. + + A reference structure is required to define the target + coordinate system. All input conformations are aligned against + this reference so that equivalent structural regions occupy the + same spatial frame. Choosing a biologically representative and + well-curated reference generally improves the interpretability + of the resulting aligned ensemble. + + Structural Correspondence Between Models + + One of the most important considerations when aligning atomic + structures is determining which atoms should be considered + equivalent between the reference and the input structures. In + simple cases, all structures may already share identical atom + ordering and composition, allowing direct alignment. + + More complex datasets may contain differences in atom ordering, + chain organization, or segmentation conventions. The protocol + supports correspondence strategies based on chain identity or + segment identity together with residue numbering. These options + help ensure that equivalent biological regions are compared even + when file organization differs between structures. + + From a biological perspective, careful correspondence selection + is critical. Incorrect matching can produce alignments that are + geometrically valid but biologically meaningless. + + Working with Molecular Dynamics Trajectories + + The protocol is particularly useful for molecular dynamics + studies where thousands of conformations may be generated during + a simulation. In these situations, users can analyze only a + selected portion of the trajectory by specifying a starting + frame, ending frame, and sampling interval. + + This capability allows researchers to focus on equilibrated + regions of a simulation, reduce computational cost, or study + specific conformational transitions. Sampling trajectories at + regular intervals is often sufficient to capture large-scale + motions while avoiding unnecessary redundancy. + + Alignment and Biological Interpretation + + Rigid-body alignment removes global motion while preserving + internal structural differences. As a result, conformational + changes observed after alignment are more likely to reflect + biologically relevant flexibility rather than arbitrary + differences in molecular orientation. + + This distinction is particularly important when studying domain + movements, allosteric transitions, hinge motions, or ensemble + variability. By eliminating overall translation and rotation, + researchers can focus on the structural changes that are most + relevant to biological function. + + Outputs and Their Interpretation + + The protocol produces an aligned structural ensemble expressed + in the coordinate system of the selected reference. The aligned + structures can be inspected visually, used for statistical + analyses, or incorporated into additional flexibility studies. + + Alignment parameters describing the rigid-body transformations + are also generated. These transformations provide a compact + representation of the spatial relationship between each + conformation and the reference structure. + + Optional Application to Other Data + + In many cryo-EM and integrative structural biology workflows, + structural models are associated with other experimental data + such as particle images or reconstructed volumes. The protocol + can propagate the computed rigid-body transformations to these + associated datasets, ensuring that all related information is + represented within a consistent coordinate system. + + This capability is particularly useful when combining atomic + models with volumetric maps, subtomograms, or particle datasets, + allowing structural and imaging information to remain + synchronized throughout subsequent analyses. + + Practical Recommendations + + For most applications, users should select a reference + structure that represents the dominant or most biologically + relevant conformation. When structures originate from different + sources or processing pipelines, verifying atom correspondence + before alignment is strongly recommended. + + For molecular dynamics trajectories, it is often beneficial to + exclude non-equilibrated regions and analyze representative + frames. When large conformational changes are expected, visual + inspection of the aligned ensemble can help distinguish genuine + biological motions from artifacts arising from incomplete atom + correspondence. + + Final Perspective + + Rigid-body alignment is a foundational step in the analysis of + structural ensembles. By placing all conformations into a common + spatial frame, the protocol enables meaningful comparison of + molecular states, supports quantitative studies of flexibility, + and facilitates integration between atomic models and cryo-EM + data. Careful selection of the reference structure and proper + definition of atomic correspondence are the key factors for + obtaining biologically reliable results. + """ + _label = 'pdbs rigid body alignment' + + # --------------------------- DEFINE param functions -------------------------------------------- + def _defineParams(self, form): + form.addSection(label='Input') + form.addParam('pdbSource', EnumParam, default=PDB_SOURCE_PATTERN, + label='Source of PDBs', + choices=['File pattern', 'Object', 'Trajectory Files'], + help='Use the file pattern as file location with /*.pdb') + form.addParam('pdbs_file', params.PathParam, + condition='pdbSource == %i'%PDB_SOURCE_PATTERN, + label="List of PDBs", + help='Use the file pattern as file location with /*.pdb') + form.addParam('setOfPDBs', params.PointerParam, pointerClass='SetOfPDBs, SetOfAtomStructs', + condition='pdbSource == %i'%PDB_SOURCE_OBJECT, + label="Set of PDBs", + help='Use a scipion object SetOfPDBs / SetOfAtomStructs') + form.addParam('dcds_file', params.PathParam, + condition='pdbSource == %i'%PDB_SOURCE_TRAJECT, + label="DCD trajectory file (s)", + help='Use the file pattern as file location with /*.dcd') + form.addParam('dcd_ref_pdb', params.PointerParam, pointerClass='AtomStruct', + condition='pdbSource == %i'%PDB_SOURCE_TRAJECT, + label="trajectory Reference PDB", + help='Reference PDB of the trajectory (Only used for structural information (Atom name, residue number etc)' + '. The coordinates inside this PDB are not used. The atoms number and position in the file must' + ' correspond to the DCD file. ') + form.addParam('dcd_start', params.IntParam, default=0, + condition='pdbSource == %i'%PDB_SOURCE_TRAJECT, + label="Beginning of the trajectory", + help='Index of the desired begining of the trajectory', expertLevel=params.LEVEL_ADVANCED) + form.addParam('dcd_end', params.IntParam, default=-1, + condition='pdbSource == %i'%PDB_SOURCE_TRAJECT, + label="Ending of the trajectory", + help='Index of the desired end of the trajectory', expertLevel=params.LEVEL_ADVANCED) + form.addParam('dcd_step', params.IntParam, default=1, + condition='pdbSource == %i'%PDB_SOURCE_TRAJECT, + label="Step of the trajectory", + help='Step to skip points in the trajectory', expertLevel=params.LEVEL_ADVANCED) + + form.addParam('alignRefPDB', params.PointerParam, pointerClass='AtomStruct', + label="Alignment Reference PDB", + help='Reference PDB to align the PDBs with') + form.addParam('matchingType', params.EnumParam, label="Match PDBs and reference PDB ?", default=MATCHING_PDB_NONE, + choices=['All PDBs are matching', 'Match chain name + residue no', + 'Match segment name + residue no'], + help="Method to find atomic coordinates correspondence between the pdb set " + "coordinates and the reference PDB. The method will select the matching atoms" + " and sort them in the corresponding order. If the structures in the files are" + " already matching, choose All structures are matching") + + form.addParam('createOutput', params.BooleanParam, default=True, + label="Create output Set of PDBs ?", + help='Create output set. This step can be time consuming and not necessary if you are only ' + ' interested by the alignment parameters. The aligned coordinate are conserved as DCD file ' + 'in the extra directory.' + , expertLevel=params.LEVEL_ADVANCED) + + form.addSection(label='Apply alignment to other set') + form.addParam('applyAlignment', params.BooleanParam, default=False, + label="Apply alignment to other data set ?", + help='Use the PDB alignment to align another data set.') + form.addParam('otherSet', params.PointerParam, pointerClass='SetOfParticles, SetOfVolumes', + condition='applyAlignment', + label="Other set of Particles / Volumes", + help='Use a scipion EMSet object') + + + + # --------------------------- INSERT steps functions -------------------------------------------- + def _insertAllSteps(self): + self._insertFunctionStep('readInputFiles') + self._insertFunctionStep('rigidBodyAlignmentStep') + if self.applyAlignment.get(): + self._insertFunctionStep('applyAlignmentStep') + if self.createOutput.get(): + self._insertFunctionStep('createOutputStep') + + # --------------------------- STEPS functions -------------------------------------------- + def readInputFiles(self): + inputFiles = self.getInputFiles() + + # Get pdbs coordinates + if self.pdbSource.get() == PDB_SOURCE_TRAJECT: + pdbs_arr = dcd2numpyArr(inputFiles[0]) + start = self.dcd_start.get() + step = self.dcd_step.get() + end = self.dcd_end.get() if self.dcd_end.get() != -1 else pdbs_arr.shape[0] + pdbs_arr = pdbs_arr[start:end:step] + for i in range(1,len(inputFiles)): + pdb_arr_i = dcd2numpyArr(inputFiles[i]) + pdbs_arr = np.concatenate((pdbs_arr, pdb_arr_i[start:end:step]), axis=0) + + else: + pdbs_matrix = [] + for pdbfn in inputFiles: + try: + # Read PDBs + mol = ContinuousFlexPDBHandler(pdbfn) + pdbs_matrix.append(mol.coords) + except RuntimeError: + print("Warning : Can not read PDB file %s " % pdbfn) + pdbs_arr = np.array(pdbs_matrix) + + # save as dcd file + numpyArr2dcd(pdbs_arr, self._getExtraPath("coords.dcd")) + + def rigidBodyAlignmentStep(self): + + # open files + inputPDB = ContinuousFlexPDBHandler(self.getPDBRef()) + inputPDB.write_pdb(self._getExtraPath("reference.pdb")) + refPDB = ContinuousFlexPDBHandler(self.alignRefPDB.get().getFileName()) + arrDCD = dcd2numpyArr(self._getExtraPath("coords.dcd")) + nframe, natom,_ =arrDCD.shape + alignXMD = md.MetaData() + + # find matching index between reference and pdbs + if self.matchingType.get() == MATCHING_PDB_CHAIN: + idx_matching_atoms = inputPDB.matchPDBatoms(reference_pdb=refPDB, matchingType=0) + refPDB.select_atoms(idx_matching_atoms[:, 1]) + elif self.matchingType.get() == MATCHING_PDB_SEG: + idx_matching_atoms = inputPDB.matchPDBatoms(reference_pdb=refPDB, matchingType=1) + refPDB.select_atoms(idx_matching_atoms[:, 1]) + else: + idx_matching_atoms = None + + # loop over all pdbs + for i in range(nframe): + print("Aligning PDB %i ... " %i) + + # rotate + if self.matchingType.get() != MATCHING_PDB_NONE : + coord = arrDCD[i][idx_matching_atoms[:, 0]] + else: + coord = arrDCD[i] + rot_mat, tran = ContinuousFlexPDBHandler.alignCoords(refPDB.coords, coord) + arrDCD[i] = (np.dot(arrDCD[i], rot_mat) + tran).astype(np.float32) + + # add to MD + trans_mat = np.zeros((4,4)) + trans_mat[:3,:3] = rot_mat + trans_mat[:,3][:3] = tran + rot, tilt, psi,shftx, shfty, shftz = matrix2eulerAngles(trans_mat) + index = alignXMD.addObject() + alignXMD.setValue(md.MDL_ANGLE_ROT, rot, index) + alignXMD.setValue(md.MDL_ANGLE_TILT, tilt, index) + alignXMD.setValue(md.MDL_ANGLE_PSI, psi, index) + alignXMD.setValue(md.MDL_SHIFT_X, shftx, index) + alignXMD.setValue(md.MDL_SHIFT_Y, shfty, index) + alignXMD.setValue(md.MDL_SHIFT_Z, shftz, index) + alignXMD.setValue(md.MDL_IMAGE, "", index) + + numpyArr2dcd(arrDCD, self._getExtraPath("coords.dcd")) + alignXMD.write(self._getExtraPath("alignment.xmd")) + + + def createOutputStep(self): + pdbset = self._createSetOfPDBs("outputPDBs") + arrDCD = dcd2numpyArr(self._getExtraPath("coords.dcd")) + refPDB = ContinuousFlexPDBHandler(self.getPDBRef()) + + nframe, natom,_ = arrDCD.shape + for i in range(nframe): + filename = self._getExtraPath("output_%s.pdb" %str(i+1).zfill(6)) + refPDB.coords = arrDCD[i] + refPDB.write_pdb(filename) + pdb = AtomStruct(filename=filename) + pdbset.append(pdb) + + self._defineOutputs(outputPDBs=pdbset) + + def applyAlignmentStep(self): + inputSet = self.otherSet.get() + + if isinstance(inputSet, SetOfVolumes): + inputAlignment = self._createSetOfVolumes("inputAlignment") + readSetOfVolumes(self._getExtraPath("alignment.xmd"), inputAlignment) + alignedSet = self._createSetOfVolumes("alignedSet") + else: + inputAlignment = self._createSetOfParticles("inputAlignment") + alignedSet = self._createSetOfParticles("alignedSet") + readSetOfParticles(self._getExtraPath("alignment.xmd"), inputAlignment) + + alignedSet.setSamplingRate(inputSet.getSamplingRate()) + alignedSet.setAlignment(ALIGN_PROJ) + iter1 = inputSet.iterItems() + iter2 = inputAlignment.iterItems() + for i in range(inputSet.getSize()): + p1 = iter1.__next__() + p2 = iter2.__next__() + r1 = p1.getTransform() + r2 = p2.getTransform() + rot = r2.getRotationMatrix() + tran = np.array(r2.getShifts()) / inputSet.getSamplingRate() + new_trans = np.zeros((4, 4)) + new_trans[:3, 3] = tran + new_trans[:3, :3] = rot + new_trans[3, 3] = 1.0 + r1.composeTransform(new_trans) + p1.setTransform(r1) + alignedSet.append(p1) + self._defineOutputs(alignedSet = alignedSet) + + if isinstance(inputSet, SetOfVolumes): + writeSetOfVolumes(alignedSet, self._getExtraPath("alignedSet.xmd")) + else: + writeSetOfParticles(alignedSet, self._getExtraPath("alignedSet.xmd")) + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['harastani2022continuousflex'] + + def _methods(self): + pass + + # --------------------------- UTILS functions -------------------------------------------- + def _printWarnings(self, *lines): + """ Print some warning lines to 'warnings.xmd', + the function should be called inside the working dir.""" + fWarn = open("warnings.xmd", 'w') + for l in lines: + print >> fWarn, l + fWarn.close() + + def getInputFiles(self): + if self.pdbSource.get()==PDB_SOURCE_PATTERN: + l= [f for f in glob.glob(self.pdbs_file.get())] + elif self.pdbSource.get()==PDB_SOURCE_OBJECT: + l= [i.getFileName() for i in self.setOfPDBs.get()] + elif self.pdbSource.get()==PDB_SOURCE_TRAJECT: + l= [f for f in glob.glob(self.dcds_file.get())] + l.sort() + return l + + def getPDBRef(self): + if self.pdbSource.get()==PDB_SOURCE_TRAJECT: + return self.dcd_ref_pdb.get().getFileName() + else: + return self.getInputFiles()[0] diff --git a/continuousflex/protocols/protocol_apply_volumeset_alignment.py b/continuousflex/protocols/protocol_apply_volumeset_alignment.py index 002c81b..50e7a7d 100644 --- a/continuousflex/protocols/protocol_apply_volumeset_alignment.py +++ b/continuousflex/protocols/protocol_apply_volumeset_alignment.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -28,102 +28,387 @@ from pyworkflow.utils.path import makePath, copyFile from os.path import basename from pwem.utils import runProgram +from os.path import exists, basename, abspath, relpath, join, splitext +import pwem.objects as emobj +from xmipp3.convert import writeSetOfVolumes, readSetOfVolumes +from .convert import eulerAngles2matrix, matrix2eulerAngles +import numpy as np +from pyworkflow.utils.path import makePath, copyFile +import json +from ast import literal_eval as make_tuple +import os +from pwem.constants import ALIGN_3D + +class FlexProtApplyVolSetAlignment(ProtAnalysis3D): + """ + Applies subtomogram alignment parameters obtained from external + subtomogram averaging workflows to a set of 3D volumes. The protocol + standardizes the spatial orientation of subtomograms so they can be + consistently interpreted, compared, visualized, or used in downstream + structural analysis. + AI Generated: -REFERENCE_EXT = 0 -REFERENCE_STA = 1 + Apply Subtomogram Alignment (FlexProtApplyVolSetAlignment) - User Manual + Overview + The Apply Subtomogram Alignment protocol transfers alignment + parameters generated during subtomogram averaging workflows onto + individual subtomograms or reconstructed volumes. Its main purpose + is to place all input volumes into a common spatial reference frame + so that structural variability, conformational organization, or + biological patterns can be studied consistently across a dataset. -class FlexProtApplyVolSetAlignment(ProtAnalysis3D): - """ Protocol for subtomogram alignment after STA """ + In cryo-electron tomography workflows, subtomograms are often + aligned using external software packages specialized in subtomogram + averaging and refinement. However, the resulting transformations are + not always directly applied to the original volumes within the same + environment. This protocol bridges that gap by importing alignment + information from several commonly used tomography platforms and + applying those transformations to the input data. + + Biological Context + + For biological users, subtomogram alignment is essential when + studying macromolecular complexes in their native cellular + environment. Proper alignment enables direct comparison of + structures extracted from different cellular regions, experimental + conditions, or conformational states. Without a consistent spatial + orientation, biological interpretation becomes difficult because + structural variability may reflect geometric inconsistency rather + than genuine molecular differences. + + This protocol is particularly useful after subtomogram averaging + refinement, where the averaging software has already estimated the + orientation and position of each subtomogram relative to a + consensus structure. Applying these alignments back onto the + original subtomograms allows users to visualize aligned particles, + perform focused analyses, generate curated datasets, or prepare + inputs for classification and heterogeneity studies. + + Supported Alignment Sources + + The protocol supports importing alignment information from several + major tomography processing ecosystems. This flexibility is valuable + in collaborative environments where datasets may originate from + different facilities or processing pipelines. + + Xmipp alignment metadata can be imported directly from metadata + files containing rotational and translational parameters. This mode + is particularly convenient for users already working within Scipion + and Xmipp-based tomography workflows. + + EMAN alignment information can also be imported from refinement + metadata generated during subtomogram alignment procedures. This + allows users to continue processing EMAN-refined datasets within a + unified analysis environment. + + Dynamo tables are additionally supported, enabling integration with + Dynamo-based subtomogram averaging projects. This is especially + important for users studying large in situ assemblies where Dynamo + remains a widely adopted refinement platform. + + The protocol is designed with extensibility in mind so that + additional tomography alignment formats may be incorporated into + future workflows. + + Input Requirements and Consistency + + The protocol requires a set of input subtomograms together with + alignment parameters describing their orientations and positional + shifts. The number of alignment records must match the number of + input volumes to ensure that every subtomogram receives the correct + transformation. + + From a biological perspective, maintaining consistency between the + alignment metadata and the subtomogram dataset is critical. Applying + transformations to mismatched particles can generate misleading + structural interpretations and compromise downstream analyses. + + Ideally, the subtomograms should already share a consistent voxel + size and box dimensions before alignment application. Significant + differences in sampling or volume dimensions may complicate + comparison and visualization after transformation. + + Spatial Transformations and Coordinate Systems + + The protocol applies rigid-body spatial transformations that include + rotations and translational shifts. These operations reposition each + subtomogram into a standardized orientation relative to the + alignment reference used during subtomogram averaging. + + In tomography workflows, coordinate system conventions may differ + between software packages. The protocol therefore handles the + interpretation of orientation conventions internally to ensure that + imported transformations remain biologically meaningful when applied + within the current environment. + + Particular attention is given to subtomogram orientations affected + by missing wedge geometry, since this artifact can strongly + influence alignment interpretation in cryo-electron tomography. + Correct handling of orientation conventions improves consistency + between visualization and refinement environments. + + Outputs and Biological Interpretation + + The primary output is a set of aligned subtomograms expressed in a + common coordinate frame. Once aligned, volumes become easier to + compare visually and quantitatively because corresponding structural + regions occupy consistent spatial positions. + + Biologically, aligned subtomograms can reveal conserved structural + features across particles while making conformational differences + easier to interpret. This is particularly important in studies of + flexible molecular assemblies, membrane-associated complexes, or + large cellular machineries observed directly inside cells. + + The aligned outputs can also serve as inputs for downstream + classification, averaging, dimensionality reduction, variability + analysis, or visualization workflows. Because all subtomograms share + a unified orientation, subsequent analyses become more robust and + easier to interpret biologically. + + Practical Recommendations + + In routine tomography practice, users should first verify that the + imported alignment parameters correspond exactly to the subtomogram + dataset being processed. Small inconsistencies in ordering or file + correspondence can propagate into major structural interpretation + errors. + + It is also advisable to visually inspect a subset of aligned + subtomograms after processing. Successful alignment should place + major structural landmarks into similar orientations across the + dataset. Unexpected variability may indicate problems in the + original averaging refinement, coordinate conventions, or metadata + consistency. + + When combining subtomograms refined in different software packages, + users should remain aware that alignment conventions may differ + slightly between platforms. Careful validation and visualization are + therefore recommended before proceeding to biological conclusions. + + Final Perspective + + For cryo-electron tomography studies, applying subtomogram + alignments is a crucial step that transforms independently oriented + cellular particles into a coherent structural dataset. By placing + subtomograms into a shared spatial framework, the protocol enables + more reliable structural interpretation, clearer visualization of + biological variability, and improved integration between tomography + processing environments. + """ _label = 'apply subtomogram alignment' + IMPORT_FROM_XMIPP=0 + IMPORT_FROM_EMAN=1 + IMPORT_FROM_DYNAMO=2 + IMPORT_FROM_TOMBOX=3 # --------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection(label='Input') form.addParam('inputVolumes', params.PointerParam, - pointerClass='SetOfVolumes,Volume', + pointerClass='SetOfVolumes', label="Input volume(s)", important=True, help='Select volumes') - form.addParam('AlignmentParameters', params.EnumParam, - choices=['from input file', 'from STA run'], - default=REFERENCE_EXT, - label='Alignment parameters', display=params.EnumParam.DISPLAY_COMBO, - help='either an external metadata file containing alignment parameters or STA run') - form.addParam('MetaDataFile', params.FileParam, - pointerClass='params.FileParam', allowsNull=True, - condition='AlignmentParameters==%d' % REFERENCE_EXT, - label="Alignment parameters MetaData", - help='Alignment parameters, typically from a STA previous run') - form.addParam('MetaDataSTA', params.PointerParam, - pointerClass='FlexProtSubtomogramAveraging', allowsNull=True, - condition='AlignmentParameters==%d' % REFERENCE_STA, - label="Subtomogram averaging run", - help='Alignment parameters, typically from a STA previous run') - form.addParam('angleY', params.BooleanParam, - default=True, - label='Are those parameters come from Scipion/Xmipp?', - help='If the original alignment was done on Dynamo or if the alignment was done ' - 'without missing wedge compensation, switch this to no') + + form.addParam('importFrom', params.EnumParam, default=self.IMPORT_FROM_XMIPP, + allowsNull=True, + choices=['XMIPP', 'EMAN', 'DYNAMO', 'TOMBOX'], + label='import STA alignment from', + help='Select the alignment files to apply to the volumes') + + form.addParam('xmdFile', params.FileParam, + condition='(importFrom == %d)' % self.IMPORT_FROM_XMIPP, + label='Input Xmipp Metatada file', + help="Select the XMD file containing subtomograms and alignment ") + + form.addParam('inputVolsDynamo', params.PointerParam, + condition='(importFrom == %d)' % self.IMPORT_FROM_DYNAMO, pointerClass='SetOfVolumes', + label='Input volumes', + help="Select a set of volumes") + form.addParam('dynamoTable', params.PathParam, + condition='(importFrom == %d)' % self.IMPORT_FROM_DYNAMO, + label='Dynamo Table [Beta]', + help="import a Dynamo table that contains the StA parameters. ") + + form.addParam('emanJSON', params.PathParam, allowsNull=True, + condition='importFrom==%d' % self.IMPORT_FROM_EMAN, + label='Import a JSON file from EMAN [Beta]', + help='import a JSON file that contains the STA parameters. ') # --------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): # Define some outputs filenames - self.imgsFn = self._getExtraPath('volumes.xmd') - self._insertFunctionStep('convertInputStep') - self._insertFunctionStep('prepareMetaData') self._insertFunctionStep('applyAlignment') self._insertFunctionStep('createOutputStep') # --------------------------- STEPS functions -------------------------------------------- def convertInputStep(self): - # Write a metadata with the volumes - xmipp3.convert.writeSetOfVolumes(self.inputVolumes.get(), self._getExtraPath('input.xmd')) + if self.importFrom == self.IMPORT_FROM_XMIPP: + volSet = self.inputFromXmipp() + elif self.importFrom == self.IMPORT_FROM_EMAN: + volSet = self.inputFromEman() + elif self.importFrom == self.IMPORT_FROM_DYNAMO: + volSet = self.inputFromDynamo() + elif self.importFrom == self.IMPORT_FROM_TOMBOX: + volSet = self.inputFromTombox() + else: + raise NotImplementedError("") - def prepareMetaData(self): - tempdir = self._getTmpPath() - imgFn = self.imgsFn - AlignmentParameters = self.AlignmentParameters.get() - MetaDataFile = self.MetaDataFile.get() - if AlignmentParameters == REFERENCE_STA: - MetaDataSTA = self.MetaDataSTA.get()._getExtraPath('final_md.xmd') - MetaDataFile = MetaDataSTA - copyFile(MetaDataFile,imgFn) - - mdImgs = md.MetaData(imgFn) - # in case of metadata from an external file, it has to be updated with the proper filenames from 'input.xmd' - inputSet = self.inputVolumes.get() + inputVols = self.inputVolumes.get() + + if inputVols.getSize() == volSet.getSize(): + # Write a metadata with the volumes + iter1 = volSet.iterItems() + iter2 = inputVols.iterItems() + inputset = self._createSetOfVolumes("inputSet") + inputset.setSamplingRate(inputVols.getSamplingRate()) + inputset.setAlignment(ALIGN_3D) + + for i in range(volSet.getSize()): + p1 = iter1.__next__() + p2 = iter2.__next__() + p2.setTransform(p1.getTransform()) + inputset.append(p2) + xmipp3.convert.writeSetOfVolumes(inputset, self._getExtraPath('volumes.xmd')) + else: + raise RuntimeError("The number of volumes and STA parameters mismatch") + + + + + def inputFromXmipp(self): + + mdImgs = md.MetaData(self.xmdFile) + flag = None + try: + flag = mdImgs.getValue(md.MDL_ANGLE_Y, 1) + except: + pass + + if flag == 90: + mdImgs = md.MetaData(self.xmdFile) + for objId in mdImgs: + rot = mdImgs.getValue(md.MDL_ANGLE_ROT, objId) + tilt = mdImgs.getValue(md.MDL_ANGLE_TILT, objId) + psi = mdImgs.getValue(md.MDL_ANGLE_PSI, objId) + x = mdImgs.getValue(md.MDL_SHIFT_X, objId) + y = mdImgs.getValue(md.MDL_SHIFT_Y, objId) + z = mdImgs.getValue(md.MDL_SHIFT_Z, objId) + T = eulerAngles2matrix(rot, tilt, psi, x, y, z) + # Rotate 90 degrees (compensation for missing wedge) + T0 = eulerAngles2matrix(0, 90, 0, 0, 0, 0) + T = np.linalg.inv(np.matmul(T, T0)) + rot, tilt, psi, x, y, z = matrix2eulerAngles(T) + mdImgs.setValue(md.MDL_ANGLE_ROT, rot, objId) + mdImgs.setValue(md.MDL_ANGLE_TILT, tilt, objId) + mdImgs.setValue(md.MDL_ANGLE_PSI, psi, objId) + mdImgs.setValue(md.MDL_SHIFT_X, x, objId) + mdImgs.setValue(md.MDL_SHIFT_Y, y, objId) + mdImgs.setValue(md.MDL_SHIFT_Z, z, objId) + mdImgs.setValue(md.MDL_ANGLE_Y, 0.0, objId) + return self.createVolSetSubtomo(mdImgs) + + def inputFromEman(self): + Table = self.emanJSON.get() + + with open(Table, "r") as f: + jf = json.load(f) + n_data = len(jf) + + index = [] + fname = [] + matrices = [] + for i in jf: + fname_i, index_i = make_tuple(i) + index.append(index_i) + fname.append(fname_i) + mat = np.array(json.loads(jf[i]["xform.align3d"]["matrix"]), dtype=np.float64).reshape(3, 4) + matrices.append(matrix2eulerAngles(mat)) + matrices = np.array(matrices) + + for i in range(n_data): + fileext = os.path.splitext(fname[i])[1] + if fileext == ".lst": + with open(fname[i], "r") as f: + for line in f: + if not line.startswith('#'): + spl = line.split() + if int(spl[0]) == index[i]: + fname[i] = spl[1] + break + elif fileext == ".hdf" or fileext == ".mrc" or fileext == ".mrcs" or fileext == ".vol" or fileext == ".spi": + pass + else: + raise RuntimeError("Unkown file type for subtomograms") + + volSet = self._createSetOfVolumes() + volSet.setSamplingRate(self.inputVolumes.get().getSamplingRate()) + + for i in range(n_data): + + imgPath = "%s@%s" % (str(index[i] + 1).zfill(6), abspath(fname[i])) + transform = emobj.Transform() + transform.setMatrix(matrices[i]) + vol = emobj.Volume() + vol.setSamplingRate(self.inputVolumes.get().getSamplingRate()) + vol.cleanObjId() + vol.setTransform(transform) + vol.setLocation(imgPath) + volSet.append(vol) + volSet.setAlignment3D() + return volSet + + def inputFromDynamo(self): + from continuousflex.protocols.utilities.dynamo import tbl2metadata + + volumes_in = self._getExtraPath('input.xmd') + xmipp3.convert.writeSetOfVolumes(self.inputVolumes.get(), volumes_in) + tbl2metadata(self.dynamoTable.get(), volumes_in, md_out) + + mdImgs = md.MetaData(md_out) + return self.createVolSetSubtomo(mdImgs) + + def inputFromTombox(self): + raise NotImplementedError() + + def createVolSetSubtomo(self, mdImgs): + volSet = self._createSetOfVolumes() + volSet.setSamplingRate(self.inputVolumes.get().getSamplingRate()) for objId in mdImgs: - imgPath = mdImgs.getValue(md.MDL_IMAGE, objId) - index, fn = xmipp3.convert.xmippToLocation(imgPath) - if (index): # case the input is a stack - # Conside the index is the id in the input set - particle = inputSet[index] - else: # input is not a stack - # convert the inputSet to metadata: - mdtemp = md.MetaData(self._getExtraPath('input.xmd')) - # Loop and find the index based on the basename: - bn_retrieved = basename(imgPath) - for searched_index in mdtemp: - imgPath_temp = mdtemp.getValue(md.MDL_IMAGE, searched_index) - bn_searched = basename(imgPath_temp) - if bn_searched == bn_retrieved: - index = searched_index - particle = inputSet[index] - break - mdImgs.setValue(md.MDL_IMAGE, xmipp3.convert.getImageLocation(particle), objId) - mdImgs.setValue(md.MDL_ITEM_ID, int(particle.getObjId()), objId) - mdImgs.write(self.imgsFn) + + # imgPath = abspath(mdImgs.getValue(md.MDL_IMAGE, objId)) + rot = mdImgs.getValue(md.MDL_ANGLE_ROT, objId) + tilt = mdImgs.getValue(md.MDL_ANGLE_TILT, objId) + psi = mdImgs.getValue(md.MDL_ANGLE_PSI, objId) + + x_shift = mdImgs.getValue(md.MDL_SHIFT_X, objId) + y_shift = mdImgs.getValue(md.MDL_SHIFT_Y, objId) + z_shift = mdImgs.getValue(md.MDL_SHIFT_Z, objId) + matrix = eulerAngles2matrix(rot, tilt, psi, x_shift, y_shift, z_shift) + + transform = emobj.Transform() + transform.setMatrix(matrix) + + vol = emobj.Volume() + vol.setSamplingRate(self.inputVolumes.get().getSamplingRate()) + vol.cleanObjId() + vol.setTransform(transform) + # vol.setLocation(imgPath) + volSet.append(vol) + volSet.setAlignment3D() + return volSet def applyAlignment(self): - makePath(self._getExtraPath()+'/aligned') + makePath(self._getExtraPath() + '/aligned') tempdir = self._getTmpPath() - mdImgs = md.MetaData(self.imgsFn) + mdImgs = md.MetaData(self._getExtraPath('volumes.xmd')) for objId in mdImgs: imgPath = mdImgs.getValue(md.MDL_IMAGE, objId) new_imgPath = self._getExtraPath()+'/aligned/' + basename(imgPath) @@ -136,18 +421,11 @@ def applyAlignment(self): shiftz = str(mdImgs.getValue(md.MDL_SHIFT_Z, objId)) # rotate 90 around y, align, then rotate -90 to get to neutral params = '-i ' + imgPath + ' -o ' + tempdir + '/temp.vol ' - if(self.angleY): - params += '--rotate_volume euler 0 90 0 ' - else: # only to convert - params += '--rotate_volume euler 0 0 0 ' runProgram('xmipp_transform_geometry', params) params = '-i ' + tempdir + '/temp.vol -o ' + new_imgPath + ' ' params += '--rotate_volume euler ' + rot + ' ' + tilt + ' ' + psi + ' ' params += '--shift ' + shiftx + ' ' + shifty + ' ' + shiftz + ' ' - if (not(self.angleY)): - params += ' --inverse ' - - # print('xmipp_transform_geometry',params) + params += ' --inverse ' runProgram('xmipp_transform_geometry', params) self.fnaligned = self._getExtraPath('volumes_aligned.xmd') mdImgs.write(self.fnaligned) @@ -166,7 +444,7 @@ def _summary(self): return summary def _citations(self): - return [] + return ['harastani2022continuousflex'] def _methods(self): pass diff --git a/continuousflex/protocols/protocol_batch_cluster.py b/continuousflex/protocols/protocol_batch_cluster.py index d4b5b63..cc806e1 100644 --- a/continuousflex/protocols/protocol_batch_cluster.py +++ b/continuousflex/protocols/protocol_batch_cluster.py @@ -1,6 +1,7 @@ # ************************************************************************** # * # * Authors: +# * Mohamad Harastani (mohamad.harastani@igbmc.fr) # * J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es) # * Slavica Jonic (slavica.jonic@upmc.fr) # * @@ -24,19 +25,120 @@ # * # ************************************************************************** - +from os.path import isfile from pyworkflow.protocol.params import PointerParam, FileParam from pwem.protocols import BatchProtocol -from pwem.objects import SetOfParticles, Volume - +from pwem.objects import SetOfParticles, Volume, AtomStruct from xmipp3.convert import writeSetOfParticles from pwem.utils import runProgram import pwem.emlib.metadata as md +import numpy as np class FlexBatchProtNMACluster(BatchProtocol): - """ Protocol executed when a cluster is created - from NMA images and theirs deformations. + """ + Creates a representative three-dimensional reconstruction and structural model from a cluster + of particles associated with a Normal Mode Analysis exploration. The protocol summarizes a + selected conformational population by generating both an average volumetric reconstruction and + a corresponding molecular structure that represents the central deformation state of the + cluster. + + AI Generated: + + NMA Cluster Reconstruction (FlexBatchProtNMACluster) - User Manual + Overview + + The NMA Cluster Reconstruction protocol is designed to analyze groups of particles that + belong to the same region of a Normal Mode Analysis conformational landscape. Its primary + objective is to transform a cluster of related particle images into an interpretable + structural representation that reflects the dominant characteristics of that population. + + In studies of molecular flexibility, dimensionality reduction and clustering are commonly + used to identify groups of particles that share similar conformational properties. Once + such a cluster has been identified, researchers often need a representative volume and a + corresponding structural model that summarize the behavior of the selected population. + This protocol provides those representative outputs. + + Inputs and General Workflow + + The protocol operates on a cluster derived from a previous Normal Mode Analysis workflow. + The selected particles are gathered into a dedicated dataset while preserving the + conformational information associated with each member of the cluster. + + The particle images are then combined to generate a three-dimensional reconstruction that + represents the average structural state of the selected population. In parallel, the + conformational information associated with the cluster is used to determine a central + deformation state, allowing the generation of a representative structural model. + + Relationship Between Clustering and Conformational Landscapes + + Clusters within a Normal Mode Analysis landscape frequently correspond to regions occupied + by related molecular conformations. Depending on the biological system, a cluster may + represent a stable state, a transition intermediate, or a family of closely related + structural arrangements. + + By focusing on a specific cluster, the protocol allows researchers to move from abstract + coordinates in a reduced conformational space to physically interpretable structural + representations. This connection is particularly valuable when investigating continuous + motions, domain rearrangements, or large-scale conformational transitions. + + Three-Dimensional Reconstruction + + The reconstructed volume provides a consensus representation of the particle population + contained within the cluster. Structural features consistently present across the selected + particles tend to be reinforced, while random noise is reduced through the reconstruction + process. + + For relatively homogeneous clusters, the resulting volume can provide a clear description + of the underlying molecular state. When structural variability remains within the cluster, + flexible regions may appear broadened or less sharply defined. Such behavior should be + interpreted as evidence of residual heterogeneity rather than as a reconstruction artifact. + + Representative Structural Model + + In addition to the reconstructed volume, the protocol produces a structural model + representing the central conformational state of the cluster. This model serves as a + convenient structural reference for visualization, interpretation, and comparison with + other regions of the conformational landscape. + + From a biological perspective, the representative structure can help identify the dominant + motions associated with a cluster and provide insight into how conformational variability + relates to molecular function. Comparisons between representative structures from different + clusters may reveal transition pathways or alternative functional states. + + Outputs and Their Interpretation + + The protocol generates two complementary outputs. The first is a reconstructed volume that + summarizes the experimental information contained within the particle cluster. The second + is a representative molecular structure associated with the central conformational state of + that cluster. + + Together, these outputs provide both an experimental and a structural description of the + selected population, facilitating interpretation of conformational variability and + biological function. + + Practical Recommendations + + The quality and interpretability of the results depend strongly on the coherence of the + selected cluster. Clusters representing well-defined conformational states generally + produce representative volumes and structures that are straightforward to interpret. + + When studying complex molecular motions, it is often beneficial to compare the outputs + generated from multiple clusters. Such comparisons can reveal progressive structural + changes across the conformational landscape and help identify biologically meaningful + transitions. + + Visual inspection of both the reconstructed volume and the representative structure is + recommended, particularly when clusters contain broad conformational variability or when + multiple structural states may coexist within the same region of the landscape. + + Final Perspective + + For researchers investigating continuous molecular flexibility, this protocol provides a + direct bridge between clustered particle populations and biologically interpretable + structural representations. By generating both a consensus reconstruction and a + representative conformational model, it helps transform abstract conformational clusters + into tangible structural states that can be analyzed, compared, and communicated. """ _label = 'nma cluster' @@ -53,6 +155,7 @@ def _insertAllSteps(self): self._insertFunctionStep('convertInputStep', imagesMd) params = '-i %(imagesMd)s -o %(outputVol)s --fast' % locals() self._insertFunctionStep('reconstructStep', params) + self._insertFunctionStep('centroidPdbStep') self._insertFunctionStep('createOutputStep', outputVol) #--------------------------- STEPS functions -------------------------------------------- @@ -91,13 +194,54 @@ def convertInputStep(self, imagesMd): def reconstructStep(self, params): runProgram('xmipp_reconstruct_fourier_accel', params) + + + def centroidPdbStep(self): + imagesMd = self._getExtraPath('images.xmd') + md_file = md.MetaData(imagesMd) + deformations = [] + for j in md_file: + defor = md_file.getValue(md.MDL_NMA, j) + if defor: + deformations.append(defor) + ampl = np.mean(np.array(deformations), axis= 0) + print(self.getFnPDB()) + + fnPDB, pseudo = self.getFnPDB() + fnModeList = self.getFnModes() + fnOutPDB = self._getExtraPath('centroid.pdb') + params = " --pdb " + fnPDB + params += " --nma " + fnModeList + params += " -o " + fnOutPDB + params += " --deformations " + ' '.join(str(i) for i in ampl) + runProgram('xmipp_pdb_nma_deform', params) def createOutputStep(self, outputVol): vol = Volume() vol.setFileName(outputVol) vol.setSamplingRate(self.outputParticles.getSamplingRate()) + atm = AtomStruct() + fnPDB, pseudo = self.getFnPDB() + fnOutPDB = self._getExtraPath('centroid.pdb') + atm.setPseudoAtoms(pseudo) + atm.setFileName(fnOutPDB) + atm.setVolume(vol) + self._defineOutputs(centroidPDB=atm) self._defineOutputs(outputVol=vol) - + + #--------------------------- Utility functions ----------------------------------------- + def getFnPDB(self): + # This functions returns the path of the structure, false if is atomic, true if pseudoatomic + path = self.inputNmaDimred.get().inputNMA.get()._getExtraPath('atoms.pdb') + if isfile(path): + return path, False + else: + path = self.inputNmaDimred.get().inputNMA.get()._getExtraPath('pseudoatoms.pdb') + return path, True + + def getFnModes(self): + return self.inputNmaDimred.get().getInputModes() + #--------------------------- INFO functions -------------------------------------------- def _summary(self): summary = [] @@ -108,7 +252,7 @@ def _validate(self): return errors def _citations(self): - return [] + return ['harastani2022continuousflex'] def _methods(self): return [] diff --git a/continuousflex/protocols/protocol_batch_cluster_heteroflow.py b/continuousflex/protocols/protocol_batch_cluster_heteroflow.py deleted file mode 100755 index b86b059..0000000 --- a/continuousflex/protocols/protocol_batch_cluster_heteroflow.py +++ /dev/null @@ -1,119 +0,0 @@ -# ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) -# * -# * This program is free software; you can redistribute it and/or modify -# * it under the terms of the GNU General Public License as published by -# * the Free Software Foundation; either version 2 of the License, or -# * (at your option) any later version. -# * -# * This program is distributed in the hope that it will be useful, -# * but WITHOUT ANY WARRANTY; without even the implied warranty of -# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# * GNU General Public License for more details. -# * -# * You should have received a copy of the GNU General Public License -# * along with this program; if not, write to the Free Software -# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -# * 02111-1307 USA -# * -# * All comments concerning this program package may be sent to the -# * e-mail address 'scipion@cnb.csic.es' -# * -# ************************************************************************** - -from pyworkflow.protocol.params import PointerParam, FileParam, IntParam -from pwem.protocols import BatchProtocol -from pwem.objects import Volume, SetOfVolumes -from xmipp3.convert import writeSetOfVolumes -import pwem.emlib.metadata as md -import os - - -class FlexBatchProtHeteroFlowCluster(BatchProtocol): - """ Protocol executed when a cluster is created - from HeteroFlow dimred. - """ - _label = 'tomoflow vol cluster' - - def _defineParams(self, form): - form.addHidden('inputHeteroFlowDimred', PointerParam, pointerClass='EMObject') - form.addHidden('sqliteFile', FileParam) - - #--------------------------- INSERT steps functions -------------------------------------------- - - def _insertAllSteps(self): - volumesMd = self._getExtraPath('volumes.xmd') - outputVol = self._getExtraPath('average.spi') - - self._insertFunctionStep('convertInputStep', volumesMd) - self._insertFunctionStep('averagingStep') - self._insertFunctionStep('createOutputStep', outputVol) - - #--------------------------- STEPS functions -------------------------------------------- - - def convertInputStep(self, volumesMd): - # It is unusual to create the output in the convertInputStep, - # but just to avoid reading twice the sqlite with particles - # inputSet = self.inputHeteroFlowDimred.get().getInputParticles().get() - inputSet = self.inputHeteroFlowDimred.get().getInputParticles() - partSet = self._createSetOfVolumes() - # partSet = SetOfVolumes() - partSet.copyInfo(inputSet) - tmpSet = SetOfVolumes(filename=self.sqliteFile.get()) - partSet.appendFromImages(tmpSet) - # Register outputs - partSet.setAlignmentProj() - - self._defineOutputs(OutputVolumes=partSet) - # self._defineTransformRelation(inputSet, partSet) - writeSetOfVolumes(partSet, volumesMd) - - - def averagingStep(self): - volumesMd = self._getExtraPath('volumes.xmd') - mdVols = md.MetaData(volumesMd) - counter = 0 - for objId in mdVols: - counter = counter + 1 - imgPath = mdVols.getValue(md.MDL_IMAGE, objId) - outputVol = self._getExtraPath('average.spi') - tempVol = self._getExtraPath('temp.spi') - extra = self._getExtraPath() - - params = '-i %(imgPath)s -o %(tempVol)s --type vol ' % locals() - self.runJob('xmipp_image_convert',params) - - if counter == 1 : - os.system("mv %(tempVol)s %(outputVol)s" % locals()) - - else: - params = '-i %(tempVol)s --plus %(outputVol)s -o %(outputVol)s ' % locals() - self.runJob('xmipp_image_operate', params) - - params = '-i %(outputVol)s --divide %(counter)s -o %(outputVol)s ' % locals() - self.runJob('xmipp_image_operate', params) - os.system("rm -f %(tempVol)s" % locals()) - - - def createOutputStep(self, outputVol): - vol = Volume() - vol.setFileName(outputVol) - #outputParticles - vol.setSamplingRate(self.OutputVolumes.getSamplingRate()) - self._defineOutputs(outputVol=vol) - - #--------------------------- INFO functions -------------------------------------------- - def _summary(self): - summary = [] - return summary - - def _validate(self): - errors = [] - return errors - - def _citations(self): - return [] - - def _methods(self): - return [] - diff --git a/continuousflex/protocols/protocol_batch_cluster_tomoflow.py b/continuousflex/protocols/protocol_batch_cluster_tomoflow.py new file mode 100755 index 0000000..aa84715 --- /dev/null +++ b/continuousflex/protocols/protocol_batch_cluster_tomoflow.py @@ -0,0 +1,203 @@ +# ************************************************************************** +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# * +# ************************************************************************** + +from pyworkflow.protocol.params import PointerParam, FileParam +from pwem.protocols import BatchProtocol +from pwem.objects import Volume, SetOfVolumes +from xmipp3.convert import writeSetOfVolumes +import pwem.emlib.metadata as md +import os +from pwem.utils import runProgram + + +class FlexBatchProtTomoFlowCluster(BatchProtocol): + """ + Creates a representative volume from a cluster of tomographic structures obtained after + dimensionality reduction analysis. The protocol gathers all volumes belonging to a selected + cluster and generates a consensus structural representation that summarizes the common features + present within that population. + + AI Generated: + + TomoFlow Cluster Volume (FlexBatchProtTomoFlowCluster) - User Manual + Overview + + The TomoFlow Cluster Volume protocol is designed to characterize a cluster of related + structures identified during TomoFlow dimensionality reduction analyses. Its main purpose + is to transform a collection of clustered volumes into a biologically meaningful consensus + representation that can be inspected, interpreted, and compared with other structural + states. + + In studies of structural heterogeneity, clustering is commonly used to separate volumes + into groups that represent similar conformations, functional states, or trajectories + within a continuous landscape. Once a cluster has been identified, researchers often need + a representative structure that captures the average properties of that population. This + protocol provides that summary representation. + + Inputs and General Workflow + + The protocol operates on a previously defined cluster generated from a TomoFlow + dimensionality reduction workflow. The selected cluster contains a subset of volumes that + share similar structural characteristics according to their position in the reduced + conformational space. + + During execution, all volumes associated with the cluster are gathered into a dedicated + dataset while preserving the experimental information required for downstream analysis. + The protocol then combines the structural information from every member of the cluster to + generate a representative average volume. + + Biological Interpretation of Clusters + + Clusters often correspond to regions of the conformational landscape that contain related + molecular states. Depending on the biological system, a cluster may represent a stable + conformation, an intermediate state, or a family of structures sharing similar global + organization. + + The representative volume generated by this protocol provides an intuitive way to inspect + the dominant structural features present within the cluster. Regions that are consistently + observed across the population tend to be reinforced in the average, whereas highly + variable regions may appear less defined. + + Averaging and Structural Heterogeneity + + Averaging is useful because it reduces random noise and enhances reproducible structural + information. For clusters that contain relatively homogeneous structures, the resulting + volume often provides a clear description of the underlying molecular state. + + When a cluster contains substantial variability, however, averaging should be interpreted + carefully. Flexible domains, transient interactions, or continuous motions may become + blurred in the final representation. In such cases, the average volume should be viewed as + a summary of the cluster rather than an exact depiction of any individual structure. + + Outputs and Their Interpretation + + The main output is a representative volume corresponding to the average of all volumes + belonging to the selected cluster. This volume can be visualized directly, compared with + averages from other clusters, or used as input for additional structural analyses. + + Because the output preserves the sampling information associated with the original data, + it can be integrated into downstream cryo-EM and cryo-electron tomography workflows + without requiring additional preparation. + + Practical Recommendations + + The biological value of the resulting average depends strongly on the quality of the + clustering stage. Clusters that represent coherent structural populations generally + produce informative averages that facilitate interpretation and visualization. + + Researchers are encouraged to compare representative volumes from multiple clusters to + identify conformational transitions, alternative structural states, or distinct functional + substates. Visual inspection of cluster members can also help determine whether the + resulting average accurately reflects the underlying population. + + Final Perspective + + For studies focused on continuous heterogeneity and structural landscapes, cluster-based + representative volumes provide an effective bridge between large collections of individual + structures and biologically interpretable models. By summarizing the common characteristics + of a selected cluster, this protocol helps transform complex conformational information + into forms that are easier to analyze, compare, and communicate. + """ + _label = 'tomoflow vol cluster' + + def _defineParams(self, form): + form.addHidden('inputHeteroFlowDimred', PointerParam, pointerClass='EMObject') + form.addHidden('sqliteFile', FileParam) + + #--------------------------- INSERT steps functions -------------------------------------------- + + def _insertAllSteps(self): + volumesMd = self._getExtraPath('volumes.xmd') + outputVol = self._getExtraPath('average.spi') + + self._insertFunctionStep('convertInputStep', volumesMd) + self._insertFunctionStep('averagingStep') + self._insertFunctionStep('createOutputStep', outputVol) + + #--------------------------- STEPS functions -------------------------------------------- + + def convertInputStep(self, volumesMd): + # It is unusual to create the output in the convertInputStep, + # but just to avoid reading twice the sqlite with particles + # inputSet = self.inputHeteroFlowDimred.get().getInputParticles().get() + inputSet = self.inputHeteroFlowDimred.get().getInputParticles() + partSet = self._createSetOfVolumes() + # partSet = SetOfVolumes() + partSet.copyInfo(inputSet) + tmpSet = SetOfVolumes(filename=self.sqliteFile.get()) + partSet.appendFromImages(tmpSet) + # Register outputs + partSet.setAlignmentProj() + + self._defineOutputs(OutputVolumes=partSet) + # self._defineTransformRelation(inputSet, partSet) + writeSetOfVolumes(partSet, volumesMd) + + + def averagingStep(self): + volumesMd = self._getExtraPath('volumes.xmd') + mdVols = md.MetaData(volumesMd) + counter = 0 + for objId in mdVols: + counter = counter + 1 + imgPath = mdVols.getValue(md.MDL_IMAGE, objId) + outputVol = self._getExtraPath('average.spi') + tempVol = self._getExtraPath('temp.spi') + extra = self._getExtraPath() + + params = '-i %(imgPath)s -o %(tempVol)s --type vol ' % locals() + runProgram('xmipp_image_convert',params) + + if counter == 1 : + os.system("mv %(tempVol)s %(outputVol)s" % locals()) + + else: + params = '-i %(tempVol)s --plus %(outputVol)s -o %(outputVol)s ' % locals() + runProgram('xmipp_image_operate', params) + + params = '-i %(outputVol)s --divide %(counter)s -o %(outputVol)s ' % locals() + runProgram('xmipp_image_operate', params) + os.system("rm -f %(tempVol)s" % locals()) + + + def createOutputStep(self, outputVol): + vol = Volume() + vol.setFileName(outputVol) + vol.setSamplingRate(self.OutputVolumes.getSamplingRate()) + self._defineOutputs(outputVol=vol) + + #--------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['harastani2022continuousflex'] + + def _methods(self): + return [] + diff --git a/continuousflex/protocols/protocol_batch_cluster_vol.py b/continuousflex/protocols/protocol_batch_cluster_vol.py index 1c17f2e..959af8e 100755 --- a/continuousflex/protocols/protocol_batch_cluster_vol.py +++ b/continuousflex/protocols/protocol_batch_cluster_vol.py @@ -1,6 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -23,27 +23,128 @@ # * # ************************************************************************** - -from pyworkflow.protocol.params import PointerParam, FileParam, IntParam +from os.path import isfile +from pyworkflow.protocol.params import PointerParam, FileParam from pwem.protocols import BatchProtocol -from pwem.objects import Volume, SetOfVolumes +from pwem.objects import Volume, SetOfVolumes, AtomStruct from xmipp3.convert import writeSetOfVolumes import pwem.emlib.metadata as md import os from pwem.utils import runProgram - +import numpy as np class FlexBatchProtNMAClusterVol(BatchProtocol): - """ Protocol executed when a cluster is created - from NMA volumes and theirs deformations. + """ + Generates a representative structural and volumetric description of a cluster of + conformations obtained from normal mode analysis. The protocol summarizes the + structural variability present within a selected group of volumes by producing both + an average density map and a representative molecular model corresponding to the + central tendency of the cluster. + + AI Generated: + + NMA Volume Cluster (FlexBatchProtNMAClusterVol) - User Manual + Overview + + The NMA Volume Cluster protocol is designed to analyze a subset of volumes that + belong to the same conformational cluster after dimensionality reduction and + normal mode analysis. Its main objective is to provide a biologically meaningful + representation of the conformational state described by the cluster by combining + information from all member volumes into a single consensus result. + + In studies of molecular flexibility, clusters often represent groups of + structures sharing similar conformations. Rather than inspecting every volume + individually, researchers can use this protocol to obtain a compact summary of + the structural characteristics of an entire conformational population. + + Inputs and General Workflow + + The protocol operates on a cluster extracted from a previous normal mode + analysis workflow. The selected volumes are gathered together and their + associated conformational descriptors are preserved so that both structural + and dynamical information remain available throughout the analysis. + + The workflow produces two complementary outputs. First, it generates an average + volume that represents the overall density distribution of the cluster. + Second, it creates a representative structural model corresponding to the + average conformational state observed among all cluster members. + + Cluster Averaging + + A central component of the protocol is the generation of a consensus volume. + All volumes belonging to the cluster contribute to this result, allowing the + protocol to emphasize structural features that are consistently present across + the population while reducing the influence of noise and individual variations. + + From a biological perspective, the resulting average volume can be interpreted + as the characteristic density map of the conformational state represented by + the cluster. This is particularly useful when exploring continuous molecular + motions where individual structures may differ slightly but still belong to + the same functional state. + + Interpretation of Conformational Variability + + In addition to density information, the protocol considers the conformational + descriptors associated with the normal mode analysis. These descriptors + characterize the position of each structure within the conformational landscape. + + By combining information from all members of the cluster, the protocol derives + a representative conformational state that reflects the average behavior of the + population. This provides a useful reference for understanding the dominant + structural characteristics of the cluster and facilitates comparison with other + conformational states identified during the analysis. + + Representative Structural Model + + The protocol generates a molecular structure corresponding to the centroid of + the cluster. Biologically, this model can be interpreted as the structure that + best represents the average conformation sampled by the cluster population. + + This centroid model is particularly valuable when visualizing molecular motions, + comparing conformational states, preparing figures, or selecting representative + structures for downstream analyses. Because it reflects an average state rather + than a single observation, it often provides a clearer description of the + conformational ensemble. + + Outputs and Their Interpretation + + The protocol produces an average volume representing the consensus density of + the cluster and a representative atomic or pseudoatomic structure describing + the centroid conformation. These outputs complement each other by providing + both volumetric and structural views of the same conformational state. + + The average volume can be used for visualization, comparison with experimental + maps, or subsequent image-processing tasks. The centroid structure can be used + for structural interpretation, animation of molecular motions, fitting + procedures, or integration with additional modeling workflows. + + Practical Recommendations + + This protocol is most informative when applied to clusters that represent + coherent conformational populations. Well-defined clusters generally produce + representative averages that preserve biologically meaningful structural + features. If a cluster contains highly heterogeneous conformations, the + resulting average may become less representative of any individual state. + + When comparing multiple clusters, examining both the centroid structures and + the corresponding average volumes can provide valuable insight into the nature + of the conformational transitions captured by the normal mode analysis. + + Final Perspective + + For researchers studying molecular flexibility, this protocol serves as a bridge + between large collections of conformationally related volumes and an + interpretable biological description of the underlying structural state. By + generating a consensus density map together with a representative structural + model, it enables efficient exploration and communication of conformational + variability within complex molecular systems. """ _label = 'nma vol cluster' def _defineParams(self, form): form.addHidden('inputNmaDimred', PointerParam, pointerClass='EMObject') form.addHidden('sqliteFile', FileParam) - form.addHidden('angleYflag', IntParam) #--------------------------- INSERT steps functions -------------------------------------------- @@ -53,6 +154,7 @@ def _insertAllSteps(self): self._insertFunctionStep('convertInputStep', volumesMd) self._insertFunctionStep('averagingStep') + self._insertFunctionStep('centroidPdbStep') self._insertFunctionStep('createOutputStep', outputVol) #--------------------------- STEPS functions -------------------------------------------- @@ -80,7 +182,6 @@ def convertInputStep(self, volumesMd): id_org = md_file_org.getValue(md.MDL_ITEM_ID, objID) for j in md_file_nma: id_nma = md_file_nma.getValue(md.MDL_ITEM_ID, j) - #print(id_nma) if id_org == id_nma: displacements = md_file_nma.getValue(md.MDL_NMA, j) md_file_org.setValue(md.MDL_NMA, displacements, objID) @@ -90,13 +191,10 @@ def convertInputStep(self, volumesMd): def averagingStep(self): - flag = self.angleYflag.get() - volumesMd = self._getExtraPath('volumes.xmd') mdVols = md.MetaData(volumesMd) counter = 0 - first = True for objId in mdVols: counter = counter + 1 imgPath = mdVols.getValue(md.MDL_IMAGE, objId) @@ -108,35 +206,15 @@ def averagingStep(self): y_shift = mdVols.getValue(md.MDL_SHIFT_Y, objId) z_shift = mdVols.getValue(md.MDL_SHIFT_Z, objId) - # The flip one is used here to determine if we need to use the option --inverse - # with xmipp_transform_geometry - flip = mdVols.getValue(md.MDL_ANGLE_Y, objId) - outputVol = self._getExtraPath('average.vol') tempVol = self._getExtraPath('temp.vol') extra = self._getExtraPath() - if flag == 0 : - if first: - print("THERE IS NO COMPENSATION FOR THE MISSING WEDGE") - first = False - - params = '-i %(imgPath)s -o %(tempVol)s --inverse --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ - ' --shift %(x_shift)s %(y_shift)s %(z_shift)s -v 0' % locals() - - else: - if first: - print("THERE IS A COMPENSATION FOR THE MISSING WEDGE") - first = False - # First got to rotate each volume 90 degrees about the y axis, align it, then rotate back and sum it - params = '-i %(imgPath)s -o %(tempVol)s --rotate_volume euler 0 90 0' % locals() - runProgram('xmipp_transform_geometry', params) - params = '-i %(tempVol)s -o %(tempVol)s --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ - ' --shift %(x_shift)s %(y_shift)s %(z_shift)s ' % locals() - + params = '-i %(imgPath)s -o %(tempVol)s --inverse --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ + ' --shift %(x_shift)s %(y_shift)s %(z_shift)s -v 0' % locals() runProgram('xmipp_transform_geometry', params) - if counter == 1 : + if counter == 1: os.system("mv %(tempVol)s %(outputVol)s" % locals()) else: @@ -148,12 +226,49 @@ def averagingStep(self): os.system("rm -f %(tempVol)s" % locals()) + def centroidPdbStep(self): + volumesMd = self._getExtraPath('volumes.xmd') + md_file = md.MetaData(volumesMd) + deformations = [] + for j in md_file: + deformations.append(md_file.getValue(md.MDL_NMA, j)) + ampl = np.mean(np.array(deformations), axis= 0) + print(self.getFnPDB()) + + fnPDB, pseudo = self.getFnPDB() + fnModeList = self.getFnModes() + fnOutPDB = self._getExtraPath('centroid.pdb') + params = " --pdb " + fnPDB + params += " --nma " + fnModeList + params += " -o " + fnOutPDB + params += " --deformations " + ' '.join(str(i) for i in ampl) + runProgram('xmipp_pdb_nma_deform', params) + + def createOutputStep(self, outputVol): vol = Volume() vol.setFileName(outputVol) - #outputParticles vol.setSamplingRate(self.OutputVolumes.getSamplingRate()) + atm = AtomStruct() + fnPDB, pseudo = self.getFnPDB() + fnOutPDB = self._getExtraPath('centroid.pdb') + atm.setPseudoAtoms(pseudo) + atm.setFileName(fnOutPDB) + atm.setVolume(vol) + self._defineOutputs(centroidPDB=atm) self._defineOutputs(outputVol=vol) + #--------------------------- Utility functions ----------------------------------------- + def getFnPDB(self): + # This functions returns the path of the structure, false if is atomic, true if pseudoatomic + path = self.inputNmaDimred.get().inputNMA.get()._getExtraPath('atoms.pdb') + if isfile(path): + return path, False + else: + path = self.inputNmaDimred.get().inputNMA.get()._getExtraPath('pseudoatoms.pdb') + return path, True + + def getFnModes(self): + return self.inputNmaDimred.get().inputNMA.get()._getExtraPath('modes.xmd') #--------------------------- INFO functions -------------------------------------------- def _summary(self): @@ -165,8 +280,7 @@ def _validate(self): return errors def _citations(self): - return [] + return ['harastani2022continuousflex'] def _methods(self): return [] - diff --git a/continuousflex/protocols/protocol_batch_pdb_cluster.py b/continuousflex/protocols/protocol_batch_pdb_cluster.py new file mode 100644 index 0000000..74e2e1c --- /dev/null +++ b/continuousflex/protocols/protocol_batch_pdb_cluster.py @@ -0,0 +1,223 @@ +# ************************************************************************** +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +import multiprocessing +from pyworkflow.protocol.params import PointerParam, FileParam, USE_GPU, GPU_LIST, BooleanParam, StringParam,LEVEL_ADVANCED +from pwem.protocols import BatchProtocol +from pwem.objects import SetOfClasses2D +from xmipp3.convert import writeSetOfParticles, writeSetOfVolumes, readSetOfVolumes +from pyworkflow.utils import runCommand +from pwem.emlib.image import ImageHandler +import pwem.emlib.metadata as md +import os + +class FlexBatchProtClusterSet(BatchProtocol): + """ + Creates a collection of representative 3D volumes from a set of particle or volume clusters. + The protocol is intended to generate structural representatives for previously identified + classes, allowing each cluster to be visualized, compared, and interpreted as an independent + conformational or structural state. + + AI Generated: + + Cluster Set Reconstruction (FlexBatchProtClusterSet) - User Manual + Overview + + The Cluster Set Reconstruction protocol generates representative 3D volumes from a collection + of previously defined classes. Its primary objective is to transform clustered experimental + data into interpretable structural representations that can be used for visualization, + comparison, classification, and downstream structural analysis. + + In cryo-EM and structural heterogeneity studies, clustering is frequently used to separate + particles, volumes, or molecular conformations into groups that share similar characteristics. + Once these groups have been identified, researchers often require a representative volume for + each cluster in order to understand the structural meaning of the classification. This + protocol provides that transition from abstract classes to biologically interpretable + structures. + + Inputs and Biological Context + + The protocol operates on a set of classes generated by previous classification or clustering + procedures. Each class is assumed to represent a population of observations sharing common + structural features. Depending on the workflow, these observations may correspond to particle + images, reconstructed volumes, or structures derived from conformational analysis. + + From a biological perspective, clusters frequently correspond to distinct conformational + states, structural intermediates, assembly configurations, or functional substates of a + macromolecular complex. Generating representative volumes allows researchers to examine these + populations individually and assess the biological relevance of the observed variability. + + Reconstruction of Class Representatives + + For classes derived from particle images, the protocol generates a three-dimensional + representative volume for each cluster. The resulting structures summarize the information + contained within all members of the class and provide a direct structural interpretation of + the clustered population. + + When the input already consists of volumetric information, the protocol produces a + representative volume that reflects the average characteristics of the structures assigned to + the corresponding class. This enables consistent treatment of heterogeneous datasets that may + originate from different stages of a structural analysis workflow. + + Computational Execution + + The protocol can take advantage of modern computational resources to accelerate processing. + Depending on the available hardware, reconstruction may be performed using either CPU-based or + GPU-accelerated execution. This flexibility allows the protocol to scale from small + exploratory studies to large classification projects involving substantial numbers of classes. + + For biological users, the computational strategy generally does not alter the scientific + interpretation of the results. Instead, it affects execution speed and resource utilization, + making it possible to process large datasets more efficiently. + + Outputs and Interpretation + + The primary output is a set of representative 3D volumes, one for each input class. Each + output volume can be examined independently to identify structural characteristics associated + with the corresponding population. + + These reconstructed representatives are particularly useful for studying conformational + landscapes, identifying dominant structural states, evaluating classification quality, and + exploring transitions between biological states. Differences observed between cluster + representatives may reveal meaningful molecular motions, assembly changes, or functional + rearrangements. + + Practical Recommendations + + Before interpreting the resulting volumes, it is advisable to verify that the underlying + classification accurately separates biologically meaningful populations. Poorly defined + clusters may produce representative structures that appear noisy, ambiguous, or difficult to + interpret. + + When multiple representatives exhibit subtle differences, side-by-side visualization and + quantitative comparison can help determine whether the observed variability reflects genuine + biological heterogeneity or residual classification uncertainty. The protocol is most valuable + when used as part of a broader workflow aimed at understanding structural variability within a + molecular system. + + Final Perspective + + Cluster representatives provide an essential bridge between classification results and + biological interpretation. By transforming groups of related observations into representative + three-dimensional structures, the protocol enables researchers to visualize, compare, and + understand the structural diversity present within complex cryo-EM datasets. The resulting + volumes serve as a foundation for studying conformational variability, functional mechanisms, + and the organization of heterogeneous molecular populations. + """ + _label = 'cluster set' + + def _defineParams(self, form): + form.addHidden('inputSet', PointerParam, pointerClass='SetOfParticles,SetOfVolumes') + form.addHidden('inputClasses', PointerParam, pointerClass='SetOfClasses2D,SetOfClasses3D') + form.addHidden('inputPDBs', PointerParam, pointerClass='SetOfAtomStructs') + form.addHidden(USE_GPU, BooleanParam, default=True, + label="Use GPU for execution", + help="This protocol has both CPU and GPU implementation.\ + Select the one you want to use.") + + form.addHidden(GPU_LIST, StringParam, default='0', + expertLevel=LEVEL_ADVANCED, + label="Choose GPU IDs", + help="Add a list of GPU devices that can be used") + form.addParallelSection(threads=4, mpi=1) + + # --------------------------- INSERT steps functions -------------------------------------------- + + def _insertAllSteps(self): + self._insertFunctionStep('convertInputStep') + self._insertFunctionStep('reconstructStep') + self._insertFunctionStep('createOutputStep') + + # --------------------------- STEPS functions -------------------------------------------- + + def convertInputStep(self): + pass + + def reconstructStep(self): + inputClasses = self.inputClasses.get() + + for i in inputClasses: + if i.getObjId() != 0: + classFile = self._getExtraPath("class%s.xmd" % str(i.getObjId()).zfill(6)) + if isinstance(inputClasses, SetOfClasses2D): + writeSetOfParticles(i, classFile) + else: + writeSetOfVolumes(i,classFile) + + for i in inputClasses: + if i.getObjId() != 0: + classFile = self._getExtraPath("class%s.xmd" % str(i.getObjId()).zfill(6)) + classVol = self._getExtraPath("class%s.vol" % str(i.getObjId()).zfill(6)) + if isinstance(inputClasses, SetOfClasses2D): + args = "-i %s -o %s " % (classFile, classVol) + args += ' --sampling %f' % self.inputClasses.get().getSamplingRate() + + if self.useGpu.get(): + args += ' --thr %d' % self.numberOfThreads.get() + + if self.useGpu.get(): + if self.numberOfMpi.get() > 1: + self.runJob('xmipp_cuda_reconstruct_fourier', args, + numberOfMpi=len((self.gpuList.get()).split(',')) + 1) + else: + self.runJob('xmipp_cuda_reconstruct_fourier', args) + else: + if self.numberOfMpi.get() > 1 : + progname = "xmipp_mpi_reconstruct_fourier " + self.runJob(progname, args) + else: + progname = "xmipp_reconstruct_fourier " + runCommand(progname + args) + else: + classAvg = ImageHandler().computeAverage(i) + classAvg.write(classVol) + + def createOutputStep(self): + outputMd = md.MetaData() + inputClasses = self.inputClasses.get() + for i in inputClasses: + if i.getObjId() != 0: + classVol = self._getExtraPath("class%s.vol" % str(i.getObjId()).zfill(6)) + index = outputMd.addObject() + outputMd.setValue(md.MDL_IMAGE, classVol, index) + outputMd.setValue(md.MDL_ITEM_ID, i.getObjId(), index) + outputMd.write(self._getExtraPath("outputVols.xmd")) + outputVols = self._createSetOfVolumes() + readSetOfVolumes(self._getExtraPath("outputVols.xmd"),outputVols) + outputVols.setSamplingRate(inputClasses.getSamplingRate()) + self._defineOutputs(outputVols=outputVols) + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['harastani2022continuousflex'] + + def _methods(self): + return [] diff --git a/continuousflex/protocols/protocol_ca2aa.py b/continuousflex/protocols/protocol_ca2aa.py new file mode 100644 index 0000000..df5ba96 --- /dev/null +++ b/continuousflex/protocols/protocol_ca2aa.py @@ -0,0 +1,273 @@ +# ************************************************************************** +# * Authors: Remi Vuillemot (remi.vuillemot@upmc.fr) +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +from pyworkflow.protocol.params import (PointerParam, EnumParam, IntParam) +from pwem.protocols import ProtAnalysis3D +from pyworkflow.protocol import params +from continuousflex.protocols.utilities.genesis_utilities import numpyArr2dcd, dcd2numpyArr +from .utilities.pdb_handler import ContinuousFlexPDBHandler +from pwem.objects import AtomStruct, SetOfParticles, SetOfVolumes +from continuousflex.protocols.convert import matrix2eulerAngles + +import numpy as np + +PDB_SOURCE_PATTERN = 0 +PDB_SOURCE_OBJECT = 1 +PDB_SOURCE_TRAJECT = 2 +class FlexProtCA2AA(ProtAnalysis3D): + """ + Converts a collection of coarse-grained C-alpha structural models into corresponding all-atom + structural models using a reference all-atom structure. The protocol is intended for situations + where conformational variability has been described using simplified backbone representations, + but subsequent biological interpretation, visualization, molecular analysis, or downstream + structural studies require complete atomic detail. + + AI Generated: + + C-alpha to All-Atom Conversion (FlexProtCA2AA) - User Manual + Overview + + The C-alpha to All-Atom Conversion protocol reconstructs full atomic protein models from + C-alpha representations by using a known all-atom reference structure as a structural + template. Its main objective is to recover atomic detail while preserving the conformational + changes observed in a series of coarse-grained models. This approach is particularly useful + in studies of molecular flexibility, normal mode analysis, structural interpolation, and + continuous conformational landscapes where reduced representations are commonly employed to + simplify calculations. + + From a biological perspective, C-alpha models are often sufficient to describe large-scale + motions and conformational transitions, but they lack the atomic information required for + detailed structural interpretation. Reconstructing all-atom models enables further analyses + such as molecular visualization, interaction studies, docking experiments, residue-level + interpretation, and preparation for molecular dynamics simulations. + + Inputs and Biological Context + + The protocol requires a collection of C-alpha structures representing different conformational + states together with an all-atom reference structure. The reference serves as the source of + atomic detail and defines the molecular architecture that will be transferred to the target + conformations. + + In many practical applications, the input structures originate from flexibility analysis + methods that generate large numbers of conformations describing molecular motion. These + conformations often capture biologically meaningful transitions such as domain rearrangements, + hinge motions, opening and closing events, or collective movements of macromolecular + assemblies. The protocol enables these motions to be represented at full atomic resolution. + + Reference Selection + + Choosing an appropriate all-atom reference is one of the most important decisions for obtaining + biologically meaningful results. The reference should correspond to the same molecular system + represented by the C-alpha models and should contain a complete and reliable atomic + description whenever possible. + + In some situations, an independent C-alpha reference may also be available. This can be useful + when the coarse-grained models were generated from a specific reduced representation that does + not perfectly match the C-alpha coordinates extracted from the all-atom structure. Using a + dedicated C-alpha reference may improve consistency between the conformational models and the + reconstructed atomic structures. + + Structural Alignment + + Biological structures generated from different sources or processing steps may not always share + exactly the same coordinate system. For this reason, the protocol can perform a rigid-body + alignment between the reference structures and the conformational models before reconstruction. + + Alignment is generally recommended when there is uncertainty regarding the relative orientation + of the structures. Proper alignment ensures that the conformational changes are interpreted + correctly and prevents artificial distortions in the resulting all-atom models. When all + structures are already known to be expressed in the same coordinate frame, alignment may be + unnecessary. + + Reconstruction Strategy + + The reconstruction process transfers atomic information from the reference structure to each + target conformation while preserving the large-scale motions encoded in the C-alpha models. + Nearby structural relationships within the reference are used to estimate how atomic positions + should adapt to the new conformational state. + + A distance cutoff controls the local structural neighborhood used during this reconstruction. + Conceptually, this parameter determines how much surrounding structural information contributes + to the placement of atoms. Smaller values emphasize highly local structural relationships, + whereas larger values incorporate broader structural context. + + The optimal cutoff depends on the size, flexibility, and architecture of the biological + system. Moderate values are often suitable for most proteins, while highly flexible assemblies + may benefit from additional testing to identify the most realistic reconstruction behavior. + + Outputs and Interpretation + + The protocol produces a new collection of all-atom structures corresponding to the input + conformational ensemble. Each output model preserves the conformational characteristics of its + associated C-alpha structure while providing a complete atomic description suitable for + visualization and downstream analysis. + + These reconstructed structures can be inspected individually to study specific conformational + states or analyzed collectively to explore molecular trajectories and structural variability. + Because the outputs share a common atomic framework, they are particularly useful for comparing + residue-level changes across a conformational landscape. + + Practical Recommendations + + For most biological applications, it is advisable to begin with a high-quality all-atom + reference that closely represents the system under investigation. Visual inspection of the + reconstructed models is recommended, especially when large conformational changes are present. + + When working with highly flexible proteins or assemblies containing multiple moving domains, + users should verify that the reconstructed atomic models remain biologically plausible across + the entire conformational range. Testing different cutoff values may help improve the balance + between local structural fidelity and global conformational consistency. + + Final Perspective + + The conversion from C-alpha representations to all-atom structures bridges the gap between + computationally efficient flexibility analyses and biologically detailed structural + interpretation. By restoring atomic information while preserving conformational variability, + the protocol enables researchers to move from coarse-grained descriptions of motion to + atomically resolved models that can support visualization, mechanistic understanding, and + further structural investigations. + """ + _label = 'c-alpha PDBs to all-atom PDBs' + + # --------------------------- DEFINE param functions -------------------------------------------- + def _defineParams(self, form): + form.addSection(label='Input') + form.addParam('setOfPDBs', params.PointerParam, pointerClass='SetOfPDBs, SetOfAtomStructs', + label="Set of PDBs", + help='Use a scipion object SetOfPDBs / SetOfAtomStructs') + form.addParam('aaPDB', params.PointerParam, pointerClass='AtomStruct', + label="All-atom pdb reference", + help='Use a reference all-atom PDB') + + form.addParam('useExternalCaRef', params.BooleanParam, default=False, + label="Uses a external C-alpha reference ?", + help='If yes, provides an external PDB as reference for the c-alpha model, otherwise, ' + 'uses a c-alpha-converted version of the all-atom reference') + + form.addParam('caPDB', params.PointerParam, pointerClass='AtomStruct', + label="c-alpha pdb reference", + help='Use a reference c-alpha PDB', condition="useExternalCaRef") + form.addParam('cutoff', params.FloatParam, default=10.0, + label="cutoff distance (A)", + help='Cutoff distance used to calculate interpolation') + form.addParam('align', params.BooleanParam, default=True, + label="Align references ?", + help='If yes, a rigid-body alignment against the reference and the PDBs to convert is performed.') + + # --------------------------- INSERT steps functions -------------------------------------------- + def _insertAllSteps(self): + self._insertFunctionStep('ca2aa') + self._insertFunctionStep('createOutputStep') + + def ca2aa(self): + + pdbSet = self.setOfPDBs.get() + aa_ref_pdb = self.aaPDB.get().getFileName() + matchingType = None + + aa_ref = ContinuousFlexPDBHandler(aa_ref_pdb) + if self.useExternalCaRef.get(): + ca_ref_pdb = self.caPDB.get().getFileName() + ca_ref = ContinuousFlexPDBHandler(ca_ref_pdb) + else: + ca_ref = aa_ref.copy() + ca_ref.select_atoms(aa_ref.allatoms2ca()) + match = aa_ref.matchPDBatoms(ca_ref, matchingType=matchingType) + final_id = self.compute_interpolation_index(init=aa_ref, match=match, cutoff=self.cutoff.get()) + + ndata = pdbSet.getSize() + + new_pdb = aa_ref.copy() + for j in range(ndata): + print("frame processed %i /%i " % (j + 1, ndata)) + pdbin = pdbSet[j+1].getFileName() + pdbout = self._getExtraPath("output_%s.pdb"%str(j+1).zfill(6)) + ca_ref.coords = ContinuousFlexPDBHandler.read_coords(pdbin) + + if self.align.get(): + aa_ref = aa_ref.alignMol(ca_ref, idx_matching_atoms=match) + + vec = ca_ref.coords[match[:, 1]] - aa_ref.coords[match[:, 0]] + for i in range(aa_ref.n_atoms): + new_pdb.coords[i] = aa_ref.coords[i] + vec[final_id[i]].mean(axis=0) + new_pdb.write_pdb(pdbout) + + def compute_interpolation_index(self, init, match, cutoff): + tmp_idx = {} + + def add(dic, key, val): + if key in dic: + if not val in dic[key]: + dic[key].append(val) + else: + pass + else: + dic[key] = [val] + + print("Computing pairlist ...") + for i in range(init.n_atoms): + if i % (init.n_atoms // 10) == 0: + print("\t %i %%" % (10 * i // (init.n_atoms // 10))) + dist_idx = match[:, 0] + dist = np.linalg.norm(init.coords[dist_idx] - init.coords[i], axis=1) + idx = np.where(dist < cutoff)[0] + if len(idx) == 0: + raise RuntimeError("At least one atoms is too far from the others with the current cutoff parameter") + else: + for j in idx: + add(tmp_idx, i, j) + # add(tmp_idx, j,i) + for i in tmp_idx: + tmp_idx[i] = np.array(tmp_idx[i]) + return tmp_idx + + def createOutputStep(self): + pdbset = self._createSetOfPDBs("outputPDBs") + for i in range(self.setOfPDBs.get().getSize()): + filename = self._getExtraPath("output_%s.pdb" %str(i+1).zfill(6)) + pdb = AtomStruct(filename=filename) + pdbset.append(pdb) + self._defineOutputs(outputPDBs = pdbset) + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['harastani2022continuousflex'] + + def _methods(self): + pass + + # --------------------------- UTILS functions -------------------------------------------- + def _printWarnings(self, *lines): + """ Print some warning lines to 'warnings.xmd', + the function should be called inside the working dir.""" + fWarn = open("warnings.xmd", 'w') + for l in lines: + print >> fWarn, l + fWarn.close() diff --git a/continuousflex/protocols/protocol_deep_hemnma_infer.py b/continuousflex/protocols/protocol_deep_hemnma_infer.py new file mode 100644 index 0000000..e61337c --- /dev/null +++ b/continuousflex/protocols/protocol_deep_hemnma_infer.py @@ -0,0 +1,287 @@ +# ************************************************************************** +# * +# * Authors: +# * Ilyes Hamitouche +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# * +# ************************************************************************** + +import xmipp3.convert +from pyworkflow.protocol.params import PointerParam +import pyworkflow.protocol.params as params +from pwem.protocols import ProtAnalysis3D +from subprocess import check_call +import sys +from os.path import isfile +import continuousflex +from pyworkflow.utils.path import copyFile +import pwem as em +import pwem.emlib.metadata as md +from xmipp3.convert import (createItemMatrix, setXmippAttributes) +from pyworkflow import BETA +from continuousflex import Plugin +from pwem.utils import runProgram + +OPTION_NMA = 0 +OPTION_ANGLES = 1 +OPTION_SHFITS = 2 +OPTION_ALL = 3 + +DEVICE_CUDA = 0 +DEVICE_CPU = 1 + +class FlexProtDeepHEMNMAInfer(ProtAnalysis3D): + """ + This protocol is DeepHEMNMA + + AI Generated: + + Deep HEMNMA Inference (FlexProtDeepHEMNMAInfer) - User Manual + Overview + + The Deep HEMNMA Inference protocol applies a previously trained Deep HEMNMA model to + estimate structural variability parameters directly from cryo-EM particle images. Its + primary objective is to use knowledge learned during a prior training stage to rapidly + predict conformational and rigid-body descriptors for new datasets, avoiding the need to + perform a complete variability analysis from the beginning. + + In studies of molecular flexibility, researchers often need to characterize large numbers + of particles that may represent a continuum of structural states. Once a predictive model + has been trained, this protocol enables efficient estimation of the underlying variability + parameters, making large-scale analyses substantially more practical. + + Inputs and General Workflow + + The protocol requires a trained Deep HEMNMA model together with a new particle dataset that + will be analyzed. The trained model serves as a learned representation of the relationship + between particle appearance and structural variability, while the input particles provide + the experimental observations from which predictions are generated. + + The protocol is intended to be used after a successful training stage. The quality of the + predictions depends strongly on how well the training dataset represents the structural + variability present in the new particles. Datasets that differ substantially from the data + used during training may produce less reliable results. + + Prediction Targets + + Different categories of structural descriptors can be predicted depending on the scientific + objective. Conformational variability can be represented through normal mode amplitudes, + which describe collective molecular motions and continuous structural transitions between + biological states. + + The protocol can also estimate rotational and translational parameters associated with + rigid-body variability. These descriptors are useful when structural differences are + dominated by large-scale movements of domains, subunits, or complete molecular assemblies. + + In many applications, predicting all available parameters simultaneously provides the most + comprehensive description of particle heterogeneity. However, restricting the prediction + task to a specific category may be advantageous when the biological question focuses on a + particular type of motion. + + Normal Modes and Structural Interpretation + + The number of normal modes determines the dimensionality of the conformational description. + A larger number of modes can capture more complex motions, while a smaller number often + focuses on the dominant collective movements that explain most of the observed variability. + + From a biological perspective, normal mode amplitudes should be interpreted as coordinates + within a continuous conformational landscape. Similar amplitude values generally correspond + to related structural states, whereas larger differences may indicate distinct conformations + or transitions between functional forms. + + Computational Resources + + The protocol supports execution on graphical processing units and conventional central + processing units. GPU execution is generally preferred because neural network inference can + be performed significantly faster, especially when processing large particle collections. + + CPU execution remains useful when accelerator hardware is unavailable or when analyzing + smaller datasets. The choice of computational device affects performance but does not + change the biological interpretation of the predicted parameters. + + Outputs and Their Interpretation + + The protocol produces a particle set enriched with predicted structural descriptors. These + predictions can be used for downstream analyses of conformational variability, structural + clustering, visualization of continuous motions, or comparison with previously characterized + states. + + The resulting dataset preserves the connection between each particle and its estimated + variability parameters, enabling researchers to explore structural landscapes at the + individual-particle level. This information can be valuable for identifying dominant motions, + mapping functional transitions, or studying heterogeneous molecular assemblies. + + In addition to generating predictions for the new dataset, the protocol integrates the + inferred information with the variability information associated with the training data. + This facilitates direct comparison between previously characterized particles and newly + analyzed observations within a common variability framework. + + Practical Recommendations + + For best results, the training model should originate from a dataset that adequately samples + the conformational space expected in the inference dataset. Predictions are generally more + reliable when the new particles belong to the same biological system and imaging conditions + used during training. + + Researchers should carefully select the prediction target according to their biological + objectives. Studies focused on molecular flexibility often benefit from emphasizing normal + mode amplitudes, whereas investigations involving particle orientation or positional + variability may require angular and translational predictions as well. + + When working with very large datasets, GPU execution is typically the most efficient option. + It allows rapid processing while maintaining the same predictive framework established during + training. + + Final Perspective + + Deep HEMNMA Inference transforms a trained deep learning model into a practical tool for + exploring structural heterogeneity in cryo-EM data. By predicting conformational and + rigid-body descriptors directly from particle images, it enables efficient characterization + of molecular variability and supports the study of continuous structural landscapes across + large experimental datasets. + """ + _label = 'deep hemnma infer' + _devStatus = BETA + + + #--------------------------- DEFINE param functions -------------------------------------------- + def _defineParams(self, form): + form.addSection(label='Input') + form.addParam('analyze_option', params.EnumParam, label='set the parameter to predict', + display=params.EnumParam.DISPLAY_COMBO, + choices=['Predict Normal Mode Amplitudes', + 'Predict Angles', + 'Predict Shifts', + 'predict All parameters', + ], default=OPTION_ALL, + help='select a set of parameter to predict') + form.addParam('device_option', params.EnumParam, label='set the device for training', + display=params.EnumParam.DISPLAY_COMBO, + choices=['train on GPUs', + 'tain on CPUs'], default=DEVICE_CUDA, + help='set a device to run the training on') + form.addParam('trained_model', params.PointerParam, pointerClass='FlexProtDeepHEMNMATrain', + label = 'Trained model', help='import the training weights') + form.addParam('inputParticles', PointerParam, pointerClass='SetOfParticles', + label="Previous run of rigid-body alignment", + help='Select a previous run of rigid-body alignment.', allowsNull=True) + form.addParam('num_modes', params.IntParam, label='Number of modes',default=3) + form.addParam('batch_size', params.IntParam, expertLevel=params.LEVEL_ADVANCED, label='Batch size', default=2) + form.addParallelSection(threads=0, mpi=0) + + + #--------------------------- INSERT steps functions -------------------------------------------- + + def _insertAllSteps(self): + self._insertFunctionStep('convertInputStep') + self._insertFunctionStep('performDeepHEMNMAStep') + self._insertFunctionStep('createOutputStep') + + #--------------------------- STEPS functions -------------------------------------------- + + def convertInputStep(self): + xmipp3.convert.writeSetOfParticles(self.inputParticles.get(), self._getExtraPath('particles.xmd')) + # copy atoms or pseudoatoms file from HEMNMA + file = self.trained_model.get().inputNMA.get()._getExtraPath('atoms.pdb') + if isfile(file): + copyFile(file, self._getExtraPath('atoms.pdb')) + else: + copyFile(self.trained_model.get().inputNMA.get()._getExtraPath('pseudoatoms.pdb'), self._getExtraPath('pseudoatoms.pdb')) + + + + def performDeepHEMNMAStep(self): + weights = self.trained_model.get()._getExtraPath('weights.pth') + #copyFile(self.inputParticles.get('atoms.pdb'), self._getExtraPath('atoms.pdb')) + #copyFile(self.inputParticles.get('modes.pdb'), self._getExtraPath('modes.pdb')) + batch_size = self.batch_size.get() + mode = self.analyze_option.get() + device = self.device_option.get() + num_modes = self.num_modes.get() + self.imgsFn = self._getExtraPath('particles.xmd') + params = " %s %s %s %d %d %d %d" % (self.imgsFn, weights, self._getExtraPath(), num_modes, batch_size, mode, device) + script_path = continuousflex.__path__[0]+'/protocols/utilities/deep_hemnma_infer.py' + command = "python " + script_path + params + command = Plugin.getContinuousFlexCmd(command) + check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr, env=None, cwd=None) + pass + + + def createOutputStep(self): + inputSet = self.inputParticles.get() + partSet = self._createSetOfParticles() + partSet.copyInfo(inputSet) + self.imgsFn = self._getExtraPath('images.xmd') + copyFile(self.imgsFn, self._getExtraPath('infer.xmd')) + partSet.copyItems(inputSet, + updateItemCallback=self._updateParticle, + itemDataIterator=md.iterRows(self.imgsFn, sortByLabel=md.MDL_ITEM_ID)) + partSet.copyItems(self.trained_model.get().inputNMA.get().outputParticles) + self._defineOutputs(outputParticles=partSet) + # Lets write a metadata that combines both of these training and inference sets: + fn_train = self.trained_model.get().inputNMA.get()._getExtraPath('images.xmd') + fn_infer = self._getExtraPath('infer.xmd') + fn_combined = self._getExtraPath('images.xmd') + args = '-i %(fn_train)s -o %(fn_combined)s --set union %(fn_infer)s' % locals() + runProgram('xmipp_metadata_utilities', args) + + + #--------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['harastani2022continuousflex','hamitouche2022deephemnma'] + + def _methods(self): + return [] + + #--------------------------- UTILS functions -------------------------------------------- + + def getInputParticles(self): + """ Get the output particles of the input NMA protocol. """ + return self.inputNMA.get().outputParticles + + def getParticlesMD(self): + "Get the metadata files that contain the NMA displacement" + return self.inputNMA.get()._getExtraPath('images.xmd') + + def getInputPdb(self): + return self.inputNMA.get().getInputPdb() + + def getOutputMatrixFile(self): + return self._getExtraPath('output_matrix.txt') + + def getDeformationFile(self): + return self._getExtraPath('deformations.txt') + + def getProjectorFile(self): + return self.mappingFile.get() + + + def _updateParticle(self, item, row): + setXmippAttributes(item, row, md.MDL_ANGLE_ROT, md.MDL_ANGLE_TILT, md.MDL_ANGLE_PSI, md.MDL_SHIFT_X, + md.MDL_SHIFT_Y, md.MDL_FLIP, md.MDL_NMA, md.MDL_COST) + createItemMatrix(item, row, align=em.ALIGN_PROJ) \ No newline at end of file diff --git a/continuousflex/protocols/protocol_deep_hemnma_train.py b/continuousflex/protocols/protocol_deep_hemnma_train.py new file mode 100644 index 0000000..6f8c532 --- /dev/null +++ b/continuousflex/protocols/protocol_deep_hemnma_train.py @@ -0,0 +1,252 @@ +# ************************************************************************** +# * +# * Authors: +# * Ilyes Hamitouche +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# * +# ************************************************************************** + +from pyworkflow.protocol.params import PointerParam +import pyworkflow.protocol.params as params +from pwem.protocols import ProtAnalysis3D +from subprocess import check_call +import sys +import continuousflex +from pyworkflow import BETA +from continuousflex import Plugin + +OPTION_NMA = 0 +OPTION_ANGLES = 1 +OPTION_SHFITS = 2 +OPTION_ALL = 3 + +DEVICE_CUDA = 0 +DEVICE_CPU = 1 + + +class FlexProtDeepHEMNMATrain(ProtAnalysis3D): + """ + DeepHEMNMA protocol, a neural network that learns the rigid-body parameters and the normal mode + amplitudes estimated by HEMNMA protocol. + + AI Generated: + + Deep HEMNMA Training (FlexProtDeepHEMNMATrain) - User Manual + Overview + + The Deep HEMNMA Training protocol is designed to learn the relationship between cryo-EM + particle images and the structural variability parameters previously estimated through + HEMNMA analyses. Its purpose is to train a deep learning model capable of predicting + conformational and rigid-body motion descriptors directly from experimental data, providing + a faster and more scalable alternative for studying molecular heterogeneity in large datasets. + + In structural biology, understanding continuous flexibility is often essential for revealing + biologically relevant motions that cannot be captured by a single static structure. This + protocol enables researchers to build predictive models that reproduce the variability + information obtained from previous analyses and apply that knowledge to extensive particle + collections. + + Inputs and Training Data + + The protocol relies on previously characterized datasets in which flexibility parameters + have already been estimated. These reference measurements serve as the learning targets + used during training. Depending on the scientific objective, the model can focus on + conformational variability, rigid-body variability, or both simultaneously. + + Conformational variability is represented through normal mode amplitudes that describe + collective structural motions. These amplitudes provide a compact description of molecular + flexibility and are particularly useful when studying continuous transitions between + functional states. + + Rigid-body variability corresponds to rotational and translational motions. These parameters + describe how entire molecular assemblies or domains move relative to the imaging reference + frame and can be important when flexibility is dominated by large-scale motions rather than + internal deformations. + + Choice of Training Objective + + The protocol allows training on different categories of structural parameters. Researchers + interested primarily in molecular flexibility can focus on conformational descriptors, + whereas studies involving particle orientation variability may benefit from training on + angular parameters, translational parameters, or a combination of all available descriptors. + + Training on a single category often simplifies the learning problem and may improve model + specialization. In contrast, training on all available parameters simultaneously can provide + a more comprehensive representation of structural variability and may be advantageous when + multiple motion types contribute to the observed heterogeneity. + + Computational Resources + + Training can be performed using either graphical processing units or conventional central + processing units. GPU-based execution is generally recommended because deep learning models + benefit substantially from hardware acceleration, particularly when working with large image + datasets or extended training schedules. + + CPU execution remains useful when dedicated accelerators are unavailable or when performing + exploratory tests with smaller datasets. However, training times may increase considerably + depending on dataset size and model complexity. + + Learning Parameters + + Several parameters control the optimization process. The learning rate determines how + rapidly the model updates its internal representation during training. Small values often + provide stable convergence, while larger values may accelerate training but increase the + risk of instability. + + The number of epochs defines how many times the complete training dataset is presented to + the model. Higher values generally allow deeper learning but may increase computational + cost and the possibility of overfitting if training continues beyond the point where + generalization improves. + + Batch size controls how many samples are processed together during each optimization step. + Smaller batches typically require less memory and may improve generalization, whereas + larger batches can accelerate training when sufficient hardware resources are available. + + Interpretation of the Trained Model + + The resulting model captures the relationship between particle appearance and the structural + descriptors selected for training. Biologically, this means that information previously + extracted through computationally intensive analyses can be approximated by a learned model, + enabling rapid estimation of flexibility-related parameters for new data. + + The quality of the learned representation depends strongly on the quality and diversity of + the training dataset. Datasets that adequately sample the full range of conformational and + rigid-body variability generally produce more robust and biologically meaningful models. + + Practical Recommendations + + For most studies, it is advisable to begin with carefully validated HEMNMA results before + initiating training. The neural network can only learn the variability patterns present in + the reference dataset, making the quality of the initial characterization a critical factor + in overall performance. + + When computational resources permit, GPU execution combined with sufficient training epochs + usually provides the most effective learning conditions. Researchers should monitor model + behavior and adjust optimization parameters when convergence is unstable or predictive + performance plateaus prematurely. + + Studies focused on continuous molecular motions may benefit from emphasizing normal mode + amplitudes, while investigations involving orientation or positional variability may obtain + better results by incorporating angular and translational descriptors. + + Final Perspective + + Deep HEMNMA Training bridges traditional flexibility analysis and modern deep learning by + transforming previously estimated structural variability into a predictive framework. For + researchers studying continuous conformational landscapes, this approach provides an + efficient way to model complex molecular motions and extend flexibility analysis to larger + cryo-EM datasets while preserving the biological interpretation of the learned variability. + """ + _label = 'deep hemnma train' + _devStatus = BETA + + #--------------------------- DEFINE param functions -------------------------------------------- + def _defineParams(self, form): + form.addSection(label='Input') + form.addParam('analyze_option', params.EnumParam, label='set the parameter to train on', + display=params.EnumParam.DISPLAY_COMBO, + choices=['Train on Normal Mode Amplitudes', + 'Train on Angles', + 'Train on Shifts', + 'Train on All parameters', + ], default = OPTION_ALL, + help='select a set of parameter to train on') + group = form.addGroup('Train on conformational variability', condition='analyze_option == %d or analyze_option == %d'% (OPTION_NMA, OPTION_ALL)) + group.addParam('inputNMA', PointerParam, pointerClass='FlexProtAlignmentNMA', + label="Previous HEMNMA run", + help='Select a previous run of the NMA image alignment.', allowsNull=True) + group = form.addGroup('Train on rigid-body variability ', condition='analyze_option == %d or analyze_option == %d' %(OPTION_SHFITS, OPTION_ANGLES)) + group.addParam('inputParticles', PointerParam, pointerClass='SetOfParticles', + label="Preious run of rigid-body alignment", + help='Select a previous run of rigid-body alignment.', allowsNull=True) + form.addParam('device_option', params.EnumParam, label='set the device for training', + display=params.EnumParam.DISPLAY_COMBO, + choices=['train on GPUs', + 'tain on CPUs'], default = DEVICE_CUDA, + help='set a device to run the training on') + form.addParam('learning_rate', params.FloatParam, label = 'Learning rate', default = 0.0001) + form.addParam('epochs', params.IntParam, expertLevel=params.LEVEL_ADVANCED,label = 'Number of epochs', default = 400) + form.addParam('batch_size', params.IntParam ,expertLevel=params.LEVEL_ADVANCED, label = 'Batch size', default = 2) + form.addParallelSection(threads=0, mpi=0) + + + #--------------------------- INSERT steps functions -------------------------------------------- + + def _insertAllSteps(self): + self._insertFunctionStep('performDeepHEMNMAStep') + self._insertFunctionStep('createOutputStep') + + #--------------------------- STEPS functions -------------------------------------------- + + def performDeepHEMNMAStep(self): + epochs = self.epochs.get() + batch_size = self.batch_size.get() + lr = self.learning_rate.get() + mode = self.analyze_option.get() + device = self.device_option.get() + imgsFn = self.inputNMA.get()._getExtraPath('images.xmd') + + params = " %s %s %d %d %f %d %d" % (imgsFn, self._getExtraPath(), epochs, batch_size, lr, mode, device) + script_path = continuousflex.__path__[0]+'/protocols/utilities/deep_hemnma.py' + command = "python " + script_path + params + command = Plugin.getContinuousFlexCmd(command) + check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr, env=None, cwd=None) + + + def createOutputStep(self): + pass + + #--------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['harastani2022continuousflex','hamitouche2022deephemnma'] + + def _methods(self): + return [] + + #--------------------------- UTILS functions -------------------------------------------- + + def getInputParticles(self): + """ Get the output particles of the input NMA protocol. """ + return self.inputNMA.get().outputParticles + + def getParticlesMD(self): + "Get the metadata files that contain the NMA displacement" + return self.inputNMA.get()._getExtraPath('images.xmd') + + def getInputPdb(self): + return self.inputNMA.get().getInputPdb() + + def getOutputMatrixFile(self): + return self._getExtraPath('output_matrix.txt') + + def getDeformationFile(self): + return self._getExtraPath('deformations.txt') + + def getProjectorFile(self): + return self.mappingFile.get() + diff --git a/continuousflex/protocols/protocol_denoise_volumes.py b/continuousflex/protocols/protocol_denoise_volumes.py index e221be1..d5d32ac 100644 --- a/continuousflex/protocols/protocol_denoise_volumes.py +++ b/continuousflex/protocols/protocol_denoise_volumes.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -27,10 +27,7 @@ import pyworkflow.protocol.params as params from pyworkflow.utils.path import makePath, copyFile from os.path import basename, isfile -from sh_alignment.tompy.transform import fft, ifft, fftshift, ifftshift -from .utilities.spider_files3 import save_volume, open_volume from pyworkflow.utils import replaceBaseExt -import numpy as np from continuousflex.protocols.utilities.bm4d import bm4d from pwem.utils import runProgram @@ -50,7 +47,154 @@ class FlexProtVolumeDenoise(ProtAnalysis3D): - """ Protocol for subtomogram missingwedge filling. """ + """ + Denoises three-dimensional volumes using advanced noise reduction + techniques. The protocol improves volume quality by reducing unwanted + noise while attempting to preserve biologically relevant structural + information. + + AI Generated: + + Volume Denoise (FlexProtVolumeDenoise) - User Manual + Overview + + The Volume Denoise protocol is designed to enhance the quality of + three-dimensional volumes by reducing noise that may obscure + meaningful structural features. In cryo-electron microscopy, + subtomogram analysis, and related volumetric imaging workflows, + noise is an unavoidable component of experimental data and can + significantly affect visualization, interpretation, classification, + and downstream computational analyses. + + The primary objective of this protocol is to improve the signal-to- + noise ratio while maintaining the integrity of biologically relevant + structures. By producing cleaner volumes, the protocol facilitates + subsequent procedures such as averaging, flexible analysis, + segmentation, structural comparison, and molecular interpretation. + + Inputs and General Workflow + + The protocol accepts either a single volume or a collection of + volumes. This flexibility allows users to process individual + reconstructions as well as large datasets generated during + subtomogram averaging, classification, or conformational studies. + + Each input volume is processed independently using the selected + denoising strategy. The resulting outputs preserve the identity and + organization of the original dataset while providing improved image + quality for further analysis. + + Choice of Denoising Method + + The protocol provides two alternative approaches for noise reduction, + each suited to different scientific objectives and data conditions. + + The BM4D method is an advanced volumetric denoising strategy + specifically designed for three-dimensional data. It is generally + preferred when preserving subtle structural details is important. + This approach is particularly valuable for cryo-EM and tomography + datasets where signal levels are low and structural features may be + difficult to distinguish from background noise. + + The Fourier low-pass filtering method is a simpler and computationally + efficient approach. It attenuates high-frequency components that are + frequently dominated by noise while retaining lower-frequency + structural information. This method is useful for rapid exploratory + analysis or for datasets where fine high-resolution information is + not the primary focus. + + BM4D Noise Modeling + + When using BM4D, the protocol allows the user to specify the expected + statistical behavior of the noise. Different noise distributions may + better describe different imaging conditions, and selecting an + appropriate model can improve denoising performance. + + The protocol also provides control over the estimated noise level. + This parameter strongly influences the balance between noise removal + and structural preservation. Lower values generally preserve more + detail but may leave residual noise, whereas higher values produce + smoother volumes at the risk of suppressing weak biological features. + + Several processing profiles are available to accommodate different + computational and denoising requirements. These profiles allow users + to adapt the method to the characteristics of their data and the + desired level of noise suppression. + + An optional Wiener refinement stage may also be employed. This + additional processing can improve denoising performance in some + datasets by further enhancing signal recovery while maintaining + structural consistency. + + Fourier Low-Pass Filtering + + The Fourier filtering approach removes high-frequency information + beyond a selected cutoff frequency. Biologically, this operation can + be interpreted as emphasizing large-scale structural organization + while reducing small-scale fluctuations dominated by noise. + + The cutoff frequency determines the effective resolution retained in + the processed volume. Lower cutoff values produce smoother volumes + with stronger noise suppression, whereas higher values preserve more + structural detail. A gradual transition region can also be applied to + reduce filtering artifacts and generate more natural-looking results. + + Biological Considerations + + Denoising should always be performed with awareness of the biological + question being addressed. Excessive noise reduction may remove weak + but meaningful structural features, particularly in flexible regions, + small domains, or low-occupancy conformations. + + For exploratory visualization and qualitative interpretation, + stronger denoising may be acceptable. However, for quantitative + analyses or studies involving subtle conformational differences, + conservative processing is generally recommended to avoid introducing + bias or obscuring genuine variability. + + In heterogeneous datasets, users should be especially cautious when + comparing denoised volumes. Differences introduced by aggressive + filtering may sometimes be mistaken for biological variation. + + Outputs and Their Interpretation + + The protocol produces a denoised volume or set of denoised volumes + corresponding directly to the provided inputs. The outputs retain the + original sampling characteristics while exhibiting reduced noise and + improved visual clarity. + + These processed volumes can be used for visualization, classification, + flexible analysis, segmentation, or as inputs to additional + computational workflows. The denoised results should nevertheless be + interpreted alongside the original data whenever critical biological + conclusions are being drawn. + + Practical Recommendations + + For most cryo-EM and subtomogram analysis applications, BM4D is + generally the preferred starting point because it provides strong + noise reduction while preserving structural information more + effectively than simple frequency filtering. + + Fourier low-pass filtering is useful for rapid preprocessing, + visualization, or situations where computational simplicity is + desired. It can also serve as an initial assessment tool before more + advanced denoising methods are applied. + + Users should evaluate denoising results visually and, whenever + possible, compare them against the original volumes to ensure that + biologically meaningful features have not been inadvertently removed. + + Final Perspective + + Noise reduction is often a crucial step in volumetric structural + biology workflows. Effective denoising can substantially improve the + interpretability of experimental data and facilitate downstream + analyses. The most reliable results are obtained when the denoising + strategy is selected according to the characteristics of the dataset + and the biological objectives of the study, balancing noise + suppression with faithful preservation of structural information. + """ _label = 'volume denoise' # --------------------------- DEFINE param functions -------------------------------------------- @@ -227,7 +371,7 @@ def _summary(self): return summary def _citations(self): - return [] + return ['harastani2022continuousflex'] def _methods(self): pass diff --git a/continuousflex/protocols/protocol_generate_topology.py b/continuousflex/protocols/protocol_generate_topology.py new file mode 100644 index 0000000..8f511c3 --- /dev/null +++ b/continuousflex/protocols/protocol_generate_topology.py @@ -0,0 +1,465 @@ +# ************************************************************************** +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +from pwem.protocols import EMProtocol +import pyworkflow.protocol.params as params +from pwem.objects.data import AtomStruct +from .utilities.pdb_handler import ContinuousFlexPDBHandler +from pyworkflow.utils import runCommand +import os +from pwem.convert.atom_struct import cifToPdb +import pyworkflow.utils as pwutils +from continuousflex import Plugin +import continuousflex + +NUCLEIC_NO = 0 +NUCLEIC_RNA =1 +NUCLEIC_DNA = 2 + +FORCEFIELD_CHARMM = 0 +FORCEFIELD_AAGO = 1 +FORCEFIELD_CAGO = 2 + + +class ProtGenerateTopology(EMProtocol): + """ + Generates topology-ready molecular models for GENESIS simulations from + atomic structures. The protocol prepares biomolecular systems so they can + be used in molecular dynamics and structure-based modeling workflows. + + AI Generated: + + Generate Topology Model (ProtGenerateTopology) - User Manual + Overview + + The Generate Topology Model protocol prepares an atomic structure for + molecular simulations by creating a topology-compatible molecular model. + Its primary purpose is to transform an experimentally derived structure + into a form that can be used by simulation engines, including all-atom + and coarse-grained modeling approaches. This step is often one of the + first requirements before performing molecular dynamics simulations, + conformational exploration, or flexible fitting studies. + + The protocol is designed to support different force field strategies. + Depending on the scientific objective, users may generate a standard + all-atom representation suitable for detailed molecular dynamics or + create topology models based on Go-like potentials that emphasize the + native structure and are commonly used for large-scale conformational + studies. This flexibility makes the protocol useful for both high- + resolution atomistic simulations and reduced-complexity models intended + for studying collective motions. + + Inputs and General Workflow + + The protocol requires an atomic structure as input. The structure may + originate from experimental methods such as X-ray crystallography, + cryo-EM, or NMR, as well as from computational modeling procedures. + Before topology generation, the molecular description is standardized to + ensure compatibility with the selected simulation framework. + + During preparation, residue and atom naming conventions are harmonized + and molecular organization is validated. This helps avoid common + problems arising from differences between structural databases and force + field expectations. The resulting model is therefore more suitable for + subsequent simulation steps and less likely to encounter topology- + generation failures. + + Choice of Force Field Representation + + The protocol supports multiple force field philosophies that address + different scientific questions. + + The CHARMM option is intended for detailed all-atom simulations where + atomic interactions are represented explicitly. This approach is + generally preferred when studying local structural changes, ligand + interactions, energetic properties, or processes requiring high physical + realism. + + The All-Atom Go model preserves an atomistic representation while + simplifying the interaction scheme around the experimentally observed + native structure. Such models are useful when the goal is to investigate + large conformational transitions while reducing computational cost. + + The C-Alpha Go model provides an even more reduced representation by + focusing on backbone-level structural behavior. This option is often + selected for very large macromolecular assemblies, long-timescale + simulations, or exploratory studies of conformational landscapes. + + For many biological applications, a topology generated first using an + all-atom representation can serve as a reliable starting point before + constructing simplified Go-model variants. + + Residue and Sequence Preparation + + Structural files frequently contain residue numbering irregularities, + insertion codes, or sequence discontinuities introduced during + experimental structure determination. These issues may complicate + topology generation and simulation setup. + + The protocol provides options to reorganize residue numbering and create + a more consistent molecular description. This is particularly important + when structures have been assembled from multiple experimental sources + or contain insertion labels that may not be interpreted consistently by + simulation software. + + From a biological perspective, correcting residue organization does not + alter the molecular structure itself but improves the consistency of the + model used throughout the simulation workflow. + + Protein and Nucleic Acid Systems + + The protocol supports proteins as well as nucleic acid molecules. RNA + and DNA components are recognized and prepared according to the + conventions expected by the selected force field representation. + + This capability is important for studies involving ribonucleoprotein + complexes, chromatin-associated systems, ribosomes, viral genomes, or + other assemblies containing mixed biomolecular components. By ensuring + compatibility between molecular components and topology definitions, the + resulting models are better suited for integrated simulations of complex + biological systems. + + Structure Standardization + + Experimental structures often contain naming conventions that differ + from those expected by simulation packages. The protocol performs + standardization steps that improve compatibility while preserving the + biological meaning of the model. + + Such preparation is particularly valuable when structures originate from + different databases, software pipelines, or experimental sources. A + standardized topology-ready model simplifies downstream simulation + setup and reduces the need for manual intervention. + + Outputs and Their Interpretation + + The protocol produces a topology-compatible molecular structure ready + for use in subsequent simulation workflows. The resulting model + represents the same biological system as the input structure but has + been adapted to satisfy the requirements of the selected force field and + simulation environment. + + The output should be viewed as a prepared simulation model rather than a + modified biological interpretation. Structural features present in the + original input are preserved while the molecular description is made + consistent with the computational framework. + + Practical Recommendations + + For detailed molecular dynamics studies, the CHARMM representation is + generally the preferred choice because it retains the highest level of + atomic detail. For investigations focused on large conformational + motions, folding-like transitions, or broad exploration of structural + landscapes, Go-model representations often provide substantial + computational advantages. + + Before topology generation, users should inspect the input structure for + missing regions, unusual residue names, or inconsistencies in sequence + numbering. Ensuring that the experimental model accurately represents + the intended biological system will improve the quality of downstream + simulations. + + When working with mixed protein-nucleic acid assemblies, it is + particularly important to verify molecular completeness and chain + organization before beginning the topology preparation process. + + Final Perspective + + Topology generation is a foundational step in molecular simulation + workflows. Although it is often viewed as a technical preparation stage, + the quality and consistency of the generated model strongly influence + the reliability of subsequent analyses. Careful selection of the force + field representation and thoughtful preparation of the molecular + structure help ensure that simulation results remain biologically + meaningful and scientifically robust. + """ + _label = 'generate topology model' + + def _defineParams(self, form): + + form.addSection(label='Inputs') + + form.addParam('inputPDB', params.PointerParam, + pointerClass='AtomStruct', label="Input PDB", + help='Select the input PDB.', important=True) + + form.addParam('forcefield', params.EnumParam, label="Forcefield type", default=FORCEFIELD_CHARMM, important=True, + choices=['CHARMM', 'All-atom Go model', 'C-Alpha Go model'], + help="Type of the force field used for energy and force calculation. For Go models, it is strongly" + " recommended to first generate a topology model using CHARMM, then create a new protocol to generate" + " Go model topology based on the output CHARMM all-atom PDB model." + " This will ensure that residue sequences are consecutive and TER statements are present in PDB." + " CHARMM requires VMD psfgen installed. Go models requires SMOG 2 installed. ") + + form.addParam('reorderResidues', params.BooleanParam, label="Reorder residues and remove insertions", default=False, + help='Remove insertion code in the PDB and reorder residues accordingly') + + form.addParam('reorderType', params.BooleanParam, label="Reorder based on segment name?", + default=False, condition="reorderResidues", + help='If yes reorder the residues within a segment, otherwise, reorder residues within a chain') + + def _insertAllSteps(self): + ff = self.forcefield.get() + + self._insertFunctionStep("convertInput") + + if ff == FORCEFIELD_CAGO or ff == FORCEFIELD_AAGO: + self._insertFunctionStep("prepareGROTOP") + self._insertFunctionStep("runGROTOP") + + if ff == FORCEFIELD_CHARMM: + self._insertFunctionStep("preparePSF") + self._insertFunctionStep("runPSF") + + self._insertFunctionStep("checkPDB") + self._insertFunctionStep("createOutput") + + def convertInput(self): + inputPDB = self.inputPDB.get().getFileName() + outPDB = self._getExtraPath("input.pdb") + ext = os.path.splitext(inputPDB)[1] + + if ext == ".pdb" or ext == ".ent" : + runCommand("cp %s %s" % (inputPDB, outPDB)) + elif ext == ".cif" or ext == ".mmcif" : + cifToPdb(inputPDB, outPDB) + else: + print("ERROR (toPdb), Unknown file type for file = %s" % inputPDB) + + def createOutput(self): + self._defineOutputs(outputPDB=AtomStruct(self._getExtraPath("output.pdb"))) + + def preparePSF(self): + inputPDB = self._getExtraPath("input.pdb") + mol = ContinuousFlexPDBHandler(inputPDB) + + mol.alias_res("HIS", "HSE") + mol.alias_res("MSE", "MET") + mol.alias_atom("CD1", "CD", "ILE") + + rna = 0 + rna += mol.alias_res("A", "ADE") + rna += mol.alias_res("G", "GUA") + rna += mol.alias_res("C", "CYT") + rna += mol.alias_res("U", "URA") + + dna = 0 + dna += mol.alias_res("DA", "ADE") + dna += mol.alias_res("DG", "GUA") + dna += mol.alias_res("DC", "CYT") + dna += mol.alias_res("DT", "THY") + + if dna > 0 : + self.nucleicChoice = NUCLEIC_DNA + if rna >0 : + self.nucleicChoice = NUCLEIC_RNA + else: + self.nucleicChoice = NUCLEIC_NO + + + if self.reorderResidues.get(): + if self.reorderType.get() : + mol.atom_res_reorder(chainType=1) + else: + mol.atom_res_reorder(chainType=0) + + mol.write_pdb(self._getExtraPath("tmp.pdb")) + + def prepareGROTOP(self): + inputPDB = self._getExtraPath("input.pdb") + + mol = ContinuousFlexPDBHandler(inputPDB) + # mol.remove_alter_atom() + mol.remove_hydrogens() + mol.check_res_order() + + mol.alias_atom("CD", "CD1", "ILE") + mol.alias_atom("OT1", "O") + mol.alias_atom("OT2", "OXT") + mol.alias_res("HSE", "HIS") + mol.alias_res("HSD", "HIS") + mol.alias_res("HSP", "HIS") + + rna = 0 + rna += mol.alias_res("CYT", "C") + rna += mol.alias_res("GUA", "G") + rna += mol.alias_res("ADE", "A") + rna += mol.alias_res("URA", "U") + + dna = 0 + dna += mol.alias_res("CYT", "DC") + dna += mol.alias_res("GUA", "DG") + dna += mol.alias_res("ADE", "DA") + dna += mol.alias_res("THY", "DT") + if dna > 0: + self.nucleicChoice = NUCLEIC_DNA + if rna > 0: + self.nucleicChoice = NUCLEIC_RNA + else: + self.nucleicChoice = NUCLEIC_NO + + mol.alias_atom("O1'", "O1*") + mol.alias_atom("O2'", "O2*") + mol.alias_atom("O3'", "O3*") + mol.alias_atom("O4'", "O4*") + mol.alias_atom("O5'", "O5*") + mol.alias_atom("C1'", "C1*") + mol.alias_atom("C2'", "C2*") + mol.alias_atom("C3'", "C3*") + mol.alias_atom("C4'", "C4*") + mol.alias_atom("C5'", "C5*") + mol.alias_atom("C5M", "C7") + mol.add_terminal_res() + if self.reorderResidues.get(): + if self.reorderType.get() : + mol.atom_res_reorder(chainType=1) + else: + mol.atom_res_reorder(chainType=0) + mol.write_pdb(self._getExtraPath("tmp.pdb")) + + def runPSF(self): + inputPDB = self._getExtraPath("tmp.pdb") + inputTopo = self.getCHARMMInputs()[0] + outputPrefix = self._getExtraPath("output") + + fnPSFgen = self._getExtraPath("psfgen.tcl") + with open(fnPSFgen, "w") as psfgen: + psfgen.write("mol load pdb %s\n" % inputPDB) + psfgen.write("\n") + psfgen.write("package require psfgen\n") + psfgen.write("topology %s\n" % inputTopo) + psfgen.write("\n") + if self.nucleicChoice == NUCLEIC_RNA or self.nucleicChoice == NUCLEIC_DNA: + psfgen.write("set nucleic [atomselect top nucleic]\n") + psfgen.write("set chains [lsort -unique [$nucleic get chain]] ;\n") + psfgen.write("foreach chain $chains {\n") + psfgen.write(" set sel [atomselect top \"nucleic and chain $chain\"]\n") + psfgen.write(" $sel writepdb %s_tmp.pdb\n" % outputPrefix) + psfgen.write(" segment N${chain} { pdb %s_tmp.pdb }\n" % outputPrefix) + psfgen.write(" coordpdb %s_tmp.pdb N${chain}\n" % outputPrefix) + if self.nucleicChoice == NUCLEIC_DNA: + psfgen.write(" set resids [lsort -unique [$sel get resid]]\n") + psfgen.write(" foreach r $resids {\n") + psfgen.write(" patch DEOX N${chain}:$r\n") + psfgen.write(" }\n") + psfgen.write("}\n") + if self.nucleicChoice == NUCLEIC_DNA: + psfgen.write("regenerate angles dihedrals\n") + psfgen.write("\n") + psfgen.write("set protein [atomselect top protein]\n") + psfgen.write("set chains [lsort -unique [$protein get pfrag]]\n") + psfgen.write("foreach chain $chains {\n") + psfgen.write(" set sel [atomselect top \"protein and pfrag $chain\"]\n") + psfgen.write(" $sel writepdb %s_tmp.pdb\n" % outputPrefix) + psfgen.write(" segment P${chain} {pdb %s_tmp.pdb}\n" % outputPrefix) + psfgen.write(" coordpdb %s_tmp.pdb P${chain}\n" % outputPrefix) + psfgen.write("}\n") + psfgen.write("rm -f %s_tmp.pdb\n" % outputPrefix) + psfgen.write("\n") + psfgen.write("guesscoord\n") + psfgen.write("writepdb %s.pdb\n" % outputPrefix) + psfgen.write("writepsf %s.psf\n" % outputPrefix) + psfgen.write("exit\n") + fnPSFgen = self._getExtraPath("psfgen.tcl") + + # Run VMD PSFGEN + from pwem.viewers import Vmd + runCommand("vmd -dispdev text -e %s" % (fnPSFgen), + env=Vmd.getEnviron()) + + def runGROTOP(self): + outputPrefix = self._getExtraPath("output") + inputPDB = self._getExtraPath("tmp.pdb") + + # Run Smog2 + environ = pwutils.Environ(os.environ) + environ.set('PATH', os.path.join(Plugin.getVar("SMOG_HOME"), 'bin'), + position=pwutils.Environ.BEGIN) + cmd = "smog2 -i %s -dname %s -%s -limitbondlength -limitcontactlength" %\ + (inputPDB, outputPrefix, + "CA" if self.forcefield.get() == FORCEFIELD_CAGO else "AA") + runCommand(cmd, env=environ) + + # ADD CHARGE TO TOP FILE + grotopFile = outputPrefix + ".top" + with open(grotopFile, 'r') as f1: + with open(grotopFile + ".tmp", 'w') as f2: + atom_scope = False + write_line = False + for line in f1: + if "[" in line and "]" in line: + if "atoms" in line: + atom_scope = True + if atom_scope: + if "[" in line and "]" in line: + if not "atoms" in line: + atom_scope = False + write_line = False + elif not ";" in line and not (not line or line.isspace()): + write_line = True + else: + write_line = False + if write_line: + f2.write("%s\t0.0\n" % line[:-1]) + else: + f2.write(line) + runCommand("cp %s.tmp %s" % (grotopFile, grotopFile)) + runCommand("rm -f %s.tmp" % grotopFile) + + if self.forcefield.get() == FORCEFIELD_CAGO: + mol = ContinuousFlexPDBHandler(self._getExtraPath("input.pdb")) + mol.select_atoms(mol.allatoms2ca()) + mol.write_pdb(outputPrefix + ".pdb") + else: + runCommand("cp %s %s"%(inputPDB,outputPrefix + ".pdb")) + + def checkPDB(self): + outPDB = self._getExtraPath("output.pdb") + + # Check PDB + if not os.path.isfile(outPDB) : + raise RuntimeError("Can not locate output PDB file %s, check log files for more details " % outPDB) + if os.path.getsize(outPDB) ==0 : + raise RuntimeError("PDB file %s is empty, check log files for more details " % outPDB) + + outMol = ContinuousFlexPDBHandler(outPDB) + if outMol.n_atoms == 0: + raise RuntimeError("PDB file %s is empty, check log files for more details " % outPDB) + + + def getCHARMMInputs(self): + return continuousflex.__path__[0] + '/protocols/utilities/top_all36_prot_na.rtf',\ + continuousflex.__path__[0] + '/protocols/utilities/par_all36_prot_na.prm',\ + continuousflex.__path__[0] + '/protocols/utilities/toppar_water_ions.str' + + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _citations(self): + return ['harastani2022continuousflex','vuillemot2022NMMD'] + + def _methods(self): + pass diff --git a/continuousflex/protocols/protocol_genesis.py b/continuousflex/protocols/protocol_genesis.py new file mode 100644 index 0000000..77efaa6 --- /dev/null +++ b/continuousflex/protocols/protocol_genesis.py @@ -0,0 +1,1362 @@ +# ************************************************************************** +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +import os.path +import subprocess +import pyworkflow.protocol.params as params +from pwem.protocols import EMProtocol +from pwem.objects.data import AtomStruct, SetOfAtomStructs, SetOfPDBs, SetOfVolumes,SetOfParticles, Volume +import mrcfile +from pwem.utils import runProgram +from pyworkflow.utils import getListFromRangeString +from .utilities.genesis_utilities import * +from .utilities.pdb_handler import ContinuousFlexPDBHandler +import pyworkflow.utils as pwutils +from pyworkflow.utils import runCommand, buildRunCommand +from xmipp3.convert import writeSetOfParticles, writeSetOfVolumes +from pwem.convert.atom_struct import cifToPdb +from continuousflex import Plugin +from pyworkflow.utils.path import makePath +import continuousflex +import pwem.emlib.metadata as md +import re + +class FlexProtGenesis(EMProtocol): + """ + Performs molecular dynamics and normal mode molecular dynamics simulations + using the GENESIS framework. The protocol provides an integrated environment + for combining atomic structural models, force-field based physical + simulations, and electron microscopy data in order to investigate + conformational variability, structural refinement, and dynamic behavior of + biological macromolecules. + + AI Generated: + + MD-NMMD Genesis (FlexProtGenesis) - User Manual + Overview + + The MD-NMMD Genesis protocol is a general-purpose simulation framework + for studying structural dynamics in biological systems. It enables + molecular dynamics and related simulation strategies that can be + applied to atomic models, coarse-grained representations, and + experimentally derived structures. Its primary goal is to explore how + macromolecules move, fluctuate, and adapt while remaining consistent + with physical principles and, when available, experimental data. + + In structural biology, static structures often represent only a single + snapshot of a dynamic process. Proteins, nucleic acids, molecular + assemblies, and membrane complexes frequently undergo conformational + changes that are essential for their biological function. This protocol + provides a computational environment for investigating those motions + and generating structural trajectories that can be analyzed in + conjunction with experimental observations. + + Inputs and General Workflow + + The protocol supports simulations starting from prepared topology + models, previously completed simulations, or directly supplied + structural coordinates. This flexibility allows users to initiate new + calculations, continue existing studies, or explore alternative + simulation conditions without rebuilding the entire workflow. + + Depending on the scientific objective, simulations may focus on local + fluctuations, large-scale conformational transitions, flexible fitting, + or the characterization of structural ensembles. The protocol serves as + a central platform that connects structural preparation, simulation + execution, and downstream analysis. + + Force Fields and Physical Modeling + + A key component of the protocol is the use of molecular force fields + that define the energetic behavior of the system. These physical models + describe how atoms or coarse-grained particles interact and determine + the forces governing structural motion throughout the simulation. + + Different force-field representations may be appropriate depending on + system size, desired accuracy, and computational resources. Detailed + atomic models provide a realistic description of molecular interactions, + whereas simplified models can facilitate the exploration of large-scale + motions and long-timescale processes. + + Molecular Dynamics and Normal Mode Approaches + + The protocol supports both conventional molecular dynamics and + simulation strategies that incorporate collective motions derived from + normal mode analysis. This combination is particularly useful when the + objective is to investigate biologically relevant conformational + changes that involve coordinated movements of multiple domains or + subunits. + + For many macromolecular systems, large-scale functional transitions are + dominated by collective motions rather than random fluctuations. + Incorporating these motions into simulations can improve sampling + efficiency and help identify conformations that are difficult to reach + through standard molecular dynamics alone. + + Integration with Electron Microscopy Data + + One of the major strengths of the protocol is its ability to incorporate + information derived from electron microscopy experiments. Structural + models can be guided by volumetric or particle-based observations, + allowing simulations to remain consistent with experimentally observed + conformations. + + This capability is especially valuable for cryo-EM and cryo-electron + tomography studies, where experimental maps may reveal multiple + structural states or partially resolved conformational landscapes. + Combining simulation and experimental information often provides a more + complete understanding of molecular behavior than either approach alone. + + Simulation Parameters + + Users can control the duration, sampling behavior, physical conditions, + and simulation strategy according to the requirements of the biological + problem. Short exploratory simulations can be used to evaluate system + stability, while longer calculations may be necessary to characterize + conformational transitions or generate statistically meaningful + structural ensembles. + + The choice of simulation parameters should reflect the size of the + system, the expected magnitude of structural changes, and the desired + balance between computational cost and sampling depth. + + Parallel Execution + + The protocol supports execution on parallel computing resources, + enabling simulations of large biological assemblies and computationally + demanding systems. Efficient parallelization is particularly important + for high-resolution models, extensive trajectory generation, and + large-scale conformational studies. + + Outputs and Their Interpretation + + The protocol produces simulation trajectories and refined structural + models that describe the evolution of the system over time. These + results can be used to investigate flexibility, identify dominant + motions, characterize intermediate states, and evaluate consistency + with experimental data. + + Structural trajectories should be interpreted as dynamic ensembles + rather than single definitive conformations. Biological insight is + often obtained by examining recurring motions, persistent structural + features, and relationships between simulated conformations and + experimental observations. + + Practical Recommendations + + Successful simulations typically begin with a structurally reasonable + starting model and carefully selected simulation conditions. When + experimental data are available, incorporating them as guiding + information can improve biological relevance and help constrain the + exploration of conformational space. + + Users are encouraged to evaluate convergence, inspect structural + trajectories visually, and compare simulation outcomes with independent + biochemical, structural, or functional evidence whenever possible. + + Final Perspective + + MD-NMMD Genesis provides a versatile platform for studying molecular + structure and dynamics through physics-based simulations integrated + with experimental information. By combining molecular dynamics, normal + mode guided exploration, and electron microscopy data, the protocol + enables detailed investigation of conformational variability and the + dynamic mechanisms underlying biological function. + """ + _label = 'MD-NMMD-Genesis' + + def __init__(self, **kwargs): + EMProtocol.__init__(self, **kwargs) + self._inputEMMetadata =None + + # --------------------------- DEFINE param functions -------------------------------------------- + def _defineParams(self, form): + + # Inputs ============================================================================================ + form.addSection(label='Inputs') + + form.addParam('inputType', params.EnumParam, label="Simulation inputs", default=INPUT_TOPOLOGY, + choices=['New simulation from topology model', 'Restart previous simulation', "New simulation from files"], + help="Chose the type of input for your simulation", + important=True) + + # INPUT_TOPOLOGY + form.addParam('topoProt', params.PointerParam, label="Input topology protocol", + pointerClass="ProtGenerateTopology", + help='Provide a generate topology protocol to initialize the simulation', + condition="inputType==%i"%INPUT_TOPOLOGY) + + # INPUT_RESTART + form.addParam('restartProt', params.PointerParam, label="Input GENESIS protocol", + pointerClass="FlexProtGenesis", + help='Provide a MD-NMMD-GENESIS protocol to restart.', condition="inputType==%i"%INPUT_RESTART) + + # INPUT_NEW_SIM + form.addParam('inputPDB', params.PointerParam, + pointerClass='AtomStruct', label="Input PDB", + help='Select the input PDB.', important=True, condition="inputType==%i"%INPUT_NEW_SIM) + group = form.addGroup('Forcefield Inputs', condition="inputType==%i"%INPUT_NEW_SIM) + group.addParam('forcefield', params.EnumParam, label="Forcefield type", default=FORCEFIELD_CHARMM, important=True, + + choices=['CHARMM', 'AAGO', 'CAGO'], help="Type of the force field used for energy and force calculation") + + group.addParam('inputTOP', params.FileParam, label="GROMACS Topology File (top)", + condition="(forcefield==%i or forcefield==%i)"%(FORCEFIELD_CAGO, FORCEFIELD_AAGO), + help='Gromacs ‘top’ file containing information of the system such as atomic masses, charges,' + ' atom connectivities. To generate this file for your system, you can either use the protocol' + '\" generate topology files\" (SMOG 2 installation is required, https://smog-server.org/smog2/ ),' + ' or using SMOG sever (https://smog-server.org/cgi-bin/GenTopGro.pl )') + group.addParam('inputPRM', params.FileParam, label="CHARMM parameter file (prm)", + condition = "forcefield==%i"%FORCEFIELD_CHARMM, + help='CHARMM parameter file containing force field parameters, e.g. force constants and librium' + ' geometries. Latest forcefields can be founded at http://mackerell.umaryland.edu/charmm_ff.shtml ' ) + group.addParam('inputRTF', params.FileParam, label="CHARMM topology file (rtf)", + condition="forcefield==%i"%FORCEFIELD_CHARMM, + help='CHARMM topology file containing information about atom connectivity of residues and' + ' other molecules. Latest forcefields can be founded at http://mackerell.umaryland.edu/charmm_ff.shtml ') + group.addParam('inputPSF', params.FileParam, label="CHARMM Structure File (psf)", + condition="forcefield==%i"%FORCEFIELD_CHARMM, + help='CHARMM/X-PLOR psf file containing information of the system such as atomic masses,' + ' charges, and atom connectivities. To generate this file for your system, you can either use the protocol' + '\" generate topology files\", VMD psfgen, or online CHARMM GUI ( https://www.charmm-gui.org/ ).') + group.addParam('inputSTR', params.FileParam, label="CHARMM stream file (str, optional)", + condition="forcefield==%i"%FORCEFIELD_CHARMM, default="", + help='CHARMM stream file containing both topology information and parameters. ' + 'Latest forcefields can be founded at http://mackerell.umaryland.edu/charmm_ff.shtml ') + + form.addParam('centerPDB', params.BooleanParam, label="Center PDB ?", + default=False, help="Center the input PDBs with the center of mass", + expertLevel=params.LEVEL_ADVANCED) + + + # Simulation ================================================================================================= + form.addSection(label='Simulation') + form.addParam('simulationType', params.EnumParam, label="Simulation type", default=0, + choices=['Minimization', 'Molecular Dynamics (MD)', 'Normal Mode Molecular Dynamics (NMMD)', 'Replica-Exchange MD', 'Replica-Exchange NMMD'], + help="Type of simulation to be performed by GENESIS", important=True) + + group = form.addGroup('Simulation parameters') + group.addParam('integrator', params.EnumParam, label="Integrator", default=0, + choices=['Velocity Verlet', 'Leapfrog', ''], + help="Type of integrator for the simulation", condition="simulationType!=0", + expertLevel=params.LEVEL_ADVANCED) + group.addParam('n_steps', params.IntParam, default=10000, label='Number of steps', + help="Total number of steps in one MD run") + group.addParam('time_step', params.FloatParam, default=0.002, label='Time step (ps)', + help="Time step in the MD run", condition="simulationType!=0") + group.addParam('eneout_period', params.IntParam, default=100, label='Energy output period', + help="Output period for the energy data", + expertLevel=params.LEVEL_ADVANCED) + group.addParam('crdout_period', params.IntParam, default=100, label='Coordinate output period', + help="Output period for the coordinates data", + expertLevel=params.LEVEL_ADVANCED) + group.addParam('nbupdate_period', params.IntParam, default=10, label='Non-bonded update period', + help="Update period of the non-bonded pairlist", + expertLevel=params.LEVEL_ADVANCED) + + group = form.addGroup('NMMD parameters', condition="simulationType==%i or simulationType==%i"%(SIMULATION_NMMD, + SIMULATION_RENMMD)) + group.addParam('inputModes', params.PointerParam, pointerClass="SetOfNormalModes", label='Input Modes', + default=None, allowsNull = True, + help="Input set of normal modes") + group.addParam('modeList', params.NumericRangeParam, + label="Modes selection", allowsNull = True, default="", + help='Select the normal modes that will be used for analysis. \n' + 'If you leave this field empty, all the computed modes will be selected for simulation.\n' + 'You have several ways to specify the modes.\n' + ' Examples:\n' + ' "7,8-10" -> [7,8,9,10]\n' + ' "8, 10, 12" -> [8,10,12]\n' + ' "8 9, 10-12" -> [8,9,10,11,12])\n') + + group.addParam('nm_dt', params.FloatParam, label='NM time step', default=0.001, + help="Time step of normal modes integration. Should be equal to MD time step. Could be increased " + "to accelerate NM integration, however can make the simulation unstable.", + expertLevel=params.LEVEL_ADVANCED) + group.addParam('nm_mass', params.FloatParam, default=10.0, label='NM mass', + help="Mass value of Normal modes for NMMD. Lower values accelerate the fitting but can make the " + "simulation unstable", + expertLevel=params.LEVEL_ADVANCED) + group = form.addGroup('REMD parameters', condition="simulationType==%i or simulationType==%i"%(SIMULATION_REMD, + SIMULATION_RENMMD)) + group.addParam('exchange_period', params.IntParam, default=1000, label='Exchange Period', + help="Number of MD steps between replica exchanges") + group.addParam('nreplica', params.IntParam, default=1, label='Number of replicas', + help="Number of replicas for REMD") + + # MD params ================================================================================================= + form.addSection(label='MD parameters') + + group = form.addGroup('Ensemble', condition="simulationType!=0") + + group.addParam('temperature', params.FloatParam, default=300.0, label='Temperature (K)', + help="Initial and target temperature", important=True) + group.addParam('ensemble', params.EnumParam, label="Ensemble", default=0, + choices=['NVT', 'NVE', 'NPT'], + help="Type of ensemble, NVE: Microcanonical ensemble, NVT: Canonical ensemble," + " NPT: Isothermal-isobaric ensemble") + group.addParam('tpcontrol', params.EnumParam, label="Thermostat/Barostat", default=1, + choices=['NO', 'LANGEVIN', 'BERENDSEN', 'BUSSI'], + help="Type of thermostat and barostat. The availabe algorithm depends on the integrator :" + " Leapfrog : BERENDSEN, LANGEVIN; Velocity Verlet : BERENDSEN (NVT only), LANGEVIN, BUSSI; " + " NMMD : LANGEVIN (NVT only)") + group.addParam('pressure', params.FloatParam, default=1.0, label='Pressure (atm)', + help="Target pressure in the NPT ensemble", condition="ensemble==%i"%ENSEMBLE_NPT) + + group = form.addGroup('Energy') + group.addParam('implicitSolvent', params.EnumParam, label="Implicit Solvent", default=1, + choices=['GBSA', 'NONE'], + help="Turn on Generalized Born/Solvent accessible surface area model (Implicit Solvent). Boundary condition must be NO." + " ATDYN only.") + + group.addParam('boundary', params.EnumParam, label="Boundary", default=BOUNDARY_NOBC, + choices=['No boundary', 'Periodic Boundary Condition'], + help="Type of boundary condition. In case of implicit solvent, " + " GO models or vaccum simulation, choose No boundary") + group.addParam('box_size_x', params.FloatParam, label='Box size X', + help="Box size along the x dimension", condition="boundary==%i"%BOUNDARY_PBC) + group.addParam('box_size_y', params.FloatParam, label='Box size Y', + help="Box size along the y dimension", condition="boundary==%i"%BOUNDARY_PBC) + group.addParam('box_size_z', params.FloatParam, label='Box size Z', + help="Box size along the z dimension", condition="boundary==%i"%BOUNDARY_PBC) + + group.addParam('electrostatics', params.EnumParam, label="Non-bonded interactions", default=1, + choices=['PME', 'Cutoff'], + help="Type of Non-bonded interactions. " + " CUTOFF: Non-bonded interactions including the van der Waals interaction are just" + " truncated at cutoffdist; " + " PME : Particle mesh Ewald (PME) method is employed for long-range interactions." + " This option is only availabe in the periodic boundary condition", + condition="boundary==%i"%BOUNDARY_PBC) + group.addParam('vdw_force_switch', params.BooleanParam, label="Switch function Van der Waals", default=True, + help="This paramter determines whether the force switch function for van der Waals interactions is" + " employed or not. The users must take care about this parameter, when the CHARMM" + " force field is used. Typically, vdw_force_switch=YES should be specified in the case of" + " CHARMM36",expertLevel=params.LEVEL_ADVANCED) + group.addParam('switch_dist', params.FloatParam, default=10.0, label='Switch Distance', + help="Switch-on distance for nonbonded interaction energy/force quenching") + group.addParam('cutoff_dist', params.FloatParam, default=12.0, label='Cutoff Distance', + help="Cut-off distance for the non-bonded interactions. This distance must be larger than" + " switchdist, while smaller than pairlistdist") + group.addParam('pairlist_dist', params.FloatParam, default=15.0, label='Pairlist Distance', + help="Distance used to make a Verlet pair list for non-bonded interactions . This distance" + " must be larger than cutoffdist") + + group = form.addGroup('Contraints', condition="simulationType==%i or simulationType==%i"%(SIMULATION_MD,SIMULATION_REMD)) + group.addParam('rigid_bond', params.BooleanParam, label="Rigid bonds (SHAKE/RATTLE)", + default=False, + help="Turn on or off the SHAKE/RATTLE algorithms for covalent bonds involving hydrogen. " + "Must be False for NMMD.") + group.addParam('fast_water', params.BooleanParam, label="Fast water (SETTLE)", + default=False, + help="Turn on or off the SETTLE algorithm for the constraints of the water molecules") + group.addParam('water_model', params.StringParam, label='Water model', default="TIP3", + help="Residue name of the water molecule to be rigidified in the SETTLE algorithm", condition="fast_water") + group.addParam('posi_restr', params.BooleanParam, label='Positional restraint on Calpha atoms', default=False, + help="Apply a restraint on the positions of Ca atoms") + + # Experiments ================================================================================================= + form.addSection(label='EM data') + form.addParam('EMfitChoice', params.EnumParam, label="Cryo-EM Flexible Fitting", default=0, + choices=['None', 'Volume (s)', 'Image (s)'], important=True, + help="Type of cryo-EM data to be processed") + + group = form.addGroup('Fitting parameters', condition="EMfitChoice!=%i"%EMFIT_NONE) + group.addParam('constantK', params.StringParam, default="10000", label='Force constant (kcal/mol)', + help="Force constant in Eem = k*(1 - c.c.). Determines the strengh of the fitting. " + " This parameters must be tuned with caution : " + "too high values will deform the structure and overfit the data, too low values will not " + "move the atom senough to fit properly the data. Note that in the case of REUS, the number of " + " force constant value must be equal to the number of replicas, for example for 4 replicas," + " a valid force constant is \"1000 2000 3000 4000\", otherwise you can specify a range of " + " values (for example \"1000-4000\") and the force constant values will be linearly distributed " + " to each replica." + , condition="EMfitChoice!=%i"%EMFIT_NONE) + group.addParam('emfit_sigma', params.FloatParam, default=2.0, label="Gaussian kernels variance", + help="Resolution parameter of the simulated map. This is usually set to the half of the resolution" + " of the target map. For example, if the target map resolution is 5 Å, emfit_sigma=2.5", + condition="EMfitChoice!=%i"%EMFIT_NONE, expertLevel=params.LEVEL_ADVANCED) + group.addParam('emfit_tolerance', params.FloatParam, default=0.01, label='Tolerance', + help="This variable determines the tail length of the Gaussian function. For example, if em-" + " fit_tolerance=0.001 is specified, the Gaussian function is truncated to zero when it is less" + " than 0.1% of the maximum value. Smaller value requires large computational cost", + condition="EMfitChoice!=%i"%EMFIT_NONE, expertLevel=params.LEVEL_ADVANCED) + group.addParam('emfit_period', params.IntParam, default=10, label='Update period', + help="Number of MD iteration every which the EM poential is updated", + condition="EMfitChoice!=%i"%EMFIT_NONE, expertLevel=params.LEVEL_ADVANCED) + + # Volumes + group = form.addGroup('Volume Parameters', condition="EMfitChoice==%i"%EMFIT_VOLUMES) + group.addParam('inputVolume', params.PointerParam, pointerClass="Volume, SetOfVolumes", + label="Input volume (s)", help='Select the target EM density volume', + condition="EMfitChoice==%i"%EMFIT_VOLUMES, important=True) + group.addParam('voxel_size', params.FloatParam, default=1.0, label='Voxel size (A)', + help="Voxel size in Angstrom of the target volume (s)", condition="EMfitChoice==%i"%EMFIT_VOLUMES) + group.addParam('centerOrigin', params.BooleanParam, label="Center Origin", default=False, + help="Center the volume to the origin", condition="EMfitChoice==%i"%EMFIT_VOLUMES, + expertLevel=params.LEVEL_ADVANCED) + group.addParam('origin_x', params.FloatParam, default=0, label="Origin X", + help="Origin of the first voxel in X direction (in Angstrom) ", + condition="EMfitChoice==%i and not centerOrigin"%EMFIT_VOLUMES, expertLevel=params.LEVEL_ADVANCED) + group.addParam('origin_y', params.FloatParam, default=0, label="Origin Y", + help="Origin of the first voxel in Y direction (in Angstrom) ", + condition="EMfitChoice==%i and not centerOrigin"%EMFIT_VOLUMES, expertLevel=params.LEVEL_ADVANCED) + group.addParam('origin_z', params.FloatParam, default=0, label="Origin Z", + help="Origin of the first voxel in Z direction (in Angstrom) ", + condition="EMfitChoice==%i and not centerOrigin"%EMFIT_VOLUMES, expertLevel=params.LEVEL_ADVANCED) + + # Images + group = form.addGroup('Image Parameters', condition="EMfitChoice==%i"%EMFIT_IMAGES) + group.addParam('inputImage', params.PointerParam, pointerClass="SetOfParticles", + label="Input images ", help='Select the target image set', + condition="EMfitChoice==%i"%EMFIT_IMAGES, important=True) + group.addParam('pixel_size', params.FloatParam, default=1.0, label='Pixel size (A)', + help="Pixel size of the EM data in Angstrom", condition="EMfitChoice==%i"%EMFIT_IMAGES) + group.addParam('projectAngleChoice', params.EnumParam, default=PROJECTION_ANGLE_SAME, label='Projection angles', + choices=['same as image set', 'from xmipp file'], + help="Source of projection angles to align the input PDB with the set of images", + condition="EMfitChoice==%i"%EMFIT_IMAGES) + group.addParam('projectAngleXmipp', params.FileParam, default=None, label='projection angle Xmipp file', + help="Xmipp metadata file with projection alignment parameters ", + condition="EMfitChoice==%i and projectAngleChoice==%i"%(EMFIT_IMAGES,PROJECTION_ANGLE_XMIPP)) + + group = form.addGroup('Fitting parameters', condition="EMfitChoice!=%i"%EMFIT_NONE) + group.addParam('constantK', params.StringParam, default="10000", label='Force constant (kcal/mol)', + help="Force constant in Eem = k*(1 - c.c.). Determines the strengh of the fitting. " + " This parameters must be tuned with caution : " + "too high values will deform the structure and overfit the data, too low values will not " + "move the atom senough to fit properly the data. Note that in the case of REUS, the number of " + " force constant value must be equal to the number of replicas, for example for 4 replicas," + " a valid force constant is \"1000 2000 3000 4000\", otherwise you can specify a range of " + " values (for example \"1000-4000\") and the force constant values will be linearly distributed " + " to each replica." + , condition="EMfitChoice!=%i"%EMFIT_NONE) + group.addParam('emfit_sigma', params.FloatParam, default=2.0, label="EM fit gaussian variance", + help="Resolution parameter of the simulated map. This is usually set to the half of the resolution" + " of the target map. For example, if the target map resolution is 5 Å, emfit_sigma=2.5", + condition="EMfitChoice!=%i"%EMFIT_NONE, + expertLevel=params.LEVEL_ADVANCED) + group.addParam('emfit_tolerance', params.FloatParam, default=0.01, label='EM Fit Tolerance', + help="This variable determines the tail length of the Gaussian function. For example, if em-" + " fit_tolerance=0.001 is specified, the Gaussian function is truncated to zero when it is less" + " than 0.1% of the maximum value. Smaller value requires large computational cost", + condition="EMfitChoice!=%i"%EMFIT_NONE, + expertLevel=params.LEVEL_ADVANCED) + group.addParam('emfit_period', params.IntParam, default=10, label='EM Fit period', + help="Number of MD iteration every which the EM poential is updated", + condition="EMfitChoice!=%i"%EMFIT_NONE, + expertLevel=params.LEVEL_ADVANCED) + + form.addSection(label='MPI parallelization') + + form.addParam('parallelType', params.EnumParam, label="How to process EM data ?", default=PARALLEL_MPI, + choices=['parallel (MPI)', 'parallel (GNU parallel)', "serial"], important=True, + help="Defines how the program will parallelize the MD simulations. If \"parallel (MPI)\" is selected, each simulation " + "is distributed on a single core. This settings should work on most local machines and clusters." + "Note that on clusters with multiple nodes, the user can chose to use rankfiles options (mpirun only) " + " to distribute efficiently each simulations on the available cores. If mpirun mpirun is not" + "available, one might have to edit the PARALLEL_COMMAND in host.conf file (for instance, for a cluster " + "using SLURM queuing system, one should use srun --exact --nodes 1) and chose \"use parallel command\"." + " If \"parallel (GNU parallel)\" is selected, each simulation is distributed on a single core and use " + " GNU parallel to distributed each simulation in parallel. This option might solve some issues of distrbuting" + "the simulation to each cores on some clusters architectures. If \"seriel\" is selected, " + "the MD simulation are exectuted one after the other (serial) and are using the maximum number of cores" + " available (the performance are not comparable to MPI or GNU parallel and can be suitable only " + "for very small datasets) ") + + form.addParam('use_rankfiles', params.BooleanParam, default=False, label="Running on cluster ? ", + help="If yes, will use rankfiles to attribute a core to each simulation. This option should be use on " + "cluster systems with multiple nodes. Note that the parallel command in host.conf must be mpirun", + condition="parallelType==%i"%PARALLEL_MPI) + form.addParam('use_parallelCmd', params.BooleanParam, default=False, label="Use parallel command ? ", + help="If yes, will use the parallel command set in host.conf to run the simulations. " + "This option may be required to run on clusters with mulitple nodes.", + condition="parallelType==%i" % PARALLEL_MPI, + expertLevel=params.LEVEL_ADVANCED) + form.addParam('num_core_per_node', params.IntParam, default=0, label="Number of cores per node", + help="The number of MPI cores per node. If set to 0, will use number_of_mpi / number_of_nodes ", + condition="parallelType==%i and use_rankfiles"%PARALLEL_MPI) + form.addParam('num_socket_per_node', params.IntParam, default=1, label="Number of socket per node", + help="The number of sockets present on each nodes ", + condition="parallelType==%i and use_rankfiles"%PARALLEL_MPI) + form.addParam('num_node', params.IntParam, default=1, label="Number of node", + help="The number of nodes available ", + condition="parallelType==%i and use_rankfiles"%PARALLEL_MPI) + form.addParam('localhost', params.BooleanParam, default=False, label="Run as local host ? ", + help="If yes, will execute one single host (localhost), otherwise will use relative host for MPI.", + condition="parallelType==%i and use_rankfiles"%PARALLEL_MPI) + form.addParam('mpirun_arguments', params.StringParam, default="", label="Additional arguments for mpirun", + help="Additional arguments to pass to mpirun", + condition="parallelType==%i and use_rankfiles"%PARALLEL_MPI) + + form.addParam('md_program', params.EnumParam, label="MD program", default=PROGRAM_ATDYN, + choices=['ATDYN', 'SPDYN'], + help="ADTYN is recommanded. The performance of ATDYN is not comparable to SPDYN due to the" + " simple parallelization scheme but contains new methods and features such as normal-mode empowered " + "dynamics used in MDSPACE", + expertLevel=params.LEVEL_ADVANCED) + + form.addParallelSection(threads=1, mpi=NUMBER_OF_CPU) + # --------------------------- INSERT steps functions -------------------------------------------- + + def _insertAllSteps(self): + # make path + self._insertFunctionStep("makePathStep") + + # Create INP files + self._insertFunctionStep("createGenesisInputStep") + + # Convert input PDB + self._insertFunctionStep("convertInputPDBStep") + + # Convert normal modes + if (self.simulationType.get() == SIMULATION_NMMD or self.simulationType.get() == SIMULATION_RENMMD): + self._insertFunctionStep("convertNormalModeFileStep") + + # Convert input EM data + if self.EMfitChoice.get() != EMFIT_NONE: + self._insertFunctionStep("convertInputEMStep") + + # RUN simulation + if self.parallelType.get() == PARALLEL_MPI and self.getNumberOfSimulation() >1: + self._insertFunctionStep("runSimulationMPI") + elif self.parallelType.get() == PARALLEL_GNU and self.getNumberOfSimulation() >1 and existsCommand("parallel") : + self._insertFunctionStep("runSimulationParallel") + else: + for i in range(self.getNumberOfSimulation()): + self._insertFunctionStep("runSimulation", self.getGenesisInputFile(i), self.getOutputPrefix(i)) + + # Create output data + self._insertFunctionStep("createOutputStep") + + + def makePathStep(self): + makePath(self.getGenFiles()) + makePath(self.getEmdFiles()) + makePath(self._getTmpPath()) + # --------------------------- Convert Input PDBs -------------------------------------------- + + def convertInputPDBStep(self): + """ + Convert input PDB step. + :return None: + """ + + # COPY PDBS ------------------------------------------------------------- + inputPDBfn = self.getInputPDBfn() + n_pdb = self.getNumberOfInputPDB() + for i in range(n_pdb): + ext = os.path.splitext(inputPDBfn[i])[1] + if ext == ".pdb" or ext == ".ent": + runCommand("cp %s %s.pdb" % (inputPDBfn[i], self.getInputPDBprefix(i))) + elif ext == ".cif" or ext == ".mmcif": + cifToPdb(inputPDBfn[i], self.getInputPDBprefix(i)+".pdb") + else: + print("ERROR (toPdb), Unknown file type for file = %s" % inputPDBfn[i]) + + # TOPOLOGY FILES ------------------------------------------------- + inputPrefix = self.getInputPDBprefix() + if self.getForceField() == FORCEFIELD_CHARMM: + if self.inputType.get() == INPUT_NEW_SIM: + inputPSF = self.inputPSF.get() + elif self.inputType.get() == INPUT_RESTART: + inputPSF = self.restartProt.get().getInputPDBprefix() + ".psf" + elif self.inputType.get() == INPUT_TOPOLOGY: + inputPSF = self.topoProt.get()._getExtraPath("output.psf") + runCommand("cp %s %s.psf" % (inputPSF, inputPrefix)) + inputRTF, inputPRM, inputSTR = self.getCHARMMInputs() + runCommand("cp %s %s_charmm.rtf" % (inputRTF, inputPrefix)) + runCommand("cp %s %s_charmm.prm" % (inputPRM, inputPrefix)) + runCommand("cp %s %s_charmm.str" % (inputSTR, inputPrefix)) + + + elif self.getForceField() == FORCEFIELD_CAGO or self.getForceField() == FORCEFIELD_AAGO : + if self.inputType.get() == INPUT_NEW_SIM: + inputTOP = self.inputTOP.get() + elif self.inputType.get() == INPUT_RESTART: + inputTOP = self.restartProt.get().getInputPDBprefix() + ".top" + elif self.inputType.get() == INPUT_TOPOLOGY: + inputTOP = self.topoProt.get()._getExtraPath("output.top") + runCommand("cp %s %s.top" % (inputTOP, inputPrefix)) + + # Center PDBs ----------------------------------------------------- + if self.centerPDB.get(): + for i in range(self.getNumberOfInputPDB()): + cmd = "xmipp_pdb_center" + args = "-i %s.pdb -o %s.pdb" %\ + (self.getInputPDBprefix(i),self.getInputPDBprefix(i)) + runProgram(cmd, args) + print(cmd) + + def convertNormalModeFileStep(self): + """ + Convert NM data step + :return None: + """ + nm_file = self.getInputPDBprefix() + ".nma" + if self.modeList.empty(): + modeSelection = np.arange(7,self.inputModes.get().getSize()+1) + else: + modeSelection = getListFromRangeString(self.modeList.get()) + with open(nm_file, "w") as f: + for i in range(self.inputModes.get().getSize()): + if i+1 in modeSelection: + f.write(" VECTOR %i VALUE 0.0\n" % (i + 1)) + f.write(" -----------------------------------\n") + nm_vec = np.loadtxt(self.inputModes.get()[i + 1].getModeFile()) + for j in range(nm_vec.shape[0]): + f.write(" %e %e %e\n" % (nm_vec[j, 0], nm_vec[j, 1], nm_vec[j, 2])) + + # --------------------------- Convert Input EM data -------------------------------------------- + + def convertInputEMStep(self): + """ + Convert EM data step + :return None: + """ + # Convert EM data + + n_em = self.getNumberOfInputEM() + dest_ext = "mrc" if self.EMfitChoice.get() == EMFIT_VOLUMES else "spi" + self.readInputEMMetadata() + runProgram("xmipp_image_convert", "-i %s/inputEM.xmd --oext %s --oroot %s/inputEM_" % + (self.getEmdFiles(), dest_ext, self.getEmdFiles())) + + # Fix volumes origin + if self.EMfitChoice.get() == EMFIT_VOLUMES: + for i in range(n_em): + # Update mrc header + volPrefix = self.getInputEMprefix(i) + with mrcfile.open("%s.mrc" % volPrefix) as old_mrc: + with mrcfile.new("%s.mrc" % volPrefix, overwrite=True) as new_mrc: + new_mrc.set_data(old_mrc.data) + new_mrc.voxel_size = self.voxel_size.get() + new_mrc.header['origin'] = old_mrc.header['origin'] + if self.centerOrigin.get(): + origin = -np.array(old_mrc.data.shape) / 2 * self.voxel_size.get() + new_mrc.header['origin']['x'] = origin[0] + new_mrc.header['origin']['y'] = origin[1] + new_mrc.header['origin']['z'] = origin[2] + else: + new_mrc.header['origin']['x'] = self.origin_x.get() + new_mrc.header['origin']['y'] = self.origin_y.get() + new_mrc.header['origin']['z'] = self.origin_z.get() + new_mrc.update_header_from_data() + new_mrc.update_header_stats() + + # --------------------------- GENESIS step -------------------------------------------- + + def createGenesisInputStep(self): + """ + Create GENESIS input files + :return None: + """ + for indexFit in range(self.getNumberOfSimulation()): + # INP file name + inp_file = self.getGenesisInputFile(indexFit) + args = self.getDefaultArgs(indexFit) + createGenesisInput(inp_file, **args) + + def getDefaultArgs(self, indexFit=0): + """ + get default argument to run GENESIS + @param indexFit: + @return: + + """ + inputRTF, inputPRM, inputSTR = self.getCHARMMInputs() + args = { + # Inputs files + "outputPrefix": self.getOutputPrefix(indexFit), + "inputPDBprefix": self.getInputPDBprefix(indexFit), + "inputEMprefix": self.getInputEMprefix(indexFit), + "rstFile": self.getRestartFile(indexFit), + "nm_number": self.getNumberOfNormalModes(), + "rigid_body_params": self.getRigidBodyParams(indexFit), + "forcefield": self.getForceField(), + + # Input Params + "inputType": self.inputType.get(), + "simulationType": self.simulationType.get(), + "electrostatics": self.electrostatics.get(), + "switch_dist": self.switch_dist.get(), + "cutoff_dist": self.cutoff_dist.get(), + "pairlist_dist": self.pairlist_dist.get(), + "vdw_force_switch": self.vdw_force_switch.get(), + "implicitSolvent": self.implicitSolvent.get(), + "integrator": self.integrator.get(), + "time_step": self.time_step.get(), + "eneout_period": self.eneout_period.get(), + "crdout_period": self.crdout_period.get(), + "n_steps": self.n_steps.get(), + "nbupdate_period": self.nbupdate_period.get(), + "nm_dt": self.nm_dt.get(), + "nm_mass": self.nm_mass.get(), + "rigid_bond": self.rigid_bond.get(), + "posi_restr": self.posi_restr.get(), + "fast_water": self.fast_water.get(), + "water_model": self.water_model.get(), + "box_size_x": self.box_size_x.get(), + "box_size_y": self.box_size_y.get(), + "box_size_z": self.box_size_z.get(), + "boundary": self.boundary.get(), + "ensemble": self.ensemble.get(), + "tpcontrol": self.tpcontrol.get(), + "temperature": self.temperature.get(), + "pressure": self.pressure.get(), + "EMfitChoice": self.EMfitChoice.get(), + "constantK": self.constantK.get(), + "nreplica": self.nreplica.get(), + "emfit_sigma": self.emfit_sigma.get(), + "emfit_tolerance": self.emfit_tolerance.get(), + "emfit_period": self.emfit_period.get(), + "pixel_size": self.pixel_size.get(), + "exchange_period": self.exchange_period.get() + } + return args + + def runSimulation(self, inp_file, outPref): + """ + Run GENESIS simulations + :return None: + """ + programname = "atdyn" if self.md_program.get() == PROGRAM_ATDYN else "spdyn" + params = "%s > %s.log" % (inp_file,outPref) + env = self.getGenesisEnv() + env.set("OMP_NUM_THREADS",str(self.numberOfThreads.get())) + command = buildRunCommand(programname, params, numberOfMpi=self.numberOfMpi.get(), + hostConfig=self._stepsExecutor.hostConfig, + env=env) + # command = Plugin.getContinuousFlexCmd(command) + runCommand(command, env=env) + + def runSimulationParallel(self): + """ + Run multiple GENESIS simulations in parallel + :return None: + """ + + # Set number of MPI per fit + if self.getNumberOfSimulation() <= self.numberOfMpi.get(): + numberOfMpiPerFit = self.numberOfMpi.get()//self.getNumberOfSimulation() + else: + if self.simulationType.get() == SIMULATION_REMD or self.simulationType.get() == SIMULATION_RENMMD: + nreplica = self.nreplica.get() + if nreplica > self.numberOfMpi.get(): + raise RuntimeError("Number of MPI cores should be larger than the number of replicas.") + else: + nreplica = 1 + numberOfMpiPerFit = nreplica + + # Set environnement + env = self.getGenesisEnv() + env.set("OMP_NUM_THREADS",str(self.numberOfThreads.get())) + + # Build command + programname = os.path.join( Plugin.getVar("GENESIS_HOME"), "bin/atdyn") + outPath, outName = os.path.split(self.getOutputPrefix()) + outLog = os.path.join(outPath,re.sub("output_\d+", "output_{}",outName)) + params = "%s/INP_{} > %s.log " %(self.getGenFiles(), outLog) + cmd = buildRunCommand(programname, params, numberOfMpi=numberOfMpiPerFit, hostConfig=self._stepsExecutor.hostConfig, + env=env) + # Build parallel command + parallel_cmd = "seq -f \"%%06g\" 1 %i | parallel -P %i \" %s\" " % ( + self.getNumberOfSimulation(),self.numberOfMpi.get()//numberOfMpiPerFit, cmd) + # parallel_cmd = Plugin.getContinuousFlexCmd(parallel_cmd) + + print("Command : %s" % cmd) + print("Parallel Command : %s" % parallel_cmd) + try : + runCommand(parallel_cmd, env=env) + except subprocess.CalledProcessError : + print("Warning : Some processes returned with errors") + + + + def runSimulationMPI(self): + """ + Run multiple GENESIS simulations in parallel using MPI + :return None: + """ + + if self.simulationType.get() == SIMULATION_REMD or self.simulationType.get() == SIMULATION_RENMMD: + raise RuntimeError("REMD simulation should be run using the GNU parallel option") + + mpi_inputs = self._getExtraPath("mpi_inputs") + mpi_outputs = self._getExtraPath("mpi_outputs") + with open(mpi_inputs,"w") as fi: + with open(mpi_outputs,"w") as fo: + for i in range(self.getNumberOfSimulation()): + fi.write(self.getGenesisInputFile(i)+"\n") + fo.write(self.getOutputPrefix(i)+".log\n") + + script = os.path.join(continuousflex.__path__[0], "protocols/utilities/mpi_genesis.py") + programname = os.path.join( Plugin.getVar("GENESIS_HOME"), "bin/atdyn") + if self.use_parallelCmd.get() or self.use_rankfiles.get(): + mpi_command = self._stepsExecutor.hostConfig.mpiCommand.get() % \ + {'JOB_NODES': 1,'COMMAND': ""} + else: + mpi_command = "" + + if self.num_core_per_node.get() == 0: + num_core_per_node = self.numberOfMpi.get() + else: + num_core_per_node = self.num_core_per_node.get() + cmd = "python %s " %script + cmd += "--mpi_command \'%s\' --num_mpi %s --num_threads %s --inputs %s --outputs %s --executable %s "%( + mpi_command, self.numberOfMpi.get(), self.numberOfThreads.get(),mpi_inputs, mpi_outputs, programname) + if self.use_rankfiles.get(): + cmd += "--num_core_per_node %s --num_socket_per_node %s --num_node %s " \ + "--rankdir %s "% (num_core_per_node , self.num_socket_per_node.get(), + self.num_node.get(),self._getExtraPath("rankfiles")) + if self.localhost.get() : + cmd += "--localhost " + if self.mpirun_arguments.get() != "": + cmd += "--mpi_argument \'%s\' "%self.mpirun_arguments.get() + + with open(self._getExtraPath("mpi_command"), "w") as f: + f.write(cmd) + + runCommand(cmd) + + # --------------------------- Create output step -------------------------------------------- + + def createOutputStep(self): + """ + Create output PDB or set of PDBs + :return None: + """ + # Extract the pdb from the DCD file in case of SPDYN + if self.md_program.get() == PROGRAM_SPDYN: + for i in range(self.getNumberOfSimulation()): + outputPrefix = self.getOutputPrefixAll(i) + for j in outputPrefix: + lastPDBFromDCD( + inputDCD=j + ".dcd", + outputPDB=j + ".pdb", + inputPDB=self.getInputPDBprefix(i) + ".pdb") + + # ensure GENESIS maintains input pdb format + if self.getForceField() == FORCEFIELD_CAGO: + input = ContinuousFlexPDBHandler(self.getInputPDBprefix() + ".pdb") + for i in range(self.getNumberOfSimulation()): + outputPrefix = self.getOutputPrefixAll(i) + for j in outputPrefix: + fn_output = j + ".pdb" + if os.path.exists(fn_output) and os.path.getsize(fn_output) !=0: + input.coords = ContinuousFlexPDBHandler.read_coords(fn_output) + input.write_pdb(j + ".pdb") + + # CREATE a output PDB + if (self.simulationType.get() != SIMULATION_REMD and self.simulationType.get() != SIMULATION_RENMMD )\ + and self.getNumberOfSimulation() == 1: + self._defineOutputs(outputPDB=AtomStruct(self.getOutputPrefix() + ".pdb")) + + # CREATE SET OF output PDBs + else: + missing_pdbs = [] + pdbset = self._createSetOfPDBs("outputPDBs") + # Add each output PDB to the Set + for i in range(self.getNumberOfSimulation()): + outputPrefix =self.getOutputPrefixAll(i) + for j in outputPrefix: + pdb_fname = j + ".pdb" + if os.path.isfile(pdb_fname) and os.path.getsize(pdb_fname) != 0 : + pdbset.append(AtomStruct(pdb_fname)) + else: + missing_pdbs.append(i+1) + self._defineOutputs(outputPDBs=pdbset) + + # If some pdbs are missing, output a subset of the EM data that have actually been anaylzed + if self.EMfitChoice.get() != EMFIT_NONE and len( missing_pdbs)>0: + if self.EMfitChoice.get() == EMFIT_VOLUMES: + inSet = self.inputVolume.get() + outSet = self._createSetOfVolumes("subsetVolumes") + outSet.setSamplingRate(self.voxel_size.get()) + + else: + inSet = self.inputImage.get() + outSet = self._createSetOfParticles("subsetParticles") + outSet.setSamplingRate(self.pixel_size.get()) + + for i in inSet: + if not i.getObjId() in missing_pdbs: + outSet.append(i) + self._defineOutputs(subsetEM=outSet) + + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = ["Genesis in a software for Molecular Dynamics Simulation, " + "Normal Mode Molecular Dynamics (NMMD), Replica Exchange Umbrela " + "Sampling (REUS) and Energy Minimization"] + return summary + + def _validate(self): + errors = [] + if not os.path.exists(os.path.join( + Plugin.getVar("GENESIS_HOME"), 'bin/atdyn')): + errors.append("Missing GENESIS program : atdyn ") + + if not os.path.exists(os.path.join( + Plugin.getVar("GENESIS_HOME"), 'bin/spdyn')): + errors.append("Missing GENESIS program : spdyn ") + + return errors + + def _citations(self): + return ["kobayashi2017genesis","vuillemot2022NMMD","harastani2022continuousflex"] + + def _methods(self): + pass + + # --------------------------- UTILS functions -------------------------------------------- + + def getNumberOfInputPDB(self): + """ + Get the number of input PDBs + :return int: number of input PDBs + """ + return len(self.getInputPDBfn()) + + def getNumberOfInputEM(self): + """ + Get the number of input EM data to analyze + :return int : number of input EM data + """ + if self.EMfitChoice.get() == EMFIT_VOLUMES: + if isinstance(self.inputVolume.get(), SetOfVolumes): return self.inputVolume.get().getSize() + else: return 1 + elif self.EMfitChoice.get() == EMFIT_IMAGES: + if isinstance(self.inputImage.get(), SetOfParticles): return self.inputImage.get().getSize() + else: return 1 + else: return 0 + + def getNumberOfSimulation(self): + """ + Get the number of simulations to perform + :return int: Number of simulations + """ + numberOfInputPDB = self.getNumberOfInputPDB() + numberOfInputEM = self.getNumberOfInputEM() + + # Check input volumes/images correspond to input PDBs + if numberOfInputPDB != numberOfInputEM and \ + numberOfInputEM != 1 and numberOfInputPDB != 1 \ + and numberOfInputEM != 0: + raise RuntimeError("Number of input EM data and PDBs must be the same.") + return np.max([numberOfInputEM, numberOfInputPDB]) + + def getNumberOfNormalModes(self): + if self.simulationType.get() == SIMULATION_NMMD or self.simulationType.get() == SIMULATION_RENMMD : + if self.modeList.empty(): + modeSelection = np.arange(7,self.inputModes.get().getSize()+1) + else: + modeSelection\ + = getListFromRangeString(self.modeList.get()) + return len(modeSelection) + else: + return None + + def getInputPDBfn(self): + """ + Get the input PDB file names + :return list : list of input PDB file names + """ + initFn = [] + + if self.inputType.get() == INPUT_RESTART: + for i in range(self.restartProt.get().getNumberOfSimulation()): + initFn += self.restartProt.get().getOutputPrefixAll(i) + initFn = [i+".pdb" for i in initFn] + elif self.inputType.get() == INPUT_TOPOLOGY: + initFn = [self.topoProt.get().outputPDB.getFileName()] + else: + if isinstance(self.inputPDB.get(), SetOfAtomStructs) or \ + isinstance(self.inputPDB.get(), SetOfPDBs): + for i in range(self.inputPDB.get().getSize()): + initFn.append(self.inputPDB.get()[i+1].getFileName()) + + else: + initFn.append(self.inputPDB.get().getFileName()) + return initFn + + def getGenesisInputFile(self, index=0): + return "%s/INP_%s" % (self.getGenFiles(),str(index + 1).zfill(6)) + + def getInputPDBprefix(self, index=0): + """ + Get the input PDB prefix of the specified index + :param int index: index of input PDB + :return str: Input PDB prefix + """ + prefix = self._getExtraPath("inputPDB_%s") + if self.getNumberOfInputPDB() == 1: + return prefix % str(1).zfill(6) + else: + return prefix % str(index + 1).zfill(6) + + def getInputEMprefix(self, index=0): + """ + Get the input EM data prefix of the specified index + :param int index: index of the EM data + :return str: Input EM data prefix + """ + prefix = self.getEmdFiles()+"/inputEM_%s" + if self.getNumberOfInputEM() == 0: + return "" + elif self.getNumberOfInputEM() == 1: + return prefix % str(1).zfill(6) + else: + return prefix % str(index + 1).zfill(6) + + + def getOutputPrefix(self, index=0): + """ + Output prefix of the specified index + :param int index: index of the simulation to get + :return string : Output prefix of the specified index + """ + return self._getExtraPath("output_%s" % str(index + 1).zfill(6)) + + def getOutputPrefixAll(self, index=0): + """ + All output prefix of the specified index including multiple replicas in case of REUS + :param int index: index of the simulation to get + :return list: list of all output prefix of the specified index + """ + outputPrefix=[] + if self.simulationType.get() == SIMULATION_REMD or self.simulationType.get() == SIMULATION_RENMMD: + for i in range(self.nreplica.get()): + outputPrefix.append(self._getExtraPath("output_%s_remd%i" % + (str(index + 1).zfill(6), i + 1))) + else: + outputPrefix.append(self._getExtraPath("output_%s" % str(index + 1).zfill(6))) + return outputPrefix + def getEmdFiles(self): + return self._getExtraPath("EM_data") + def getGenFiles(self): + return self._getExtraPath("genesis_inputs") + + def getRigidBodyParams(self, index=0): + """ + Get the current rigid body parameters for the specified index in case of EMFIT with iamges + :param int index: Index of the simulation + :return list: angle_rot, angle_tilt, angle_psi, shift_x, shift_y + """ + if self.EMfitChoice.get() == EMFIT_IMAGES : + inputMd = self.getInputEMMetadata() + + idx = int(index + 1) + params = [ + inputMd.getValue(md.MDL_ANGLE_ROT, idx), + inputMd.getValue(md.MDL_ANGLE_TILT, idx), + inputMd.getValue(md.MDL_ANGLE_PSI, idx), + inputMd.getValue(md.MDL_SHIFT_X, idx), + inputMd.getValue(md.MDL_SHIFT_Y, idx), + ] + if any([i is None for i in params]): + raise RuntimeError("Can not find angles or shifts") + return params + else: + return None + + + def getGenesisEnv(self): + """ + Get environnement for running GENESIS + :return Environ: environnement + """ + environ = pwutils.Environ(os.environ) + environ.set('PATH', os.path.join(Plugin.getVar("GENESIS_HOME"), 'bin'), + position=pwutils.Environ.BEGIN) + environ.update({'LD_LIBRARY_PATH': Plugin.getCondaLibPath()}, position=pwutils.Environ.BEGIN) + return environ + + def getRestartFile(self, index=0): + """ + Get input restart file + :param int index: Index of the simulation + :return str: restart file + """ + if self.inputType.get() == INPUT_RESTART: + if len(self.restartProt.get().getOutputPrefixAll(index))>1: + raise RuntimeError("Multiple restart not implemented") + rstfile = self.getInputPDBprefix(index) + ".rst" + if not os.path.exists(rstfile): + runCommand("cp %s.rst %s" % (self.restartProt.get().getOutputPrefix(), rstfile)) + return rstfile + else: + return None + + def getForceField(self): + """ + Get simulation forcefield + :return int: forcefield + """ + if self.inputType.get() == INPUT_RESTART: + return self.restartProt.get().getForceField() + elif self.inputType.get() == INPUT_TOPOLOGY: + return self.topoProt.get().forcefield.get() + else: + return self.forcefield.get() + + def getInputEMMetadata(self): + if self._inputEMMetadata is None: + self._inputEMMetadata = self.readInputEMMetadata() + return self._inputEMMetadata + + def readInputEMMetadata(self): + nameMd = "%s/inputEM.xmd"%self.getEmdFiles() + + if self.EMfitChoice.get() == EMFIT_IMAGES: + writeSetOfParticles(self.inputImage.get(), nameMd) + inputEMMetadata = md.MetaData(nameMd) + if self.projectAngleChoice.get() == PROJECTION_ANGLE_XMIPP: + xmd = md.MetaData(self.projectAngleXmipp.get()) + for i in xmd: + rot = xmd.getValue(md.MDL_ANGLE_ROT, i) + tilt = xmd.getValue(md.MDL_ANGLE_TILT, i) + psi = xmd.getValue(md.MDL_ANGLE_PSI, i) + shx = xmd.getValue(md.MDL_SHIFT_X, i) + shy = xmd.getValue(md.MDL_SHIFT_Y, i) + inputEMMetadata.setValue(md.MDL_ANGLE_ROT, rot, i) + inputEMMetadata.setValue(md.MDL_ANGLE_TILT, tilt, i) + inputEMMetadata.setValue(md.MDL_ANGLE_PSI, psi, i) + inputEMMetadata.setValue(md.MDL_SHIFT_X, shx, i) + inputEMMetadata.setValue(md.MDL_SHIFT_Y, shy, i) + inputEMMetadata.write(nameMd) + + elif self.EMfitChoice.get() == EMFIT_VOLUMES: + if isinstance(self.inputVolume.get(), Volume): + inputEMMetadata = md.MetaData() + inputEMMetadata.setValue(md.MDL_IMAGE, + self.inputVolume.get().getFileName(), inputEMMetadata.addObject()) + inputEMMetadata.write(nameMd) + else: + writeSetOfVolumes(self.inputVolume.get(), nameMd) + inputEMMetadata = md.MetaData(nameMd) + return inputEMMetadata + + def getCHARMMInputs(self): + if self.forcefield.get() == FORCEFIELD_CHARMM: + if self.inputType.get() == INPUT_RESTART: + return self.restartProt.get().getCHARMMInputs() + elif self.inputType.get() == INPUT_TOPOLOGY: + return self.topoProt.get().getCHARMMInputs() + elif self.inputType.get() == INPUT_NEW_SIM: + return self.inputRTF.get(),self.inputPRM.get(), self.inputSTR.get() + else: + return None,None,None + +def createGenesisInput(inp_file, outputPrefix="", inputPDBprefix="", inputEMprefix="", rstFile="", nm_number=0, + rigid_body_params=None, forcefield= FORCEFIELD_CAGO, inputType=INPUT_NEW_SIM, simulationType=SIMULATION_MIN, + electrostatics=ELECTROSTATICS_CUTOFF, switch_dist=10.0, cutoff_dist=12.0, + pairlist_dist=15.0, vdw_force_switch=True, implicitSolvent=IMPLICIT_SOLVENT_NONE, + integrator=INTEGRATOR_LEAPFROG, time_step=0.001, eneout_period=100, crdout_period=100, + n_steps=10000, nbupdate_period=10, nm_dt=0.001, nm_mass=10.0, rigid_bond=False,posi_restr=False, + fast_water = False, water_model="TIP3", box_size_x=None, box_size_y=None, box_size_z=None, + boundary=BOUNDARY_NOBC, ensemble=ENSEMBLE_NVE, tpcontrol=TPCONTROL_NONE, temperature=300.0, + pressure=1.0, EMfitChoice=EMFIT_NONE, constantK=1000.0, nreplica=4, emfit_sigma=2.0, + emfit_tolerance=0.01, emfit_period=10, pixel_size=1.0, exchange_period=100): + s = "\n[INPUT] \n" # ----------------------------------------------------------- + s += "pdbfile = %s.pdb\n" % inputPDBprefix + if forcefield == FORCEFIELD_CHARMM: + s += "psffile = %s.psf\n" % inputPDBprefix + s += "topfile = %s_charmm.rtf\n" % inputPDBprefix + s += "parfile = %s_charmm.prm\n" % inputPDBprefix + s += "strfile = %s_charmm.str\n" % inputPDBprefix + elif forcefield == FORCEFIELD_AAGO or forcefield == FORCEFIELD_CAGO: + s += "grotopfile = %s.top\n" % inputPDBprefix + if inputType == INPUT_RESTART: + s += "rstfile = %s \n" % rstFile + if posi_restr: + s += "reffile = %s.pdb \n" % inputPDBprefix + + + s += "\n[OUTPUT] \n" # ----------------------------------------------------------- + if simulationType == SIMULATION_REMD or simulationType == SIMULATION_RENMMD: + s += "remfile = %s_remd{}.rem\n" % outputPrefix + s += "logfile = %s_remd{}.log\n" % outputPrefix + s += "dcdfile = %s_remd{}.dcd\n" % outputPrefix + s += "rstfile = %s_remd{}.rst\n" % outputPrefix + s += "pdbfile = %s_remd{}.pdb\n" % outputPrefix + else: + s += "dcdfile = %s.dcd\n" % outputPrefix + s += "rstfile = %s.rst\n" % outputPrefix + s += "pdbfile = %s.pdb\n" % outputPrefix + + s += "\n[ENERGY] \n" # ----------------------------------------------------------- + if forcefield == FORCEFIELD_CHARMM: + s += "forcefield = CHARMM \n" + elif forcefield == FORCEFIELD_AAGO: + s += "forcefield = AAGO \n" + elif forcefield == FORCEFIELD_CAGO: + s += "forcefield = CAGO \n" + + if electrostatics == ELECTROSTATICS_CUTOFF: + s += "electrostatic = CUTOFF \n" + else: + s += "electrostatic = PME \n" + s += "switchdist = %.2f \n" % switch_dist + s += "cutoffdist = %.2f \n" % cutoff_dist + s += "pairlistdist = %.2f \n" % pairlist_dist + if vdw_force_switch: + s += "vdw_force_switch = YES \n" + if implicitSolvent == IMPLICIT_SOLVENT_GBSA: + s += "implicit_solvent = GBSA \n" + s += "gbsa_eps_solvent = 78.5 \n" + s += "gbsa_eps_solute = 1.0 \n" + s += "gbsa_salt_cons = 0.2 \n" + s += "gbsa_surf_tens = 0.005 \n" + + if simulationType == SIMULATION_MIN: + s += "\n[MINIMIZE]\n" # ----------------------------------------------------------- + s += "method = SD\n" + else: + s += "\n[DYNAMICS] \n" # ----------------------------------------------------------- + if simulationType == SIMULATION_NMMD or simulationType == SIMULATION_RENMMD: + s += "integrator = NMMD \n" + elif integrator == INTEGRATOR_VVERLET: + s += "integrator = VVER \n" + elif integrator == INTEGRATOR_LEAPFROG: + s += "integrator = LEAP \n" + + s += "timestep = %f \n" % time_step + s += "nsteps = %i \n" % n_steps + s += "eneout_period = %i \n" % eneout_period + s += "crdout_period = %i \n" % crdout_period + s += "rstout_period = %i \n" % crdout_period + s += "nbupdate_period = %i \n" % nbupdate_period + + if simulationType == SIMULATION_NMMD or simulationType == SIMULATION_RENMMD: + s += "\n[NMMD] \n" # ----------------------------------------------------------- + s += "nm_number = %i \n" % nm_number + s += "nm_mass = %f \n" % nm_mass + s += "nm_file = %s.nma \n" % inputPDBprefix + if nm_dt is None: + s += "nm_dt = %f \n" % time_step + else: + s += "nm_dt = %f \n" % nm_dt + + if simulationType != SIMULATION_MIN: + s += "\n[CONSTRAINTS] \n" # ----------------------------------------------------------- + if rigid_bond: + s += "rigid_bond = YES \n" + else: + s += "rigid_bond = NO \n" + if fast_water: + s += "fast_water = YES \n" + s += "water_model = %s \n" % water_model + else: + s += "fast_water = NO \n" + + s += "\n[BOUNDARY] \n" # ----------------------------------------------------------- + if boundary == BOUNDARY_PBC: + s += "type = PBC \n" + s += "box_size_x = %f \n" % box_size_x + s += "box_size_y = %f \n" % box_size_y + s += "box_size_z = %f \n" % box_size_z + else: + s += "type = NOBC \n" + + if simulationType != SIMULATION_MIN: + s += "\n[ENSEMBLE] \n" # ----------------------------------------------------------- + if ensemble == ENSEMBLE_NVE: + s += "ensemble = NVE \n" + elif ensemble == ENSEMBLE_NPT: + s += "ensemble = NPT \n" + else: + s += "ensemble = NVT \n" + if tpcontrol == TPCONTROL_LANGEVIN: + s += "tpcontrol = LANGEVIN \n" + elif tpcontrol == TPCONTROL_BERENDSEN: + s += "tpcontrol = BERENDSEN \n" + elif tpcontrol == TPCONTROL_BUSSI: + s += "tpcontrol = BUSSI \n" + else: + s += "tpcontrol = NO \n" + s += "temperature = %.2f \n" % temperature + if ensemble == ENSEMBLE_NPT: + s += "pressure = %.2f \n" % pressure + + if ((EMfitChoice == EMFIT_VOLUMES or EMfitChoice == EMFIT_IMAGES) \ + and simulationType != SIMULATION_MIN ) or posi_restr: + s += "\n[SELECTION] \n" # ----------------------------------------------------------- + if ((EMfitChoice == EMFIT_VOLUMES or EMfitChoice == EMFIT_IMAGES) \ + and simulationType != SIMULATION_MIN): + s += "group1 = all and not hydrogen\n" + if posi_restr: + s += "group1 = an:CA\n" + + + if ((EMfitChoice == EMFIT_VOLUMES or EMfitChoice == EMFIT_IMAGES) \ + and simulationType != SIMULATION_MIN ) or posi_restr: + + s += "\n[RESTRAINTS] \n" # ----------------------------------------------------------- + if ((EMfitChoice == EMFIT_VOLUMES or EMfitChoice == EMFIT_IMAGES) \ + and simulationType != SIMULATION_MIN): + s += "nfunctions = 1 \n" + s += "function1 = EM \n" + constStr = constantK + if "-" in constStr: + splt = constStr.split("-") + constStr = " ".join( + [str(int(i)) for i in np.linspace(int(splt[0]), int(splt[1]), nreplica)]) + s += "constant1 = %s \n" % constStr + s += "select_index1 = 1 \n" + else: + s += "nfunctions = 1 \n" + s += "function1 = POSI \n" + s += "constant1 = 1 \n" + s += "select_index1 = 1 \n" + + if (EMfitChoice == EMFIT_VOLUMES or EMfitChoice == EMFIT_IMAGES) \ + and simulationType != SIMULATION_MIN: + s += "\n[EXPERIMENTS] \n" # ----------------------------------------------------------- + s += "emfit = YES \n" + s += "emfit_sigma = %.4f \n" % emfit_sigma + s += "emfit_tolerance = %.6f \n" % emfit_tolerance + s += "emfit_period = %i \n" % emfit_period + if EMfitChoice == EMFIT_VOLUMES: + s += "emfit_target = %s.mrc \n" % inputEMprefix + elif EMfitChoice == EMFIT_IMAGES: + s += "emfit_type = IMAGE \n" + s += "emfit_target = %s.spi \n" % inputEMprefix + s += "emfit_pixel_size = %f\n" % pixel_size + s += "emfit_roll_angle = %f\n" % rigid_body_params[0] + s += "emfit_tilt_angle = %f\n" % rigid_body_params[1] + s += "emfit_yaw_angle = %f\n" % rigid_body_params[2] + s += "emfit_shift_x = %f\n" % rigid_body_params[3] + s += "emfit_shift_y = %f\n" % rigid_body_params[4] + + if simulationType == SIMULATION_REMD or simulationType == SIMULATION_RENMMD: + s += "\n[REMD] \n" # ----------------------------------------------------------- + s += "dimension = 1 \n" + s += "exchange_period = %i \n" % exchange_period + s += "type1 = RESTRAINT \n" + s += "nreplica1 = %i \n" % nreplica + s += "rest_function1 = 1 \n" + + with open(inp_file, "w") as f: + f.write(s) \ No newline at end of file diff --git a/continuousflex/protocols/protocol_histogram_matching.py b/continuousflex/protocols/protocol_histogram_matching.py deleted file mode 100644 index f3e147a..0000000 --- a/continuousflex/protocols/protocol_histogram_matching.py +++ /dev/null @@ -1,135 +0,0 @@ -# ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) -# * -# * This program is free software; you can redistribute it and/or modify -# * it under the terms of the GNU General Public License as published by -# * the Free Software Foundation; either version 2 of the License, or -# * (at your option) any later version. -# * -# * This program is distributed in the hope that it will be useful, -# * but WITHOUT ANY WARRANTY; without even the implied warranty of -# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# * GNU General Public License for more details. -# * -# * You should have received a copy of the GNU General Public License -# * along with this program; if not, write to the Free Software -# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -# * 02111-1307 USA -# * -# * All comments concerning this program package may be sent to the -# * e-mail address 'scipion@cnb.csic.es' -# * -# ************************************************************************** - -from pwem.protocols import ProtAnalysis3D -import xmipp3.convert -import pwem.emlib.metadata as md -import pyworkflow.protocol.params as params -from pyworkflow.utils.path import makePath, copyFile -from os.path import basename, isfile -from .utilities.spider_files3 import save_volume, open_volume -from pyworkflow.utils import replaceBaseExt -import numpy as np -from pwem.utils import runProgram -from pwem.emlib.image import ImageHandler -from skimage.exposure import match_histograms - -class FlexProtHistogramMatch(ProtAnalysis3D): - """ Protocol for volume histogram matching. """ - _label = 'histogram matching' - - # --------------------------- DEFINE param functions -------------------------------------------- - def _defineParams(self, form): - form.addSection(label='Input') - form.addParam('inputVolumes', params.PointerParam, - pointerClass='SetOfVolumes,Volume', - label="Input volume(s)", important=True, - help='Select a volume of a set of volumes') - form.addParam('reference', params.PointerParam, - pointerClass='Volume', - label="Reference volume", important=True, - help='Select a reference volume') - - - # --------------------------- INSERT steps functions -------------------------------------------- - - def _insertAllSteps(self): - # Define some outputs filenames - self.imgsFn = self._getExtraPath('volumes.xmd') - makePath(self._getExtraPath() + '/histogram_matched') - self._insertFunctionStep('convertInputStep') - self._insertFunctionStep('doHistogramMatchingStep') - self._insertFunctionStep('createOutputStep') - - # --------------------------- STEPS functions -------------------------------------------- - def convertInputStep(self): - # Write a metadata with the volumes - try: - xmipp3.convert.writeSetOfVolumes(self.inputVolumes.get(), self._getExtraPath('input.xmd')) - except: - mdF = md.MetaData() - mdF.setValue(md.MDL_IMAGE, self.inputVolumes.get().getFileName(), mdF.addObject()) - mdF.write(self.imgsFn) - pass - - def doHistogramMatchingStep(self): - # looping on all images and performing mwr - reference = self.reference.get().getFileName() - # xmipp convert to spider format just in case: - params = '-i ' + reference + ' -o ' + self._getExtraPath('reference.spi') - runProgram('xmipp_image_convert', params) - ref = ImageHandler().read(self._getExtraPath('reference.spi')).getData() - ref = np.squeeze(ref) - mdImgs = md.MetaData(self._getExtraPath('input.xmd')) - for objId in mdImgs: - imgPath = mdImgs.getValue(md.MDL_IMAGE, objId) - index, fname = xmipp3.convert.xmippToLocation(imgPath) - new_imgPath = self._getExtraPath() + '/histogram_matched/' - if index: # case of stack - new_imgPath += str(index).zfill(6) + '.spi' - else: - new_imgPath += basename(replaceBaseExt(basename(imgPath), 'spi')) - # Get a copy of the volume converted to spider format - temp_path = self._getTmpPath('temp.spi') - # params = '-i ' + imgPath + ' -o ' + new_imgPath + ' --type vol' - params = '-i ' + imgPath + ' -o ' + temp_path + ' --type vol' - runProgram('xmipp_image_convert', params) - # perform the mwr: - # in case the file exists (continuing or injecting) - if (isfile(new_imgPath)): - continue - else: - v = ImageHandler().read(temp_path).getData() - v = np.squeeze(v) - map = match_histograms(v, ref) - save_volume(np.float32(map), new_imgPath) - # update the name in the metadata file - mdImgs.setValue(md.MDL_IMAGE, new_imgPath, objId) - mdImgs.write(self.imgsFn) - - def createOutputStep(self): - partSet = self._createSetOfVolumes('histogram_matched') - xmipp3.convert.readSetOfVolumes(self._getExtraPath('volumes.xmd'), partSet) - partSet.setSamplingRate(self.inputVolumes.get().getSamplingRate()) - self._defineOutputs(HistogramMatched=partSet) - - - # --------------------------- INFO functions -------------------------------------------- - def _summary(self): - summary = [] - return summary - - def _citations(self): - return [''] - - def _methods(self): - pass - - # --------------------------- UTILS functions -------------------------------------------- - def _printWarnings(self, *lines): - """ Print some warning lines to 'warnings.xmd', - the function should be called inside the working dir.""" - fWarn = open("warnings.xmd", 'w') - for l in lines: - print >> fWarn, l - fWarn.close() \ No newline at end of file diff --git a/continuousflex/protocols/protocol_image_synthesize.py b/continuousflex/protocols/protocol_image_synthesize.py index 63b5bf2..2a99b38 100644 --- a/continuousflex/protocols/protocol_image_synthesize.py +++ b/continuousflex/protocols/protocol_image_synthesize.py @@ -1,4 +1,4 @@ -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Rémi Vuillemot (remi.vuillemot@upmc.fr) # * # * IMPMC, UPMC Sorbonne University @@ -40,7 +40,7 @@ import glob from joblib import dump from math import cos, sin, pi -import xmippLib +from continuousflex.protocols.convert import matrix2eulerAngles NMA_ALIGNMENT_WAV = 0 NMA_ALIGNMENT_PROJ = 1 @@ -51,8 +51,8 @@ MODE_RELATION_RANDOM = 3 MODE_RELATION_PARABOLA = 4 -MISSINGWEDGE_YES = 0 -MISSINGWEDGE_NO = 1 +LOWPASS_YES = 0 +LOWPASS_NO = 1 ROTATION_SHIFT_YES = 0 ROTATION_SHIFT_NO = 1 @@ -71,7 +71,192 @@ class FlexProtSynthesizeImages(ProtAnalysis3D): - """ Protocol for synthesizing images. """ + """ + Protocol for synthesizing cryo-EM particle images from atomic structures, + EM volumes, or conformational ensembles. The protocol generates realistic + image datasets that can include structural variability, imaging artifacts, + and rigid-body transformations, making it suitable for benchmarking, + validation, and methodological development in structural biology. + + AI Generated: + + Synthesize Images (FlexProtSynthesizeImages) - User Manual + + Overview + + The Synthesize Images protocol creates artificial cryo-EM particle + images that mimic the appearance and variability of experimental + datasets. Its primary objective is to provide controlled image + collections where the underlying structural states and imaging + parameters are known in advance. Such datasets are valuable for + developing, testing, and validating image-processing algorithms, + machine-learning approaches, and methods for studying structural + heterogeneity. + + The protocol can generate images either from a single atomic + structure, from an existing EM volume, or from a collection of + conformational states. This flexibility allows users to reproduce a + broad range of biological scenarios, from rigid particles with no + structural variability to highly dynamic molecular systems exhibiting + continuous conformational changes. + + Conformational Variability + + One of the central capabilities of the protocol is the simulation of + conformational heterogeneity. Biological macromolecules frequently + populate multiple structural states, and understanding this variability + is often a major objective of cryo-EM studies. + + Conformational variability can be generated from normal mode analysis, + where selected modes define the directions of structural motion. + Different relationships between the modes can be used to create + distinct patterns of structural diversity. These include continuous + trajectories, clustered states, regularly sampled conformational + landscapes, random distributions, and curved pathways representing + nonlinear transitions between states. + + Alternatively, users may provide a collection of heterogeneous atomic + models. This option is particularly useful when conformations originate + from molecular dynamics simulations, experimentally derived ensembles, + or previously generated structural trajectories. In this case, the + protocol preserves the supplied diversity and converts the structural + models into synthetic imaging data. + + Input Structures and Volume Generation + + The protocol supports both atomic structures and density maps as + starting points. When atomic models are provided, volumetric + representations are generated before image synthesis. This enables + realistic simulation of cryo-EM observations directly from structural + coordinates. + + When an EM volume is supplied, the protocol can generate multiple + projections from the same structure without introducing conformational + changes. This mode is useful for studying orientation effects, + reconstruction performance, or image-processing behavior under + controlled conditions. + + Sampling and Image Dimensions + + Users can define the sampling rate and image dimensions of the + generated data. These parameters determine the physical scale and size + of the synthetic images and should be selected to resemble the + experimental conditions that the simulated dataset is intended to + represent. + + Matching these parameters to real cryo-EM acquisitions allows the + resulting images to be used in realistic benchmarking experiments and + algorithm validation studies. + + Conformational Sampling Strategies + + Different conformational sampling strategies can be used depending on + the biological question being investigated. Linear sampling is useful + for representing smooth transitions between states. Clustered sampling + is appropriate when the molecule occupies a small number of discrete + conformations. Grid-based sampling provides systematic coverage of a + conformational landscape and is valuable for method development and + visualization. + + Random sampling can be used to emulate complex heterogeneous systems + where states are broadly distributed throughout conformational space. + Curved trajectories are useful for representing nonlinear transitions + and continuous motions that cannot be adequately described by a simple + linear relationship. + + Rigid-Body Variability + + In addition to structural heterogeneity, the protocol can introduce + rigid-body variability through random rotations and translations. This + reproduces the orientation diversity observed in experimental cryo-EM + datasets and generates realistic projection images from multiple + viewing directions. + + Users can define the statistical distributions governing rotational + and translational parameters. Uniform distributions are useful for + broad orientation coverage, while Gaussian distributions can reproduce + preferred orientations or limited particle mobility. + + For many benchmarking applications, realistic orientation diversity is + essential because it strongly influences reconstruction quality and + downstream analysis. + + Noise and Microscope Effects + + The protocol can simulate important imaging artifacts commonly present + in cryo-EM experiments. These include contrast transfer function + effects and controlled levels of noise corresponding to a specified + signal-to-noise ratio. + + Incorporating these effects allows synthetic images to resemble real + microscope data more closely. This is particularly important when + evaluating algorithms designed for particle alignment, classification, + reconstruction, heterogeneity analysis, or denoising. + + By adjusting imaging parameters, users can emulate different microscope + conditions and acquisition settings, enabling systematic studies of + algorithm robustness under varying experimental scenarios. + + Additional Resolution Effects + + The protocol can optionally apply low-pass filtering to mimic the loss + of high-resolution information that often occurs during imaging. This + feature can be used to reproduce additional degradation effects beyond + those introduced by the contrast transfer function. + + Such simulations are valuable when assessing the sensitivity of + computational methods to resolution limitations or when generating + datasets that reflect challenging experimental conditions. + + Ground Truth Information + + A major advantage of synthetic datasets is the availability of exact + ground truth information. The protocol preserves the relationship + between generated images and their underlying structural states, + conformational coordinates, orientations, and shifts. + + This information provides a reference against which reconstruction, + classification, dimensionality reduction, and flexibility-analysis + methods can be quantitatively evaluated. Because the true structural + parameters are known, users can measure algorithm accuracy directly + rather than relying solely on qualitative assessments. + + Outputs and Interpretation + + The primary output is a set of synthetic particle images suitable for + use in cryo-EM processing workflows. Depending on the selected options, + the dataset may represent rigid particles, discrete structural states, + or continuous conformational landscapes. + + The generated images can be processed using standard cryo-EM software + pipelines in the same manner as experimental particle images. Since + the underlying structural variability is controlled and documented, + the resulting datasets are particularly useful for benchmarking new + methodologies and comparing alternative analysis strategies. + + Practical Recommendations + + For exploratory studies of structural heterogeneity, using a small + number of normal modes with continuous sampling often provides a clear + and interpretable conformational landscape. When evaluating + classification methods, clustered conformations can be advantageous + because the expected states are well defined. + + Realistic benchmarking experiments generally benefit from including + orientation variability, microscope effects, and moderate noise levels. + Excessively simplified datasets may overestimate algorithm performance, + whereas carefully simulated experimental conditions provide more + meaningful assessments. + + Final Perspective + + Synthetic image generation is a powerful approach for understanding + the strengths and limitations of cryo-EM analysis methods. By + controlling structural variability, imaging conditions, and noise + characteristics, this protocol enables the creation of realistic + benchmark datasets that support method development, validation, and + biological interpretation of conformational dynamics. + """ _label = 'synthesize images' # --------------------------- DEFINE param functions -------------------------------------------- @@ -196,6 +381,24 @@ def _defineParams(self, form): label='CTF Q0', help='Microscope attribute') + form.addSection(label='Low pass filtering') + form.addParam('lowPassChoice', params.EnumParam, default=LOWPASS_NO, + choices=['Add extra dose accumulation', 'Stay with only CTF'], + label='Use low pass filtering', + help='The generated volumes will be low pass filtered before projection to images.' + ' This simulates extra distortions similar to dose accumulation.' + ' However, CTF will already have such an effect.') + line = form.addLine('Frequency (normalized)', + condition='lowPassChoice==%d' % LOWPASS_YES, + help='The cufoff frequency and raised coside width of the low pass filter.' + ' For details: see "xmipp_transform_filter --fourier low_pass"') + line.addParam('w1', params.FloatParam, default=0.25, + condition='lowPassChoice==%d' % LOWPASS_YES, + label='Cutoff frequency (0 -> 0.5)') + line.addParam('raisedw', params.FloatParam, default=0.02, + condition='lowPassChoice==%d' % LOWPASS_YES, + label='Raised cosine width') + form.addSection('Rigid body variability') form.addParam('rotationShiftChoice', params.EnumParam, default=ROTATION_SHIFT_YES, choices=['Yes', 'No'], @@ -413,9 +616,9 @@ def generate_deformations(self): subtomogramMD.setValue(md.MDL_NMA, list(deformations), i+1) subtomogramMD.write(deformationFile) - def copy_deformations(self): pdbs_list = [f for f in glob.glob(self.pdbs_path.get())] + pdbs_list.sort() # print(pdbs_list) # saving the list dump(pdbs_list, self._getExtraPath('pdb_list.pkl')) @@ -424,7 +627,7 @@ def copy_deformations(self): for pdbfn in pdbs_list: i += 1 createLink(pdbfn, self._getExtraPath(str(i).zfill(5)+'_df.pdb')) - subtomogramMD.setValue(md.MDL_IMAGE, self._getExtraPath(str(i).zfill(5)+'_subtomogram'+'.vol'), + subtomogramMD.setValue(md.MDL_IMAGE, self._getExtraPath(str(i).zfill(5)+'_projected'+'.spi'), subtomogramMD.addObject()) subtomogramMD.write(self._getExtraPath('GroundTruth.xmd')) @@ -438,6 +641,14 @@ def generate_volume_from_pdb(self): params += " -v 0 --centerPDB " runProgram('xmipp_volume_from_pdb', params) + if self.lowPassChoice.get() is LOWPASS_YES: + cutoff = self.w1.get() + raisedw = self.raisedw.get() + for i in range(numberOfVolumes): + params = " -i " + self._getExtraPath(str(i + 1).zfill(5) + '_df.vol') + params += " --fourier low_pass " + str(cutoff) + ' ' + str(raisedw) + runProgram('xmipp_transform_filter', params) + def generate_rotation_and_shift(self): subtomogramMD = md.MetaData(self._getExtraPath('GroundTruth.xmd')) numberOfVolumes = self.get_number_of_volumes() @@ -464,6 +675,29 @@ def generate_rotation_and_shift(self): psi1 = np.random.uniform(self.LowPsi.get(), self.HighPsi.get()) else: psi1 = np.random.normal(self.MeanPsi.get(), self.StdPsi.get()) + + # uniform over the sphere + if (self.psi.get() == ROTATION_UNIFORM) and\ + (self.tilt.get()==ROTATION_UNIFORM) and \ + (self.rot.get()==ROTATION_UNIFORM) and \ + self.LowRot.get() == 0.0 and self.HighRot.get() == 360.0 and \ + self.LowTilt.get() == 0.0 and self.HighTilt.get() == 180.0 and \ + self.LowPsi.get() == 0.0 and self.HighPsi.get() == 360.0: + x1,x2,x3 = np.random.uniform(0,1,3) + R = np.array([ + [np.cos(2*np.pi*x1), np.sin(2*np.pi*x1), 0], + [-np.sin(2*np.pi*x1), np.cos(2*np.pi*x1), 0], + [0, 0, 1] + ]) + v = np.array([[np.cos(2*np.pi*x2)*np.sqrt(x3), + np.sin(2*np.pi*x2)*np.sqrt(x3), + np.sqrt(1-x3)]]) + H = np.eye(3) - 2*np.dot(v.T,v) + M = -np.dot(H,R) + trans_mat = np.zeros((4,4)) + trans_mat[:3,:3] = M + rot1,tilt1,psi1,_,_,_ = matrix2eulerAngles(trans_mat) + subtomogramMD.setValue(md.MDL_SHIFT_X, shift_x1, i + 1) subtomogramMD.setValue(md.MDL_SHIFT_Y, shift_y1, i + 1) subtomogramMD.setValue(md.MDL_ANGLE_ROT, rot1, i + 1) @@ -631,7 +865,7 @@ def createOutputStep(self): runProgram('xmipp_metadata_selfile_create', command) # now creating the output set of images as output: partSet = self._createSetOfParticles('images') - xmipp3.convert.readSetOfParticles(out_mdfn, partSet) + xmipp3.convert.readSetOfParticles(self._getExtraPath('GroundTruth.xmd'), partSet) if (self.refVolume.get()): sr = self.refVolume.get().getSamplingRate() else: @@ -639,20 +873,7 @@ def createOutputStep(self): partSet.setSamplingRate(sr) self._defineOutputs(outputImages=partSet) - # --------------------------- INFO functions -------------------------------------------- - def _summary(self): - summary = [] - return summary - def _validate(self): - errors = [] - return errors - - def _citations(self): - return ['harastani2020hybrid','Jonic2005', 'Sorzano2004b', 'Jin2014'] - - def _methods(self): - pass def get_number_of_volumes(self): if(self.importPdbs.get()): @@ -675,3 +896,18 @@ def _printWarnings(self, *lines): def _getLocalModesFn(self): modesFn = self.inputModes.get().getFileName() return self._getBasePath(modesFn) + + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['harastani2022continuousflex'] + + def _methods(self): + pass \ No newline at end of file diff --git a/continuousflex/protocols/protocol_mdspace.py b/continuousflex/protocols/protocol_mdspace.py new file mode 100644 index 0000000..3d7ca05 --- /dev/null +++ b/continuousflex/protocols/protocol_mdspace.py @@ -0,0 +1,523 @@ +# ************************************************************************** +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** +import numpy as np + +from continuousflex.protocols.protocol_genesis import * +import pyworkflow.protocol.params as params +from sklearn import decomposition +from xmipp3.convert import writeSetOfVolumes, writeSetOfParticles, readSetOfVolumes, readSetOfParticles +from pwem.constants import ALIGN_PROJ +from continuousflex.protocols.convert import matrix2eulerAngles +from pwem.emlib import MetaData, MDL_ENABLED, MDL_NMA_MODEFILE,MDL_ORDER +from pwem.objects import SetOfNormalModes +from .convert import rowToMode +from xmipp3.base import XmippMdRow + +class FlexProtMDSPACE(FlexProtGenesis): + """ + Performs iterative molecular dynamics based conformational refinement and exploration by combining + GENESIS simulations, structural alignment, and principal component analysis. The protocol is designed + to characterize continuous molecular flexibility, progressively refine structural ensembles, and build + a reduced representation of the dominant motions present within a molecular system. + + AI Generated: + + MDSPACE Refinement (FlexProtMDSPACE) - User Manual + Overview + + The MDSPACE protocol provides an iterative framework for studying structural variability in + macromolecular systems through molecular dynamics simulations guided by conformational analysis. + Its primary objective is to identify the dominant collective motions of a molecule while + progressively refining the structural model used to describe those motions. + + In structural biology, many macromolecules do not exist in a single rigid conformation. + Instead, they populate a range of states connected through continuous transitions. MDSPACE + is intended for situations where understanding these transitions is as important as obtaining + a single structure. The protocol combines simulation, structural comparison, and dimensionality + reduction techniques to reveal the major directions of conformational variability. + + Inputs and General Workflow + + The protocol starts from an atomic structure together with the simulation parameters required + for molecular dynamics calculations. Depending on the experimental setup, additional information + such as electron microscopy data or previously determined motion models may also be incorporated + into the refinement process. + + The workflow proceeds through multiple refinement rounds. During each round, molecular dynamics + simulations generate structural ensembles that sample the conformational landscape accessible to + the system. These conformations are then compared and analyzed collectively in order to identify + the most significant structural variations present in the ensemble. + + Rather than treating each simulation independently, the protocol continuously updates its + description of the system using information gathered from all generated conformations. This + iterative strategy allows the exploration of flexibility to become progressively focused on the + biologically relevant motions observed during previous rounds. + + Iterative Refinement Strategy + + A defining characteristic of MDSPACE is its iterative nature. After each simulation cycle, + the generated conformations are analyzed to determine the dominant collective movements within + the ensemble. These motions are then used to construct an updated description of the system + that serves as the starting point for the next refinement round. + + From a biological perspective, this approach allows the protocol to gradually concentrate on + conformational pathways that are repeatedly observed across simulations. As the refinement + progresses, the representation of molecular flexibility becomes increasingly adapted to the + behavior of the system under study. + + Principal Component Analysis and Conformational Space + + Principal component analysis plays a central role in the protocol. The objective is to reduce + the complexity of large structural ensembles into a smaller set of collective motions that + explain most of the observed variability. + + Each principal component can often be interpreted as a large-scale conformational movement, + such as domain rearrangements, hinge motions, breathing movements, or coordinated shifts + involving multiple regions of a macromolecular assembly. By focusing on the most important + components, users can study biologically meaningful flexibility while filtering out smaller + fluctuations and noise. + + The number of principal components retained determines the dimensionality of the reduced + conformational space. Lower values emphasize only the strongest motions, whereas larger values + preserve a more detailed description of the structural variability. + + Structural Alignment and Ensemble Consistency + + Before conformational variability can be analyzed, all generated structures must be expressed + within a common coordinate system. The protocol therefore performs rigid-body alignment of the + simulated conformations. + + This alignment step is biologically important because it removes differences arising from + overall translation and rotation. As a result, the subsequent analysis focuses on genuine + internal structural changes rather than trivial rigid-body movements. + + Proper alignment is particularly critical for large complexes, multidomain proteins, and + flexible assemblies where small orientation differences can otherwise obscure meaningful + conformational trends. + + Molecular Dynamics Simulations + + The protocol relies on molecular dynamics simulations to generate physically plausible + conformational trajectories. Depending on the selected simulation settings, the refinement + may explore motions driven by normal modes, energy minimization procedures, or additional + simulation strategies available within the GENESIS framework. + + The simulations serve as a mechanism for sampling the conformational landscape rather than + producing a single optimized structure. Consequently, the biological value of the protocol + comes from the ensemble of generated conformations and the relationships among them. + + Handling of Structural Diversity + + MDSPACE is particularly useful when the system exhibits substantial conformational variability. + Examples include molecular motors, ribonucleoprotein complexes, membrane proteins, multi-domain + enzymes, and assemblies undergoing functional transitions. + + By repeatedly identifying dominant motions and updating the conformational model, the protocol + can capture gradual transitions between states that may be difficult to characterize using + conventional static structural approaches. + + Outputs and Their Interpretation + + The protocol produces a refined structural representation together with a set of principal + components describing the dominant motions identified during the iterative analysis. These + components can be interpreted similarly to normal modes, providing a compact description of + the most important directions of conformational change. + + The resulting mean structure represents the central conformation of the analyzed ensemble, + while the extracted motion components describe how the system deviates from that average. + Together, these outputs provide a reduced but biologically informative model of molecular + flexibility. + + The generated motion set can subsequently be used for visualization, conformational analysis, + structural interpretation, or integration into downstream flexibility studies. + + Practical Recommendations + + For most applications, a moderate number of refinement iterations provides a good balance + between computational cost and conformational exploration. Systems with highly complex + flexibility may benefit from additional iterations, while relatively rigid structures often + converge more rapidly. + + The number of retained principal components should reflect the expected complexity of the + biological motions. Retaining too few components may overlook relevant conformational states, + whereas retaining too many may introduce motions that contribute little to the overall + structural variability. + + Visual inspection of the resulting principal motions is strongly recommended. Interpreting + the dominant components in the context of known biological functions often provides valuable + insight into the mechanisms underlying molecular activity. + + Final Perspective + + MDSPACE is designed to bridge molecular dynamics simulation and conformational landscape + analysis. Rather than focusing solely on individual trajectories, it seeks to identify the + collective motions that define the functional flexibility of a molecular system. For studies + of continuous structural variability, it provides a powerful framework for building compact, + interpretable, and biologically meaningful models of molecular motion. + """ + _label = 'MDSPACE' + + def __init__(self, **kwargs): + FlexProtGenesis.__init__(self, **kwargs) + self._iter = 0 + self._missing_pdbs = None + + # --------------------------- DEFINE param functions -------------------------------------------- + def _defineParams(self, form): + form.addSection(label='MDSPACE Refinement') + + form.addParam('numberOfIter', params.IntParam, label="Number of iterations", default=3, + help="Number of round of fitting for MDSPACE", important=True) + + form.addParam('numberOfPCA', params.IntParam, label="Number of PCA component", default=5, + help="Number of principal component to keep at each round", expertLevel=params.LEVEL_ADVANCED) + + FlexProtGenesis._defineParams(self, form) + + + def _insertAllSteps(self): + # make path + self._insertFunctionStep("makePathStep") + + # Convert input PDB + self._insertFunctionStep("convertInputPDBStep") + + # Convert normal modes + if (self.simulationType.get() == SIMULATION_NMMD or self.simulationType.get() == SIMULATION_RENMMD): + self._insertFunctionStep("convertNormalModeFileStep") + + # Convert input EM data + if self.EMfitChoice.get() != EMFIT_NONE: + self._insertFunctionStep("convertInputEMStep") + + for iter_global in range(self.numberOfIter.get()): + + # Create INP files + self._insertFunctionStep("createGenesisInputStep") + + # RUN simulation + if self.parallelType.get() == PARALLEL_MPI and self.getNumberOfSimulation() > 1: + self._insertFunctionStep("runSimulationMPI") + elif self.parallelType.get() == PARALLEL_GNU and self.getNumberOfSimulation() > 1 and existsCommand( + "parallel"): + self._insertFunctionStep("runSimulationParallel") + else: + for i in range(self.getNumberOfSimulation()): + self._insertFunctionStep("runSimulation", self.getGenesisInputFile(i), self.getOutputPrefix(i)) + + self._insertFunctionStep("pdb2dcdStep") + + self._insertFunctionStep("rigidBodyAlignmentStep") + + self._insertFunctionStep("updateAlignmentStep") + + self._insertFunctionStep("PCAStep") + + self._insertFunctionStep("runMinimizationStep") + + self._insertFunctionStep("newIterationStep") + + self._insertFunctionStep("createOutputStep") + + def pdb2dcdStep(self): + pdbs_matrix = [] + missing_pdbs = [] + + for i in range(self.getNumberOfSimulation()): + pdb_fname = self.getOutputPrefix(i) +".pdb" + if os.path.isfile(pdb_fname) and os.path.getsize(pdb_fname) != 0: + mol = ContinuousFlexPDBHandler(pdb_fname) + pdbs_matrix.append(mol.coords) + else: + missing_pdbs.append(i) + + pdbs_arr = np.array(pdbs_matrix) + + # save as dcd file + numpyArr2dcd(pdbs_arr, self._getExtraPath("coords.dcd")) + + # If some pdbs are missing (fitting failed), save indexes + self._missing_pdbs = np.array(missing_pdbs).astype(int) + print("MiSSING ARRAY : ") + print(self._missing_pdbs) + + def rigidBodyAlignmentStep(self): + + # open files + refPDB = ContinuousFlexPDBHandler(self.getInputPDBprefix()+".pdb") + arrDCD = dcd2numpyArr(self._getExtraPath("coords.dcd")) + nframe, natom,_ =arrDCD.shape + alignXMD = md.MetaData() + + # loop over all pdbs + for i in range(nframe): + print("Aligning PDB %i ... " %i) + + # rotate + coord = arrDCD[i] + rot_mat, tran = ContinuousFlexPDBHandler.alignCoords(refPDB.coords, coord) + arrDCD[i] = (np.dot(arrDCD[i], rot_mat) + tran).astype(np.float32) + + # add to MD + trans_mat = np.zeros((4,4)) + trans_mat[:3,:3] = rot_mat + trans_mat[:,3][:3] = tran + rot, tilt, psi,shftx, shfty, shftz = matrix2eulerAngles(trans_mat) + index = alignXMD.addObject() + alignXMD.setValue(md.MDL_ANGLE_ROT, rot, index) + alignXMD.setValue(md.MDL_ANGLE_TILT, tilt, index) + alignXMD.setValue(md.MDL_ANGLE_PSI, psi, index) + alignXMD.setValue(md.MDL_SHIFT_X, shftx, index) + alignXMD.setValue(md.MDL_SHIFT_Y, shfty, index) + alignXMD.setValue(md.MDL_SHIFT_Z, shftz, index) + alignXMD.setValue(md.MDL_IMAGE, "", index) + + numpyArr2dcd(arrDCD, self._getExtraPath("coords.dcd")) + alignXMD.write(self.getTransformation()) + + def updateAlignmentStep(self): + + if self._iter == 0: + inputSet = self.inputImage.get() + else: + inputSet = self._createSetOfParticles("inputSet") + readSetOfParticles(self.getAlignmentPrefix(self._iter-1), inputSet) + inputSet.setSamplingRate(self.inputImage.get().getSamplingRate()) + + inputTransformation = self._createSetOfParticles("inputTransformation") + readSetOfParticles(self.getTransformation(), inputTransformation) + alignedSet = self._createSetOfParticles("alignedSet") + + alignedSet.setSamplingRate(inputSet.getSamplingRate()) + alignedSet.setAlignment(ALIGN_PROJ) + iter1 = inputSet.iterItems() + iter2 = inputTransformation.iterItems() + for i in range(self.getNumberOfSimulation()): + p1 = iter1.__next__() + r1 = p1.getTransform() + if not i in self._missing_pdbs : + p2 = iter2.__next__() + r2 = p2.getTransform() + rot = r2.getRotationMatrix() + tran = np.array(r2.getShifts()) / inputSet.getSamplingRate() + new_trans = np.zeros((4, 4)) + new_trans[:3, 3] = tran + new_trans[:3, :3] = rot + new_trans[3, 3] = 1.0 + r1.composeTransform(new_trans) + else: + print("MISSING PDBS %s"%(i+1)) + p1.setTransform(r1) + alignedSet.append(p1) + + writeSetOfParticles(alignedSet, self.getAlignmentPrefix()) + self._inputEMMetadata = md.MetaData(self.getAlignmentPrefix()) + + def PCAStep(self): + + numberOfPCA = self.numberOfPCA.get() + + pdbs_arr = dcd2numpyArr(self._getExtraPath("coords.dcd")) + nframe, natom,_ = pdbs_arr.shape + pdbs_matrix = pdbs_arr.reshape(nframe, natom*3) + + pca = decomposition.PCA(n_components=numberOfPCA) + Y = pca.fit_transform(pdbs_matrix) + + pdb = ContinuousFlexPDBHandler(self.getInputPDBprefix()+".pdb") + pdb.coords = pca.mean_.reshape(pdbs_matrix.shape[1] // 3, 3) + + matrix = pca.components_.reshape(numberOfPCA,pdbs_matrix.shape[1]//3,3) + + # SAVE NEW inputs + pca_prefix = self.getPCAPrefix() + pdb.write_pdb(pca_prefix+".pdb") + nm_file = pca_prefix+".nma" + np.savetxt(pca_prefix+"_matrix.txt", Y) + with open(nm_file, "w") as f: + for i in range(numberOfPCA): + f.write(" VECTOR %i VALUE 0.0\n" % (i + 1)) + f.write(" -----------------------------------\n") + for j in range(matrix.shape[1]): + f.write(" %e %e %e\n" % (matrix[i,j, 0], matrix[i,j, 1], matrix[i,j, 2])) + + def runMinimizationStep(self): + + # INP file name + inp_file = "%s/INP_min"%self.getGenFiles() + + # copy inputs + pcapref = self.getPCAPrefix() + tmppref = self._getExtraPath("tmp") + runCommand("cp %s.pdb %s.pdb"%(pcapref, tmppref)) + runCommand("cp %s.nma %s.nma"%(pcapref, tmppref)) + if self.getForceField() == FORCEFIELD_CHARMM: + runCommand("cp %s.psf %s.psf"%(self.getInputPDBprefix(), tmppref)) + else: + runCommand("cp %s.top %s.top"%(self.getInputPDBprefix(), tmppref)) + + # Set Inputs files + args = self.getDefaultArgs() + args["inputPDBprefix"] = tmppref + args["outputPrefix"] = self.getInputPDBprefix()+"_min" + args["simulationType"] = SIMULATION_MIN + args["inputType"] = INPUT_NEW_SIM + args["n_steps"] = 10000 + args["EMfitChoice"] = EMFIT_NONE + + # Create input genesis file + createGenesisInput(inp_file, **args) + + # Run minimization + self.runSimulation(inp_file, self.getInputPDBprefix()+"_min") + + def newIterationStep(self): + for i in range(self.getNumberOfSimulation()): + outpref = self._getExtraPath("output_%s" % str(i + 1).zfill(6)) + outpref_itr =self.getOutputPrefix(i) + runCommand("cat %s.log >> %s.log" % (outpref_itr,outpref)) + + dcdfile_itr = outpref_itr+ ".dcd" + if os.path.isfile(dcdfile_itr): + dcdfile = outpref+".dcd" + if os.path.isfile(dcdfile): + try: + dcdarr = np.concatenate((dcd2numpyArr(dcdfile),dcd2numpyArr(dcdfile_itr)), axis=0) + numpyArr2dcd(dcdarr, dcdfile) + except ValueError: + print("Incomplete DCD file") + else: + runCommand("cp %s %s"%(dcdfile_itr, dcdfile)) + + pdbfile = outpref_itr+".pdb" + if os.path.isfile(pdbfile): + runCommand("cp %s %s.pdb" % (pdbfile, outpref)) + + inputPref = self.getInputPDBprefix() + pcaPref = self.getPCAPrefix() + + ############# INCREMENT ITERATION ################### + if self._iter < self.numberOfIter.get()-1: + self._iter += 1 + print("New Iteration %i"%self._iter) + ################################################### + + inputPref_incr = self.getInputPDBprefix() + + runCommand("cp %s_min.pdb %s.pdb"%(inputPref, inputPref_incr)) + runCommand("cp %s_min.rst %s.rst"%(inputPref, inputPref_incr)) + runCommand("cp %s.nma %s.nma"%(pcaPref, inputPref_incr)) + if self.getForceField() == FORCEFIELD_CHARMM: + runCommand("cp %s.psf %s.psf" % (inputPref, inputPref_incr)) + elif self.getForceField() == FORCEFIELD_CAGO or self.getForceField() == FORCEFIELD_AAGO : + runCommand("cp %s.top %s.top" % (inputPref, inputPref_incr)) + + def createGenesisInputStep(self): + """ + Create GENESIS input files + :return None: + """ + for indexFit in range(self.getNumberOfSimulation()): + inp_file = self.getGenesisInputFile(indexFit) + args = self.getDefaultArgs(indexFit) + if self._iter != 0 : + args["inputType"] = INPUT_NEW_SIM + args["simulationType"] = SIMULATION_NMMD + args["nm_number"] = self.numberOfPCA.get() + args["nm_dt"] = 0.002 + args["nm_mass"] = 5.0 + createGenesisInput(inp_file, **args) + + def createOutputStep(self): + FlexProtGenesis.createOutputStep(self) + + runCommand("cp %s.pdb %s"%(self.getPCAPrefix(), self.getPath("atoms.pdb"))) + pdb = AtomStruct(self._getPath("atoms.pdb")) + natoms = ContinuousFlexPDBHandler(self._getPath("atoms.pdb")).n_atoms + self._defineOutputs(outputMean=pdb) + + makePath(self._getPath("modes")) + pc_file = self.getPCAPrefix()+".nma" + with open(pc_file, "r") as f: + for i in range(self.numberOfPCA.get()): + f.readline() + f.readline() + modefile = self._getPath("modes", "vec.%d" % (i + 1)) + with open(modefile, "w") as fout: + for j in range(natoms): + fout.write(f.readline()) + mdOut = MetaData() + for i in range(self.numberOfPCA.get()): + objId = mdOut.addObject() + modefile = self._getPath("modes", "vec.%d" % (i + 1)) + mdOut.setValue(MDL_NMA_MODEFILE, modefile, objId) + mdOut.setValue(MDL_ORDER, i + 1, objId) + mdOut.setValue(MDL_ENABLED, 1, objId) + mdOut.write(self._getPath("modes.xmd")) + pcSet = SetOfNormalModes(filename=self._getPath("modes.sqlite")) + row = XmippMdRow() + for objId in mdOut: + row.readFromMd(mdOut, objId) + pcSet.append(rowToMode(row)) + pcSet.setPdb(pdb) + self._defineOutputs(outputPCA=pcSet) + + def getOutputPrefix(self, index=0): + return self._getExtraPath("output_%s_iter_%s" % (str(index + 1).zfill(6),str(self._iter+1).zfill(3))) + + def getInputPDBprefix(self, index=0): + """ + Get the input PDB prefix of the specified index + :param int index: index of input PDB + :return str: Input PDB prefix + """ + prefix = self._getExtraPath("inputPDB_%s_iter_%s") + if self.getNumberOfInputPDB() == 1: + return prefix % (str(1).zfill(6),str(self._iter+1).zfill(3)) + else: + return prefix % (str(index + 1).zfill(6),str(self._iter+1).zfill(3)) + def getPCAPrefix(self): + return self._getExtraPath("pca_iter_%s" % (str(self._iter+1).zfill(3))) + + def getAlignmentPrefix(self, itr=None): + if itr is None : itr = self._iter + return "%s/alignment_iter_%s.xmd"%(self.getEmdFiles(),str(itr+1).zfill(3)) + def getTransformation(self, itr=None): + if itr is None : itr = self._iter + return "%s/transformation_iter_%s.xmd"%(self.getEmdFiles(),str(itr+1).zfill(3)) + + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['vuillemot2023mdspace','vuillemot2022NMMD','harastani2022continuousflex'] + + def _methods(self): + return [] \ No newline at end of file diff --git a/continuousflex/protocols/protocol_mdtomo.py b/continuousflex/protocols/protocol_mdtomo.py new file mode 100644 index 0000000..626cec3 --- /dev/null +++ b/continuousflex/protocols/protocol_mdtomo.py @@ -0,0 +1,141 @@ +# ************************************************************************** +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +from continuousflex.protocols.protocol_genesis import FlexProtGenesis, EMFIT_VOLUMES, SIMULATION_NMMD + +class FlexProtMDTOMO(FlexProtGenesis): + """ + Performs molecular dynamics flexible fitting of structural models into + electron microscopy volumes using the GENESIS simulation framework. The + protocol is intended to explore conformational variability and structural + transitions while maintaining physically realistic molecular behavior, + allowing experimental density information to guide the simulation toward + biologically meaningful conformations. + + AI Generated: + + MDTOMO (FlexProtMDTOMO) - User Manual + Overview + + MDTOMO is a molecular dynamics tomography protocol designed to combine + structural modeling with electron microscopy information in a unified + simulation environment. Its main objective is to refine and explore + conformational states of macromolecules by integrating molecular + dynamics simulations with volumetric experimental data. This approach + helps bridge the gap between static structural models and the dynamic + behavior that biological systems often exhibit in solution. + + In structural biology, many macromolecular assemblies undergo motions + that are essential for their function. Experimental density maps may + capture one or more of these states but often do not directly describe + the pathways connecting them. MDTOMO provides a framework for studying + these motions while preserving physically plausible molecular + interactions throughout the simulation. + + Inputs and General Workflow + + The protocol typically starts from an existing structural model and + combines it with electron microscopy volume information. The structural + model serves as the initial representation of the system, while the + volumetric data provide experimental guidance that influences the + conformational evolution during the simulation. + + The workflow is particularly useful when the available structural model + does not perfectly match the observed density or when the objective is + to investigate structural heterogeneity. By allowing the structure to + adapt under both physical and experimental constraints, the protocol + can reveal conformations that better explain the observed data. + + Molecular Dynamics and Flexible Fitting + + Unlike rigid fitting approaches, MDTOMO allows continuous structural + deformation throughout the simulation. This capability is important for + systems that experience domain movements, hinge motions, subunit + rearrangements, or other large-scale conformational transitions. + + The molecular dynamics engine provides a physically motivated framework + in which atomic interactions, structural restraints, and experimental + information are balanced. As a result, the generated conformations are + generally more realistic than those obtained through purely geometric + fitting procedures. + + Use in Cryo-EM and Tomography + + MDTOMO is particularly valuable for cryo-EM and cryo-electron + tomography studies where structural flexibility plays a significant + role. Experimental maps often contain regions of varying resolution or + represent ensembles of related conformations. Flexible fitting can help + interpret these data by identifying structural arrangements that are + consistent with the observed densities. + + For large molecular assemblies, membrane proteins, and dynamic + complexes, the protocol can provide insight into motions that may be + difficult to infer from static reconstructions alone. + + Outputs and Their Interpretation + + The primary outputs consist of molecular conformations generated during + the simulation and refined against the experimental information. + Depending on the biological system, these results may represent + improved structural fits, alternative conformational states, or + trajectories describing transitions between states. + + Interpretation should focus on biologically meaningful motions and on + consistency with available experimental evidence. Structural changes + that repeatedly appear during the simulation may indicate functionally + relevant flexibility, although independent validation is always + recommended. + + Practical Recommendations + + MDTOMO is most effective when the initial structural model already + captures the overall architecture of the biological assembly. Large + discrepancies between the starting model and the experimental density + may require additional preprocessing or intermediate refinement steps. + + Users should evaluate simulation results together with biochemical, + structural, and functional knowledge of the system. Flexible fitting + can reveal plausible motions, but the biological significance of those + motions should be assessed within the broader experimental context. + + Final Perspective + + MDTOMO provides a powerful strategy for integrating molecular dynamics + simulations with electron microscopy volume data. By combining physical + realism with experimental guidance, it enables the investigation of + structural flexibility, conformational variability, and dynamic + biological processes that are often inaccessible through static + structural analysis alone. + """ + _label = 'MDTOMO' + + # --------------------------- DEFINE param functions -------------------------------------------- + def _defineParams(self, form): + FlexProtGenesis._defineParams(self, form) + param = form.getParam("simulationType") + param.setDefault(SIMULATION_NMMD) + param = form.getParam("n_steps") + param.setDefault(50000) + param = form.getParam("EMfitChoice") + param.setDefault(EMFIT_VOLUMES) diff --git a/continuousflex/protocols/protocol_missing_wedge_filling.py b/continuousflex/protocols/protocol_mw_restoration.py similarity index 51% rename from continuousflex/protocols/protocol_missing_wedge_filling.py rename to continuousflex/protocols/protocol_mw_restoration.py index 66f8d36..d24244e 100644 --- a/continuousflex/protocols/protocol_missing_wedge_filling.py +++ b/continuousflex/protocols/protocol_mw_restoration.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -25,21 +25,150 @@ import xmipp3.convert import pwem.emlib.metadata as md import pyworkflow.protocol.params as params -from pyworkflow.utils.path import makePath, copyFile +from pyworkflow.utils.path import makePath from os.path import basename, isfile -from sh_alignment.tompy.transform import fft, ifft, fftshift, ifftshift -from .utilities.spider_files3 import save_volume, open_volume +from .utilities.spider_files3 import save_volume from pyworkflow.utils import replaceBaseExt import numpy as np from continuousflex.protocols.utilities.mwr_wrapper import mwr -from continuousflex.protocols.protocol_subtomogrmas_synthesize import FlexProtSynthesizeSubtomo +from continuousflex.protocols.protocol_subtomograms_synthesize import FlexProtSynthesizeSubtomo from pwem.utils import runProgram METHOD_MCSFILL = 0 class FlexProtMissingWedgeRestoration(ProtAnalysis3D): - """ Protocol for subtomogram missingwedge restoration. """ + """ + Restores missing information in subtomogram volumes affected by the missing wedge artifact + generated during electron tomography data acquisition. The protocol aims to reduce anisotropic + distortions and recover a more complete representation of the underlying structure, improving + the interpretability of tomographic reconstructions. + + AI Generated: + + Missing Wedge Restoration (FlexProtMissingWedgeRestoration) - User Manual + Overview + + The Missing Wedge Restoration protocol is designed to compensate for one of the most common + limitations in electron tomography: the incomplete angular sampling that occurs during tilt + series acquisition. Because physical and experimental constraints prevent collecting images + over the full angular range, reconstructed tomograms contain a region of missing information + in Fourier space commonly referred to as the missing wedge. + + This missing information introduces directional artifacts, anisotropic resolution, elongation + effects, and distortions that can complicate structural interpretation. The purpose of this + protocol is to reduce the impact of these artifacts and generate volumes that more accurately + represent the biological structures present in the sample. + + Biological Motivation + + In cryo-electron tomography, macromolecular complexes are often studied directly within their + native cellular environment. Although this approach provides unique biological insight, the + limited tilt range leads to incomplete sampling of structural information. + + The resulting missing wedge can affect particle classification, structural averaging, conformational + analysis, and visualization. Features oriented along poorly sampled directions may appear blurred, + elongated, or partially absent. Restoration methods seek to alleviate these limitations and + provide a more balanced representation of structural details. + + For biological users, missing wedge correction can improve the reliability of downstream analyses, + particularly when comparing conformational states, identifying structural features, or studying + heterogeneous populations of macromolecular assemblies. + + Inputs and Experimental Parameters + + The protocol accepts one or multiple reconstructed volumes as input. These volumes are assumed + to originate from electron tomography experiments where the angular acquisition range is known. + + The user must specify the lower and upper tilt angles used during data collection. These values + define the region of Fourier space that was experimentally sampled and therefore determine the + shape and extent of the missing wedge artifact affecting the reconstruction. + + Accurate tilt limits are important because they directly influence the restoration process. + Whenever possible, users should provide values that match the actual acquisition conditions + rather than idealized microscope settings. + + Monte Carlo Based Restoration + + The protocol employs a Monte Carlo based restoration strategy specifically designed to estimate + plausible structural information within the missing wedge region. Rather than simply filtering + the reconstruction, the method attempts to infer missing content while maintaining consistency + with the experimentally observed data. + + This probabilistic approach is particularly attractive for tomographic datasets because it can + model uncertainty within unsampled regions while preserving the information already supported + by the measurements. The result is typically a more isotropic reconstruction with reduced + directional artifacts. + + Since the missing information is fundamentally unknown, restored regions should be interpreted + as statistically plausible estimates rather than direct experimental observations. Biological + conclusions should therefore rely on features that remain consistent across the dataset and + are supported by additional evidence whenever possible. + + Noise Modeling and Regularization + + The restoration process incorporates a noise parameter that controls the balance between + preserving detail and enforcing smoothness. Larger values generally produce smoother volumes + and stronger regularization, whereas smaller values preserve finer structural features. + + From a biological perspective, selecting an appropriate value depends on the quality of the + tomographic reconstruction. Noisy datasets may benefit from stronger regularization, while + high-quality reconstructions often allow more conservative settings that preserve subtle + structural details. + + As with many restoration methods, excessive smoothing can suppress meaningful biological + features, whereas insufficient regularization may leave residual artifacts. Testing multiple + values and visually comparing the results is often beneficial. + + Iterative Sampling Parameters + + The protocol provides control over the number of restoration iterations and the length of the + burn-in phase used during the sampling procedure. Increasing the number of iterations generally + improves convergence and stability of the estimated solution but also increases computational + cost. + + The burn-in phase represents an initial period during which intermediate estimates are discarded. + This allows the restoration process to move away from its starting conditions before generating + the final solution. For most datasets, the default values provide a reasonable compromise between + computational efficiency and restoration quality. + + Advanced users may adjust these parameters when working with particularly noisy datasets or when + pursuing highly quantitative analyses. + + Outputs and Their Interpretation + + The protocol generates a restored set of volumes in which the effects of the missing wedge have + been reduced. These restored volumes can be used in subsequent stages of analysis, including + classification, averaging, flexibility studies, dimensionality reduction, and structural + interpretation. + + Restoration often improves visual continuity and isotropy within the reconstructed structures. + Features that were previously obscured by directional artifacts may become easier to identify + and analyze. Nevertheless, users should remember that restoration cannot recreate the exact + missing experimental information and therefore does not replace careful biological validation. + + Practical Recommendations + + Before applying restoration, it is advisable to verify that the tilt limits accurately reflect + the acquisition geometry. Incorrect angular ranges may lead to suboptimal correction and could + introduce additional artifacts. + + Visual comparison between original and restored volumes is strongly recommended. Improvements + should be assessed not only by appearance but also by consistency with known biological features + and independent experimental evidence. + + When restored volumes are intended for downstream quantitative analyses, users should evaluate + whether the restoration procedure alters measurements relevant to their specific biological + questions. + + Final Perspective + + Missing wedge artifacts remain one of the major limitations of electron tomography. This protocol + provides a dedicated framework for mitigating their impact through probabilistic restoration, + helping researchers obtain more isotropic and biologically interpretable reconstructions. When + applied carefully and interpreted appropriately, missing wedge restoration can substantially + improve the quality and usefulness of tomographic datasets. + """ _label = 'missing wedge restoration' # --------------------------- DEFINE param functions -------------------------------------------- @@ -177,7 +306,7 @@ def _summary(self): return summary def _citations(self): - return ['moebel2020monte'] + return ['harastani2022continuousflex','moebel2020monte'] def _methods(self): pass diff --git a/continuousflex/protocols/protocol_nma.py b/continuousflex/protocols/protocol_nma.py index 2c85666..d5d7244 100644 --- a/continuousflex/protocols/protocol_nma.py +++ b/continuousflex/protocols/protocol_nma.py @@ -35,19 +35,178 @@ from pwem.emlib import MetaData, MDL_NMA_ATOMSHIFT, MDL_NMA_MODEFILE from pyworkflow.utils import redStr, replaceBaseExt from pyworkflow.utils.path import copyFile, createLink, makePath, cleanPath, moveFile -from pyworkflow.protocol.params import (PointerParam, IntParam, FloatParam, +from pyworkflow.protocol.params import (PointerParam, IntParam, FloatParam, LEVEL_ADVANCED) from pwem.objects import SetOfNormalModes - from xmipp3.base import XmippMdRow from .protocol_nma_base import FlexProtNMABase, NMA_CUTOFF_REL from .convert import rowToMode, getNMAEnviron +from pwem import Domain class FlexProtNMA(FlexProtNMABase): - """ Flexible angular alignment using normal modes """ + """ + Performs Normal Mode Analysis (NMA) on atomic or pseudoatomic + structural models in order to characterize the intrinsic collective + motions of biological macromolecules. The protocol generates a set of + normal modes that can be used for flexibility analysis, conformational + exploration, structural interpretation, and subsequent image or volume + analysis workflows. + + AI Generated: + + Normal Mode Analysis (FlexProtNMA) - User Manual + Overview + + The Normal Mode Analysis protocol is designed to identify and + characterize the intrinsic motions available to a macromolecular + structure. Rather than treating a biological assembly as a static + object, the protocol models its potential collective movements and + provides a compact description of the directions along which the + structure can naturally deform. + + In cryo-EM and structural biology studies, many biologically + important processes involve continuous conformational changes rather + than discrete structural states. Normal modes offer an efficient way + to describe these transitions and frequently capture large-scale + domain rearrangements, hinge motions, and cooperative movements that + are directly related to molecular function. + + Inputs and Biological Context + + The protocol accepts either an atomic structure or a pseudoatomic + representation derived from an electron microscopy density map. + Atomic structures are appropriate when an experimentally determined + model is available, whereas pseudoatomic models provide a practical + alternative when only volumetric information exists. + + From a biological perspective, the quality and completeness of the + input structure strongly influence the relevance of the resulting + motions. Structures representing functional states, biologically + meaningful assemblies, or well-resolved density interpretations are + generally the most suitable starting points for analysis. + + Elastic Network Representation + + The protocol models the structure as an interconnected system whose + collective movements can be approximated through normal mode theory. + Interactions are defined according to a selected distance criterion, + allowing the construction of an elastic representation of the + molecule. + + Two approaches are available for defining structural connectivity. + Absolute distance thresholds use a fixed interaction distance, + whereas relative thresholds determine connectivity from the overall + distribution of neighboring distances. Relative thresholds are often + preferred for pseudoatomic models because they adapt more naturally + to variations in particle density and sampling. + + Choice of Number of Modes + + The protocol computes a user-defined number of normal modes. In most + biological applications, only a subset of the lowest-frequency + non-trivial modes is required because these typically correspond to + the largest and most functionally relevant collective motions. + + Increasing the number of modes may provide a more complete + description of flexibility, but it also introduces motions that are + progressively more localized and potentially less biologically + informative. For many systems, a moderate number of modes is + sufficient to capture the dominant conformational variability. + + Atomic Structures and RTB Approximation + + When working with atomic models, the protocol uses a coarse-grained + representation that groups neighboring residues into blocks. This + strategy enables efficient analysis of large biological assemblies + while preserving the essential characteristics of collective + molecular motion. + + The block size influences the balance between computational + efficiency and structural detail. Larger blocks generally accelerate + calculations, whereas smaller blocks may provide a more detailed + description of local flexibility. In most practical situations, the + default settings offer a suitable compromise. + + Evaluation of Mode Collectivity + + Not all normal modes contribute equally to biologically meaningful + motions. The protocol evaluates the collectivity of each mode, which + reflects how broadly a deformation is distributed throughout the + structure. + + Highly collective modes involve coordinated movement across large + portions of the molecule and are often associated with functional + transitions. Less collective modes tend to describe localized + fluctuations that may be less relevant for global conformational + analysis. Users can therefore focus subsequent studies on the most + collective motions. + + Visualization and Animation + + One of the most valuable aspects of normal mode analysis is the + ability to visualize predicted motions. The protocol generates + animations that illustrate how the structure deforms along each + selected mode, helping users interpret the physical meaning of the + computed motions. + + These animations are intended as qualitative visualizations rather + than direct representations of experimentally observed amplitudes. + They provide an intuitive way to identify flexible domains, hinge + regions, coordinated movements, and potential functional pathways. + + Interpretation of Atomic Displacements + + The protocol also evaluates displacement profiles that indicate how + strongly different regions of the structure move within each mode. + These profiles can reveal flexible loops, mobile domains, or regions + that participate in large conformational transitions. + + From a biological standpoint, regions exhibiting substantial motion + may correspond to functional interfaces, regulatory elements, + ligand-binding regions, or structural components involved in + allosteric communication. + + Outputs and Downstream Applications + + The main output is a set of normal modes associated with the input + structure. These modes can be used directly for visualization, + flexibility characterization, conformational interpretation, and + integration with additional cryo-EM analysis workflows. + + The generated modes frequently serve as the foundation for flexible + fitting, particle analysis, volume analysis, dimensionality + reduction, and conformational landscape reconstruction. Because the + modes provide a compact representation of structural variability, + they enable efficient exploration of continuous molecular motions. + + Practical Recommendations + + For most biological systems, it is advisable to focus on the + lowest-frequency collective modes, as these are often the most + informative and easiest to interpret. Users should visually inspect + animations and displacement profiles to verify that the predicted + motions are consistent with known structural and functional + properties of the molecule. + + When analyzing pseudoatomic models, relative connectivity criteria + generally provide robust results. For atomic structures, appropriate + block sizes and realistic interaction parameters help ensure stable + and biologically meaningful motion predictions. + + Final Perspective + + Normal Mode Analysis provides a powerful bridge between static + structural models and dynamic biological behavior. By identifying + the collective motions that a molecule can naturally undergo, the + protocol offers valuable insight into conformational variability, + molecular function, and the mechanisms underlying biological + activity. These modes often form the basis for advanced studies of + flexibility and continuous heterogeneity in cryo-EM and structural + biology. + """ _label = 'nma analysis' - + def _defineParams(self, form): form.addSection(label='Normal Mode Analysis') form.addParam('inputStructure', PointerParam, label="Input structure", @@ -56,61 +215,62 @@ def _defineParams(self, form): help='The input structure can be an atomic model ' '(true PDB) or a pseudoatomic model\n' '(an EM volume converted into pseudoatoms)') - FlexProtNMABase._defineParamsCommon(self,form) + FlexProtNMABase._defineParamsCommon(self, form) form.addParam('rtbBlockSize', IntParam, default=10, expertLevel=LEVEL_ADVANCED, label='Number of residues per RTB block (for atomic structures)', - help='Used only with atoms. Normal modes of atomic structures are computed with the RTB method. \n' - 'This is the RTB block size. In the RTB method, aminoacids are grouped into blocks of this size ' - 'that are moved translationally and rotationally together.') - - form.addSection(label='Animation') + help='Used only with atoms. Normal modes of atomic structures are computed with the RTB method. ' + '\n ' + 'This is the RTB block size. In the RTB method, aminoacids are grouped into blocks of this ' + 'size ' + 'that are moved translationally and rotationally together.') + + form.addSection(label='Animation') form.addParam('amplitude', FloatParam, default=50, label='Amplitude', - help='Used only for animations of computed normal modes. ' - 'This is the amplitude with which atoms or pseudoatoms are moved ' - 'along normal modes in the animations. \n' - 'Normal-mode amplitudes corresponding to given images are computed by image analysis.') + help='Used only for animations of computed normal modes. ' + 'This is the amplitude with which atoms or pseudoatoms are moved ' + 'along normal modes in the animations. \n' + 'Normal-mode amplitudes corresponding to given images are computed by image analysis.') form.addParam('nframes', IntParam, default=10, expertLevel=LEVEL_ADVANCED, label='Number of frames', - help='Number of frames used in animations.') + help='Number of frames used in animations.') form.addParam('downsample', FloatParam, default=1, expertLevel=LEVEL_ADVANCED, # condition=isEm label='Downsample pseudoatoms (for visualization)', help='Used only with pseudoatoms and only for visualization purposes. \n' - 'A downsample factor of 2 means removing one half of the pseudoatoms.') + 'A downsample factor of 2 means removing one half of the pseudoatoms.') form.addParam('pseudoAtomThreshold', FloatParam, default=0, expertLevel=LEVEL_ADVANCED, # condition=isEm label='Pseudoatom mass threshold (for visualization)', help='Used only with pseudoatoms and only for visualization purposes. \n ' - 'Pseudoatoms whose mass is below this threshold are removed. \n' + 'Pseudoatoms whose mass is below this threshold are removed. \n' 'The threshold value should be between 0 and 1. ' 'A threshold of 0 implies no pseudoatom removal.') - def _insertAllSteps(self): # Some steps will differ if the input is a volume or a pdb file self.structureEM = self.inputStructure.get().getPseudoAtoms() n = self.numberOfModes.get() # Link the input inputFn = self.inputStructure.get().getFileName() - localFn = self._getPath(replaceBaseExt(basename(inputFn),'pdb')) + localFn = self._getPath(replaceBaseExt(basename(inputFn), 'pdb')) self._insertFunctionStep('copyPdbStep', inputFn, localFn, self.structureEM) - + # Construct string for relative-absolute cutoff # This is used to detect when to reexecute a step or not - cutoffStr='' + cutoffStr = '' if self.cutoffMode == NMA_CUTOFF_REL: - cutoffStr = 'Relative %f'%self.rcPercentage.get() + cutoffStr = 'Relative %f' % self.rcPercentage.get() else: - cutoffStr = 'Absolute %f'%self.rc.get() + cutoffStr = 'Absolute %f' % self.rc.get() # Compute modes - self.pseudoAtomRadius=1 + self.pseudoAtomRadius = 1 if self.structureEM: with open(inputFn, 'r') as fh: first_line = fh.readline() @@ -118,19 +278,22 @@ def _insertAllSteps(self): self.pseudoAtomRadius = float(second_line.split()[2]) if self.cutoffMode == NMA_CUTOFF_REL: params = '-i %s --operation distance_histogram %s' \ - % (localFn, self._getExtraPath('pseudoatoms_distance.hist')) - self._insertRunJobStep("xmipp_pdb_analysis", params) + % (localFn, self._getExtraPath('pseudoatoms_distance.hist')) + self._insertFunctionStep('analyzePdbStep', params) + self._insertFunctionStep('computeModesStep', localFn, n, cutoffStr) - self._insertFunctionStep('reformatOutputStep',"pseudoatoms.pdb") + self._insertFunctionStep('reformatOutputStep', "pseudoatoms.pdb") else: if self.cutoffMode == NMA_CUTOFF_REL: - params = '-i %s --operation distance_histogram %s' % (localFn, self._getExtraPath('atoms_distance.hist')) - self._insertRunJobStep("xmipp_pdb_analysis", params) + params = '-i %s --operation distance_histogram %s' % ( + localFn, self._getExtraPath('atoms_distance.hist')) + self._insertFunctionStep('analyzePdbStep', params) + self._insertFunctionStep('computePdbModesStep', n, self.rtbBlockSize.get(), cutoffStr) self._insertFunctionStep('reformatPdbOutputStep', n) - + self._insertFunctionStep('qualifyModesStep', n, self.collectivityThreshold.get(), self.structureEM) @@ -141,7 +304,7 @@ def _insertAllSteps(self): self.pseudoAtomRadius) self._insertFunctionStep('computeAtomShiftsStep', n) self._insertFunctionStep('createOutputStep') - + def copyPdbStep(self, inputFn, localFn, isEM): """ Copy the input pdb file and also create a link 'atoms.pdb' """ @@ -175,7 +338,7 @@ def copyPdbStep(self, inputFn, localFn, isEM): for line in lines: if line.startswith("ATOM ") or line.startswith("TER "): # print(int(line.split()[1])) - if int(line.split()[1])>99999: + if int(line.split()[1]) > 99999: if line.startswith("ATOM "): newline = line.replace("ATOM 1", "ATOM 1") else: @@ -185,18 +348,22 @@ def copyPdbStep(self, inputFn, localFn, isEM): newlines.append(line) with open(localFn, mode='w') as f: f.writelines(newlines) - + + def analyzePdbStep(self, params): + self.runJob("xmipp_pdb_analysis", params, env=Domain.importFromPlugin('xmipp3').Plugin.getEnviron()) + + def computePdbModesStep(self, numberOfModes, RTBblockSize, cutoffStr): rc = self._getRc(self._getExtraPath('atoms_distance.hist')) - + self._enterWorkingDir() # For atoms, the interaction force constant was set to 10 as ElNemo RTB code may ask for its value \ - # (the RTBForceConstant entry was removed from gui as the value does not change the ENM computed normal modes). + # (the RTBForceConstant entry was removed from gui as the value does not change the ENM computed normal modes). self.runJob('nma_record_info_PDB.py', "%d %d atoms.pdb %f %f" % (numberOfModes, RTBblockSize, rc, 10.0), env=getNMAEnviron()) - self.runJob("nma_elnemo_pdbmat","",env=getNMAEnviron()) - self.runJob("nma_diagrtb","",env=getNMAEnviron()) + self.runJob("nma_elnemo_pdbmat", "", env=getNMAEnviron()) + self.runJob("nma_diagrtb", "", env=getNMAEnviron()) if not exists("diagrtb.eigenfacs"): msg = "Modes cannot be computed. Check the number of modes you " \ @@ -210,87 +377,91 @@ def computePdbModesStep(self, numberOfModes, RTBblockSize, cutoffStr): msg += "between 200 and 6 times the number of RTB blocks, consider " \ "increasing cut-off distance." self._printWarnings(redStr(msg) + '\n') - self.runJob("rm","-f *.dat_run diagrtb.dat pdbmat.xyzm pdbmat.sdijf " - "pdbmat.dat") - + self.runJob("rm", "-f *.dat_run diagrtb.dat pdbmat.xyzm pdbmat.sdijf " + "pdbmat.dat") + self._leaveWorkingDir() - + def reformatPdbOutputStep(self, numberOfModes): self._enterWorkingDir() - + makePath('modes') Natoms = self._countAtoms("atoms.pdb") fhIn = open('diagrtb.eigenfacs') - fhAni = open('vec_ani.txt','w') - + fhAni = open('vec_ani.txt', 'w') + for n in range(numberOfModes): # Skip two lines fhIn.readline() fhIn.readline() - fhOut=open('modes/vec.%d'%(n+1),'w') + fhOut = open('modes/vec.%d' % (n + 1), 'w') for i in range(Natoms): - line=fhIn.readline() + line = fhIn.readline() fhOut.write(line) - fhAni.write(line.rstrip().lstrip()+" ") + fhAni.write(line.rstrip().lstrip() + " ") fhOut.close() - if n!=(numberOfModes-1): + if n != (numberOfModes - 1): fhAni.write("\n") fhIn.close() fhAni.close() - self.runJob("nma_prepare_for_animate.py","",env=getNMAEnviron()) + self.runJob("nma_prepare_for_animate.py", "", env=getNMAEnviron()) cleanPath("vec_ani.txt") moveFile('vec_ani.pkl', 'extra/vec_ani.pkl') self._leaveWorkingDir() - - def animateModesStep(self, numberOfModes,amplitude,nFrames,downsample, - pseudoAtomThreshold,pseudoAtomRadius): + + def animateModesStep(self, numberOfModes, amplitude, nFrames, downsample, + pseudoAtomThreshold, pseudoAtomRadius): makePath(self._getExtraPath('animations')) self._enterWorkingDir() - + if self.structureEM: fn = "pseudoatoms.pdb" - self.runJob("nma_animate_pseudoatoms.py","%s extra/vec_ani.pkl 7 %d " - "%f extra/animations/" - "animated_mode %d %d %f"%\ - (fn,numberOfModes,amplitude,nFrames,downsample, - pseudoAtomThreshold),env=getNMAEnviron()) + self.runJob("nma_animate_pseudoatoms.py", "%s extra/vec_ani.pkl 7 %d " + "%f extra/animations/" + "animated_mode %d %d %f" % \ + (fn, numberOfModes, amplitude, nFrames, downsample, + pseudoAtomThreshold), env=getNMAEnviron()) else: - fn="atoms.pdb" - self.runJob("nma_animate_atoms.py","%s extra/vec_ani.pkl 7 %d %f " - "extra/animations/animated_mode " - "%d"%\ - (fn,numberOfModes,amplitude,nFrames),env=getNMAEnviron()) - - for mode in range(7,numberOfModes+1): + fn = "atoms.pdb" + self.runJob("nma_animate_atoms.py", "%s extra/vec_ani.pkl 7 %d %f " + "extra/animations/animated_mode " + "%d" % \ + (fn, numberOfModes, amplitude, nFrames), env=getNMAEnviron()) + + for mode in range(7, numberOfModes + 1): fnAnimation = join("extra", "animations", "animated_mode_%03d" % mode) - fhCmd=open(fnAnimation+".vmd",'w') + fhCmd = open(fnAnimation + ".vmd", 'w') fhCmd.write("mol new %s.pdb\n" % self._getPath(fnAnimation)) fhCmd.write("animate style Loop\n") fhCmd.write("display projection Orthographic\n") if self.structureEM: fhCmd.write("mol modcolor 0 0 Beta\n") fhCmd.write("mol modstyle 0 0 Beads %f 8.000000\n" - %(pseudoAtomRadius)) + % (pseudoAtomRadius)) else: fhCmd.write("mol modcolor 0 0 Index\n") - #fhCmd.write("mol modstyle 0 0 Beads 1.000000 8.000000\n") - fhCmd.write("mol modstyle 0 0 NewRibbons 1.800000 6.000000 " - "2.600000 0\n") + if self._checkPDB_CA(fn): + fhCmd.write("mol modstyle 0 0 Beads 1.000000 8.000000\n") + # fhCmd.write("mol modstyle 0 0 Beads 1.800000 6.000000 " + # "2.600000 0\n") + else: + fhCmd.write("mol modstyle 0 0 NewRibbons 1.800000 6.000000 " + "2.600000 0\n") fhCmd.write("animate speed 0.5\n") fhCmd.write("animate forward\n") fhCmd.close(); - + self._leaveWorkingDir() - + def computeAtomShiftsStep(self, numberOfModes): fnOutDir = self._getExtraPath("distanceProfiles") makePath(fnOutDir) - maxShift=[] - maxShiftMode=[] - - for n in range(7, numberOfModes+1): + maxShift = [] + maxShiftMode = [] + + for n in range(7, numberOfModes + 1): fnVec = self._getPath("modes", "vec.%d" % n) if exists(fnVec): fhIn = open(fnVec) @@ -298,34 +469,34 @@ def computeAtomShiftsStep(self, numberOfModes): atomCounter = 0 for line in fhIn: x, y, z = map(float, line.split()) - d = math.sqrt(x*x+y*y+z*z) - if n==7: + d = math.sqrt(x * x + y * y + z * z) + if n == 7: maxShift.append(d) maxShiftMode.append(7) else: - if d>maxShift[atomCounter]: - maxShift[atomCounter]=d - maxShiftMode[atomCounter]=n - atomCounter+=1 - md.setValue(MDL_NMA_ATOMSHIFT,d,md.addObject()) - md.write(join(fnOutDir,"vec%d.xmd" % n)) + if d > maxShift[atomCounter]: + maxShift[atomCounter] = d + maxShiftMode[atomCounter] = n + atomCounter += 1 + md.setValue(MDL_NMA_ATOMSHIFT, d, md.addObject()) + md.write(join(fnOutDir, "vec%d.xmd" % n)) fhIn.close() md = MetaData() for i, _ in enumerate(maxShift): - fnVec = self._getPath("modes", "vec.%d" % (maxShiftMode[i]+1)) + fnVec = self._getPath("modes", "vec.%d" % (maxShiftMode[i] + 1)) if exists(fnVec): objId = md.addObject() - md.setValue(MDL_NMA_ATOMSHIFT, maxShift[i],objId) + md.setValue(MDL_NMA_ATOMSHIFT, maxShift[i], objId) md.setValue(MDL_NMA_MODEFILE, fnVec, objId) md.write(self._getExtraPath('maxAtomShifts.xmd')) - + def createOutputStep(self): fnSqlite = self._getPath('modes.sqlite') nmSet = SetOfNormalModes(filename=fnSqlite) md = MetaData(self._getPath('modes.xmd')) row = XmippMdRow() - + for objId in md: row.readFromMd(md, objId) nmSet.append(rowToMode(row)) @@ -333,3 +504,24 @@ def createOutputStep(self): nmSet.setPdb(inputPdb) self._defineOutputs(outputModes=nmSet) self._defineSourceRelation(self.inputStructure, nmSet) + + def _checkPDB_CA(self, fnPDB): + # This function returns true if all the atoms are CA and P, otherwise false + from continuousflex.protocols.utilities.pdb_parser import m_inout_read_pdb + pdb_read = m_inout_read_pdb(fnPDB) + for atom in pdb_read: + if atom.type != " C" or atom.loc != "A ": + if atom.type != " P": + return False + return True + + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _citations(self): + return ['harastani2022continuousflex'] + + def _methods(self): + pass \ No newline at end of file diff --git a/continuousflex/protocols/protocol_nma_alignment.py b/continuousflex/protocols/protocol_nma_alignment.py index 422b98c..1201b47 100644 --- a/continuousflex/protocols/protocol_nma_alignment.py +++ b/continuousflex/protocols/protocol_nma_alignment.py @@ -28,35 +28,174 @@ # * # ************************************************************************** - from os.path import basename import os -from pwem.convert.atom_struct import cifToPdb -from pyworkflow.utils import replaceBaseExt - from pyworkflow.utils import isPower2, getListFromRangeString from pyworkflow.utils.path import copyFile, cleanPath import pyworkflow.protocol.params as params from pwem.protocols import ProtAnalysis3D - from pyworkflow.protocol.params import NumericRangeParam import pwem as em import pwem.emlib.metadata as md - from xmipp3.base import XmippMdRow from xmipp3.convert import (writeSetOfParticles, xmippToLocation, getImageLocation, createItemMatrix, setXmippAttributes) from .convert import modeToRow -from pwem.utils import runProgram from pwem import Domain +import multiprocessing NMA_ALIGNMENT_WAV = 0 NMA_ALIGNMENT_PROJ = 1 class FlexProtAlignmentNMA(ProtAnalysis3D): - """ Protocol for flexible angular alignment. """ + """ + Protocol for flexible angular alignment using Normal Mode Analysis (NMA). + It estimates both conformational variability and rigid-body orientation + parameters for particle images by fitting a structural model into each + experimental observation. + + AI Generated: + + Flexible Angular Alignment with NMA (FlexProtAlignmentNMA) - User Manual + Overview + + The Flexible Angular Alignment protocol performs simultaneous + conformational and rigid-body analysis of single-particle cryo-EM + images using Normal Mode Analysis (NMA). Its primary objective is to + determine how a macromolecular structure must deform and orient itself + in order to best explain each experimental particle image. This allows + the study of continuous structural variability while preserving the + relationship between molecular motions and particle orientations. + + Unlike conventional alignment procedures that assume a rigid particle, + this protocol incorporates predefined normal modes describing possible + collective motions of the structure. As a result, it becomes possible + to characterize flexibility directly during the alignment process and + obtain deformation parameters that can later be used for conformational + landscape analysis and dimensionality reduction. + + Inputs and Biological Context + + The protocol requires a structural model associated with a previously + computed set of normal modes, together with a set of experimental + particle images. The structural model may represent either an atomic + structure or a pseudoatomic approximation generated from an electron + microscopy map. + + The selected normal modes define the biologically plausible motions + that will be explored during alignment. In many applications, users + focus on the most collective and biologically meaningful modes rather + than including every available mode. Restricting the analysis to + relevant motions often improves interpretability and reduces the risk + of fitting noise or irrelevant variability. + + General Workflow + + During execution, each particle image is compared against structural + projections generated from different combinations of molecular + conformations and orientations. The protocol searches for the optimal + balance between elastic deformation and rigid-body alignment so that + the resulting model explains the observed image as accurately as + possible. + + This integrated strategy is particularly useful for flexible proteins, + molecular machines, and complexes that exhibit continuous transitions + between states. Rather than separating alignment and flexibility + analysis into independent stages, both aspects are estimated together, + providing a more realistic representation of structural heterogeneity. + + Selection of Normal Modes + + Users may choose to analyze all available normal modes or restrict the + calculation to a selected subset. Biologically, this decision should + be guided by prior knowledge about the system and by the quality of + the modes obtained during normal mode analysis. + + Lower-frequency collective modes often correspond to large-scale domain + movements and functionally relevant conformational transitions. These + motions are usually the most informative for studying flexibility. + Including excessive numbers of modes may increase computational cost + and introduce motions that are difficult to interpret biologically. + + Elastic and Rigid-Body Optimization + + The protocol combines deformation estimation with orientation + determination. Elastic optimization explores how strongly each mode + contributes to the observed conformation, while rigid-body alignment + determines the orientation and position of the particle relative to + the structural model. + + The optimization settings are designed to work well for most datasets. + Advanced users may adjust parameters controlling the exploration of + conformational space when larger structural changes are expected. + These options are primarily intended for challenging systems with + pronounced flexibility or highly heterogeneous populations. + + Choice of Alignment Strategy + + Two alignment approaches are available. The projection matching method + provides efficient orientation estimation and is generally suitable + for large datasets where computational throughput is important. The + wavelets and splines approach places greater emphasis on alignment + accuracy and may provide improved results for difficult datasets, + although at a higher computational cost. + + For routine analyses, projection matching often provides a practical + starting point. When the highest possible alignment precision is + required, particularly for structurally complex systems, the wavelets + and splines strategy may be preferable. + + Angular Sampling Considerations + + Angular sampling controls how finely the orientation space is explored. + Coarser sampling reduces execution time but may miss subtle orientation + differences. Finer sampling improves angular precision at the expense + of additional computational effort. + + In exploratory studies, moderate angular sampling values are often + sufficient. For high-resolution analyses or detailed investigations of + conformational variability, a finer sampling scheme may provide more + accurate orientation estimates. + + Outputs and Interpretation + + The protocol produces a new particle set containing the estimated + alignment parameters together with the deformation coordinates that + describe the contribution of the selected normal modes for each + particle. These parameters establish a direct connection between image + observations and underlying structural variability. + + The resulting deformation coordinates can be used in downstream + analyses to identify conformational continua, detect structural + clusters, visualize molecular motions, and construct low-dimensional + representations of the conformational landscape. + + Practical Recommendations + + Successful application of this protocol depends strongly on the + biological relevance of the selected normal modes and the quality of + the input particle dataset. It is generally advisable to begin with + the most collective modes and evaluate whether the recovered motions + correspond to meaningful structural changes. + + When studying large molecular assemblies or proteins known to undergo + domain rearrangements, the protocol can reveal continuous transitions + that are often difficult to capture using discrete classification + methods alone. Careful interpretation of the resulting deformation + coordinates is essential to distinguish genuine molecular motions from + alignment artifacts. + + Final Perspective + + Flexible angular alignment provides a powerful framework for linking + particle images with molecular dynamics. By simultaneously estimating + conformation and orientation, the protocol enables a biologically + meaningful characterization of structural heterogeneity and serves as + a foundation for advanced studies of continuous flexibility in cryo-EM + datasets. + """ _label = 'nma alignment' # --------------------------- DEFINE param functions -------------------------------------------- @@ -107,7 +246,7 @@ def _defineParams(self, form): 'is computed for rigid-body alignment in Projection Matching and Wavelets methods. \n' 'This alignment is refined with Splines method when Wavelets and Splines alignment is chosen.') - form.addParallelSection(threads=0, mpi=5) + form.addParallelSection(threads=0, mpi=multiprocessing.cpu_count()//2-1) # --------------------------- INSERT steps functions -------------------------------------------- @@ -273,7 +412,7 @@ def _validate(self): return errors def _citations(self): - return ['harastani2020hybrid','Jonic2005', 'Sorzano2004b', 'Jin2014'] + return ['harastani2022continuousflex','harastani2020hybrid','Jin2014'] def _methods(self): pass diff --git a/continuousflex/protocols/protocol_nma_alignment_vol.py b/continuousflex/protocols/protocol_nma_alignment_vol.py index ae8ff2d..b3942cc 100644 --- a/continuousflex/protocols/protocol_nma_alignment_vol.py +++ b/continuousflex/protocols/protocol_nma_alignment_vol.py @@ -1,6 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -28,26 +28,160 @@ from pyworkflow.utils import getListFromRangeString from pwem.protocols import ProtAnalysis3D from xmipp3.convert import (writeSetOfVolumes, xmippToLocation, createItemMatrix, - setXmippAttributes, setOfParticlesToMd, getImageLocation) - + setXmippAttributes, getImageLocation) import pwem as em import pwem.emlib.metadata as md from xmipp3 import XmippMdRow from pyworkflow.utils.path import copyFile, cleanPath import pyworkflow.protocol.params as params from pyworkflow.protocol.params import NumericRangeParam -from .convert import modeToRow -from pwem.convert.atom_struct import cifToPdb -from pyworkflow.utils import replaceBaseExt -from pwem.utils import runProgram +from .convert import modeToRow, eulerAngles2matrix, matrix2eulerAngles from pwem import Domain +import numpy as np +import multiprocessing WEDGE_MASK_NONE = 0 WEDGE_MASK_THRE = 1 class FlexProtAlignmentNMAVol(ProtAnalysis3D): - """ Protocol for flexible angular alignment. """ + """ + Protocol for rigid-body and elastic alignment for volumes using Normal Mode Analysis (NMA). It enables the study of structural flexibility by fitting an atomic or pseudoatomic reference model into a collection of three-dimensional volumes while simultaneously estimating conformational changes and spatial alignment parameters. The protocol is particularly suited for cryo-electron tomography subtomograms and cryo-EM maps where structural variability is expected and quantitative characterization of continuous motions is required. + + AI Generated: + + NMA Volume Alignment (FlexProtAlignmentNMAVol) - User Manual + Overview + + The NMA Volume Alignment protocol analyzes structural variability by combining elastic + deformation modeling with rigid-body alignment. Its purpose is to determine how a + reference structure must move and deform in order to best explain a collection of + experimental three-dimensional volumes. Rather than treating each volume as an + independent reconstruction, the protocol interprets them as different manifestations + of a potentially continuous conformational landscape. + + For biological users, this approach is especially valuable when studying molecular + machines, multi-domain proteins, membrane complexes, or other systems that exhibit + flexibility. By describing each volume through a combination of normal mode amplitudes + and spatial orientation parameters, the protocol provides a quantitative representation + of conformational heterogeneity suitable for downstream analysis and visualization. + + Inputs and General Workflow + + The protocol requires a previously computed set of normal modes associated with an + atomic or pseudoatomic structural model. These modes define the possible directions + of motion available to the structure and provide a physically meaningful framework + for describing conformational changes. + + In addition, the protocol requires one or more experimental volumes. Each volume is + analyzed independently against the same structural model. During processing, the + protocol searches simultaneously for the rigid-body transformation that places the + structure into the volume and for the elastic deformation amplitudes that best + reproduce the observed density. + + The resulting description captures both orientation and flexibility, allowing + structural variability to be represented in a compact and biologically interpretable + form. + + Selection of Normal Modes + + Biological interpretation depends strongly on the selected modes. Users may analyze + all available modes or restrict the analysis to a subset of motions considered + biologically relevant. + + In many applications, low-frequency collective modes provide the most meaningful + description of large-scale conformational transitions. These modes often correspond + to domain rearrangements, hinge motions, opening and closing events, or other + functionally important structural changes. + + Restricting the analysis to biologically plausible modes can improve robustness and + reduce the risk of fitting noise or reconstruction artefacts. Conversely, including + a larger number of modes may be beneficial when the conformational landscape is + expected to be complex. + + Missing-Wedge Compensation + + For subtomogram datasets, missing-wedge artefacts represent one of the most important + sources of distortion. These artefacts arise from incomplete angular sampling during + tomographic acquisition and can bias alignment and deformation estimates. + + The protocol provides an optional missing-wedge compensation strategy designed to + account for this limitation during fitting. When enabled, the analysis incorporates + information about the acquisition tilt range, improving the reliability of the + recovered conformational parameters. + + For cryo-EM density maps or subtomograms that have already undergone appropriate + missing-wedge correction, compensation may be unnecessary. Choosing the correct + setting depends on the origin and preprocessing history of the data. + + Combined Elastic and Rigid-Body Alignment + + One of the defining characteristics of this protocol is the simultaneous treatment + of structural deformation and spatial alignment. Traditional alignment approaches + assume a rigid object and attempt only to determine orientation and translation. + Such assumptions are often insufficient for flexible biological systems. + + Here, rigid-body positioning and conformational adaptation are optimized together. + This allows the protocol to distinguish between genuine structural variability and + simple differences in orientation. As a result, the recovered parameters provide a + more realistic representation of the underlying molecular motions. + + The optimization procedure can be adjusted through advanced parameters that control + the search behavior. For most biological applications, the default settings provide + an appropriate balance between robustness and computational efficiency. Expert users + studying highly flexible systems may choose to explore alternative settings when + larger conformational amplitudes are expected. + + Interpretation of the Results + + The principal output is a set of volumes enriched with deformation and alignment + information. Each analyzed volume receives a corresponding collection of rigid-body + parameters together with amplitudes describing motion along the selected normal modes. + + Biologically, these amplitudes represent coordinates within a conformational space. + Volumes with similar amplitudes correspond to related structural states, whereas + larger differences indicate more substantial conformational changes. The resulting + dataset can therefore be interpreted as a quantitative map of structural variability. + + Because the deformation parameters are expressed in terms of normal modes, the + results remain connected to physically meaningful motions rather than arbitrary + mathematical descriptors. + + Integration with Downstream Analysis + + The protocol is commonly used as a preparatory step for dimensionality reduction + and conformational landscape exploration. Once deformation parameters have been + estimated, they can be projected into lower-dimensional spaces where dominant + motions and structural transitions become easier to visualize. + + Such analyses can reveal continuous trajectories, clusters of related states, + transition pathways, and other features that help characterize the functional + dynamics of the biological system under study. + + Practical Recommendations + + Before running the protocol, users should verify that the selected normal modes + capture motions relevant to the biological question. Low-frequency collective modes + are generally the most informative starting point. + + When analyzing subtomograms, enabling missing-wedge compensation is usually advisable + unless a reliable correction procedure has already been applied. Accurate acquisition + tilt limits should be provided whenever possible. + + The quality of the reference structure also plays a critical role. A model that + adequately represents the overall architecture of the system will generally produce + more meaningful deformation estimates than an incomplete or poorly matched reference. + + Final Perspective + + For many cryo-EM and cryo-electron tomography studies, understanding structural + flexibility is as important as determining static structure. This protocol provides + a framework for describing conformational variability directly from experimental + volumes using physically interpretable normal modes. By combining elastic deformation + analysis with rigid-body alignment, it enables researchers to characterize molecular + motions, identify conformational states, and build quantitative models of structural + dynamics across heterogeneous datasets. + """ _label = 'nma alignment vol' # --------------------------- DEFINE param functions -------------------------------------------- @@ -71,7 +205,7 @@ def _defineParams(self, form): help='Select the set of volumes that will be analyzed using normal modes.') form.addParam('copyDeformations', params.PathParam, expertLevel=params.LEVEL_ADVANCED, - label='Precomputed results (for developmemt)', + label='Precomputed results (for development)', help='Enter a metadata file with precomputed elastic \n' 'and rigid-body alignment parameters to perform \n' 'remaining steps using this file.') @@ -85,12 +219,10 @@ def _defineParams(self, form): ' You can also choose not to compensate if your data is not subtomograms but EM-maps.' ' The missing wedge is assumed to be in the Y-axis direction.') form.addParam('tiltLow', params.IntParam, default=-60, - # expertLevel=params.LEVEL_ADVANCED, condition='WedgeMode==%d' % WEDGE_MASK_THRE, label='Lower tilt value', help='The lower tilt angle used in obtaining the tilt series') form.addParam('tiltHigh', params.IntParam, default=60, - # expertLevel=params.LEVEL_ADVANCED, condition='WedgeMode==%d' % WEDGE_MASK_THRE, label='Upper tilt value', help='The upper tilt angle used in obtaining the tilt series') @@ -105,34 +237,34 @@ def _defineParams(self, form): 'This value should not be changed except by expert users. ' 'Larger values (e.g., between 1 and 2) can be tried ' 'for larger expected amplitudes of conformational change.') - # form.addParam('rhoStartBase', params.FloatParam, default=250.0, - # expertLevel=params.LEVEL_ADVANCED, - # label='CONDOR optimiser parameter rhoStartBase', - # help='rhoStartBase > 0 : (rhoStart = rhoStartBase*trustRegionScale) the lower the better,' - # ' yet the slower') - # form.addParam('rhoEndBase', params.FloatParam, default=50.0, - # expertLevel=params.LEVEL_ADVANCED, - # label='CONDOR optimiser parameter rhoEndBase ', - # help='rhoEndBase > 250 : (rhoEnd = rhoEndBase*trustRegionScale) no specific rule, ' - # 'however it is better to keep it < 1000 if set very high we risk distortions') - # form.addParam('niter', params.IntParam, default=10000, - # expertLevel=params.LEVEL_ADVANCED, - # label='CONDOR optimiser parameter niter', - # help='niter should be big enough to guarantee that the search converges to the ' - # 'right set of nma deformation amplitudes') + form.addHidden('rhoStartBase', params.FloatParam, default=250.0, + expertLevel=params.LEVEL_ADVANCED, + label='CONDOR optimiser parameter rhoStartBase', + help='rhoStartBase > 0 : (rhoStart = rhoStartBase*trustRegionScale) the lower the better,' + ' yet the slower') + form.addHidden('rhoEndBase', params.FloatParam, default=50.0, + expertLevel=params.LEVEL_ADVANCED, + label='CONDOR optimiser parameter rhoEndBase ', + help='rhoEndBase > 250 : (rhoEnd = rhoEndBase*trustRegionScale) no specific rule, ' + 'however it is better to keep it < 1000 if set very high we risk distortions') + form.addHidden('niter', params.IntParam, default=10000, + expertLevel=params.LEVEL_ADVANCED, + label='CONDOR optimiser parameter niter', + help='niter should be big enough to guarantee that the search converges to the ' + 'right set of nma deformation amplitudes') form.addParam('frm_freq', params.FloatParam, default=0.25, expertLevel=params.LEVEL_ADVANCED, label='Maximum cross correlation frequency', - help='The normalized frequency should be between 0 and 0.5 ' - 'The more it is, the bigger the search frequency is, the more time it demands, ' - 'keeping it as default is recommended.') + help='The normalized frequency should be between 0 and 0.5 \n' + 'The larger it is, the bigger the search frequency is, the more time it demands. ' + 'Keeping it as default is recommended.') form.addParam('frm_maxshift', params.IntParam, default=10, expertlevel=params.LEVEL_ADVANCED, label='Maximum shift for rigid body alignment (in pixels)', help='The maximum shift is a number between 1 and half the size of your volume. ' - 'It represents the maximum distance searched in x,y and z directions. Keep as default' + 'It represents the maximum distance searched in x, y and z directions. Keep as default' ' if your target is near the center in your subtomograms') - form.addParallelSection(threads=0, mpi=5) + form.addParallelSection(threads=0, mpi=multiprocessing.cpu_count()//2-1) # --------------------------- INSERT steps functions -------------------------------------------- def getInputPdb(self): @@ -156,9 +288,9 @@ def _insertAllSteps(self): self._insertFunctionStep('convertInputStep', atomsFn) - if self.copyDeformations.empty(): # SERVES_FOR_DEBUGGING AND COMPUTING ON CLUSTERS + if self.copyDeformations.empty(): self._insertFunctionStep("performNmaStep", self.atomsFn, self.modesFn) - else: + else: # SERVES FOR DEBUGGING AND COMPUTING ON CLUSTERS self._insertFunctionStep('copyDeformationsStep', self.copyDeformations.get()) self._insertFunctionStep('createOutputStep') @@ -171,8 +303,6 @@ def convertInputStep(self, atomsFn): # to launch the nma alignment programs writeSetOfVolumes(self.inputVolumes.get(), self.imgsFn) writeSetOfVolumes(self.inputVolumes.get(), self.imgsFn_backup) - # Copy the atoms file to current working dir - # copyFile(atomsFn, self.atomsFn) def writeModesMetaData(self): """ Iterate over the input SetOfNormalModes and write @@ -226,6 +356,37 @@ def copyDeformationsStep(self, deformationMd): mdImgs.sort(md.MDL_ITEM_ID) mdImgs.write(self.imgsFn) + # if the volumes were aligned with angle_y=90 degrees, then rotate by 90 and inverse, then set angle y to 0 + mdImgs = md.MetaData(self.imgsFn) + + flag = None + try: + flag = mdImgs.getValue(md.MDL_ANGLE_Y, 1) + except: + pass + + if flag == 90: + mdImgs = md.MetaData(self.imgsFn) + for objId in mdImgs: + rot = mdImgs.getValue(md.MDL_ANGLE_ROT, objId) + tilt = mdImgs.getValue(md.MDL_ANGLE_TILT, objId) + psi = mdImgs.getValue(md.MDL_ANGLE_PSI, objId) + x = mdImgs.getValue(md.MDL_SHIFT_X, objId) + y = mdImgs.getValue(md.MDL_SHIFT_Y, objId) + z = mdImgs.getValue(md.MDL_SHIFT_Z, objId) + T = eulerAngles2matrix(rot, tilt, psi, x, y, z) + # Rotate 90 degrees (compensation for missing wedge) + T0 = eulerAngles2matrix(0, 90, 0, 0, 0, 0) + T = np.linalg.inv(np.matmul(T, T0)) + rot, tilt, psi, x, y, z = matrix2eulerAngles(T) + mdImgs.setValue(md.MDL_ANGLE_ROT, rot, objId) + mdImgs.setValue(md.MDL_ANGLE_TILT, tilt, objId) + mdImgs.setValue(md.MDL_ANGLE_PSI, psi, objId) + mdImgs.setValue(md.MDL_SHIFT_X, x, objId) + mdImgs.setValue(md.MDL_SHIFT_Y, y, objId) + mdImgs.setValue(md.MDL_SHIFT_Z, z, objId) + mdImgs.setValue(md.MDL_ANGLE_Y, 0.0, objId) + mdImgs.write(self.imgsFn) @@ -236,9 +397,9 @@ def performNmaStep(self, atomsFn, modesFn): imgFn = self.imgsFn frm_freq = self.frm_freq.get() frm_maxshift = self.frm_maxshift.get() - # rhoStartBase = self.rhoStartBase.get() - # rhoEndBase = self.rhoEndBase.get() - # niter = self.niter.get() + rhoStartBase = self.rhoStartBase.get() + rhoEndBase = self.rhoEndBase.get() + niter = self.niter.get() rhoStartBase = 250.0 rhoEndBase = 50.0 niter = 10000 @@ -259,8 +420,6 @@ def performNmaStep(self, atomsFn, modesFn): tiltF = self.tiltHigh.get() args += "--tilt_values %(tilt0)d %(tiltF)d " - # print(args % locals()) - # runProgram("xmipp_nma_alignment_vol", args % locals()) self.runJob("xmipp_nma_alignment_vol", args % locals(), env=Domain.importFromPlugin('xmipp3').Plugin.getEnviron()) @@ -292,7 +451,31 @@ def performNmaStep(self, atomsFn, modesFn): mdImgs.sort(md.MDL_ITEM_ID) mdImgs.write(self.imgsFn) - mdImgs.write(self.imgsFn) + # if WedgeMode was Mask, then update the metadata angles and shifts to be in the same convention of the + # ground truth (rotate 90 degrees) then set angle y to 0 + if self.WedgeMode == WEDGE_MASK_THRE: + mdImgs = md.MetaData(self.imgsFn) + for objId in mdImgs: + rot = mdImgs.getValue(md.MDL_ANGLE_ROT, objId) + tilt = mdImgs.getValue(md.MDL_ANGLE_TILT, objId) + psi = mdImgs.getValue(md.MDL_ANGLE_PSI, objId) + x = mdImgs.getValue(md.MDL_SHIFT_X, objId) + y = mdImgs.getValue(md.MDL_SHIFT_Y, objId) + z = mdImgs.getValue(md.MDL_SHIFT_Z, objId) + T = eulerAngles2matrix(rot, tilt, psi, x, y, z) + # Rotate 90 degrees (compensation for missing wedge) + T0 = eulerAngles2matrix(0, 90, 0, 0, 0, 0) + T = np.linalg.inv(np.matmul(T, T0)) + rot, tilt, psi, x, y, z = matrix2eulerAngles(T) + mdImgs.setValue(md.MDL_ANGLE_ROT, rot, objId) + mdImgs.setValue(md.MDL_ANGLE_TILT, tilt, objId) + mdImgs.setValue(md.MDL_ANGLE_PSI, psi, objId) + mdImgs.setValue(md.MDL_SHIFT_X, x, objId) + mdImgs.setValue(md.MDL_SHIFT_Y, y, objId) + mdImgs.setValue(md.MDL_SHIFT_Z, z, objId) + mdImgs.setValue(md.MDL_ANGLE_Y, 0.0, objId) + mdImgs.write(self.imgsFn) + cleanPath(self._getExtraPath('copy.xmd')) def createOutputStep(self): @@ -321,26 +504,13 @@ def _validate(self): return errors def _citations(self): - return ['harastani2020hybrid','Jonic2005', 'Sorzano2004b', 'Jin2014'] + return ['harastani2021hemnma','harastani2022continuousflex'] def _methods(self): pass # --------------------------- UTILS functions -------------------------------------------- - def _printWarnings(self, *lines): - """ Print some warning lines to 'warnings.xmd', - the function should be called inside the working dir.""" - fWarn = open("warnings.xmd", 'w') - for l in lines: - print >> fWarn, l - fWarn.close() - - def _getLocalModesFn(self): - modesFn = self.inputModes.get().getFileName() - return self._getBasePath(modesFn) - def _updateParticle(self, item, row): setXmippAttributes(item, row, md.MDL_ANGLE_ROT, md.MDL_ANGLE_TILT, md.MDL_ANGLE_PSI, md.MDL_SHIFT_X, - md.MDL_SHIFT_Y, md.MDL_SHIFT_Z, md.MDL_FLIP, md.MDL_NMA, md.MDL_COST, md.MDL_MAXCC, - md.MDL_ANGLE_Y) + md.MDL_SHIFT_Y, md.MDL_SHIFT_Z, md.MDL_FLIP, md.MDL_NMA, md.MDL_COST, md.MDL_MAXCC) createItemMatrix(item, row, align=em.ALIGN_PROJ) diff --git a/continuousflex/protocols/protocol_nma_base.py b/continuousflex/protocols/protocol_nma_base.py index 98627f3..7e2a114 100644 --- a/continuousflex/protocols/protocol_nma_base.py +++ b/continuousflex/protocols/protocol_nma_base.py @@ -27,10 +27,9 @@ # * # ************************************************************************** - from pwem import * from pwem.emlib import (MetaData, MDL_X, MDL_COUNT, MDL_NMA_MODEFILE, MDL_ORDER, - MDL_ENABLED, MDL_NMA_COLLECTIVITY, MDL_NMA_SCORE) + MDL_ENABLED, MDL_NMA_COLLECTIVITY, MDL_NMA_SCORE, MDL_NMA_EIGENVAL) from pwem.protocols import EMProtocol from pyworkflow.protocol.params import IntParam, FloatParam, EnumParam from pyworkflow.utils import * @@ -45,7 +44,151 @@ class FlexProtNMABase(EMProtocol): - """ Protocol for flexible analysis using NMA. """ + """ + Provides the foundational framework for Normal Mode Analysis (NMA) of + macromolecular structures and pseudoatomic models. The protocol is intended + to characterize intrinsic molecular flexibility by identifying collective + motions that describe biologically relevant conformational changes. These + motions can later be used in flexible fitting, variability analysis, motion + exploration, and the interpretation of structural heterogeneity observed in + cryo-EM experiments. + + AI Generated: + + Normal Mode Analysis Base (FlexProtNMABase) - User Manual + Overview + + The Normal Mode Analysis Base protocol provides the core functionality + required to compute and evaluate normal modes describing the intrinsic + flexibility of molecular structures. In structural biology, normal mode + analysis is widely used to investigate how large biomolecular assemblies + move between different conformational states while preserving their + overall architecture. + + The protocol is designed to support both atomic and pseudoatomic + representations. This flexibility allows researchers to study systems + ranging from high-resolution atomic models to lower-resolution cryo-EM + reconstructions that have been converted into pseudoatomic forms. The + resulting modes provide a compact description of collective molecular + motions and often reveal biologically meaningful pathways of structural + change. + + Biological Significance of Normal Modes + + Biological macromolecules are dynamic entities rather than static + structures. Proteins, ribosomes, viral capsids, and molecular machines + frequently perform their functions through coordinated movements of + domains, subunits, or flexible regions. Normal mode analysis seeks to + identify these collective motions and rank them according to their + energetic accessibility. + + Lower-frequency modes are often the most biologically relevant because + they describe large-scale coordinated movements that can be associated + with ligand binding, allosteric regulation, assembly rearrangements, + transport mechanisms, or transitions between functional states. + Understanding these motions can provide valuable insight into molecular + mechanisms that are difficult to infer from a single static structure. + + Defining the Elastic Network + + A key aspect of normal mode analysis is the definition of interactions + between atoms or pseudoatoms. The protocol allows users to control how + neighboring elements are connected through an interaction cutoff. + + For atomic structures, a fixed interaction distance is often suitable + because atomic coordinates provide detailed geometric information. For + pseudoatomic models derived from cryo-EM maps, relative cutoffs are + generally preferred because they adapt automatically to the density and + distribution of pseudoatoms. This often produces more stable and + physically meaningful elastic networks. + + Choosing an appropriate interaction range is important because it + determines the balance between local rigidity and global flexibility. + Cutoffs that are too restrictive may fragment the network and prevent + meaningful mode calculation, whereas excessively large cutoffs may + suppress biologically relevant flexibility. + + Number of Modes + + The protocol allows users to select how many normal modes should be + computed. In most biological applications, only a subset of the + available modes is required because the lowest-frequency collective + motions typically capture the most relevant conformational variability. + + A moderate number of modes is often sufficient for exploring structural + flexibility, generating deformed models, or performing downstream + conformational analyses. Computing an excessive number of modes may + increase computational cost without providing additional biological + insight. + + Mode Qualification and Selection + + Not all computed modes are equally informative. The protocol evaluates + the collective nature of each mode and identifies those that are most + likely to represent meaningful concerted motions. + + Collectivity measures the extent to which a motion involves large + portions of the structure rather than only a few localized elements. + Highly collective modes are often associated with functional molecular + rearrangements, whereas poorly collective modes may correspond to local + fluctuations with limited biological significance. + + The protocol therefore provides mechanisms for identifying and + prioritizing the most informative modes. This helps users focus on + motions that are more likely to contribute to biologically relevant + conformational transitions. + + Interpretation of Eigenvalues and Flexibility + + Each normal mode is associated with an eigenvalue that reflects the + energetic cost of the corresponding motion. Lower eigenvalues indicate + softer motions that can occur more easily, while higher eigenvalues + correspond to increasingly constrained deformations. + + From a biological perspective, the lowest-frequency non-rigid-body modes + are often the most informative because they represent motions that the + molecular system can naturally access. These modes frequently correlate + with experimentally observed conformational variability. + + Outputs and Their Interpretation + + The protocol produces a collection of normal modes together with + quantitative descriptors that help evaluate their importance. The + resulting mode set can be used directly in downstream flexibility + analyses, conformational sampling, flexible fitting procedures, and + structural interpretation workflows. + + Researchers can inspect the relative importance of different modes, + evaluate their collectivity, and determine which motions should be used + for subsequent analyses. The outputs provide a structured description of + the accessible conformational space surrounding the input structure. + + Practical Recommendations + + For pseudoatomic models derived from cryo-EM maps, relative interaction + cutoffs are generally recommended because they adapt more naturally to + the pseudoatom distribution. For atomic structures, carefully chosen + absolute cutoffs often provide reliable results. + + In most studies, attention should focus on the lowest-frequency + collective modes rather than attempting to interpret every computed + motion. Reviewing collectivity values and ensuring that the interaction + network is sufficiently connected are important quality-control steps. + + When mode computation becomes unstable or produces fewer modes than + expected, increasing the interaction cutoff is often an effective way to + improve network connectivity and obtain a more complete description of + molecular flexibility. + + Final Perspective + + Normal mode analysis provides a powerful bridge between static + structural models and the dynamic behavior of biological molecules. By + identifying collective motions that are energetically accessible, the + protocol enables researchers to explore conformational landscapes, + interpret experimental heterogeneity, and gain mechanistic insight into + the functional flexibility of complex macromolecular systems. + """ _label = 'nma analysis' def _defineParamsCommon(self, form): @@ -62,42 +205,42 @@ def _defineParamsCommon(self, form): default=NMA_CUTOFF_REL, label='Cut-off mode', help='The cut-off mode can be Absolute or Relative. \n' - 'Absolute distance allows specifying the maximum distance (in Angstroms) for which it ' + 'Absolute distance allows specifying the maximum distance (in Angstroms) for which it ' 'is considered that two atoms or pseudoatoms are connected. ' 'Relative distance allows to specify this distance ' - 'as a percentile of all the distances between ' - 'an atom or a pseudoatom and its nearest neighbors. \n' - 'For pseudoatoms, the Relative cut-off mode is recommened.') + 'as a percentile of all the distances between ' + 'an atom or a pseudoatom and its nearest neighbors. \n' + 'For pseudoatoms, the Relative cut-off mode is recommened.') form.addParam('rc', FloatParam, default=8, label="Cut-off distance (A)", condition='cutoffMode==%d' % NMA_CUTOFF_ABS, help='Atoms or pseudoatoms beyond this distance will not interact. \n' - 'For atoms, the distance of 8 Angstroms can work in majority of cases. \n' - 'For pseudoatoms, it is recommended to use Relative as the cut-off mode, together with ' - 'the Cut-off percentage parameter so that the distance can be computed automatically.') + 'For atoms, the distance of 8 Angstroms can work in majority of cases. \n' + 'For pseudoatoms, it is recommended to use Relative as the cut-off mode, together with ' + 'the Cut-off percentage parameter so that the distance can be computed automatically.') form.addParam('rcPercentage', FloatParam, default=95, label="Cut-off percentage", condition='cutoffMode==%d' % NMA_CUTOFF_REL, help='The parameter used to compute the interaction cutoff distance automatically. \n' - 'The interaction cutoff distance is calculated as the distance below which is ' - 'the percentage of interatomic or interpseudoatomic distances given by this parameter. \n' + 'The interaction cutoff distance is calculated as the distance below which is ' + 'the percentage of interatomic or interpseudoatomic distances given by this parameter. \n' 'Atoms or pseudoatoms beyond the interaction cutoff distance will not interact. \n' - 'For pseudoatoms, this is the recommended way to compute the interaction cutoff distance, ' - 'obtained via the Relative cut-off mode.') + 'For pseudoatoms, this is the recommended way to compute the interaction cutoff distance, ' + 'obtained via the Relative cut-off mode.') form.addParam('collectivityThreshold', FloatParam, default=0.15, label='Threshold on collectivity', help='Collectivity degree is related to the number of atoms or pseudoatoms that are affected by ' - 'the mode, and it is normalized between 0 and 1. Modes below this threshold are deselected in ' + 'the mode, and it is normalized between 0 and 1. Modes below this threshold are deselected in ' 'the modes metadata file, which means these modes are much less collective. \n' - 'For no deselection, this parameter should be set to 0 . \n' - 'Modes 1-6 are always deselected as they are related to rigid-body movements. \n' - 'The modes metadata file can be used to see which modes are more collective ' - 'in order to decide which modes to use at the image analysis step.') + 'For no deselection, this parameter should be set to 0 . \n' + 'Modes 1-6 are always deselected as they are related to rigid-body movements. \n' + 'The modes metadata file can be used to see which modes are more collective ' + 'in order to decide which modes to use at the image analysis step.') def _printWarnings(self, *lines): """ Print some warning lines to 'warnings.xmd', the function should be called inside the working dir.""" fWarn = open("warnings.xmd", 'a') for l in lines: - print( fWarn, l) + print(fWarn, l) fWarn.close() def computeModesStep(self, fnPseudoatoms, numberOfModes, cutoffStr): @@ -192,9 +335,12 @@ def qualifyModesStep(self, numberOfModes, collectivityThreshold, structureEM, su self._printWarnings(redStr(msg % (len(fnVec), numberOfModes))) print(redStr('Warning: There are only %d modes instead of %d.' % (len(fnVec), numberOfModes))) print(redStr("Check the number of modes you asked to compute and/or consider increasing cut-off distance.")) - print(redStr("The maximum number of modes allowed by the method for atomic normal mode analysis is 6 times")) - print(redStr("the number of RTB blocks and for pseudoatomic normal mode analysis 3 times the number of pseudoatoms.")) - print(redStr("However, the protocol allows only up to 200 modes as 20-100 modes are usually enough. If the number of")) + print( + redStr("The maximum number of modes allowed by the method for atomic normal mode analysis is 6 times")) + print(redStr( + "the number of RTB blocks and for pseudoatomic normal mode analysis 3 times the number of pseudoatoms.")) + print(redStr( + "However, the protocol allows only up to 200 modes as 20-100 modes are usually enough. If the number of")) print(redStr("modes is below the minimum between these two numbers, consider increasing cut-off distance.")) fnDiag = "diagrtb.eigenfacs" @@ -215,6 +361,8 @@ def qualifyModesStep(self, numberOfModes, collectivityThreshold, structureEM, su mdOut = MetaData() collectivityList = [] + ids, eigvals = self._get_eigval() + print(eigvals) for n in range(len(fnVec)): line = fh.readline() collectivity = float(line.split()[1]) @@ -229,8 +377,11 @@ def qualifyModesStep(self, numberOfModes, collectivityThreshold, structureEM, su mdOut.setValue(MDL_ENABLED, 1, objId) else: mdOut.setValue(MDL_ENABLED, -1, objId) + try: + mdOut.setValue(MDL_NMA_EIGENVAL, eigvals[n], objId) + except: + pass mdOut.setValue(MDL_NMA_COLLECTIVITY, collectivity, objId) - if collectivity < collectivityThreshold: mdOut.setValue(MDL_ENABLED, -1, objId) fh.close() @@ -259,6 +410,21 @@ def qualifyModesStep(self, numberOfModes, collectivityThreshold, structureEM, su self._leaveWorkingDir() + def _get_eigval(self): + # We are inside the working directory + fn = 'logs/run.stdout' + # fn = 'run.stdout' + content = open(fn, 'r') + Lines = content.readlines() + ids = [] + eigval = [] + for line in Lines: + if line.startswith(' Rdmodfacs> Eigenvector number:'): + ids.append(int(line[32:])) + if line.startswith(' Rdmodfacs> Corresponding eigenvalue:'): + eigval.append(float(line[37:])) + return ids, eigval + def _validate(self): errors = [] nmaBin = Plugin.getVar(NMA_HOME) @@ -271,14 +437,15 @@ def _validate(self): for prog in nma_programs: if not exists(join(nmaBin, prog)): errors.append("Some NMA programs are missing in the NMA folder.") - #errors.append("Check that Scipion was installed with NMA: 'scipion installb nma'") + # errors.append("Check that Scipion was installed with NMA: 'scipion installb nma'") errors.append("Check that Scipion was installed with NMA") break from pyworkflow.utils.which import which if (which("csh") == "") and (which("bash") == ""): - errors.append("Please install csh (can be a link to tcsh) or bash (e.g., on Ubuntu 'sudo apt-get install csh' or 'sudo apt-get install bash')") + errors.append("Please install csh (can be a link to tcsh) or bash (e.g., on Ubuntu 'sudo apt-get install " + "csh' or 'sudo apt-get install bash')") return errors def _citations(self): - return ['Nogales2013', 'Jin2014'] + return ['harastani2022continuousflex','Nogales2013', 'Jin2014'] diff --git a/continuousflex/protocols/protocol_nma_choose.py b/continuousflex/protocols/protocol_nma_choose.py index d23cd21..b62ef09 100644 --- a/continuousflex/protocols/protocol_nma_choose.py +++ b/continuousflex/protocols/protocol_nma_choose.py @@ -23,7 +23,6 @@ # * # ************************************************************************** - from pwem.emlib import (MetaData, MDL_NMA, MDL_ENABLED, MDL_NMA_MINRANGE, MDL_NMA_MAXRANGE) from pwem.objects import AtomStruct @@ -34,12 +33,145 @@ from pwem.utils import runProgram -#from xmipp3.protocols.pdb.protocol_pseudoatoms_base import * -#from ..pdb.protocol_pseudoatoms_base import * +class FlexrotNMAChoose(FlexProtConvertToPseudoAtomsBase, FlexProtNMABase): + """ + Protocol for choosing a volume to construct an NMA analysis. + + AI Generated: + Choose NMA (FlexrotNMAChoose) - User Manual -class FlexrotNMAChoose(FlexProtConvertToPseudoAtomsBase, FlexProtNMABase): - """ Protocol for choosing a volume to construct an NMA analysis """ + Overview + + The Choose NMA protocol identifies the most representative volume from + a collection of related three-dimensional density maps and uses it as + the foundation for a Normal Mode Analysis (NMA) study. Its primary goal + is to select a structural state that best captures the overall behavior + of the dataset, providing a biologically meaningful starting point for + exploring conformational variability and molecular flexibility. + + In structural biology projects, it is common to obtain multiple volumes + representing different conformations, experimental conditions, or stages + of a dynamic process. Rather than arbitrarily selecting one of these + states for further analysis, this protocol evaluates the entire ensemble + and determines which volume lies closest to the center of the observed + structural landscape. The selected volume can then serve as a robust + reference for downstream flexibility analysis. + + Inputs and General Workflow + + The protocol requires a set of volumes representing different structural + states of the same biological system. These volumes should describe + comparable molecular assemblies and ideally share the same sampling, + dimensions, and overall structural content. + + Each volume is converted into a pseudoatomic representation suitable for + Normal Mode Analysis. The resulting models provide a simplified yet + biologically informative description of the structure that can capture + large-scale motions while remaining computationally efficient. + + Once pseudoatomic models have been generated, a Normal Mode Analysis is + performed independently for each candidate structure. The resulting + normal modes describe the intrinsic directions of motion available to + each conformation and provide the basis for comparing structural states + across the dataset. + + Evaluating Structural Similarity + + After normal modes have been computed, each candidate structure is + compared against every other volume in the collection. The protocol + evaluates how well one structure can deform to resemble another using + biologically plausible motions described by the normal modes. + + This pairwise comparison creates a global picture of structural + relationships within the dataset. Volumes that can easily deform into + one another are considered closely related, while larger deformations + indicate greater structural separation. + + From a biological perspective, this analysis can reveal whether the + dataset forms a continuous conformational spectrum or contains several + distinct structural states. The representative volume is chosen from + within this context rather than based on visual inspection alone. + + Optional Volume Alignment + + An optional alignment stage can be enabled before evaluating structural + deformations. This is particularly useful when volumes may differ not + only because of genuine conformational changes but also because of + orientation differences introduced during reconstruction or processing. + + For datasets originating from multiple experiments, independent + refinement procedures, or heterogeneous reconstruction pipelines, + alignment often improves the biological interpretability of the results. + When volumes are already expressed in a common coordinate system, this + option may provide only limited additional benefit. + + Choosing the Representative Structure + + The central objective of the protocol is to identify the structure that + best represents the complete ensemble. This representative model is the + one exhibiting the smallest average deformation distance to all other + structures in the dataset. + + Biologically, this selected volume can be interpreted as the most + typical conformation within the observed population. It is often a + suitable reference for flexibility studies because it minimizes bias + toward any extreme conformational state. + + The resulting pseudoatomic model and its associated normal modes become + the principal outputs of the protocol and can be used directly in later + analyses involving conformational landscapes, flexible fitting, or + motion characterization. + + Interpretation of Motion Ranges + + Beyond selecting a representative structure, the protocol estimates the + range of observed deformations associated with each retained normal + mode. These ranges provide an approximation of how strongly each mode + contributes to the structural variability present in the dataset. + + Modes exhibiting broad deformation ranges may correspond to dominant + biological motions, while modes with limited variation are generally + less influential in explaining the observed conformational diversity. + Such information can guide the interpretation of molecular dynamics and + aid in selecting relevant modes for downstream exploration. + + Outputs and Their Interpretation + + The protocol produces a representative pseudoatomic model together with + a curated set of normal modes describing its accessible motions. These + outputs form a compact description of the structural variability + observed across the entire collection of volumes. + + The representative model can be used as a reference structure for + subsequent Normal Mode Analysis workflows, flexible fitting procedures, + dimensionality reduction studies, or visualization of conformational + transitions. The associated modes provide a biologically meaningful + framework for understanding the dominant motions encoded in the data. + + Practical Recommendations + + The protocol performs best when all input volumes correspond to the + same molecular assembly and differ primarily because of conformational + variability. Large differences arising from reconstruction artifacts, + inconsistent preprocessing, or unrelated biological states can reduce + the reliability of the representative selection. + + Careful preparation of the input dataset is therefore important. + Volumes should be inspected to ensure consistency in scale, sampling, + and molecular content before analysis. When substantial orientation + differences are expected, enabling alignment is generally advisable. + + Final Perspective + + Choosing an appropriate reference structure is a critical step in many + flexibility analysis workflows. By identifying the volume that best + represents the overall conformational ensemble, this protocol provides + a principled and biologically meaningful foundation for Normal Mode + Analysis. The resulting model and motion descriptors help transform a + collection of individual structural states into a coherent description + of molecular dynamics and functional flexibility. + """ _label = 'choose NMA' def __init__(self, **args): @@ -250,4 +382,4 @@ def _methods(self): return summary def _citations(self): - return ['Nogales2013', 'Jin2014'] + return ['harastani2022continuousflex','Nogales2013', 'Jin2014'] diff --git a/continuousflex/protocols/protocol_nma_dimred.py b/continuousflex/protocols/protocol_nma_dimred.py index 42c4300..1852d7e 100644 --- a/continuousflex/protocols/protocol_nma_dimred.py +++ b/continuousflex/protocols/protocol_nma_dimred.py @@ -3,6 +3,7 @@ # * Authors: # * J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es), Nov 2014 # * Slavica Jonic (slavica.jonic@upmc.fr) +# * Mohamad Harastani (mohamad.harastani@igbmc.fr) # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -23,14 +24,19 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** - - from pyworkflow.object import String -from pyworkflow.protocol.params import (PointerParam, StringParam, EnumParam, - IntParam, LEVEL_ADVANCED) +from pyworkflow.protocol.params import (PointerParam, EnumParam, IntParam) from pwem.protocols import ProtAnalysis3D +from pwem.convert import cifToPdb +from pyworkflow.utils.path import makePath, copyFile +from pyworkflow.protocol import params from pwem.utils import runProgram +from continuousflex.protocols import FlexProtAlignmentNMA +import numpy as np +import glob +from sklearn import decomposition +from joblib import dump DIMRED_PCA = 0 DIMRED_LTSA = 1 @@ -43,43 +49,185 @@ DIMRED_HLLE = 8 DIMRED_SPE = 9 DIMRED_NPE = 10 +DIMRED_SKLEAN_PCA = 11 USE_PDBS = 0 USE_NMA_AMP = 1 # Values to be passed to the program -DIMRED_VALUES = ['PCA', 'LTSA', 'DM', 'LLTSA', 'LPP', 'kPCA', 'pPCA', 'LE', 'HLLE', 'SPE', 'NPE'] +DIMRED_VALUES = ['PCA', 'LTSA', 'DM', 'LLTSA', 'LPP', 'kPCA', 'pPCA', 'LE', 'HLLE', 'SPE', 'NPE', 'sklearn_PCA','None'] # Methods that allows mapping DIMRED_MAPPINGS = [DIMRED_PCA, DIMRED_LLTSA, DIMRED_LPP, DIMRED_PPCA, DIMRED_NPE] - +DATA_CHOICE = ['PDBs', 'NMAs'] + + class FlexProtDimredNMA(ProtAnalysis3D): - """ This protocol will take the images with NMA deformations - as points in a N-dimensional space (where N is the number - of computed normal modes) and will project them onto a reduced space + """ + Reduces the dimensionality of conformational information obtained from Normal Mode Analysis (NMA) + and related flexible fitting workflows. The protocol represents structural variability as points in + a high-dimensional conformational space and projects those data into a lower-dimensional space that + is easier to visualize, interpret, and analyze. + + AI Generated: + + NMA Dimensionality Reduction (FlexProtDimredNMA) - User Manual + + Overview + + This protocol is designed to simplify the exploration of conformational landscapes derived from + Normal Mode Analysis. Biological macromolecules often exhibit complex motions that cannot be + easily understood when represented using many normal mode amplitudes or large collections of + deformed structures. Dimensionality reduction transforms these high-dimensional descriptions into + a compact representation that captures the dominant patterns of structural variability. + + The resulting reduced space allows users to visualize conformational distributions, identify + structural trends, detect clusters of related states, and investigate continuous transitions + between different conformations. This makes the protocol particularly valuable when studying + molecular flexibility, functional motions, and heterogeneous cryo-EM datasets. + + Inputs and General Workflow + + The protocol requires a previous conformational analysis generated through Normal Mode Analysis + alignment or compatible flexible fitting procedures. Each particle or volume is represented by a + set of normal mode amplitudes that describe its position within the conformational landscape. + + Users may choose to analyze either the normal mode amplitudes directly or the corresponding + deformed atomic models. Both approaches aim to describe the same underlying conformational + variability, although they may emphasize different aspects of the structural motion. + + The protocol converts the selected representation into a numerical conformational dataset and + projects it into a lower-dimensional space using the chosen dimensionality reduction method. + + Choice of Input Representation + + The normal mode amplitude representation is generally the most direct and computationally + efficient option. Each point corresponds to a specific combination of mode amplitudes and can be + interpreted as a position within the space defined by the selected normal modes. + + Alternatively, users may choose to analyze deformed atomic models. In this case, each conformation + is represented through its atomic coordinates. This approach can sometimes reduce interactions + between different modes and may provide a more physically intuitive description of the structural + variability. + + Since both representations capture related information, comparing the results obtained from both + approaches can provide additional confidence in the biological interpretation of the conformational + landscape. + + Dimensionality Reduction Methods + + The protocol offers a wide range of dimensionality reduction techniques spanning both linear and + nonlinear approaches. Each method attempts to preserve specific properties of the original + conformational space while generating a more compact representation. + + Principal Component Analysis is often the most suitable starting point because it provides an + interpretable linear projection that captures the largest sources of variability. For many + biological datasets, PCA produces meaningful low-dimensional representations that are easy to + analyze and visualize. + + Local Tangent Space Alignment and related manifold-learning approaches focus on preserving local + geometric relationships between neighboring conformations. These methods can reveal nonlinear + conformational pathways that may not be apparent in linear projections. + + Diffusion maps are particularly useful when studying continuous motions and gradual transitions + between states. They often provide an intuitive description of conformational trajectories and + energy landscapes. + + Kernel-based approaches extend linear methods to capture nonlinear relationships, while + probabilistic techniques introduce statistical models that can provide robustness in noisy + datasets. + + Neighborhood-preserving and embedding methods attempt to maintain local structural relationships + and can be valuable when investigating heterogeneous populations containing multiple conformational + states. + + Selection of Reduced Dimension + + The user specifies the number of dimensions that will be retained after projection. Two dimensions + are commonly used for visualization because they allow direct plotting and exploration of the + conformational landscape. + + Three-dimensional representations may provide additional information when variability is more + complex. Higher-dimensional reduced spaces can also be generated when the goal is to preserve more + structural information for subsequent computational analysis. + + The optimal choice depends on the complexity of the biological system and the intended downstream + application. + + Interpretation of the Reduced Space + + The reduced coordinates describe the relative relationships between conformations rather than + explicit physical distances or energies. Nearby points generally correspond to structurally similar + conformations, whereas distant points often represent substantially different molecular states. + + Clusters within the reduced space may indicate discrete conformational states, functional + substates, or structurally related populations. Continuous trajectories may suggest gradual motions + between states, potentially reflecting biologically relevant transitions. + + Interpretation should always be combined with structural inspection and biological knowledge of + the system under study. + + Projection and Mapping Information + + Some dimensionality reduction methods generate mappings that can be reused to project additional + conformations into the same reduced space. This capability is particularly useful when comparing + multiple datasets or extending an existing conformational analysis with newly processed particles. + + Such mappings help maintain consistency across analyses and facilitate longitudinal studies of + conformational variability. + + Outputs and Their Interpretation + + The primary output is a matrix containing the reduced-dimensional representation of the input + conformations. Each row corresponds to a specific particle, volume, or conformation, while each + column represents one dimension of the reduced space. + + These coordinates can be used for visualization, clustering, classification, trajectory analysis, + state identification, or further statistical studies. The output serves as a compact summary of + the dominant conformational variability present in the dataset. + + Practical Recommendations + + For most biological applications, PCA is an excellent initial choice because it is fast, + interpretable, and generally provides meaningful results. If the conformational landscape appears + highly nonlinear or contains complex transitions, manifold-learning approaches such as diffusion + maps or local tangent space methods may reveal additional structure. + + Users are encouraged to compare multiple dimensionality reduction methods, particularly when the + biological interpretation of the conformational landscape is not immediately clear. Consistent + patterns observed across different methods often provide stronger evidence for biologically + meaningful motions. + + Final Perspective + + Dimensionality reduction is an essential tool for transforming complex conformational datasets into + interpretable representations. By revealing the dominant patterns of structural variability, this + protocol enables researchers to explore molecular motions, identify conformational states, and + gain biological insight into the dynamic behavior of macromolecular systems. """ _label = 'nma dimred' def __init__(self, **kwargs): ProtAnalysis3D.__init__(self, **kwargs) self.mappingFile = String() - - #--------------------------- DEFINE param functions -------------------------------------------- + + # --------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection(label='Input') - form.addParam('inputNMA', PointerParam, pointerClass='FlexProtAlignmentNMA', - label="Conformational distribution", + form.addParam('inputNMA', PointerParam, pointerClass='FlexProtAlignmentNMA, FlexProtDeepHEMNMAInfer', + label="Conformational distribution", help='Select a previous run of the NMA alignment.') - form.addParam('analyzeChoice', EnumParam, default=USE_NMA_AMP, + form.addParam('dataChoice', EnumParam, default=USE_NMA_AMP, choices=['Use deformed (pseudo)atomic models', 'Use normal mode amplitudes'], label='Data to analyze', - help='Choosing to analyze the fitted PDBs is slower but more accurate.' - ' You can choose to use normal mode amplitudes for preliminary results.') + help='Theoretically, both methods should give similar results, but choosing to analyze the fitted' + ' PDBs can help reduce / eliminate the crosstalk between the normal-modes.' + ' We recommend trying both options and comparing the results.') - form.addParam('dimredMethod', EnumParam, default=DIMRED_PCA, + form.addParam('dimredMethod', EnumParam, default=DIMRED_SKLEAN_PCA, choices=['Principal Component Analysis (PCA)', 'Local Tangent Space Alignment', 'Diffusion map', @@ -90,7 +238,9 @@ def _defineParams(self, form): 'Laplacian Eigenmap', 'Hessian Locally Linear Embedding', 'Stochastic Proximity Embedding', - 'Neighborhood Preserving Embedding'], + 'Neighborhood Preserving Embedding', + 'Scikit-Learn PCA', + "Don't reduce dimensions"], label='Dimensionality reduction method', help=""" Choose among the following dimensionality reduction methods: PCA @@ -116,16 +266,17 @@ def _defineParams(self, form): NPE Neighborhood Preserving Embedding, k=number of nearest neighbours """) - form.addParam('extraParams', StringParam, level=LEVEL_ADVANCED, - label="Extra params", - help='This parameters will be passed to the program.') - + form.addParam('extraParams', params.StringParam, default=None, + expertLevel=params.LEVEL_ADVANCED, + label='Extra params', + help='These parameters are there to change the default parameters of a dimensionality reduction' + ' method. Check xmipp_matrix_dimred for full details.') + form.addParam('reducedDim', IntParam, default=2, label='Reduced dimension') - form.addParallelSection(threads=0, mpi=0) - - - #--------------------------- INSERT steps functions -------------------------------------------- + form.addParallelSection(threads=0, mpi=0) + + # --------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): # Take deforamtions text file and the number of images and modes @@ -134,69 +285,128 @@ def _insertAllSteps(self): reducedDim = self.reducedDim.get() method = self.dimredMethod.get() extraParams = self.extraParams.get('') - + dataChoice = self.getDataChoice() deformationsFile = self.getDeformationFile() - - self._insertFunctionStep('convertInputStep', - deformationsFile, inputSet.getObjId()) - self._insertFunctionStep('performDimredStep', + + self._insertFunctionStep('convertInputStep', + deformationsFile, inputSet.getObjId(), dataChoice) + self._insertFunctionStep('performDimredStep', deformationsFile, method, extraParams, - rows, reducedDim) + rows, reducedDim) self._insertFunctionStep('createOutputStep') - - - #--------------------------- STEPS functions -------------------------------------------- - - def convertInputStep(self, deformationFile, inputId): - """ Iterate through the images and write the - plain deformation.txt file that will serve as + + # --------------------------- STEPS functions -------------------------------------------- + + def convertInputStep(self, deformationFile, inputId, dataChoice): + """ Iterate through the volumes and write the + plain deformation.txt file that will serve as input for dimensionality reduction. """ inputSet = self.getInputParticles() - f = open(deformationFile, 'w') - - for particle in inputSet: - f.write(' '.join(particle._xmipp_nmaDisplacements)) - f.write('\n') - f.close() - + + if dataChoice == 'NMAs': + f = open(deformationFile, 'w') + for particle in inputSet: + f.write(' '.join(particle._xmipp_nmaDisplacements)) + f.write('\n') + f.close() + elif dataChoice == 'PDBs': + # copy the pdb + input_pdbfn = self.getInputPdb().getFileName() + pdbfn = self._getExtraPath('pdb_file.pdb') + self.copyinputPdb(input_pdbfn, pdbfn) + # use the deformations to generate deformed versions of the pdb: + selected_nma_modes = self.getInputModes() + nma_amplfn = self._getExtraPath('nma_amplitudes.txt') + f = open(nma_amplfn, 'w') + for particle in inputSet: + f.write(' '.join(particle._xmipp_nmaDisplacements)) + f.write('\n') + f.close() + nma_ampl = np.loadtxt(nma_amplfn) + makePath(self._getExtraPath('generated_pdbs')) + pdbs_folder = self._getExtraPath('generated_pdbs') + i = 1 + for line in nma_ampl: + cmd = '-o ' + pdbs_folder + '/' + str(i).zfill( + 6) + '.pdb' + ' --pdb ' + pdbfn + ' --nma ' + selected_nma_modes + \ + ' --deformations ' + ' '.join(map(str, line)) + #print(cmd) + runProgram('xmipp_pdb_nma_deform', cmd) + i += 1 + pdbs_list = [f for f in glob.glob(pdbs_folder+'/*.pdb')] + pdbs_list.sort() + pdbs_matrix = [] + for pdbfn in pdbs_list: + pdb_lines = self.readPDB(pdbfn) + pdb_coordinates = np.array(self.PDB2List(pdb_lines)) + pdbs_matrix.append(np.reshape(pdb_coordinates, -1)) + np.savetxt(deformationFile, pdbs_matrix, fmt="%s") + pass + + else: + print('Data for dimensionality reduction is not set correctly') + def performDimredStep(self, deformationsFile, method, extraParams, rows, reducedDim): outputMatrix = self.getOutputMatrixFile() methodName = DIMRED_VALUES[method] + if methodName == 'None': + copyFile(deformationsFile,outputMatrix) + return # Get number of columes in deformation files # it can be a subset of inputModes f = open(deformationsFile) - columns = len(f.readline().split()) # count number of values in first line + columns = len(f.readline().split()) # count number of values in first line f.close() - - args = "-i %(deformationsFile)s -o %(outputMatrix)s -m %(methodName)s %(extraParams)s" - args += "--din %(columns)d --samples %(rows)d --dout %(reducedDim)d" - if method in DIMRED_MAPPINGS: + + if methodName == 'sklearn_PCA': + X = np.loadtxt(fname=deformationsFile) + pca = decomposition.PCA(n_components=reducedDim) + pca.fit(X) + Y = pca.transform(X) + np.savetxt(outputMatrix,Y) + M = np.matmul(np.linalg.pinv(X),Y) mappingFile = self._getExtraPath('projector.txt') - args += " --saveMapping %(mappingFile)s" + np.savetxt(mappingFile,M) self.mappingFile.set(mappingFile) - runProgram("xmipp_matrix_dimred", args % locals()) - + # save the pca: + pca_pickled = self._getExtraPath('pca_pickled.txt') + dump(pca,pca_pickled) + + else: + args = "-i %(deformationsFile)s -o %(outputMatrix)s -m %(methodName)s %(extraParams)s" + args += "--din %(columns)d --samples %(rows)d --dout %(reducedDim)d" + if method in DIMRED_MAPPINGS: + mappingFile = self._getExtraPath('projector.txt') + args += " --saveMapping %(mappingFile)s" + self.mappingFile.set(mappingFile) + runProgram("xmipp_matrix_dimred", args % locals()) + def createOutputStep(self): pass - #--------------------------- INFO functions -------------------------------------------- + # --------------------------- INFO functions -------------------------------------------- def _summary(self): summary = [] return summary - + def _validate(self): errors = [] return errors - + def _citations(self): - return [] - + return ['harastani2022continuousflex','Jin2014'] + def _methods(self): return [] - - #--------------------------- UTILS functions -------------------------------------------- + + # --------------------------- UTILS functions -------------------------------------------- + def getInputModes(self): + if isinstance(self.inputNMA.get(), FlexProtAlignmentNMA): + return self.inputNMA.get()._getExtraPath('modes.xmd') + else: + return self.inputNMA.get().trained_model.get().inputNMA.get()._getExtraPath('modes.xmd') def getInputParticles(self): """ Get the output particles of the input NMA protocol. """ @@ -207,16 +417,48 @@ def getParticlesMD(self): return self.inputNMA.get()._getExtraPath('images.xmd') def getInputPdb(self): - return self.inputNMA.get().getInputPdb() - + if isinstance(self.inputNMA.get(), FlexProtAlignmentNMA): + return self.inputNMA.get().getInputPdb() + else: + return self.inputNMA.get().trained_model.get().inputNMA.get().getInputPdb() + + def getOutputMatrixFile(self): return self._getExtraPath('output_matrix.txt') - + def getDeformationFile(self): return self._getExtraPath('deformations.txt') - + def getProjectorFile(self): return self.mappingFile.get() - + def getMethodName(self): return DIMRED_VALUES[self.dimredMethod.get()] + + def getDataChoice(self): + return DATA_CHOICE[self.dataChoice.get()] + + def copyinputPdb(self, inputFn, localFn): + """ Copy the input pdb file + """ + # if it is not cif, no problem, it will keep a pdb as it is and copy it + cifToPdb(inputFn, localFn) + + def readPDB(self, fnIn): + with open(fnIn) as f: + lines = f.readlines() + return lines + + def PDB2List(self, lines): + newlines = [] + for line in lines: + if line.startswith("ATOM "): + try: + x = float(line[30:38]) + y = float(line[38:46]) + z = float(line[46:54]) + newline = [x, y, z] + newlines.append(newline) + except: + pass + return newlines diff --git a/continuousflex/protocols/protocol_nma_dimred_vol.py b/continuousflex/protocols/protocol_nma_dimred_vol.py index 03182b6..fdfb615 100755 --- a/continuousflex/protocols/protocol_nma_dimred_vol.py +++ b/continuousflex/protocols/protocol_nma_dimred_vol.py @@ -1,6 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -62,9 +62,131 @@ class FlexProtDimredNMAVol(ProtAnalysis3D): - """ This protocol will take the volumes with NMA deformations - as points in a N-dimensional space (where N is the number - of computed normal modes) and will project them onto a reduced space + """ + Performs dimensionality reduction on conformational distributions obtained from normal mode analysis of volumetric data. The protocol represents structural variability in a high-dimensional conformational space and projects it into a lower-dimensional representation that facilitates visualization, interpretation, and exploration of molecular flexibility. + + AI Generated: + + NMA Volume Dimensionality Reduction (FlexProtDimredNMAVol) - User Manual + Overview + + The NMA Volume Dimensionality Reduction protocol is designed to analyze the conformational + landscape generated from normal mode analysis and flexible fitting of three-dimensional + volumes. Its main objective is to simplify complex descriptions of structural variability by + projecting conformational information into a reduced coordinate space where relationships + between states can be explored more intuitively. + + In studies of molecular flexibility, large collections of conformations are often represented + by many normal mode amplitudes or by the atomic coordinates of fitted structural models. + Although these descriptions are informative, they are difficult to visualize directly because + they exist in a high-dimensional space. This protocol transforms those data into a compact + representation that captures the dominant patterns of conformational variability while + preserving meaningful relationships among structures. + + Inputs and Conformational Data + + The protocol operates on conformational distributions generated by previous normal mode + analysis workflows applied to volumetric datasets. Each analyzed state represents a point in + a conformational space describing molecular flexibility and structural motion. + + Users may choose to analyze either normal mode amplitudes or reconstructed atomic + conformations derived from those amplitudes. The amplitude-based representation focuses + directly on the coordinates within the normal mode space and is generally efficient for + exploring large datasets. The structural representation instead analyzes the resulting + conformations themselves and can provide a more direct description of structural differences. + + Both approaches seek to characterize the same underlying conformational variability, although + they may emphasize different aspects of the structural landscape. Comparing the results from + both representations can sometimes provide additional biological insight. + + Dimensionality Reduction Strategies + + The protocol supports a broad range of dimensionality reduction approaches that differ in how + they describe relationships between conformations. Some methods focus on preserving global + variance, while others emphasize local neighborhood structure or nonlinear relationships. + + Principal Component Analysis is often the most intuitive starting point because it identifies + dominant directions of conformational variability. These reduced coordinates frequently + correspond to biologically meaningful collective motions and can reveal major conformational + trends within the dataset. + + Nonlinear approaches may be advantageous when the conformational landscape contains curved + trajectories, branching pathways, multiple functional states, or complex transitions that + cannot be adequately represented by linear projections. Such methods often provide improved + visualization of heterogeneous ensembles and can uncover hidden organization within the data. + + Interpretation of Reduced Spaces + + The reduced coordinates generated by the protocol should be interpreted as a simplified map + of conformational relationships rather than as direct physical coordinates. Conformations + located near one another generally correspond to structurally similar states, whereas distant + points typically represent larger conformational differences. + + Clusters within the reduced space may correspond to stable conformational states, functional + substates, or alternative structural arrangements. Continuous trajectories can indicate + gradual transitions between states and may reveal pathways connecting different regions of + the conformational landscape. + + The reduced representation is particularly valuable for identifying trends that would be + difficult to observe directly in the original high-dimensional space. + + Selection of Reduced Dimensionality + + The number of retained dimensions determines the balance between simplicity and information + preservation. Lower-dimensional representations are easier to visualize and interpret, + whereas higher-dimensional embeddings may preserve more subtle aspects of conformational + variability. + + For exploratory studies, two-dimensional and three-dimensional representations are often + sufficient to reveal the overall organization of the conformational landscape. More complex + biological systems may benefit from retaining additional dimensions for downstream analysis, + clustering, or machine learning applications. + + Mapping and Projection Capabilities + + Certain dimensionality reduction approaches generate mathematical mappings between the + original conformational space and the reduced representation. These mappings can be useful + for projecting additional conformations into an existing reduced space and for integrating + the reduced coordinates with subsequent computational analyses. + + Such projections provide a framework for comparing newly generated conformations with + previously analyzed datasets and for studying how different experimental or computational + conditions affect the explored conformational landscape. + + Practical Recommendations + + For most applications, Principal Component Analysis provides an excellent starting point due + to its interpretability and its strong connection to collective molecular motions. The + resulting coordinates are often straightforward to relate to biologically meaningful + structural changes. + + When the conformational landscape is expected to contain complex nonlinear relationships, + alternative embedding methods may provide a more faithful representation of the underlying + structure. Exploring multiple methods and comparing their results can help determine which + representation best captures the biological behavior of the system under study. + + Visual inspection of representative conformations from different regions of the reduced space + remains essential for biological interpretation. Reduced coordinates should always be + considered together with the corresponding structural states. + + Outputs and Interpretation + + The protocol produces a reduced coordinate matrix describing the position of each analyzed + conformation within the selected low-dimensional space. Depending on the chosen reduction + strategy, additional projection information may also be generated to facilitate future + analyses and coordinate transformations. + + These outputs provide a compact description of conformational variability that can be used + for visualization, clustering, classification, exploration of structural transitions, and + characterization of molecular flexibility. + + Final Perspective + + Dimensionality reduction is a powerful tool for transforming complex normal mode analysis + results into interpretable conformational landscapes. By condensing high-dimensional + descriptions of molecular motion into a manageable representation, the protocol helps + researchers identify biologically relevant states, understand structural transitions, and + gain insight into the fundamental organization of conformational variability. """ _label = 'nma vol dimred' @@ -222,7 +344,6 @@ def performDimredStep(self, deformationsFile, method, extraParams, if methodName == 'sklearn_PCA': X = np.loadtxt(fname=deformationsFile) - # TODO: check an option to add an average pdb in clustering pca = decomposition.PCA(n_components=reducedDim) pca.fit(X) Y = pca.transform(X) @@ -257,7 +378,7 @@ def _validate(self): return errors def _citations(self): - return [] + return ['harastani2021hemnma','harastani2022continuousflex'] def _methods(self): return [] @@ -314,5 +435,3 @@ def PDB2List(self, lines): except: pass return newlines - - diff --git a/continuousflex/protocols/protocol_pdb_dimred.py b/continuousflex/protocols/protocol_pdb_dimred.py index 9ac73b4..a63d651 100644 --- a/continuousflex/protocols/protocol_pdb_dimred.py +++ b/continuousflex/protocols/protocol_pdb_dimred.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Author: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Author: Remi Vuillemot # * IMPMC, UPMC Sorbonne University # * # * This program is free software; you can redistribute it and/or modify @@ -20,168 +20,333 @@ # * All comments concerning this program package may be sent to the # * e-mail address 'scipion@cnb.csic.es' # ************************************************************************** -from pyworkflow.object import String + +import joblib from pyworkflow.protocol.params import (PointerParam, EnumParam, IntParam) from pwem.protocols import ProtAnalysis3D -from pwem.convert import cifToPdb from pyworkflow.utils.path import makePath, copyFile from pyworkflow.protocol import params -from pwem.utils import runProgram - +from pwem.emlib import MetaData, MDL_ENABLED, MDL_NMA_MODEFILE,MDL_ORDER +from pwem.objects import SetOfNormalModes, AtomStruct +from .convert import rowToMode +from xmipp3.base import XmippMdRow +from continuousflex.protocols.utilities.genesis_utilities import numpyArr2dcd,dcd2numpyArr import numpy as np import glob from sklearn import decomposition from joblib import dump -DIMRED_PCA = 0 -DIMRED_LTSA = 1 -DIMRED_DM = 2 -DIMRED_LLTSA = 3 -DIMRED_LPP = 4 -DIMRED_KPCA = 5 -DIMRED_PPCA = 6 -DIMRED_LE = 7 -DIMRED_HLLE = 8 -DIMRED_SPE = 9 -DIMRED_NPE = 10 -DIMRED_SKLEAN_PCA = 11 +from .utilities.pdb_handler import ContinuousFlexPDBHandler +import continuousflex +from continuousflex import Plugin +from subprocess import check_call +import sys -USE_PDBS = 0 -USE_NMA_AMP = 1 +PDB_SOURCE_SUBTOMO = 0 +PDB_SOURCE_PATTERN = 1 +PDB_SOURCE_OBJECT = 2 +PDB_SOURCE_TRAJECT = 3 +PDB_SOURCE_ALIGNED = 4 -# Values to be passed to the program -DIMRED_VALUES = ['PCA', 'LTSA', 'DM', 'LLTSA', 'LPP', 'kPCA', 'pPCA', 'LE', 'HLLE', 'SPE', 'NPE', 'sklearn_PCA','None'] -DIMRED_MAPPINGS = [DIMRED_PCA, DIMRED_LLTSA, DIMRED_LPP, DIMRED_PPCA, DIMRED_NPE] +REDUCE_METHOD_PCA = 0 +REDUCE_METHOD_UMAP = 1 class FlexProtDimredPdb(ProtAnalysis3D): - """ Protocol for applying dimentionality reduction on PDB files. """ + """ + Applies dimensionality reduction to collections of macromolecular structures represented as PDB files or molecular dynamics trajectories. The protocol transforms large ensembles of structural conformations into a compact low-dimensional representation that facilitates visualization, interpretation, and exploration of conformational variability. + + AI Generated: + + PDB Dimensionality Reduction (FlexProtDimredPdb) - User Manual + Overview + + The PDB Dimensionality Reduction protocol is designed to analyze structural heterogeneity in + ensembles of macromolecular conformations. Its primary goal is to transform a large collection + of atomic structures into a reduced coordinate space where the major patterns of structural + variability can be observed and interpreted more easily. This approach is particularly useful + when studying flexible proteins, molecular machines, conformational transitions, or molecular + dynamics simulations that generate thousands of structural snapshots. + + Instead of examining each structure individually, the protocol summarizes the ensemble into a + small number of dimensions that capture the dominant motions and relationships among + conformations. The resulting reduced space allows researchers to identify structural trends, + clusters, transition pathways, and regions of conformational sampling that may otherwise be + difficult to detect. + + Inputs and Supported Data Sources + + The protocol accepts structural information from several sources. Users may analyze PDB files + generated during subtomogram synthesis workflows, collections of PDB files stored on disk, + Scipion sets of atomic structures, molecular dynamics trajectories, or outputs generated by + dedicated PDB alignment workflows. + + This flexibility allows the protocol to be used in a wide variety of structural biology + applications. Experimental conformational ensembles, computational simulations, integrative + modeling results, and synthetic benchmark datasets can all be projected into a common reduced + representation for comparative analysis. + + When working with trajectory data, it is possible to analyze only a selected region of the + trajectory. This enables users to focus on equilibrated states, specific simulation intervals, + or representative subsets of very large simulations while reducing computational requirements. + + Dimensionality Reduction Strategies + + The protocol provides multiple approaches for reducing structural dimensionality. Each method + emphasizes different aspects of conformational variability and may be more appropriate depending + on the biological question being investigated. + + Principal Component Analysis is particularly useful when the dominant motions can be reasonably + described by linear combinations of atomic displacements. In many structural biology studies, + principal components correspond to biologically meaningful collective motions such as domain + rearrangements, hinge movements, opening and closing events, or large-scale flexibility. + + UMAP offers a nonlinear alternative that is often advantageous when conformational landscapes + contain complex geometries, branching pathways, or multiple separated states. This approach can + reveal relationships between structures that may not be captured by purely linear methods and + is frequently used to explore heterogeneous ensembles with rich conformational diversity. + + Structural Similarity and Distance Interpretation + + The reduced coordinates should be interpreted as a representation of structural relationships + rather than direct physical coordinates. Structures located close together in the reduced space + generally correspond to similar conformations, while structures positioned farther apart tend + to represent larger structural differences. + + In many applications, clusters observed within the reduced space correspond to metastable + conformational states, functional substates, or structurally related populations. Continuous + trajectories through the reduced space may indicate gradual conformational transitions or + dynamic pathways sampled during molecular motion. + + Selection of Dimensionality + + The number of dimensions retained in the reduced representation determines how much structural + variability can be preserved. A small number of dimensions is often sufficient for visualization + and exploratory analysis, whereas larger dimensionalities may be preferable when capturing more + subtle motions or preparing data for downstream computational processing. + + Choosing too few dimensions may oversimplify the conformational landscape and hide meaningful + structural features. Conversely, selecting too many dimensions may preserve noise and reduce the + interpretability of the results. The optimal choice depends on the complexity of the molecular + system and the scientific objectives of the study. + + Principal Components and Collective Motions + + When Principal Component Analysis is used, the protocol additionally produces a mean structure + and a set of collective motion vectors describing the dominant directions of structural + variability within the ensemble. These motions can be interpreted as large-scale conformational + trends that summarize how atomic coordinates vary across the dataset. + + Such collective modes are valuable for understanding flexibility, identifying functional + motions, and generating simplified representations of structural dynamics. They can also serve + as inputs for subsequent analyses focused on conformational exploration and modeling. + + Practical Recommendations + + For many structural biology applications, Principal Component Analysis provides an excellent + starting point because its results are easy to interpret and often correspond directly to + biologically meaningful motions. It is particularly useful when studying continuous conformational + changes and dominant collective movements. + + UMAP is often advantageous when exploring highly heterogeneous datasets, large molecular + dynamics simulations, or systems expected to contain multiple conformational basins. In these + situations, nonlinear embeddings may reveal relationships that are difficult to observe using + linear approaches alone. + + Regardless of the chosen method, careful inspection of the reduced space is recommended. + Biological interpretation should always be supported by examination of representative + structures from different regions of the embedding to ensure that observed patterns correspond + to meaningful conformational differences. + + Outputs and Interpretation + + The protocol generates a reduced coordinate matrix describing the position of every analyzed + structure within the reduced conformational space. Depending on the selected method, additional + information describing dominant structural motions may also be produced. + + These outputs provide a compact and interpretable representation of structural variability that + can be used for visualization, clustering, classification, conformational landscape analysis, + trajectory exploration, and integration with downstream flexible modeling workflows. + + Final Perspective + + For researchers studying molecular flexibility, dimensionality reduction serves as a bridge + between high-dimensional atomic coordinates and biologically interpretable conformational + landscapes. By condensing complex structural ensembles into a manageable representation, the + protocol enables efficient exploration of molecular motion, facilitates hypothesis generation, + and helps reveal the fundamental patterns governing structural variability. + """ _label = 'pdb dimentionality reduction' + # --------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection(label='Input') - form.addParam('pdbSource', EnumParam, default=0, + form.addParam('pdbSource', EnumParam, default=PDB_SOURCE_SUBTOMO, label='Source of PDBs', - choices=['Used for subtomogram synthesis', 'File pattern'], + choices=['Used for subtomogram synthesis', 'File pattern', 'Object', 'Trajectory Files', 'Align PDBs protocol'], help='Use the file pattern as file location with /*.pdb') form.addParam('pdbs', params.PointerParam, pointerClass='FlexProtSynthesizeSubtomo', - condition='pdbSource == 0', + condition='pdbSource == %i'%PDB_SOURCE_SUBTOMO, label="Subtomogram synthesis", help='Point to a protocol of synthesizing subtomograms, the ground truth PDBs will be used as input') form.addParam('pdbs_file', params.PathParam, - condition='pdbSource == 1', + condition='pdbSource == %i' % PDB_SOURCE_PATTERN, label="List of PDBs", help='Use the file pattern as file location with /*.pdb') - form.addParam('dimredMethod', EnumParam, default=DIMRED_SKLEAN_PCA, - choices=['Principal Component Analysis (PCA)', - 'Local Tangent Space Alignment', - 'Diffusion map', - 'Linear Local Tangent Space Alignment', - 'Linearity Preserving Projection', - 'Kernel PCA', - 'Probabilistic PCA', - 'Laplacian Eigenmap', - 'Hessian Locally Linear Embedding', - 'Stochastic Proximity Embedding', - 'Neighborhood Preserving Embedding', - 'Scikit-Learn PCA', - "Don't reduce dimensions"], - label='Dimensionality reduction method', - help=""" Choose among the following dimensionality reduction methods: - PCA - Principal Component Analysis - LTSA - Local Tangent Space Alignment, k=number of nearest neighbours - DM - Diffusion map, t=Markov random walk, s=kernel sigma - LLTSA - Linear Local Tangent Space Alignment, k=number of nearest neighbours - LPP - Linearity Preserving Projection, k=number of nearest neighbours, s=kernel sigma - kPCA - Kernel PCA, s=kernel sigma - pPCA - Probabilistic PCA, n=number of iterations - LE - Laplacian Eigenmap, k=number of nearest neighbours, s=kernel sigma - HLLE - Hessian Locally Linear Embedding, k=number of nearest neighbours - SPE - Stochastic Proximity Embedding, k=number of nearest neighbours, global embedding or not - NPE - Neighborhood Preserving Embedding, k=number of nearest neighbours - """) - form.addParam('extraParams', params.StringParam, default=None, - expertLevel=params.LEVEL_ADVANCED, - label='Extra params', - help='These parameters are there to change the default parameters of a dimensionality reduction' - ' method. Check xmipp_matrix_dimred for full details.') - - form.addParam('reducedDim', IntParam, default=2, - label='Reduced dimension') - - # form.addParallelSection(threads=0, mpi=8) + form.addParam('setOfPDBs', params.PointerParam, pointerClass='SetOfPDBs, SetOfAtomStructs', + condition='pdbSource == %i' % PDB_SOURCE_OBJECT, + label="Set of PDBs", + help='Use a scipion object SetOfPDBs / SetOfAtomStructs') + form.addParam('dcds_file', params.PathParam, + condition='pdbSource == %i' % PDB_SOURCE_TRAJECT, + label="DCD trajectory file (s)", + help='Use the file pattern as file location with /*.dcd') + form.addParam('dcd_ref_pdb', params.PointerParam, pointerClass='AtomStruct', + condition='pdbSource == %i' % PDB_SOURCE_TRAJECT, + label="trajectory Reference PDB", + help='Reference PDB of the trajectory (Only used for structural information (Atom name, residue number etc)' + '. The coordinates inside this PDB are not used. The atoms number and position in the file must' + ' correspond to the DCD file. ') + form.addParam('dcd_start', params.IntParam, default=0, + condition='pdbSource == %i' % PDB_SOURCE_TRAJECT, + label="Beginning of the trajectory", + help='Index of the desired begining of the trajectory', expertLevel=params.LEVEL_ADVANCED) + form.addParam('dcd_end', params.IntParam, default=-1, + condition='pdbSource == %i' % PDB_SOURCE_TRAJECT, + label="Ending of the trajectory", + help='Index of the desired end of the trajectory', expertLevel=params.LEVEL_ADVANCED) + form.addParam('dcd_step', params.IntParam, default=1, + condition='pdbSource == %i' % PDB_SOURCE_TRAJECT, + label="Step of the trajectory", + help='Step to skip points in the trajectory', expertLevel=params.LEVEL_ADVANCED) + + form.addParam('alignPdbProt', params.PointerParam, pointerClass='FlexProtAlignPdb', + condition='pdbSource == %i' % PDB_SOURCE_ALIGNED, + label="Align PDBs Protocol", + help='Point to a protocol of pdb aligned. For large data set, you can use here the align pdb protocol as input ' + 'and avoid creating an output set of pdb in the align pdb protocol.') + + form.addParam('loadReducedSpace', params.BooleanParam, label="Load an existing reduced space ?", + default=False,help="Skip the analysis and load the pre existing reduced space", expertLevel=params.LEVEL_ADVANCED) + + form.addParam('reducedSpace', params.PathParam, label="Provide a txt file of the existing reduced space", condition="loadReducedSpace", + help="Cloud of point of N dimension constituing a reduced space " + " obtained by any reduction method. The file is a txt file.", expertLevel=params.LEVEL_ADVANCED) + + form.addParam('method', params.EnumParam, label="Reduction method", default=REDUCE_METHOD_PCA, + choices=['PCA', 'UMAP'],help="") + form.addParam('n_neigbors', params.IntParam, label="n_neigbors", condition="method==%i"%REDUCE_METHOD_UMAP, + default=15,help="", expertLevel=params.LEVEL_ADVANCED) + form.addParam('n_epocks', params.IntParam, label="n_epocks", condition="method==%i"%REDUCE_METHOD_UMAP, + default=1000,help="", expertLevel=params.LEVEL_ADVANCED) + form.addParam('metric_rmsd', params.BooleanParam, label="Use RMSD as metric ?", condition="method==%i"%REDUCE_METHOD_UMAP, + default=False,help="", expertLevel=params.LEVEL_ADVANCED) + form.addParam('low_memory', params.BooleanParam, label="low_memory", condition="method==%i"%REDUCE_METHOD_UMAP, + default=False,help="", expertLevel=params.LEVEL_ADVANCED) + form.addParam('reducedDim', IntParam, default=10, + label='Number of Principal Components') # --------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): - pdb_mat = self.getInputPdbs() - reducedDim = self.reducedDim.get() - method = self.dimredMethod.get() - extraParams = self.extraParams.get('') - deformationsFile = self.getDeformationFile() - self._insertFunctionStep('performPDBdimred', - pdb_mat,reducedDim,method,extraParams,deformationsFile) - self._insertFunctionStep('createOutputStep') + self._insertFunctionStep('readInputFiles') + self._insertFunctionStep('performDimred') + if self.method.get() == REDUCE_METHOD_PCA: + self._insertFunctionStep('createOutputStep') # --------------------------- STEPS functions -------------------------------------------- - def performPDBdimred(self,pdb_mat,reducedDim,method,extraParams,deformationsFile): - pdbs_list = [f for f in glob.glob(pdb_mat)] - pdbs_list.sort() - pdbs_matrix = [] - for pdbfn in pdbs_list: - pdb_lines = self.readPDB(pdbfn) - pdb_coordinates = np.array(self.PDB2List(pdb_lines)) - pdbs_matrix.append(np.reshape(pdb_coordinates, -1)) - deformationFile = self._getExtraPath('pdbs_mat.txt') - # The deformationFile is for xmipp methods - np.savetxt(deformationFile, pdbs_matrix, fmt="%s") - - rows, columns = np.shape(pdbs_matrix) - outputMatrix = self.getOutputMatrixFile() - methodName = DIMRED_VALUES[method] - if methodName == 'None': - copyFile(deformationsFile,outputMatrix) - return + def readInputFiles(self): + inputFiles = self.getInputFiles() + + # Get pdbs coordinates + if self.pdbSource.get() == PDB_SOURCE_TRAJECT: + pdbs_arr = dcd2numpyArr(inputFiles[0]) + start = self.dcd_start.get() + step = self.dcd_step.get() + end = self.dcd_end.get() if self.dcd_end.get() != -1 else pdbs_arr.shape[0] + pdbs_arr = pdbs_arr[start:end:step] + for i in range(1,len(inputFiles)): + pdb_arr_i = dcd2numpyArr(inputFiles[i]) + pdbs_arr = np.concatenate((pdbs_arr, pdb_arr_i[start:end:step]), axis=0) + - if methodName == 'sklearn_PCA': - # X = np.loadtxt(fname=deformationsFile) - X = pdbs_matrix - pca = decomposition.PCA(n_components=reducedDim) - pca.fit(X) - Y = pca.transform(X) - np.savetxt(outputMatrix,Y) - M = np.matmul(np.linalg.pinv(X),Y) - mappingFile = self._getExtraPath('projector.txt') - np.savetxt(mappingFile,M) - # save the pca: - pca_pickled = self._getExtraPath('pca_pickled.txt') - dump(pca,pca_pickled) + elif self.pdbSource.get() == PDB_SOURCE_ALIGNED: + pdbs_arr = dcd2numpyArr(inputFiles[0]) else: - args = "-i %(deformationsFile)s -o %(outputMatrix)s -m %(methodName)s %(extraParams)s" - args += "--din %(columns)d --samples %(rows)d --dout %(reducedDim)d" - if method in DIMRED_MAPPINGS: - mappingFile = self._getExtraPath('projector.txt') - args += " --saveMapping %(mappingFile)s" - runProgram("xmipp_matrix_dimred", args % locals()) + pdbs_matrix = [] + for pdbfn in inputFiles: + try: + # Read PDBs + mol = ContinuousFlexPDBHandler(pdbfn) + pdbs_matrix.append(mol.coords) + except RuntimeError: + print("Warning : Can not read PDB file %s " % pdbfn) + pdbs_arr = np.array(pdbs_matrix) + # save as dcd file + numpyArr2dcd(pdbs_arr, self._getExtraPath("coords.dcd")) + + def performDimred(self): + + if self.loadReducedSpace.get(): + copyFile(self.reducedSpace.get(), self.getOutputMatrixFile()) + return + + pdbs_arr = dcd2numpyArr(self._getExtraPath("coords.dcd")) + nframe, natom,_ = pdbs_arr.shape + pdbs_matrix = pdbs_arr.reshape(nframe, natom*3) + + if self.method.get() == REDUCE_METHOD_PCA: + pca = decomposition.PCA(n_components=self.reducedDim.get()) + Y = pca.fit_transform(pdbs_matrix) + dump(pca, self._getExtraPath('pca_pickled.joblib')) + + pathPC = self._getPath("modes") + pdb = ContinuousFlexPDBHandler(self.getPDBRef()) + pdb.coords = pca.mean_.reshape(pdbs_matrix.shape[1] // 3, 3) + pdb.write_pdb(self._getPath("atoms.pdb")) + makePath(pathPC) + matrix = pca.components_.reshape(self.reducedDim.get(),pdbs_matrix.shape[1]//3,3) + self.writePrincipalComponents(prefix=pathPC, matrix = matrix) + np.savetxt(self.getOutputMatrixFile(),Y) + + elif self.method.get() == REDUCE_METHOD_UMAP: + pdbs_dump = self._getTmpPath('pdbs_dump.pkl') + joblib.dump(pdbs_matrix, pdbs_dump) + args = "%d %d %d %s %s %s %i %i" % (self.reducedDim.get(), self.n_neigbors.get(), self.n_epocks.get(), + pdbs_dump, self._getExtraPath('pca_pickled.joblib'), self.getOutputMatrixFile(), int(self.low_memory.get()), + int(self.metric_rmsd.get())) + script_path = continuousflex.__path__[0] + '/protocols/utilities/umap_run.py ' + command = "python " + script_path + args + command = Plugin.getContinuousFlexCmd(command) + check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr, + env=None, cwd=None) - print(pdb_mat) - pass def createOutputStep(self): - pass + # Metadata + mdOut = MetaData() + for i in range(self.reducedDim.get()): + objId = mdOut.addObject() + modefile = self._getPath("modes", "vec.%d" % (i + 1)) + mdOut.setValue(MDL_NMA_MODEFILE, modefile, objId) + mdOut.setValue(MDL_ORDER, i + 1, objId) + mdOut.setValue(MDL_ENABLED, 1, objId) + mdOut.write(self._getPath("modes.xmd")) + + # Sqlite object + pcSet =SetOfNormalModes(filename=self._getPath("modes.sqlite")) + row = XmippMdRow() + for objId in mdOut: + row.readFromMd(mdOut, objId) + pcSet.append(rowToMode(row)) + + pdb = AtomStruct(self._getPath("atoms.pdb")) + self._defineOutputs(outputMean=pdb) + + pcSet.setPdb(pdb) + self._defineOutputs(outputPCA=pcSet) # --------------------------- INFO functions -------------------------------------------- def _summary(self): @@ -193,7 +358,7 @@ def _validate(self): return errors def _citations(self): - return ['harastani2020hybrid','Jin2014'] + return ['harastani2022continuousflex'] def _methods(self): pass @@ -207,33 +372,33 @@ def _printWarnings(self, *lines): print >> fWarn, l fWarn.close() - def getInputPdbs(self): - if self.pdbSource.get()==0: - return self.pdbs.get()._getExtraPath('*.pdb') + def getInputFiles(self): + if self.pdbSource.get()==PDB_SOURCE_SUBTOMO: + l= [f for f in glob.glob(self.pdbs.get()._getExtraPath('*.pdb'))] + elif self.pdbSource.get()==PDB_SOURCE_PATTERN: + l= [f for f in glob.glob(self.pdbs_file.get())] + elif self.pdbSource.get()==PDB_SOURCE_OBJECT: + l= [i.getFileName() for i in self.setOfPDBs.get()] + elif self.pdbSource.get()==PDB_SOURCE_TRAJECT: + l= [f for f in glob.glob(self.dcds_file.get())] + elif self.pdbSource.get()==PDB_SOURCE_ALIGNED: + l=[self.alignPdbProt.get()._getExtraPath("coords.dcd")] + l.sort() + return l + + def getPDBRef(self): + if self.pdbSource.get()==PDB_SOURCE_TRAJECT: + return self.dcd_ref_pdb.get().getFileName() + elif self.pdbSource.get()==PDB_SOURCE_ALIGNED: + return self.alignPdbProt.get()._getExtraPath("reference.pdb") else: - return self.pdbs_file.get() + return self.getInputFiles()[0] def getOutputMatrixFile(self): return self._getExtraPath('output_matrix.txt') - def readPDB(self, fnIn): - with open(fnIn) as f: - lines = f.readlines() - return lines - - def getDeformationFile(self): - return self._getExtraPath('pdbs_mat.txt') - - def PDB2List(self, lines): - newlines = [] - for line in lines: - if line.startswith("ATOM "): - try: - x = float(line[30:38]) - y = float(line[38:46]) - z = float(line[46:54]) - newline = [x, y, z] - newlines.append(newline) - except: - pass - return newlines + def writePrincipalComponents(self, prefix, matrix): + for i in range(self.reducedDim.get()): + with open("%s/vec.%i"%(prefix,i+1), "w") as f: + for j in range(matrix.shape[1]): + f.write(" %e %e %e\n" % (matrix[i,j, 0], matrix[i,j, 1], matrix[i,j, 2])) diff --git a/continuousflex/protocols/protocol_pdb_synthesize.py b/continuousflex/protocols/protocol_pdb_synthesize.py new file mode 100644 index 0000000..ed47857 --- /dev/null +++ b/continuousflex/protocols/protocol_pdb_synthesize.py @@ -0,0 +1,421 @@ +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) +# * Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +import os +import time + +import pwem.emlib.metadata as md +import pyworkflow.protocol.params as params +from pwem.protocols import ProtAnalysis3D +from pyworkflow.protocol.params import NumericRangeParam +from pyworkflow.utils import getListFromRangeString +from pyworkflow.utils import replaceExt +import numpy as np +from math import cos, sin, pi +from pwem.objects import AtomStruct + +from continuousflex.protocols.utilities.pdb_handler import ContinuousFlexPDBHandler + +MODE_RELATION_LINEAR = 0 +MODE_RELATION_3CLUSTERS = 1 +MODE_RELATION_MESH = 2 +MODE_RELATION_RANDOM = 3 +MODE_RELATION_PARABOLA = 4 + + +class FlexProtSynthesizePDBs(ProtAnalysis3D): + """ + Synthesizes ensembles of flexible atomic structures from a reference + model and a set of normal modes. The protocol generates multiple PDB + conformations that represent structural variability along selected + collective motions and can be used as ground-truth data for method + development, validation, simulation, or heterogeneity studies. + + AI Generated: + + Synthesize PDBs (FlexProtSynthesizePDBs) - User Manual + Overview + + The Synthesize PDBs protocol generates collections of atomic + structures that represent different conformational states of a + macromolecule. It uses previously computed normal modes to deform + a reference structure and produce realistic structural variations + that follow biologically meaningful collective motions. The + resulting ensemble can serve as a synthetic representation of + conformational landscapes observed in flexible proteins, molecular + machines, or large biological assemblies. + + For structural biology applications, this protocol is particularly + useful when studying flexibility, benchmarking computational + methods, generating controlled datasets, or exploring how + structural variability may appear in downstream analyses. The + generated structures preserve the overall architecture of the + original model while introducing controlled conformational changes + guided by normal mode analysis. + + Inputs and General Workflow + + The protocol requires a set of normal modes associated with a + molecular structure. These modes describe collective directions of + motion that are often related to biologically relevant + conformational transitions. The user selects which modes will be + used to generate variability and defines how amplitudes along + those modes should be distributed. + + The selected modes determine the deformation space explored by the + generated structures. In many practical applications, a small + number of low-frequency modes is sufficient to capture large-scale + conformational changes. These motions often correspond to domain + movements, opening and closing transitions, or rearrangements that + are difficult to observe using static structures alone. + + Defining Relationships Between Modes + + A key aspect of the protocol is the ability to control the + relationship between mode amplitudes. Different relationships + generate different types of conformational landscapes and can be + chosen according to the biological or methodological objective. + + The Linear relationship generates structures along a coordinated + trajectory where selected modes vary together. This approach is + useful when modeling a single dominant transition between + conformational states or when creating datasets with a simple and + interpretable variability pattern. + + The Three Clusters option creates three well-separated groups of + conformations. This configuration is particularly useful for + testing classification, clustering, and heterogeneity analysis + methods because the resulting structures naturally form discrete + conformational classes. + + The Grid option systematically samples combinations of amplitudes + across two selected modes. The resulting ensemble covers the + deformation space in an organized manner and is useful for + visualizing energy landscapes, evaluating dimensionality reduction + methods, or studying continuous transitions between states. + + The Random option generates conformations with independently + sampled amplitudes. This approach produces broad structural + diversity and is often suitable for benchmarking algorithms under + heterogeneous conditions. + + The Parabolic option constrains the generated conformations to + follow a curved trajectory in deformation space. Such datasets are + valuable when investigating nonlinear conformational variability + and assessing methods designed to capture continuous but + non-Euclidean structural relationships. + + Amplitude Selection and Conformational Diversity + + The amplitude range controls the extent of structural deformation. + Small amplitudes generally produce conformations close to the + reference structure, whereas larger amplitudes generate more + pronounced motions and greater diversity. + + From a biological perspective, excessively large amplitudes may + produce structures that move beyond physically realistic + conformations. Users should therefore choose amplitude ranges that + remain consistent with the expected flexibility of the system under + study. Moderate values are often appropriate when the objective is + to model plausible conformational transitions. + + Number of Generated Structures + + The protocol allows the generation of a user-defined number of + conformations. Larger ensembles provide denser sampling of the + conformational landscape and are often beneficial when producing + benchmark datasets or studying continuous heterogeneity. + + When the Grid relationship is selected, the number of generated + structures is determined by the sampling density of the grid. A + finer grid provides more detailed coverage of the deformation + space but increases storage and computational requirements. + + Reproducibility and Randomization + + The protocol supports both randomized and reproducible generation + strategies. Randomized generation creates different ensembles in + different executions, which is useful for exploring variability + and producing independent datasets. + + Reproducible generation ensures that identical conformations are + created across repeated runs. This capability is particularly + important for benchmarking studies, algorithm comparisons, and + controlled experiments where consistency between datasets must be + maintained. + + Outputs and Their Interpretation + + The primary output is a set of PDB structures representing + different conformational states of the same molecular system. Each + generated structure corresponds to a specific position within the + selected deformation space and can be used independently or as + part of the complete ensemble. + + The generated collection can be employed in downstream workflows + such as volume synthesis, simulation studies, heterogeneity + analysis, machine learning dataset creation, or validation of + reconstruction and classification methods. Because the + conformational coordinates are known, the resulting datasets are + particularly valuable as reference standards for methodological + development. + + Practical Recommendations + + For most biological applications, selecting a small number of + dominant low-frequency modes provides the most interpretable and + realistic conformational variability. Linear or Grid sampling is + often preferred when studying continuous transitions, whereas + Three Clusters is advantageous when evaluating classification + performance. + + Random sampling is useful when broad structural diversity is + desired, while Parabolic sampling can reveal the behavior of + methods under nonlinear variability. Regardless of the chosen + strategy, users should verify that the generated conformations + remain biologically plausible and consistent with known structural + constraints. + + Final Perspective + + For researchers interested in molecular flexibility, this + protocol provides a controlled framework for generating synthetic + conformational ensembles directly from normal mode analysis. By + transforming a static structure into a collection of related + states, it enables systematic investigation of structural + heterogeneity and supports the development and validation of + advanced computational methods for cryo-EM and structural biology. + """ + _label = 'synthesize PDBs' + + # --------------------------- DEFINE param functions -------------------------------------------- + def _defineParams(self, form): + form.addSection('Input') + form.addParam('inputModes', params.PointerParam, + pointerClass='SetOfNormalModes', + label="Normal modes", + help='Set of modes computed by normal mode analysis.') + form.addParam('modeList', NumericRangeParam, + label="Modes selection", + allowsNull=True, + default='7-8', + help='Select the normal modes that will be used for PDB synthesis.' + 'It is usually two modes that should be selected, unless if the relationship is linear or ' + 'random.\n ' + 'You have several ways to specify the modes.\n' + 'Examples:\n' + ' "7,8-10" -> [7,8,9,10]\n' + ' "8, 10, 12" -> [8,10,12]\n' + ' "8 9, 10-12" -> [8,9,10,11,12])\n') + form.addParam('modeRelationChoice', params.EnumParam, default=MODE_RELATION_LINEAR, + choices=['Linear relationship', '3 clusters', 'Grid', 'Random', 'Parabolic'], + label='Relationship between the modes', + help='linear relationship: all the selected modes will have equal amplitudes. \n' + '3 clusters: the volumes will be divided exactly into three classes.\n' + 'Grid: the amplitudes will be in a grid shape (grid size is square of what grid step).\n' + 'Random: all the amplitudes will be random in the given range.\n' + 'Parabolic: The relationship between two modes will resembles an upper half circle.') + form.addParam('centerPoint', params.IntParam, default=100, + condition='modeRelationChoice==%d' % MODE_RELATION_3CLUSTERS, + label='Center point', + help='This number will be used to determine the distance between the clusters' + 'center1 = (-center_point, 0)' + 'center2 = (center_point, 0)' + 'center3 = (0, center_point)') + form.addParam('modesAmplitudeRange', params.IntParam, default=150, + allowsNull=True, + condition='modeRelationChoice != %d' % MODE_RELATION_3CLUSTERS, + label='Amplitude range N --> [-N, N]', + help='Choose the number N for which the generated normal mode amplitudes are in the range of' + ' [-N, N]') + form.addParam('meshRowPoints', params.IntParam, default=6, + allowsNull=True, + condition='modeRelationChoice==%d' % MODE_RELATION_MESH, + label='Grid number of steps', + help='This number will be the number of points in the row and the column (grid shape will be ' + 'size*size)') + form.addParam('numberOfPDBs', params.IntParam, default=36, + label='Number of PDBs', + condition='modeRelationChoice!=%d' % MODE_RELATION_MESH, + help='Number of atomic structures that will be generated') + form.addParam('seedOption', params.BooleanParam, default=True, + expertLevel=params.LEVEL_ADVANCED, + label='Random seed', + help='Keeping it as True means that different runs will generate different PDBs in terms ' + 'of conformations. If you set as False, then different runs will ' + 'have the same conformations and angles ' + '(setting to False allows you to generate the same conformations and orientations with ' + 'different noise values).') + + # form.addParallelSection(threads=0, mpi=8) + # --------------------------- INSERT steps functions -------------------------------------------- + + def _insertAllSteps(self): + if self.seedOption.get(): + np.random.seed(int(time.time())) + else: + np.random.seed(0) + self._insertFunctionStep("generateDeformationsStep") + self._insertFunctionStep("createOutputStep") + + # --------------------------- STEPS functions -------------------------------------------- + def generateDeformationsStep(self): + # Find the right PDB file to use for data synthesis + pdb_name1 = os.path.dirname(self.inputModes.get().getFileName()) + '/atoms.pdb' + pdb_name2 = os.path.dirname(self.inputModes.get().getFileName()) + '/pseudoatoms.pdb' + if os.path.exists(pdb_name1): + fnPDB = pdb_name1 + else: + fnPDB = pdb_name2 + # use the input relationship between the modes to generate normal mode amplitudes metadata + fnModeList = replaceExt(self.inputModes.get().getFileName(), 'xmd') + modeAmplitude = self.modesAmplitudeRange.get() + meshRowPoints = self.meshRowPoints.get() + numberOfModes = self.inputModes.get().getSize() + modeSelection = np.array(getListFromRangeString(self.modeList.get())) + deformationFile = self._getExtraPath('GroundTruth.xmd') + pdbMD = md.MetaData() + # these vairables for alternating the generation when 3 clusters are selected + cluster1 = cluster2 = cluster3 = False + # these variables for the generaton of a mesh if selected + XX, YY = np.meshgrid(np.linspace(start=-modeAmplitude, stop=modeAmplitude, num=meshRowPoints), + np.linspace(start=modeAmplitude, stop=-modeAmplitude, num=meshRowPoints)) + mode7_samples = XX.reshape(-1) + mode8_samples = YY.reshape(-1) + + # iterate over the number of outputs (if mesh, this has to be calculated) + numberOfPDBs = self.getNumberOfPdbs() + def readModes(fnIn): + modesMD = md.MetaData(fnIn) + vectors = [] + for objId in modesMD: + vecFn = modesMD.getValue(md.MDL_NMA_MODEFILE, objId) + vec = np.loadtxt(vecFn) + vectors.append(vec) + return vectors + + pdb = ContinuousFlexPDBHandler(fnPDB) + modes = readModes(fnModeList) + + for i in range(numberOfPDBs): + deformations = np.zeros(numberOfModes) + + if self.modeRelationChoice == MODE_RELATION_LINEAR: + amplitude = self.modesAmplitudeRange.get() + deformations[modeSelection - 1] = np.ones(len(modeSelection)) * np.random.uniform(-amplitude, amplitude) + elif self.modeRelationChoice == MODE_RELATION_3CLUSTERS: + center_point = self.centerPoint.get() + center1 = (-center_point, 0) + center2 = (center_point, 0) + center3 = (0, center_point) + if not (cluster1 or cluster2 or cluster3): + cluster1 = True + if cluster3: + deformations[modeSelection - 1] = center3 + cluster3 = False + if cluster2: + deformations[modeSelection - 1] = center2 + cluster2 = False + cluster3 = True + if cluster1: + deformations[modeSelection - 1] = center1 + cluster1 = False + cluster2 = True + elif self.modeRelationChoice == MODE_RELATION_RANDOM: + amplitude = self.modesAmplitudeRange.get() + deformations[modeSelection - 1] = np.random.uniform(-amplitude, amplitude, len(modeSelection)) + elif self.modeRelationChoice == MODE_RELATION_PARABOLA: + amplitude = self.modesAmplitudeRange.get() + rv = np.random.uniform(0, 1) + point = (amplitude * cos(rv * pi), amplitude * sin(rv * pi)) + deformations[modeSelection - 1] = point + + elif self.modeRelationChoice == MODE_RELATION_MESH: + new_point = (mode7_samples[i], mode8_samples[i]) + deformations[modeSelection - 1] = new_point + + # we won't keep the first 6 modes + deformations = deformations[6:] + + self.nma_deform_pdb(pdb.copy(), modes, self._getExtraPath(str(i + 1).zfill(5) + '_df.pdb'), deformations) + + pdbMD.setValue(md.MDL_IMAGE, self._getExtraPath(str(i + 1).zfill(5) + '_df.pdb'), + pdbMD.addObject()) + pdbMD.setValue(md.MDL_NMA, list(deformations), i + 1) + + pdbMD.write(deformationFile) + + def nma_deform_pdb(self, pdb, modes, fnOut, deformList): + for i in range(len(deformList)): + pdb.coords += deformList[i] * modes[7 - 1 + i] + pdb.write_pdb(fnOut) + + def createOutputStep(self): + pdbset = self._createSetOfPDBs("outputPDBs") + pdbMD = md.MetaData(self._getExtraPath('GroundTruth.xmd')) + for objID in pdbMD: + filename = pdbMD.getValue(md.MDL_IMAGE, objID) + pdb = AtomStruct(filename=filename) + pdbset.append(pdb) + + self._defineOutputs(outputPDBs=pdbset) + + def getNumberOfPdbs(self): + if self.modeRelationChoice.get() is MODE_RELATION_MESH: + numberOfPDBs = self.meshRowPoints.get() ** 2 + else: + numberOfPDBs = self.numberOfPDBs.get() + return numberOfPDBs + + def getInputPdb(self): + """ Return the Pdb object associated with the normal modes. """ + return self.inputModes.get().getPdb() + + # --------------------------- UTILS functions -------------------------------------------- + def _printWarnings(self, *lines): + """ Print some warning lines to 'warnings.xmd', + the function should be called inside the working dir.""" + fWarn = open("warnings.xmd", 'w') + for l in lines: + print >> fWarn, l + fWarn.close() + + def _getLocalModesFn(self): + modesFn = self.inputModes.get().getFileName() + return self._getBasePath(modesFn) + + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['harastani2022continuousflex'] + + def _methods(self): + pass diff --git a/continuousflex/protocols/protocol_structure_mapping.py b/continuousflex/protocols/protocol_structure_mapping.py index 0643780..fdc4190 100644 --- a/continuousflex/protocols/protocol_structure_mapping.py +++ b/continuousflex/protocols/protocol_structure_mapping.py @@ -44,7 +44,7 @@ #from ..pdb.protocol_pseudoatoms_base import XmippProtConvertToPseudoAtomsBase from .protocol_nma_base import FlexProtNMABase, NMA_CUTOFF_REL from pwem.utils import runProgram - +import multiprocessing def mds(d, dimensions = 2): """ @@ -71,12 +71,167 @@ def mds(d, dimensions = 2): class FlexProtStructureMapping(FlexProtConvertToPseudoAtomsBase, FlexProtNMABase): - """ - A quantitive analysis of dissimilarities (distances) among the EM maps - that placing the entire set of density maps in to a common space of - comparison.The approach is based on statistical analysis of distance - among elastically aligned EM maps, and results in visualizing those maps - as points in a lower dimensional distance space. + """ + Performs quantitative structural mapping of multiple EM volumes by measuring + their similarity in a common conformational space. The protocol is designed + to compare a collection of density maps, identify relationships among them, + and represent those relationships in a reduced-dimensionality landscape that + facilitates biological interpretation of structural variability. + + AI Generated: + + Structure Mapping (FlexProtStructureMapping) - User Manual + Overview + + The Structure Mapping protocol provides a framework for exploring + structural diversity within a collection of cryo-EM volumes. Rather + than focusing on a single reconstruction, it analyzes an entire set of + maps and determines how similar or different they are from one another. + The resulting representation places each structure within a common + coordinate space, allowing users to visualize structural relationships, + identify clusters of related conformations, and study continuous + transitions between states. + + This type of analysis is particularly useful when investigating + conformational heterogeneity, functional motions, ligand-induced + structural changes, or variability observed across independent + reconstructions. By converting pairwise structural differences into a + geometric representation, the protocol enables biological interpretation + of complex datasets that would otherwise be difficult to compare + directly. + + Inputs and General Workflow + + The protocol accepts one or more input volumes. These may represent + different conformations of the same macromolecular complex, structures + obtained under different experimental conditions, or reconstructions + originating from distinct processing workflows. + + Each volume is transformed into a pseudoatomic representation suitable + for flexible analysis. Normal mode analysis is then used to describe + the possible collective motions of the structure. Using these motions, + the protocol evaluates how well each volume can be elastically related + to every other volume in the dataset. The resulting measurements are + converted into a matrix of structural dissimilarities that summarizes + the relationships among all inputs. + + The final stage embeds these relationships into a low-dimensional + coordinate system, allowing users to visualize structural organization + in two or three dimensions while preserving the major trends present in + the original dataset. + + Pseudoatomic Representation + + A key aspect of the protocol is the conversion of density maps into + pseudoatomic models. This representation provides a compact and flexible + description of the volume while preserving its overall structural + organization. + + For biological users, pseudoatoms should be viewed as mathematical + elements used to capture the shape and flexibility of the density map. + They are not intended to replace atomic models but rather to provide a + practical framework for studying large-scale motions and structural + relationships. + + Appropriate pseudoatom parameters help balance computational efficiency + and structural fidelity. Very coarse representations may overlook + relevant details, whereas overly dense representations may increase + computational cost without significantly improving biological insight. + + Normal Mode Analysis + + Normal mode analysis is used to characterize collective motions that + can explain structural variability. These motions often correspond to + biologically meaningful movements such as domain rearrangements, + opening and closing transitions, hinge motions, or large-scale + conformational shifts. + + Users can control the number of modes considered and the criteria used + to retain meaningful motions. In practice, low-frequency collective + modes often capture the most relevant biological variability, whereas + higher-frequency modes may describe local fluctuations with less impact + on global structure. + + The quality of the resulting structural map depends strongly on whether + the selected modes adequately represent the conformational space + explored by the dataset. + + Rigid and Elastic Alignment + + Before comparing structures, the protocol may perform a rigid + alignment. This step removes differences caused by orientation, + translation, or small scale variations and ensures that subsequent + comparisons focus on genuine structural differences. + + Following rigid alignment, elastic alignment evaluates how one volume + can deform into another through collective motions. This distinction is + biologically important because many macromolecular systems differ not + only by position or orientation but also by intrinsic conformational + changes. + + For datasets containing closely related structures, rigid alignment may + be sufficient to establish correspondence. For flexible molecular + machines, however, elastic alignment often provides a much more + realistic description of structural relationships. + + Distance Space Interpretation + + The central output of the protocol is a structural distance space in + which each volume is represented as a point. Volumes located close to + one another correspond to similar conformations, whereas distant points + indicate larger structural differences. + + Clusters in the map may reveal discrete structural states, such as + ligand-bound and ligand-free forms, active and inactive conformations, + or distinct assembly intermediates. Continuous trajectories may suggest + gradual conformational transitions or dynamic pathways connecting + different functional states. + + Because the representation is based on structural similarity rather + than experimental metadata, unexpected groupings can reveal previously + unrecognized relationships within the dataset. + + Outputs and Their Interpretation + + The protocol generates distance measurements between all pairs of input + volumes and produces low-dimensional coordinate representations that + can be visualized and analyzed further. These coordinates provide a + simplified view of the structural landscape while preserving the major + patterns of variability. + + The resulting maps can be used for clustering, trajectory analysis, + identification of outliers, and exploration of conformational + continua. They are particularly valuable when studying heterogeneous + cryo-EM datasets where multiple structural states coexist. + + Practical Recommendations + + For meaningful biological interpretation, the input volumes should + represent comparable molecular systems and should be reconstructed at + reasonably similar resolutions. Large differences arising from + experimental artifacts or reconstruction quality may dominate the + analysis and obscure biologically relevant variability. + + It is generally advisable to inspect the resulting structural map in + conjunction with the original volumes. Clusters and trajectories should + be validated by visual examination of the corresponding structures to + confirm that the observed relationships reflect genuine conformational + differences. + + When studying flexible complexes, retaining sufficient collective modes + and enabling alignment procedures usually improves the ability of the + protocol to capture biologically meaningful motions. + + Final Perspective + + Structure mapping transforms a collection of cryo-EM volumes into an + interpretable structural landscape. By combining pseudoatomic + representations, normal mode analysis, flexible alignment, and + dimensionality reduction, it provides a powerful approach for exploring + conformational diversity and understanding the organization of complex + structural datasets. For many biological applications, it serves as an + effective bridge between individual reconstructions and a global view + of molecular variability. """ _label = 'structure mapping' _lastUpdateVersion = VERSION_1_1 @@ -114,7 +269,7 @@ def _defineParams(self, form): FlexProtNMABase._defineParamsCommon(self,form) - form.addParallelSection(threads=4, mpi=1) + form.addParallelSection(threads=multiprocessing.cpu_count()//2-1, mpi=0) #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): @@ -276,29 +431,7 @@ def managingOutputFilesStep(self): cleanPattern(self._getExtraPath('transformation-matrix*')) cleanPattern(self._getExtraPath('modes*')) - #--------------------------- INFO functions -------------------------------------------- - def _validate(self): - errors = [] - for pointer in self.inputVolumes: - if pointer.pointsNone(): - errors.append('Invalid input, pointer: %s' % pointer.getObjValue()) - errors.append(' extended: %s' % pointer.getExtended()) - return errors - - def _summary(self): - summary = [] - nVols = self._getNumberOfInputs() - - if nVols > 0: - summary.append("Volumes to calculate StructMap: *%d* " % nVols) - else: - summary.append("No volumes selected.") - - return summary - - def _citations(self): - return ['Sorzano2016'] - + #--------------------------- UTILS functions -------------------------------------------- def _iterInputVolumes(self): """ Iterate over all the input volumes. """ @@ -329,5 +462,26 @@ def _getNumberOfInputs(self): def _defineResultsName(self,i): return self._getExtraPath('CoordinateMatrix%d.txt'%i) - - + + # --------------------------- INFO functions -------------------------------------------- + def _validate(self): + errors = [] + for pointer in self.inputVolumes: + if pointer.pointsNone(): + errors.append('Invalid input, pointer: %s' % pointer.getObjValue()) + errors.append(' extended: %s' % pointer.getExtended()) + return errors + + def _summary(self): + summary = [] + nVols = self._getNumberOfInputs() + + if nVols > 0: + summary.append("Volumes to calculate StructMap: *%d* " % nVols) + else: + summary.append("No volumes selected.") + + return summary + + def _citations(self): + return ['harastani2022continuousflex', 'Sorzano2016'] diff --git a/continuousflex/protocols/protocol_subtomogram_averaging.py b/continuousflex/protocols/protocol_subtomogram_averaging.py index 459762e..008fd23 100644 --- a/continuousflex/protocols/protocol_subtomogram_averaging.py +++ b/continuousflex/protocols/protocol_subtomogram_averaging.py @@ -1,7 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) -# * Slavica Jonic (slavica.jonic@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -25,13 +24,18 @@ import os from pwem.protocols import ProtAnalysis3D -from xmipp3.convert import writeSetOfVolumes, xmippToLocation, createItemMatrix, setXmippAttributes -import pwem as em +from xmipp3.convert import writeSetOfVolumes, xmippToLocation from pwem.objects import Volume import pwem.emlib.metadata as md import pyworkflow.protocol.params as params from pwem.utils import runProgram from pwem import Domain +from .convert import eulerAngles2matrix, matrix2eulerAngles +import numpy as np +import multiprocessing +from ast import literal_eval as make_tuple +import json +from pwem.emlib.image import ImageHandler WEDGE_MASK_NONE = 0 WEDGE_MASK_THRE = 1 @@ -42,13 +46,189 @@ PERFORM_STA = 0 COPY_STA = 1 +ALIGNED_STA=2 IMPORT_XMIPP_MD = 0 IMPORT_DYNAMO_TBL = 1 IMPORT_TOMBOX_MTV = 2 +IMPORT_EMAN_JSON = 3 + class FlexProtSubtomogramAveraging(ProtAnalysis3D): - """ Protocol for subtomogram averaging. """ + """ + Protocol for subtomogram averaging. This protocol has two modes of operation. + The first is to perform subtomogram averaging using Fast Rotational Matching. + The second mode is to import a previously performed alignment using this protocol, + Dynamo, Artiatomi, TOM Toolbox, EMAN2, or compatible metadata sources in order + to reconstruct a consensus average from existing alignment parameters. + + AI Generated: + + Subtomogram Averaging (FlexProtSubtomogramAveraging) - User Manual + Overview + + The Subtomogram Averaging protocol is designed to generate high-quality + three-dimensional averages from collections of subtomograms obtained in + cryo-electron tomography experiments. Its primary objective is to improve + the signal-to-noise ratio by bringing structurally related particles into + a common orientation and combining them into a representative consensus + structure. This process is a central step in many tomography workflows + because individual subtomograms are often too noisy to allow detailed + structural interpretation on their own. + + The protocol supports both complete averaging workflows and workflows that + begin from previously aligned data. This flexibility allows users to + perform de novo subtomogram averaging within the same environment or to + continue processing results generated by external software packages. + + Inputs and General Workflow + + The protocol requires a collection of subtomograms representing multiple + observations of the same biological object or molecular assembly. All + subtomograms should ideally have consistent dimensions and sampling rates + to ensure meaningful averaging and downstream interpretation. + + Depending on the selected workflow, the protocol either determines the + alignment parameters automatically through iterative refinement or imports + previously calculated orientations and shifts. In both cases, the final + objective is the generation of a consensus average that represents the + common structural features present across the dataset. + + Performing Subtomogram Averaging with Fast Rotational Matching + + In its native averaging mode, the protocol uses Fast Rotational Matching + to iteratively align subtomograms against a reference volume. The process + starts from either an automatically generated reference, an externally + supplied volume, or a volume selected from the current workspace. + + Iterative refinement progressively improves the reference by repeatedly + aligning all particles and recalculating the average. This approach is + particularly useful when the dataset contains substantial noise but the + underlying biological structure is sufficiently consistent across the + particles. As iterations proceed, common structural features become more + pronounced while random noise is reduced. + + The number of refinement cycles determines how extensively the dataset is + optimized. Moderate values are often sufficient for routine analyses, + whereas challenging datasets may benefit from additional iterations. + + Starting References and Their Biological Importance + + The choice of starting reference can strongly influence convergence and + the quality of the final average. Beginning from scratch is often + appropriate when no reliable template exists and allows the protocol to + generate an unbiased initial estimate from the available particles. + + Providing a biologically relevant starting reference may accelerate + convergence and improve robustness, especially when dealing with noisy + datasets. However, users should remain aware of the potential for + reference bias and should always verify that the resulting average is + supported by the experimental data. + + Missing-Wedge Compensation + + A major challenge in cryo-electron tomography is the missing-wedge effect, + which arises from incomplete angular sampling during data acquisition. + This anisotropic loss of information can influence alignment quality and + distort structural interpretation. + + The protocol provides an option to compensate for the missing wedge during + alignment. This compensation is generally beneficial when working with + raw or newly aligned subtomograms because it reduces orientation bias and + improves the consistency of the resulting average. + + In contrast, when alignment parameters have already been generated by + external software or previous processing stages, additional compensation + may not be necessary. Users should select the strategy that best matches + the origin and processing history of their data. + + Masking and Focused Averaging + + The protocol allows the use of a three-dimensional mask during alignment. + From a biological perspective, masking can be one of the most important + factors influencing averaging quality because it determines which regions + contribute most strongly to the alignment process. + + Well-designed masks typically encompass the structurally stable portion of + the particle while excluding surrounding solvent, reconstruction artifacts, + or highly flexible regions. Focusing the alignment on conserved features + often improves convergence and produces averages that better represent the + biologically relevant core of the structure. + + Care should be taken to avoid masks that remove genuine structural + information or artificially constrain the alignment. + + Importing Existing Alignments + + Many tomography projects already contain alignment results generated by + specialized packages. To facilitate interoperability, the protocol can + import previously determined rigid-body transformations from multiple + external sources. + + This capability allows researchers to validate imported alignments, + reconstruct consensus averages, and continue downstream analyses within a + unified workflow. Reproducing a known average from imported parameters is + often a useful verification step before proceeding with refinement, + classification, or heterogeneity studies. + + The imported alignment information is converted into a common framework so + that subsequent processing remains consistent regardless of the original + software used to generate the orientations and shifts. + + Averaging Pre-Aligned Subtomograms + + For datasets that have already been aligned, the protocol can generate a + consensus average directly without performing additional refinement. This + mode is useful when alignment quality has already been validated and the + user simply wishes to obtain an averaged reconstruction. + + Such workflows are common when subtomograms originate from external + pipelines, collaborative projects, or previously completed processing + stages. + + Outputs and Their Interpretation + + The primary output is a subtomogram average representing the common + structural signal present across the input particles. This volume can be + used for visualization, structural interpretation, flexible analysis, + classification, refinement, or integration with other cryo-EM workflows. + + When alignment has been performed or imported, the associated orientation + and translation parameters are preserved as part of the workflow, enabling + reproducibility and further downstream processing. + + The biological quality of the resulting average depends not only on the + number of particles but also on their structural homogeneity. Averaging + particles belonging to different conformational states may blur important + features and obscure meaningful biological variability. + + Practical Recommendations + + For most studies, it is advisable to begin with careful inspection of the + input subtomograms and to ensure that all particles correspond to the same + molecular complex or structural state. Appropriate masking and realistic + missing-wedge settings often provide substantial improvements in alignment + stability and final map quality. + + When a reliable template is available, it can accelerate convergence and + improve robustness. When no trustworthy template exists, starting from an + unbiased average is often preferable. + + Imported alignments should always be validated by examining whether the + reconstructed average is consistent with previously obtained results. + + Final Perspective + + Subtomogram averaging transforms collections of noisy tomographic particles + into biologically interpretable three-dimensional structures. Whether used + for iterative alignment, reconstruction from imported parameters, or direct + averaging of pre-aligned data, the protocol provides a flexible framework + for extracting structural information from cryo-electron tomography + datasets. Careful consideration of reference selection, masking strategy, + missing-wedge treatment, and particle homogeneity is essential for + obtaining reliable and biologically meaningful averages. + """ + _label = 'subtomogram averaging' # --------------------------- DEFINE param functions -------------------------------------------- @@ -62,7 +242,8 @@ def _defineParams(self, form): help='Select volumes') group.addParam('StA_choice', params.EnumParam, choices=['Perform StA using Fast Rotational Matching (FRM)', - 'Import parameters of a previously performed StA'], + 'Import parameters of a previously performed StA', + 'Average a set of aligned subtomograms'], default=PERFORM_STA, label='Choose what processes you want to perform:', display=params.EnumParam.DISPLAY_COMBO, help='If you choose to "Perform StA" using FRM you have to set the parameters in the last tab.' @@ -73,7 +254,8 @@ def _defineParams(self, form): label='From which software?', choices=['Import Scipion/Xmipp metadata', 'Import Dynamo table', - 'Import TOM-ToolBox motive list'], + 'Import TOM-ToolBox motive list', + 'Import EMAN2 JSON file'], default=IMPORT_XMIPP_MD, help='You have to provide a pervious table of rigid-body alignment parameters in one of the list' 'of supported formats. The software will evaluate the average based on the provided file. ' @@ -97,6 +279,12 @@ def _defineParams(self, form): help='import a TOM-toolbox table that contains the STA parameters. This option will evaluate ' 'the average and transform the motive list to Scipion metadata format. and allows you to ' 'perform post-StA processes (refinement and heterogeneity analysis).') + group.addParam('emanJSON', params.PathParam, allowsNull=True, + condition='import_choice==%d' % IMPORT_EMAN_JSON, + label='Import a JSON file from EMAN [Beta]', + help='import a JSON file that contains the STA parameters. This option will evaluate ' + 'the average and transform the JSON file to Scipion metadata format. and allows you to ' + 'perform post-StA processes (refinement and heterogeneity analysis).') group = form.addGroup('Subtomogram Averaging using Fast Rotational Matching (FRM)', condition='StA_choice==%d'% PERFORM_STA) group.addParam('StartingReference', params.EnumParam, @@ -150,7 +338,7 @@ def _defineParams(self, form): line.addParam('frm_maxshift', params.IntParam, default=10, label='Maximum shift search (in pixels)', help='') - form.addParallelSection(threads=0, mpi=5) + form.addParallelSection(threads=0, mpi=multiprocessing.cpu_count()//2-1) # --------------------------- INSERT steps functions -------------------------------------------- @@ -167,8 +355,13 @@ def _insertAllSteps(self): self._insertFunctionStep('adaptDynamoStep', self.dynamoTable.get()) elif self.StA_choice.get() == COPY_STA and self.import_choice.get() == IMPORT_TOMBOX_MTV: self._insertFunctionStep('adaptTomboxStep', self.tomBoxTable.get()) - else: + elif self.StA_choice.get() == COPY_STA and self.import_choice.get() == IMPORT_EMAN_JSON: + self._insertFunctionStep('adaptEmanStep', self.emanJSON.get()) + elif self.StA_choice.get() == COPY_STA and self.import_choice.get() == IMPORT_XMIPP_MD: self._insertFunctionStep('adaptXmippStep', self.xmippMD.get()) + elif self.StA_choice.get() == ALIGNED_STA: + self._insertFunctionStep('averagingStep') + self._insertFunctionStep('createOutputStep') # --------------------------- STEPS functions -------------------------------------------- @@ -239,9 +432,32 @@ def doAlignmentStep(self): env = Domain.importFromPlugin('xmipp3').Plugin.getEnviron()) # By now, the alignment is done, the averaging should take place + # However, if the alignemnt has missing wedge compensation, we shall update the metadata: + if self.WedgeMode == WEDGE_MASK_THRE: + mdImgs = md.MetaData(md_itr) + for objId in mdImgs: + rot = mdImgs.getValue(md.MDL_ANGLE_ROT, objId) + tilt = mdImgs.getValue(md.MDL_ANGLE_TILT, objId) + psi = mdImgs.getValue(md.MDL_ANGLE_PSI, objId) + x = mdImgs.getValue(md.MDL_SHIFT_X, objId) + y = mdImgs.getValue(md.MDL_SHIFT_Y, objId) + z = mdImgs.getValue(md.MDL_SHIFT_Z, objId) + T = eulerAngles2matrix(rot, tilt, psi, x, y, z) + # Rotate 90 degrees (compensation for missing wedge) + T0 = eulerAngles2matrix(0, 90, 0, 0, 0, 0) + T = np.linalg.inv(np.matmul(T, T0)) + rot, tilt, psi, x, y, z = matrix2eulerAngles(T) + mdImgs.setValue(md.MDL_ANGLE_ROT, rot, objId) + mdImgs.setValue(md.MDL_ANGLE_TILT, tilt, objId) + mdImgs.setValue(md.MDL_ANGLE_PSI, psi, objId) + mdImgs.setValue(md.MDL_SHIFT_X, x, objId) + mdImgs.setValue(md.MDL_SHIFT_Y, y, objId) + mdImgs.setValue(md.MDL_SHIFT_Z, z, objId) + mdImgs.setValue(md.MDL_ANGLE_Y, 0.0, objId) + mdImgs.write(md_itr) + mdImgs = md.MetaData(md_itr) counter = 0 - first = True for objId in mdImgs: counter = counter + 1 @@ -255,28 +471,11 @@ def doAlignmentStep(self): y_shift = mdImgs.getValue(md.MDL_SHIFT_Y, objId) z_shift = mdImgs.getValue(md.MDL_SHIFT_Z, objId) - flip = mdImgs.getValue(md.MDL_ANGLE_Y, objId) tempVol = self._getExtraPath('temp.mrc') extra = self._getExtraPath() - if flip == 0: - if first: - print("THERE IS NO COMPENSATION FOR THE MISSING WEDGE") - first = False - - params = '-i %(imgPath)s -o %(tempVol)s --inverse --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ - ' --shift %(x_shift)s %(y_shift)s %(z_shift)s -v 0' % locals() - - else: - if first: - print("THERE IS A COMPENSATION FOR THE MISSING WEDGE") - first = False - # First got to rotate each volume 90 degrees about the y axis, align it, then rotate back and sum it - params = '-i %(imgPath)s -o %(tempVol)s --rotate_volume euler 0 90 0' % locals() - runProgram('xmipp_transform_geometry', params) - params = '-i %(tempVol)s -o %(tempVol)s --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ - ' --shift %(x_shift)s %(y_shift)s %(z_shift)s ' % locals() - + params = '-i %(imgPath)s -o %(tempVol)s --inverse --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ + ' --shift %(x_shift)s %(y_shift)s %(z_shift)s -v 0' % locals() runProgram('xmipp_transform_geometry', params) if counter == 1: @@ -296,13 +495,9 @@ def doAlignmentStep(self): outputMD = self.outputMD os.system("cp %(avr_itr)s %(outputVolume)s " % locals()) os.system("cp %(md_itr)s %(outputMD)s " % locals()) - # Averaging is done - - inputSet = md.MetaData(self.imgsFn) mdImgs = md.MetaData(self.outputMD) - # setting item_id (lost due to mpi usually) for objId in mdImgs: imgPath = mdImgs.getValue(md.MDL_IMAGE, objId) @@ -313,11 +508,11 @@ def doAlignmentStep(self): if (NewImgPath == imgPath): target_ID = inputSet.getValue(md.MDL_ITEM_ID, objId2) break - mdImgs.setValue(md.MDL_ITEM_ID, target_ID, objId) - + mdImgs.sort(md.MDL_ITEM_ID) mdImgs.write(self.outputMD) + def adaptDynamoStep(self, dynamoTable): volumes_in = self.imgsFn volume_out = self.outputVolume @@ -325,8 +520,6 @@ def adaptDynamoStep(self, dynamoTable): from continuousflex.protocols.utilities.dynamo import tbl2metadata tbl2metadata(dynamoTable, volumes_in, md_out) - - ### here: mdImgs = md.MetaData(md_out) counter = 0 first = True @@ -338,32 +531,20 @@ def adaptDynamoStep(self, dynamoTable): rot = mdImgs.getValue(md.MDL_ANGLE_ROT, objId) tilt = mdImgs.getValue(md.MDL_ANGLE_TILT, objId) psi = mdImgs.getValue(md.MDL_ANGLE_PSI, objId) - x_shift = mdImgs.getValue(md.MDL_SHIFT_X, objId) y_shift = mdImgs.getValue(md.MDL_SHIFT_Y, objId) z_shift = mdImgs.getValue(md.MDL_SHIFT_Z, objId) - flip = mdImgs.getValue(md.MDL_ANGLE_Y, objId) tempVol = self._getExtraPath('temp.mrc') extra = self._getExtraPath() - if flip == 0: - if first: - print("Averaging based on Dynamo parameters") - first = False - params = '-i %(imgPath)s -o %(tempVol)s --inverse --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ - ' --shift %(x_shift)s %(y_shift)s %(z_shift)s -v 0' % locals() + if first: + print("Averaging based on Dynamo parameters") + first = False - else: - if first: - print("THERE IS A COMPENSATION FOR THE MISSING WEDGE") - first = False - # First got to rotate each volume 90 degrees about the y axis, align it, then rotate back and sum it - params = '-i %(imgPath)s -o %(tempVol)s --rotate_volume euler 0 90 0' % locals() - runProgram('xmipp_transform_geometry', params) - params = '-i %(tempVol)s -o %(tempVol)s --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ - ' --shift %(x_shift)s %(y_shift)s %(z_shift)s ' % locals() + params = '-i %(imgPath)s -o %(tempVol)s --inverse --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ + ' --shift %(x_shift)s %(y_shift)s %(z_shift)s -v 0' % locals() runProgram('xmipp_transform_geometry', params) @@ -377,9 +558,7 @@ def adaptDynamoStep(self, dynamoTable): params = '-i %(volume_out)s --divide %(counter)s -o %(volume_out)s ' % locals() runProgram('xmipp_image_operate', params) os.system("rm -f %(tempVol)s" % locals()) - # Averaging is done - pass def adaptTomboxStep(self, Table): volumes_in = self.imgsFn @@ -404,7 +583,6 @@ def adaptTomboxStep(self, Table): y_shift = mdImgs.getValue(md.MDL_SHIFT_Y, objId) z_shift = mdImgs.getValue(md.MDL_SHIFT_Z, objId) - flip = mdImgs.getValue(md.MDL_ANGLE_Y, objId) tempVol = self._getExtraPath('temp.mrc') extra = self._getExtraPath() @@ -426,6 +604,7 @@ def adaptTomboxStep(self, Table): # Averaging is done pass + def adaptXmippStep(self, Table): volumes_in = self.imgsFn volume_out = self.outputVolume @@ -433,6 +612,36 @@ def adaptXmippStep(self, Table): # Averaging based on the metadata: mdImgs = md.MetaData(md_out) + + # if the volumes were aligned with angle_y=90 degrees, then rotate by 90 and inverse, then set angle y to 0 + flag = None + try: + flag = mdImgs.getValue(md.MDL_ANGLE_Y, 1) + except: + pass + + if flag == 90: + mdImgs = md.MetaData(self.imgsFn) + for objId in mdImgs: + rot = mdImgs.getValue(md.MDL_ANGLE_ROT, objId) + tilt = mdImgs.getValue(md.MDL_ANGLE_TILT, objId) + psi = mdImgs.getValue(md.MDL_ANGLE_PSI, objId) + x = mdImgs.getValue(md.MDL_SHIFT_X, objId) + y = mdImgs.getValue(md.MDL_SHIFT_Y, objId) + z = mdImgs.getValue(md.MDL_SHIFT_Z, objId) + T = eulerAngles2matrix(rot, tilt, psi, x, y, z) + # Rotate 90 degrees (compensation for missing wedge) + T0 = eulerAngles2matrix(0, 90, 0, 0, 0, 0) + T = np.linalg.inv(np.matmul(T, T0)) + rot, tilt, psi, x, y, z = matrix2eulerAngles(T) + mdImgs.setValue(md.MDL_ANGLE_ROT, rot, objId) + mdImgs.setValue(md.MDL_ANGLE_TILT, tilt, objId) + mdImgs.setValue(md.MDL_ANGLE_PSI, psi, objId) + mdImgs.setValue(md.MDL_SHIFT_X, x, objId) + mdImgs.setValue(md.MDL_SHIFT_Y, y, objId) + mdImgs.setValue(md.MDL_SHIFT_Z, z, objId) + mdImgs.setValue(md.MDL_ANGLE_Y, 0.0, objId) + mdImgs.write(self._getExtraPath('final_md.xmd')) counter = 0 @@ -448,20 +657,92 @@ def adaptXmippStep(self, Table): y_shift = mdImgs.getValue(md.MDL_SHIFT_Y, objId) z_shift = mdImgs.getValue(md.MDL_SHIFT_Z, objId) - flip = mdImgs.getValue(md.MDL_ANGLE_Y, objId) tempVol = self._getExtraPath('temp.mrc') extra = self._getExtraPath() - if flip == 0 or flip is None: - params = '-i %(imgPath)s -o %(tempVol)s --inverse --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ - ' --shift %(x_shift)s %(y_shift)s %(z_shift)s' % locals() + params = '-i %(imgPath)s -o %(tempVol)s --inverse --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ + ' --shift %(x_shift)s %(y_shift)s %(z_shift)s' % locals() + + runProgram('xmipp_transform_geometry', params) + + if counter == 1: + os.system("cp %(tempVol)s %(volume_out)s" % locals()) + else: - # First got to rotate each volume 90 degrees about the y axis, align it, then sum it - params = '-i %(imgPath)s -o %(tempVol)s --rotate_volume euler 0 90 0' % locals() - runProgram('xmipp_transform_geometry', params) - params = '-i %(tempVol)s -o %(tempVol)s --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ - ' --shift %(x_shift)s %(y_shift)s %(z_shift)s ' % locals() + params = '-i %(tempVol)s --plus %(volume_out)s -o %(volume_out)s ' % locals() + runProgram('xmipp_image_operate', params) + + params = '-i %(volume_out)s --divide %(counter)s -o %(volume_out)s ' % locals() + runProgram('xmipp_image_operate', params) + os.system("rm -f %(tempVol)s" % locals()) + + def adaptEmanStep(self, Table): + volumes_in = self.imgsFn + volume_out = self.outputVolume + mdImgs = md.MetaData() + + with open(Table, "r") as f: + jf = json.load(f) + n_data = len(jf) + + index = [] + fname = [] + matrices = [] + for i in jf: + fname_i, index_i = make_tuple(i) + index.append(index_i) + fname.append(fname_i) + mat = np.array(json.loads(jf[i]["xform.align3d"]["matrix"]), dtype=np.float64).reshape(3, 4) + matrices.append(matrix2eulerAngles(mat)) + matrices = np.array(matrices) + + for i in range(n_data): + fileext = os.path.splitext(fname[i])[1] + if fileext == ".lst": + with open(fname[i], "r") as f: + for line in f: + if not line.startswith('#'): + spl = line.split() + if int(spl[0]) == index[i]: + fname[i] = spl[1] + break + elif fileext == ".hdf" or fileext == ".mrc"or fileext == ".mrcs"or fileext == ".vol"or fileext == ".spi": + pass + else: + raise RuntimeError("Unkown file type for subtomograms") + + for i in range(n_data): + objId = mdImgs.addObject() + mdImgs.setValue(md.MDL_IMAGE, "%s@%s" % (str(index[i] + 1).zfill(6), fname[i]), objId) + mdImgs.setValue(md.MDL_ANGLE_ROT, matrices[i,0],objId) + mdImgs.setValue(md.MDL_ANGLE_TILT,matrices[i,1], objId) + mdImgs.setValue(md.MDL_ANGLE_PSI, matrices[i,2],objId) + mdImgs.setValue(md.MDL_SHIFT_X, matrices[i,3],objId) + mdImgs.setValue(md.MDL_SHIFT_Y, matrices[i,4],objId) + mdImgs.setValue(md.MDL_SHIFT_Z, matrices[i,5],objId) + mdImgs.setValue(md.MDL_ITEM_ID, int(index[i] + 1),objId) + + # Averaging based on the metadata: + mdImgs.write(self._getExtraPath('final_md.xmd')) + counter = 0 + + for objId in mdImgs: + counter = counter + 1 + imgPath = mdImgs.getValue(md.MDL_IMAGE, objId) + rot = mdImgs.getValue(md.MDL_ANGLE_ROT, objId) + tilt = mdImgs.getValue(md.MDL_ANGLE_TILT, objId) + psi = mdImgs.getValue(md.MDL_ANGLE_PSI, objId) + + x_shift = mdImgs.getValue(md.MDL_SHIFT_X, objId) + y_shift = mdImgs.getValue(md.MDL_SHIFT_Y, objId) + z_shift = mdImgs.getValue(md.MDL_SHIFT_Z, objId) + + tempVol = self._getExtraPath('temp.mrc') + extra = self._getExtraPath() + + params = '-i %(imgPath)s -o %(tempVol)s --rotate_volume euler %(rot)s %(tilt)s %(psi)s' \ + ' --shift %(x_shift)s %(y_shift)s %(z_shift)s' % locals() runProgram('xmipp_transform_geometry', params) @@ -475,24 +756,20 @@ def adaptXmippStep(self, Table): params = '-i %(volume_out)s --divide %(counter)s -o %(volume_out)s ' % locals() runProgram('xmipp_image_operate', params) os.system("rm -f %(tempVol)s" % locals()) - # Averaging is done - pass + + + + def averagingStep(self): + classAvg = ImageHandler().computeAverage(self.inputVolumes.get()) + classAvg.write(self.outputVolume) def createOutputStep(self): - # TODO: this is not needed any more, if no issue is reported then deleted it inputSet = self.inputVolumes.get() - # partSet = self._createSetOfVolumes() - # partSet.copyInfo(inputSet) - # partSet.setAlignmentProj() - # partSet.copyItems(inputSet, - # updateItemCallback=self._updateParticle, - # itemDataIterator=md.iterRows(self.imgsFn, sortByLabel=md.MDL_ITEM_ID)) outvolume = Volume() outvolume.setSamplingRate(inputSet.getSamplingRate()) outvolume.setFileName(self.outputVolume) self._defineOutputs(SubtomogramAverage=outvolume) - # self._defineOutputs(outputParticles=partSet, outputvolume=outvolume) - # self._defineTransformRelation(self.inputVolumes, partSet) + # --------------------------- INFO functions -------------------------------------------- def _summary(self): @@ -500,21 +777,7 @@ def _summary(self): return summary def _citations(self): - return [] + return ['harastani2022continuousflex','CHEN2013235'] def _methods(self): pass - - # --------------------------- UTILS functions -------------------------------------------- - def _printWarnings(self, *lines): - """ Print some warning lines to 'warnings.xmd', - the function should be called inside the working dir.""" - fWarn = open("warnings.xmd", 'w') - for l in lines: - print >> fWarn, l - fWarn.close() - - def _updateParticle(self, item, row): - setXmippAttributes(item, row, md.MDL_ANGLE_ROT, md.MDL_ANGLE_TILT, md.MDL_ANGLE_PSI, md.MDL_SHIFT_X, - md.MDL_SHIFT_Y, md.MDL_SHIFT_Z, md.MDL_MAXCC, md.MDL_ANGLE_Y) - createItemMatrix(item, row, align=em.ALIGN_PROJ) diff --git a/continuousflex/protocols/protocol_subtomograms_classify.py b/continuousflex/protocols/protocol_subtomograms_classify.py index 41f4076..ac70499 100644 --- a/continuousflex/protocols/protocol_subtomograms_classify.py +++ b/continuousflex/protocols/protocol_subtomograms_classify.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Author: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Author: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * IMPMC, UPMC Sorbonne University # * # * This program is free software; you can redistribute it and/or modify @@ -20,14 +20,12 @@ # * All comments concerning this program package may be sent to the # * e-mail address 'scipion@cnb.csic.es' # ************************************************************************** + from pyworkflow.object import String from pyworkflow.protocol.params import (PointerParam, EnumParam, IntParam) from pwem.protocols import ProtAnalysis3D -from pwem.convert import cifToPdb from pyworkflow.utils.path import makePath, copyFile, removeBaseExt from pyworkflow.protocol import params - -from .protocol_subtomogram_averaging import FlexProtSubtomogramAveraging from sklearn.cluster import AgglomerativeClustering, KMeans import time import os @@ -35,18 +33,136 @@ import pwem.emlib.metadata as md from continuousflex.protocols.utilities.spider_files3 import save_volume, open_volume import xmipp3 - from pwem.objects import Volume import numpy as np -import glob from sklearn import decomposition from joblib import dump, load from pwem.utils import runProgram - class FlexProtSubtomoClassify(ProtAnalysis3D): - """ Protocol applying post alignment classification on subtomograms. """ + """ + Performs post-alignment classification of subtomograms in order to identify structurally related groups within a heterogeneous dataset. The protocol is designed to analyze subtomograms that originate either from subtomogram synthesis workflows or from subtomogram averaging procedures, allowing researchers to organize particles into distinct classes based on their structural similarity. By separating heterogeneous populations into more homogeneous subsets, the protocol facilitates the study of conformational variability, structural states, and compositional differences that may be present within tomographic datasets. + + AI Generated: + + Classify Subtomograms (FlexProtSubtomoClassify) - User Manual + + Overview + + The Classify Subtomograms protocol groups aligned subtomograms into a user-defined number of structural classes. + Its primary objective is to reveal biologically meaningful variability within a dataset by identifying particles + that share similar structural characteristics. This classification step is often performed after subtomogram + synthesis or subtomogram averaging and can serve as an important stage for studying molecular flexibility, + conformational landscapes, or sample heterogeneity. + + In practical biological applications, classification helps distinguish different structural states of a macromolecule, + separate distinct assemblies present in the same sample, or identify rare conformations that may otherwise be + obscured when all particles are analyzed together. The resulting class averages often provide a clearer + representation of underlying structural differences than a single global average. + + Inputs and Data Sources + + The protocol can operate on subtomograms generated from synthetic datasets or on subtomograms obtained from + previous subtomogram averaging workflows. The selected source determines the metadata, geometric information, + and acquisition parameters used throughout the analysis. + + Regardless of the source, the protocol assumes that subtomograms correspond to the same biological object or + assembly and that they are suitable for direct structural comparison. Consistency in box size, sampling rate, + and overall particle content is important for obtaining meaningful classification results. + + Alignment Preparation and Missing-Wedge Compensation + + Before classification, subtomograms are brought into a common reference frame using previously determined + alignment parameters. This step ensures that structural differences detected during classification are more + likely to reflect genuine biological variability rather than orientation differences. + + Tomographic data are affected by the missing-wedge artifact, which introduces anisotropic information loss. + The protocol incorporates missing-wedge information during similarity estimation so that comparisons between + particles are less influenced by acquisition geometry and more representative of true structural differences. + + Masking Options + + An optional mask can be applied before similarity estimation. From a biological perspective, masking is often + one of the most influential choices because it determines which regions contribute most strongly to the + classification. + + A well-designed mask typically focuses on the structurally conserved region of interest while excluding + background noise, solvent regions, or highly variable peripheral features that may dominate similarity + measurements. In many cases, masks derived from a subtomogram average provide the most reliable results. + + Care should be taken to avoid overly restrictive masks that remove biologically relevant regions or masks that + crop portions of the structure. Both situations may reduce the quality of the resulting classification. + + Similarity Analysis + + The protocol estimates pairwise structural similarity between all aligned subtomograms and builds a similarity + matrix representing relationships across the dataset. This matrix serves as the foundation for subsequent + classification. + + Biologically, particles that share similar structural features produce stronger similarity values, whereas + particles representing different conformations, assemblies, or states tend to exhibit lower similarity. + Consequently, the resulting classification reflects the structural organization of the dataset. + + Classification Strategies + + Two classification approaches are available. + + Hierarchical clustering directly partitions particles into classes based on their pairwise relationships. + This approach is particularly useful when users wish to explore the organization of the dataset without + imposing strong assumptions about the underlying structure of the data. Hierarchical methods often provide + intuitive separation of major conformational groups. + + Alternatively, the protocol can first reduce the dimensionality of the similarity information and then perform + clustering. This strategy is often advantageous for larger datasets because it captures the dominant sources of + variability while reducing noise and redundancy. It can help reveal major structural trends that characterize + the population. + + Number of Classes + + Users define the desired number of output classes. This parameter directly affects the granularity of the + classification. + + A small number of classes is generally appropriate when only broad structural differences are expected. + Increasing the number of classes may reveal finer conformational distinctions, although excessive subdivision + can produce classes that contain too few particles to support meaningful biological interpretation. + + In exploratory studies, testing several class counts is often useful for identifying a biologically meaningful + level of heterogeneity. + + Outputs and Interpretation + + The protocol generates a collection of class averages representing the mean structure of each identified group. + These averages provide an accessible way to inspect structural variability across the dataset and often serve + as starting points for additional analysis or refinement. + + Individual subtomograms are also assigned to their corresponding classes, allowing users to examine class + composition and investigate the distribution of structural states within the sample. + + In addition to the class averages, a global average is produced from all aligned subtomograms. This volume + represents the overall consensus structure of the dataset and can be used as a reference for comparing class- + specific features. + + Practical Recommendations + + For most biological studies, it is beneficial to ensure that subtomograms are accurately aligned before + classification. Misalignment can artificially increase variability and reduce class quality. + + When heterogeneity is expected to be localized within a specific region of the structure, applying a carefully + designed mask can substantially improve class separation. Conversely, when the goal is to identify global + structural differences, broader masks or unmasked analyses may be more appropriate. + + The number of classes should be selected according to the biological question. Broad state identification often + requires only a few classes, whereas detailed conformational studies may benefit from a larger partitioning of + the dataset. + + Final Perspective + + Subtomogram classification is a powerful tool for transforming a heterogeneous collection of particles into an + organized representation of structural variability. By combining alignment information, missing-wedge-aware + similarity estimation, and clustering methods, the protocol enables researchers to identify distinct structural + populations and better understand the biological diversity present within tomographic datasets. + """ _label = 'classify subtomograms' # --------------------------- DEFINE param functions -------------------------------------------- @@ -359,7 +475,7 @@ def _validate(self): return errors def _citations(self): - return ['harastani2020hybrid','Jin2014'] + return ['harastani2022continuousflex'] def _methods(self): pass diff --git a/continuousflex/protocols/protocol_subtomogrmas_synthesize.py b/continuousflex/protocols/protocol_subtomograms_synthesize.py similarity index 80% rename from continuousflex/protocols/protocol_subtomogrmas_synthesize.py rename to continuousflex/protocols/protocol_subtomograms_synthesize.py index b1f6249..aabf81f 100644 --- a/continuousflex/protocols/protocol_subtomogrmas_synthesize.py +++ b/continuousflex/protocols/protocol_subtomograms_synthesize.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Rémi Vuillemot (remi.vuillemot@upmc.fr) # * IMPMC, UPMC Sorbonne University # * @@ -48,6 +48,7 @@ import glob from joblib import dump from math import cos, sin, pi +from continuousflex.protocols.convert import matrix2eulerAngles NMA_ALIGNMENT_WAV = 0 @@ -84,7 +85,162 @@ ROTATION_GAUSS = 1 class FlexProtSynthesizeSubtomo(ProtAnalysis3D): - """ Protocol for synthesizing subtomograms. """ + """ + Synthesizes realistic subtomogram datasets for cryo-electron tomography studies by generating + molecular volumes, simulating structural variability, and reproducing common imaging and + acquisition effects. The protocol is intended for benchmarking, method validation, algorithm + development, and training workflows where controlled ground-truth subtomograms are required. + + AI Generated: + + Synthesize Subtomograms (FlexProtSynthesizeSubtomo) - User Manual + + Overview + + This protocol generates synthetic subtomograms that mimic the appearance and variability + observed in cryo-electron tomography experiments. It can create datasets from atomic + structures, existing density maps, normal mode analysis models, or collections of + heterogeneous structures. The resulting subtomograms can contain conformational variability, + rigid-body variability, missing wedge effects, imaging distortions, and reconstruction + artifacts similar to those encountered in real experimental data. + + For biological users, the protocol provides a controlled environment for studying molecular + flexibility, testing classification and reconstruction methods, evaluating machine learning + approaches, and validating analysis pipelines. Because the true underlying conformations are + known, the generated datasets are particularly useful for benchmarking algorithms designed + to recover structural heterogeneity. + + Inputs and Structural Variability + + The protocol can operate either with conformational variability enabled or disabled. When + variability is disabled, a single atomic structure or electron microscopy volume serves as + the source for all generated particles. This mode is useful for evaluating the influence of + imaging artifacts, noise, or orientation variability without introducing structural changes. + + When conformational variability is enabled, the protocol can generate multiple structural + states from normal mode analysis or from a collection of user-provided structures. Normal + mode based generation is particularly useful when exploring continuous motions and flexible + transitions that are difficult to sample experimentally. Alternatively, users may provide a + set of heterogeneous structures, such as molecular dynamics snapshots, experimentally + derived models, or representative conformations from structural studies. + + Conformational Sampling Strategies + + Several strategies are available to distribute conformations across the selected motion + space. Linear sampling produces coordinated changes across the selected modes and is useful + when modeling gradual transitions between states. Clustered sampling generates distinct + groups of conformations and is appropriate when investigating classification methods or + discrete structural populations. + + Grid sampling systematically explores the conformational landscape and is often used when a + dense representation of a two-dimensional motion space is desired. Random sampling produces + heterogeneous distributions that resemble naturally occurring variability. The upper-half + circle strategy generates conformations constrained along a curved trajectory and may be + useful when modeling specific relationships between flexible motions. + + Volume Generation + + Atomic models are converted into volumetric representations using user-defined sampling + rates and volume dimensions. This allows the synthetic data to approximate experimental + maps at different voxel sizes and box dimensions. The protocol supports both compact + benchmark datasets and larger simulation studies intended to reproduce realistic tomographic + conditions. + + Optional low-pass filtering can be applied before projection. This introduces additional + loss of high-resolution information and can mimic the effects of radiation damage, dose + accumulation, or limited experimental resolution. In many situations, however, the + contrast transfer function already introduces similar attenuation effects. + + Missing Wedge Simulation + + One of the most important characteristics of cryo-electron tomography data is the missing + wedge artifact caused by incomplete angular coverage during tilt-series acquisition. The + protocol allows realistic simulation of this effect by defining the lower and upper tilt + limits together with the angular sampling interval. + + When missing wedge simulation is disabled, a complete angular range is used. Although this + produces more isotropic reconstructions, it does not accurately represent typical + experimental conditions. Users interested in developing or validating tomographic analysis + methods should generally include realistic tilt limitations. + + Noise and Microscope Effects + + The protocol can simulate imaging conditions by applying contrast transfer function effects + and controlled levels of noise. Users may specify microscope parameters such as voltage, + spherical aberration, magnification, defocus, and additional imaging characteristics. + + The signal-to-noise ratio controls the severity of noise contamination. Lower values + generate more challenging datasets that resemble difficult experimental conditions, whereas + higher values produce cleaner reconstructions suitable for algorithm development and initial + testing. The resulting datasets can therefore span a broad range of experimental scenarios. + + Reconstruction Workflow + + Synthetic volumes are projected into tilt series and reconstructed into subtomograms using + tomographic reconstruction methods. This reproduces the complete imaging pipeline rather + than generating idealized volumes directly. As a result, the final outputs contain many of + the distortions introduced during acquisition and reconstruction. + + Different reconstruction approaches can be selected depending on the intended application. + The generated subtomograms therefore provide a realistic testing environment for methods + operating on reconstructed tomographic data. + + Rigid-Body Variability + + In addition to conformational variability, the protocol can introduce random rotations and + translations. These transformations mimic the natural distribution of particle positions + and orientations observed in biological specimens. + + Users may define either uniform or Gaussian distributions for each translational and + rotational degree of freedom. This flexibility allows simulation of both broadly + distributed particles and datasets with preferred orientations or constrained positional + variability. Such control is valuable when evaluating alignment, classification, and pose + estimation methods. + + Full Tomogram Generation + + Beyond isolated subtomograms, the protocol can assemble particles into complete synthetic + tomograms. Individual molecular volumes are distributed throughout larger three-dimensional + volumes while avoiding excessive overlap between neighboring particles. + + This mode is especially useful for testing particle picking, localization, segmentation, + and subtomogram extraction workflows. Multiple tomograms can be generated simultaneously, + enabling the creation of realistic datasets suitable for large-scale method development and + benchmarking. + + Outputs and Interpretation + + The primary output is a set of reconstructed subtomograms together with metadata describing + the generated structures and acquisition parameters. Depending on the selected options, + metadata may include conformational states, deformation information, rotational parameters, + translational offsets, and imaging conditions. + + Because the underlying ground truth is known, users can directly compare algorithmic + predictions against the simulated reality. This makes the protocol particularly valuable + for quantitative evaluation of methods designed to recover structural heterogeneity, + orientation parameters, particle positions, or tomographic reconstructions. + + Practical Recommendations + + For studies focused on conformational analysis, normal mode based generation combined with + realistic noise and missing wedge effects provides a useful approximation of experimental + datasets. For benchmarking classification algorithms, clustered conformational sampling is + often advantageous because the expected classes are known in advance. + + When evaluating alignment or reconstruction methods, introducing realistic rigid-body + variability and imaging distortions creates more representative testing conditions. For + particle detection and extraction workflows, generating complete tomograms generally offers + the most biologically relevant benchmark scenario. + + Final Perspective + + This protocol serves as a comprehensive framework for generating synthetic cryo-electron + tomography data with controllable biological variability and experimental realism. By + combining structural heterogeneity, imaging physics, reconstruction artifacts, and + tomographic acquisition effects, it provides a powerful resource for developing, + validating, and comparing computational methods across a wide range of cryo-ET + applications. + """ _label = 'synthesize subtomograms' # --------------------------- DEFINE param functions -------------------------------------------- @@ -581,6 +737,27 @@ def generate_rotation_and_shift(self): else: psi1 = np.random.normal(self.MeanPsi.get(), self.StdPsi.get()) + # uniform over the sphere + if (self.psi.get() == ROTATION_UNIFORM) and\ + (self.tilt.get()==ROTATION_UNIFORM) and \ + (self.rot.get()==ROTATION_UNIFORM) and \ + self.LowRot.get() == 0.0 and self.HighRot.get() == 360.0 and \ + self.LowTilt.get() == 0.0 and self.HighTilt.get() == 180.0 and \ + self.LowPsi.get() == 0.0 and self.HighPsi.get() == 360.0: + x1,x2,x3 = np.random.uniform(0,1,3) + R = np.array([ + [np.cos(2*np.pi*x1), np.sin(2*np.pi*x1), 0], + [-np.sin(2*np.pi*x1), np.cos(2*np.pi*x1), 0], + [0, 0, 1] + ]) + v = np.array([[np.cos(2*np.pi*x2)*np.sqrt(x3), + np.sin(2*np.pi*x2)*np.sqrt(x3), + np.sqrt(1-x3)]]) + H = np.eye(3) - 2*np.dot(v.T,v) + M = -np.dot(H,R) + trans_mat = np.zeros((4,4)) + trans_mat[:3,:3] = M + rot1,tilt1,psi1,_,_,_ = matrix2eulerAngles(trans_mat) params = " -i " + self._getExtraPath(str(i + 1).zfill(5) + '_df.vol') params += " -o " + self._getExtraPath(str(i + 1).zfill(5) + '_df.vol') @@ -810,20 +987,6 @@ def createOutputStep(self): partSet.setSamplingRate(self.samplingRate.get()) self._defineOutputs(outputVolumes=partSet) - # --------------------------- INFO functions -------------------------------------------- - def _summary(self): - summary = [] - return summary - - def _validate(self): - errors = [] - return errors - - def _citations(self): - return ['harastani2020hybrid','Jonic2005', 'Sorzano2004b', 'Jin2014'] - - def _methods(self): - pass def get_number_of_volumes(self): if(self.importPdbs.get()): @@ -833,6 +996,7 @@ def get_number_of_volumes(self): else: numberOfVolumes = self.numberOfVolumes.get() return numberOfVolumes + # --------------------------- UTILS functions -------------------------------------------- def _printWarnings(self, *lines): """ Print some warning lines to 'warnings.xmd', @@ -845,3 +1009,18 @@ def _printWarnings(self, *lines): def _getLocalModesFn(self): modesFn = self.inputModes.get().getFileName() return self._getBasePath(modesFn) + + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['harastani2022continuousflex','harastani2020hybrid'] + + def _methods(self): + pass \ No newline at end of file diff --git a/continuousflex/protocols/protocol_heteroflow.py b/continuousflex/protocols/protocol_tomoflow.py similarity index 65% rename from continuousflex/protocols/protocol_heteroflow.py rename to continuousflex/protocols/protocol_tomoflow.py index a0de22f..f201e33 100644 --- a/continuousflex/protocols/protocol_heteroflow.py +++ b/continuousflex/protocols/protocol_tomoflow.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -20,25 +20,23 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** - +import joblib from pwem.protocols import ProtAnalysis3D import xmipp3.convert import pwem.emlib.metadata as md import pyworkflow.protocol.params as params from pyworkflow.utils.path import makePath, createLink -from sh_alignment.tompy.transform import fft, ifft, fftshift, ifftshift -from .utilities.spider_files3 import save_volume #, open_volume -import numpy as np -import farneback3d -from .utilities.spider_files3 import * -import time -import os +from continuousflex.protocols.utilities.spider_files3 import save_volume +import sys +from pyworkflow.utils import getListFromRangeString from os.path import isfile from joblib import Parallel, delayed import continuousflex from subprocess import check_call from pwem.utils import runProgram from pwem.emlib.image import ImageHandler +import numpy as np +from continuousflex import Plugin REFERENCE_EXT = 0 REFERENCE_STA = 1 @@ -47,7 +45,139 @@ FIND_FLOWS = 1 class FlexProtHeteroFlow(ProtAnalysis3D): - """ Protocol for HeteroFlow. """ + """ + Analyzes structural heterogeneity in sets of subtomograms by estimating optical flow fields + relative to a common reference volume. The protocol enables characterization of continuous + conformational variability by describing how each volume can be elastically transformed with + respect to a reference structure, providing a quantitative framework for studying molecular + flexibility and dynamic biological processes. + + AI Generated: + + TomoFlow Heterogeneity Analysis (FlexProtHeteroFlow) - User Manual + Overview + + The TomoFlow protocol is designed to investigate structural variability in collections of + aligned 3D subtomograms. Rather than treating each volume as an independent reconstruction, + the protocol models the spatial deformations required to transform a reference structure + into each observed volume. These deformation patterns provide a rich description of + continuous molecular motions and can reveal biologically meaningful conformational changes + that are difficult to capture using discrete classification approaches. + + For biological users, this protocol is particularly useful when studying flexible protein + complexes, molecular machines, membrane assemblies, or other systems that exhibit gradual + structural transitions. By quantifying deformation patterns across an entire dataset, the + protocol creates a foundation for downstream heterogeneity analysis and conformational + landscape exploration. + + Inputs and General Workflow + + The protocol can operate in two different modes. In the first mode, previously calculated + optical flow fields are imported from an earlier refinement workflow. This option is useful + when deformation information has already been generated and only heterogeneity analysis is + required. In the second mode, optical flow fields are computed directly from a set of + aligned subtomograms and a selected reference volume. + + The reference volume serves as the structural baseline against which all volumes are + compared. In practice, the reference is often a subtomogram average representing the most + reliable estimate of the underlying structure. Choosing a biologically representative and + high-quality reference generally improves the interpretability of the resulting deformation + patterns. + + Optical Flow and Structural Variability + + Optical flow analysis estimates local displacements throughout the volume, generating a + three-dimensional deformation field for each subtomogram. These deformation fields describe + how different regions of the structure move relative to the reference and provide a compact + representation of conformational differences. + + From a biological perspective, the resulting deformation fields can be interpreted as + signatures of structural flexibility. Similar conformational states tend to produce similar + deformation patterns, whereas distinct structural arrangements generate different patterns. + This allows the protocol to compare volumes based on their internal motions rather than + relying solely on voxel intensity similarities. + + Choice of Reference Structure + + The quality of the reference has a strong influence on the biological interpretation of the + results. A reference that represents the dominant conformational state often provides the + most intuitive deformation fields. If the reference differs substantially from many members + of the dataset, the resulting motion estimates may become harder to interpret. + + In practical workflows, users frequently select a subtomogram average obtained from + previous processing steps. External reference volumes may also be used when appropriate, + particularly when a biologically validated structure is available. + + Optical Flow Parameters + + The protocol provides several parameters that control the sensitivity and robustness of the + deformation estimation process. These settings influence how local motions are detected, + how information is propagated across scales, and how noise is handled during analysis. + + Pyramid-related parameters control the multiscale representation of the data. These options + determine how the algorithm captures both large global motions and smaller local + deformations. Window and neighborhood parameters regulate the balance between sensitivity + to fine structural changes and robustness against noise. + + For most biological datasets, the default values provide a suitable starting point. + However, highly noisy tomograms or structures with exceptionally large conformational + changes may benefit from parameter optimization. + + Similarity Analysis and Heterogeneity Characterization + + Once deformation fields have been obtained, the protocol compares them across all volumes + to generate a similarity matrix describing the relationships between conformational states. + This matrix serves as a quantitative representation of structural variability within the + dataset. + + Biologically, the similarity matrix can reveal clusters of related conformations, gradual + transitions between states, or continuous motion trajectories. It forms the basis for + subsequent dimensionality reduction and conformational landscape analysis workflows. + + Warped Reference Volumes + + An optional feature allows the generation of estimated volumes obtained by deforming the + reference according to each optical flow field. These reconstructed volumes provide a + direct visualization of how well the measured deformations explain the observed structures. + + This capability is particularly valuable for biological interpretation because it allows + users to assess whether the inferred motions capture meaningful structural differences. The + protocol also computes quantitative similarity measures between observed and estimated + volumes, helping evaluate the quality of the deformation model. + + Outputs and Their Interpretation + + The primary outputs are the optical flow fields and the similarity matrix describing the + relationships among all analyzed volumes. Together, these outputs provide a mathematical + description of conformational heterogeneity that can be explored using downstream analysis + tools. + + When warped reference generation is enabled, an additional set of estimated volumes is + produced. These volumes represent structural models reconstructed from the deformation + information and can be inspected visually to validate the biological plausibility of the + inferred motions. + + Practical Recommendations + + Reliable results depend strongly on the quality of the alignment preceding this protocol. + Volumes should already be brought into a common coordinate system before deformation + analysis begins. Misalignment can introduce artificial motions that may be incorrectly + interpreted as biological variability. + + Users are encouraged to begin with default optical flow parameters and evaluate the + resulting deformation patterns. If motions appear excessively noisy, increasing smoothing + and neighborhood-related parameters may improve stability. Conversely, when subtle + conformational differences are expected, more sensitive settings may reveal additional + structural details. + + Final Perspective + + For studies of molecular flexibility, TomoFlow provides a powerful framework for moving + beyond static structural descriptions. By representing each subtomogram through its + deformation relative to a common reference, the protocol enables quantitative exploration + of continuous conformational variability and supports a deeper understanding of the dynamic + behavior of biological macromolecules. + """ _label = 'tomoflow protocol' # --------------------------- DEFINE param functions -------------------------------------------- @@ -96,10 +226,17 @@ def _defineParams(self, form): 'distance and the mean absolute distance between the input volumes and estimated volumes') form.addSection(label='3D OpticalFLow parameters') group = form.addGroup('Optical flows', condition='copy_opflows==%d' % FIND_FLOWS) - group.addParam('N_GPU', params.IntParam, default=3, important=True, allowsNull=True, + group.addParam('N_GPU', params.IntParam, default=1, important=True, allowsNull=True, label = 'Parallel processes on GPU', help='This parameter indicates the number of volumes that will be processed in parallel' ' (independently). The more powerful your GPU, the higher the number you can choose.') + group.addParam('GPU_list', params.NumericRangeParam, + label="GPU id(s)", + help='Select the GPU id(s) that will be used for optical flow calculation.' + 'Examples: ' + 'You can select a list like 0-4, and it will take the GPUs 0 1 2 3 4' + 'You can also combine different selections like 1, 3-5 and it will take 1, 3, 4, 5', + default='0') group.addParam('pyr_scale', params.FloatParam, default=0.5, label='pyr_scale', allowsNull=True, help='parameter specifying the image scale to build pyramids for each image (pyr_scale < 1). ' @@ -173,7 +310,7 @@ def doAlignmentStep(self): # just in case the reference is in MRC format: path_vol0 = self._getExtraPath('reference.spi') params = '-i ' + STAVolume + ' -o ' + path_vol0 + ' --type vol' - self.runJob('xmipp_image_convert', params) + runProgram('xmipp_image_convert', params) pyr_scale = self.pyr_scale.get() levels = self.levels.get() @@ -194,8 +331,12 @@ def doAlignmentStep(self): # This is a spherical mask with maximum radius mask_size = int(self.getVolumeDimesion()//2) # Parallel processing (finding multiple optical flows at the same time) + GPUids = np.array(getListFromRangeString(self.GPU_list.get())) + gpu_ps = np.tile(GPUids, mdImgs.size()) + global segment def segment(objId): + gpu_p = gpu_ps[objId-1] imgPath = mdImgs.getValue(md.MDL_IMAGE, objId) # getting a copy converted to spider format to solve the problem with stacks or mrc files tmp = self._getTmpPath('tmp_' + str(objId) + '.spi') @@ -209,11 +350,12 @@ def segment(objId): if (isfile(path_flowx)): return else: - args = " %s %s %f %d %d %d %d %f %d %d %s %s %s" % (path_vol0, path_vol_i, pyr_scale, levels, winsize, + args = " %s %s %f %d %d %d %d %f %d %d %s %s %s %d" % (path_vol0, path_vol_i, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, factor1, factor2, - path_flowx, path_flowy, path_flowz) + path_flowx, path_flowy, path_flowz, gpu_p) script_path = continuousflex.__path__[0] + '/protocols/utilities/optflow_run.py' command = "python " + script_path + args + command = Plugin.getContinuousFlexCmd(command) check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr, env=None, cwd=None) @@ -271,12 +413,24 @@ def warpByFlow(self): for objId in mdImgs: N += 1 + # dumping the reference volume to use it in an outside script + ref_dump = self._getTmpPath('ref_dump.pkl') + joblib.dump(reference, ref_dump) + + # TODO: this loop can be parallelized, but it is not too computationally demanding for i in range(1, N + 1): print('Warping a copy of the reference volume by the optical flow ', i) - flow_i = self.read_optical_flow_by_number(i) - warped_i = farneback3d.warp_by_flow(reference, np.float32(flow_i)) + flow_i = np.float32(self.read_optical_flow_by_number(i)) + # dumping the optical flow to use it in an outside script + flow_dump = self._getTmpPath('flow_dump.pkl') + joblib.dump(flow_i, flow_dump) warped_path_i = estVol_root + str(i).zfill(6) + '.spi' - save_volume(warped_i, warped_path_i) + args = " %s %s %s" % (ref_dump, flow_dump, warped_path_i) + script_path = continuousflex.__path__[0] + '/protocols/utilities/optflow_warp.py' + command = "python " + script_path + args + command = Plugin.getContinuousFlexCmd(command) + check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr, + env=None, cwd=None) # Find a matrix of metrics (normalized cross correlation, mean square distance, mean absolute distance) stat_mat = np.zeros([N, 3]) @@ -287,7 +441,7 @@ def warpByFlow(self): imgPath = mdImgs.getValue(md.MDL_IMAGE, objId) # getting a copy converted to spider format to solve the problem with stacks or mrc files tmp = self._getTmpPath('tmp.spi') - self.runJob('xmipp_image_convert', '-i ' + imgPath + ' -o ' + tmp + ' --type vol') + runProgram('xmipp_image_convert', '-i ' + imgPath + ' -o ' + tmp + ' --type vol') # vol_i = open_volume(tmp) vol_i = ImageHandler().read(tmp).getData() @@ -308,7 +462,7 @@ def createOutputStep(self): out_mdfn = self._getExtraPath('volumes_out.xmd') pattern = '"' + self._getExtraPath() + '/estimated_volumes/*.spi"' command = '-p ' + pattern + ' -o ' + out_mdfn - self.runJob('xmipp_metadata_selfile_create',command) + runProgram('xmipp_metadata_selfile_create',command) # now creating the output set of volumes: partSet = self._createSetOfVolumes('Warped') xmipp3.convert.readSetOfVolumes(out_mdfn, partSet) @@ -320,24 +474,10 @@ def createOutputStep(self): pass pass - # --------------------------- INFO functions -------------------------------------------- - def _summary(self): - summary = [] - return summary - - def _citations(self): - return [] - - def _methods(self): - pass - # --------------------------- UTILS functions -------------------------------------------- def read_optical_flow(self, path_flowx, path_flowy, path_flowz): - # x = open_volume(path_flowx) x = ImageHandler().read(path_flowx).getData() - # y = open_volume(path_flowy) y = ImageHandler().read(path_flowy).getData() - # z = open_volume(path_flowz) z = ImageHandler().read(path_flowz).getData() l = np.shape(x) @@ -419,3 +559,14 @@ def vmab(self, v1, v2): def getVolumeDimesion(self): return self.inputVolumes.get().getDimensions()[0] + + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _citations(self): + return ['harastani2022tomoflow','harastani2022continuousflex'] + + def _methods(self): + pass \ No newline at end of file diff --git a/continuousflex/protocols/protocol_heteroflow_dimred.py b/continuousflex/protocols/protocol_tomoflow_dimred.py similarity index 54% rename from continuousflex/protocols/protocol_heteroflow_dimred.py rename to continuousflex/protocols/protocol_tomoflow_dimred.py index 04f2026..0d71406 100755 --- a/continuousflex/protocols/protocol_heteroflow_dimred.py +++ b/continuousflex/protocols/protocol_tomoflow_dimred.py @@ -1,6 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -22,15 +22,13 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** + from pyworkflow.object import String from pyworkflow.protocol.params import (PointerParam, StringParam, EnumParam, IntParam, LEVEL_ADVANCED) from pwem.protocols import ProtAnalysis3D -from pwem.convert import cifToPdb -from pyworkflow.utils.path import makePath, copyFile - +from pyworkflow.utils.path import copyFile import numpy as np -import glob from sklearn import decomposition from joblib import dump import xmipp3 @@ -48,8 +46,6 @@ DIMRED_NPE = 10 DIMRED_SKLEAN_PCA = 11 - - # Values to be passed to the program DIMRED_VALUES = ['PCA', 'LTSA', 'DM', 'LLTSA', 'LPP', 'kPCA', 'pPCA', 'LE', 'HLLE', 'SPE', 'NPE', 'sklearn_PCA','None'] @@ -57,10 +53,160 @@ DIMRED_MAPPINGS = [DIMRED_PCA, DIMRED_LLTSA, DIMRED_LPP, DIMRED_PPCA, DIMRED_NPE] - class FlexProtDimredHeteroFlow(ProtAnalysis3D): - """ This protocol will take volumes with optical flows, it will operate on the correlation mat - and will project it onto a reduced space + """ + Reduces the dimensionality of deformation information derived from + optical flow analysis of 3D volumes, enabling the exploration and + visualization of structural variability in a compact and interpretable + space. + + AI Generated: + + Heterogeneous Flow Dimensionality Reduction (FlexProtDimredHeteroFlow) - User Manual + + Overview + + The Heterogeneous Flow Dimensionality Reduction protocol is designed + to simplify the analysis of complex conformational variability + captured through optical flow measurements between three-dimensional + volumes. In structural biology studies, optical flow data often + describe high-dimensional deformation patterns that are difficult to + interpret directly. This protocol transforms those deformation + descriptors into a lower-dimensional representation while preserving + the most meaningful relationships between samples. + + For biological users, the main objective is to reveal the underlying + organization of conformational landscapes. By projecting deformation + information into two or a few dimensions, the protocol allows the + identification of structural continua, conformational clusters, rare + states, and transition pathways that may otherwise remain hidden in + the original high-dimensional space. + + Inputs and General Workflow + + The protocol requires as input a previous optical flow analysis in + which a collection of volumes has been compared against a reference + structure. These deformation measurements represent the structural + differences between individual volumes and the chosen reference + state. + + The dimensionality reduction process converts these deformation + descriptors into a compact coordinate system. Each volume is then + represented by a small number of variables that summarize its + position within the overall conformational landscape. The resulting + coordinates can be used for visualization, clustering, classification, + trajectory analysis, or as input for additional computational methods. + + Understanding Dimensionality Reduction + + Biological systems often exhibit complex motions involving many + degrees of freedom. Although deformation measurements may contain a + large number of variables, the biologically relevant motions are + frequently governed by a much smaller set of collective movements. + Dimensionality reduction aims to identify these dominant patterns. + + In practice, the reduced representation can help distinguish + different functional states, identify intermediate conformations, or + reveal continuous motions connecting multiple structural forms. The + reduced coordinates should not be interpreted as direct physical + quantities but rather as abstract descriptors capturing major sources + of variability within the dataset. + + Choice of Dimensionality Reduction Method + + The protocol offers multiple dimensionality reduction approaches, + each emphasizing different aspects of the data structure. Linear + methods are generally easier to interpret and often provide a useful + starting point for exploratory analysis. They are particularly + effective when conformational variability follows approximately + linear relationships. + + Nonlinear methods are better suited for datasets in which structural + changes occur along curved manifolds or complex pathways. These + approaches can uncover relationships that may be invisible to linear + projections and are often valuable when studying highly flexible + macromolecular assemblies. + + Different methods may produce different visualizations of the same + dataset. Consequently, comparing several approaches can provide + complementary insights into the organization of conformational + variability. + + Reduced Dimensionality Selection + + One of the most important decisions is the number of dimensions to + retain in the final representation. Two-dimensional projections are + commonly used because they are easy to visualize and interpret. + Three-dimensional representations may reveal additional structural + complexity while remaining accessible for interactive exploration. + + Retaining too few dimensions may hide biologically relevant + variability, whereas retaining too many dimensions can complicate + interpretation. In exploratory studies, users often begin with two + dimensions and subsequently evaluate whether additional dimensions + provide meaningful new information. + + Interpretation of the Reduced Space + + Volumes located close together in the reduced space generally + correspond to similar deformation patterns and therefore similar + conformational states. Conversely, distant points typically indicate + larger structural differences. + + Clusters may represent discrete biological states, while continuous + trajectories can indicate gradual transitions between conformations. + The biological significance of these patterns should always be + assessed together with structural inspection and complementary + experimental evidence. + + Projection and Reusability + + Some dimensionality reduction strategies generate transformation + models that can later be applied to additional datasets. This allows + newly obtained structures to be projected into an existing + conformational landscape, facilitating comparisons across experiments, + conditions, or processing campaigns. + + Such projections are particularly useful in longitudinal studies, + comparative analyses, and iterative workflows where new data become + available after the original analysis has been completed. + + Outputs and Their Interpretation + + The primary output is a reduced-coordinate representation of all + analyzed volumes. Each volume is associated with a position in the + reduced space that summarizes its deformation characteristics + relative to the reference structure. + + Depending on the selected method, an additional transformation model + may also be produced. This model can serve as a bridge between the + original deformation descriptors and the reduced representation, + enabling future projections and comparative analyses. + + Practical Recommendations + + For most biological applications, principal component analysis is an + effective starting point because it provides a stable and easily + interpretable description of dominant structural variability. + Nonlinear methods become particularly valuable when the data suggest + the presence of curved trajectories, branching pathways, or multiple + interconnected conformational states. + + It is generally advisable to visualize the reduced coordinates, + inspect possible clusters or trajectories, and compare the resulting + organization with known biochemical, functional, or experimental + information. Combining dimensionality reduction with structural + visualization often yields the most biologically meaningful + interpretation. + + Final Perspective + + Dimensionality reduction is a powerful tool for transforming complex + deformation measurements into an interpretable representation of + molecular flexibility. By revealing the dominant organization of + conformational variability, this protocol helps researchers explore + structural landscapes, identify biologically relevant states, and + generate hypotheses regarding molecular function and dynamics. """ _label = 'tomoflow dimred' @@ -201,21 +347,6 @@ def performDimredStep(self, deformationsFile, method, extraParams, def createOutputStep(self): pass - # --------------------------- INFO functions -------------------------------------------- - def _summary(self): - summary = [] - return summary - - def _validate(self): - errors = [] - return errors - - def _citations(self): - return [] - - def _methods(self): - return [] - # --------------------------- UTILS functions -------------------------------------------- def getInputParticles(self): @@ -243,3 +374,18 @@ def getProjectorFile(self): def getMethodName(self): return DIMRED_VALUES[self.dimredMethod.get()] + + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _validate(self): + errors = [] + return errors + + def _citations(self): + return ['harastani2022tomoflow','harastani2022continuousflex'] + + def _methods(self): + return [] diff --git a/continuousflex/protocols/protocol_subtomogram_refine_alignment.py b/continuousflex/protocols/protocol_tomoflow_refine_alignment.py similarity index 77% rename from continuousflex/protocols/protocol_subtomogram_refine_alignment.py rename to continuousflex/protocols/protocol_tomoflow_refine_alignment.py index 448d8fe..06901ce 100644 --- a/continuousflex/protocols/protocol_subtomogram_refine_alignment.py +++ b/continuousflex/protocols/protocol_tomoflow_refine_alignment.py @@ -1,5 +1,6 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) +# * # * IMPMC Sorbonne University # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -25,14 +26,9 @@ import pwem.emlib.metadata as md import pyworkflow.protocol.params as params from pyworkflow.utils.path import makePath, copyFile, cleanPath -from os.path import basename from sh_alignment.tompy.transform import fft, ifft, fftshift, ifftshift -from .utilities.spider_files3 import save_volume #, open_volume from pyworkflow.utils import replaceBaseExt -import numpy as np -import farneback3d from .utilities.spider_files3 import * -import time import os from os.path import basename, isfile from pwem.utils import runProgram @@ -42,14 +38,165 @@ import continuousflex from subprocess import check_call from pwem.emlib.image import ImageHandler -import math +from .convert import eulerAngles2matrix, matrix2eulerAngles +from pyworkflow.utils import getListFromRangeString +import multiprocessing +from continuousflex import Plugin +import joblib REFERENCE_EXT = 0 REFERENCE_STA = 1 class FlexProtRefineSubtomoAlign(ProtAnalysis3D): - """ Protocol for subtomogram refine alignment. """ + """ + Refines subtomogram alignment and improves reconstruction quality by combining missing-wedge compensation, + optical-flow-based elastic matching, and iterative rigid-body refinement. The protocol is intended for + subtomogram averaging workflows where an initial global average and alignment already exist, and where + additional refinement can improve the consistency of particle orientations and positions. It uses a + reference average to compensate for information lost during tomographic acquisition, estimates local + deformations between each subtomogram and the reference, and updates alignment parameters through + successive refinement cycles. + + AI Generated: + + Refine Subtomogram Alignment (FlexProtRefineSubtomoAlign) - User Manual + + Overview + + This protocol is designed to improve the quality of subtomogram averaging results by refining the + alignment of individual subtomograms against a common reference. Its main objective is to increase + structural consistency across the dataset while reducing the impact of missing information caused by + the limited angular range of electron tomography experiments. + + The workflow combines two complementary strategies. First, it can compensate for the missing wedge + by filling unsampled Fourier regions using information from a reference average. Second, it performs + iterative alignment refinement using optical flow and rigid-body matching. Together, these operations + help produce more accurate particle orientations, better averages, and improved structural detail. + + Inputs and Initial Requirements + + The protocol requires a set of subtomograms together with alignment parameters obtained from a + previous subtomogram averaging workflow. A reference volume is also required and normally corresponds + to the final average generated during a previous refinement stage. + + The quality of the input reference strongly influences the final result. References containing clear + structural features generally provide more reliable refinement, whereas noisy or poorly aligned + references may limit convergence. Users should therefore begin with the best available average. + + Missing Wedge Compensation + + Electron tomography data typically suffer from incomplete angular sampling, creating a region of + missing information known as the missing wedge. This artifact introduces anisotropic resolution and + can bias alignment procedures. + + When missing wedge correction is enabled, the protocol uses the reference average to estimate the + absent Fourier information for each subtomogram. The reference is transformed into the orientation + of each particle and contributes information only in regions affected by the missing wedge. This + process reduces directional artifacts and provides a more complete representation of each particle + before refinement. + + The user specifies the lower and upper tilt limits corresponding to the experimental acquisition + geometry. Accurate values are important because they define the extent of the missing information + being compensated. + + Reference Masking + + An optional mask can be applied to the reference volume and to the aligned subtomograms throughout + the refinement process. This allows the analysis to focus on biologically relevant regions while + reducing the influence of noise, solvent regions, or highly flexible domains. + + For many biological systems, masking the stable core of the structure improves refinement stability. + Care should be taken to avoid overly restrictive masks that exclude meaningful structural features. + + Alignment Refinement Strategy + + The protocol performs iterative refinement cycles. During each cycle, subtomograms are aligned using + the current rigid-body parameters and compared against the reference. Optical flow estimation is then + used to model local differences between the reference and each aligned subtomogram. + + These local deformation fields provide a particle-specific representation of how the reference would + need to change to resemble the observed data. The resulting matched volumes are subsequently used for + rigid-body alignment refinement. Updated transformations are combined with the previous alignment + parameters, producing progressively improved orientations and shifts. + + In most practical situations only a small number of iterations is required. Typical refinement runs + use between one and five cycles. Excessive iteration counts may increase computational cost without + providing meaningful biological improvements. + + Optical Flow Parameters + + Optical flow estimation is responsible for identifying local differences between the reference and + each subtomogram. Several parameters control the behavior of the deformation model. + + Pyramid scale and pyramid levels determine how motion is analyzed across multiple spatial scales. + Larger multi-scale analyses can capture broader deformations but require additional computation. + + Window size influences robustness to noise. Larger windows generally provide smoother and more stable + motion estimates, although they may reduce sensitivity to small local variations. + + Iteration count controls how extensively motion estimates are refined at each scale. Higher values + can improve accuracy but increase execution time. + + Polynomial neighborhood size and smoothing parameters regulate how smoothly local deformations are + modeled. Conservative values are usually sufficient for most biological datasets. + + GPU Acceleration + + Optical flow calculations can be executed using one or more GPUs. Multiple volumes may be processed + simultaneously, allowing substantial reductions in runtime for large datasets. + + The number of parallel GPU processes should be chosen according to available hardware resources. + Larger values increase throughput but also increase memory requirements. + + Rigid-Body Refinement + + After optical-flow matching, the protocol refines particle orientations and translations through + rigid-body alignment. This stage improves the global positioning of each subtomogram while preserving + the information learned from the deformation-based matching process. + + Users can control the maximum search frequency and the maximum translational displacement explored + during refinement. Conservative values are generally recommended because the protocol assumes that + particles are already approximately aligned from a previous averaging workflow. + + Generation of Updated References + + At the end of each refinement cycle, all particles are combined using the updated alignment + parameters to generate a new average volume. This updated average becomes the reference for the next + iteration. + + Through successive cycles, the reference and particle alignments evolve together, often leading to + improved structural consistency and enhanced signal quality. + + Outputs and Interpretation + + The protocol produces a refined set of aligned subtomograms together with updated rigid-body + transformations. When alignment refinement is enabled, an additional refined average volume is also + generated. + + The refined average can be used as input for subsequent rounds of subtomogram averaging, structural + interpretation, classification, or visualization. Improvements are typically observed as sharper + structural features, increased consistency across particles, and reduced effects of missing-wedge + artifacts. + + Practical Recommendations + + Users should begin with a reasonably well-aligned dataset and a high-quality reference average. + Missing wedge correction is generally beneficial when acquisition geometry introduces strong + anisotropy, although its usefulness depends on the quality of the reference volume. + + Applying a biologically meaningful mask often improves refinement stability, particularly for + complexes containing flexible regions. A small number of refinement iterations is usually sufficient, + and results should be inspected after each cycle to verify that structural quality is improving. + + Final Perspective + + This protocol extends conventional subtomogram averaging refinement by combining missing-wedge + compensation, elastic matching, and rigid-body optimization within an iterative framework. For + biological users, it provides a practical mechanism for improving alignment accuracy and enhancing + the quality of averaged structures, particularly in datasets where incomplete angular sampling and + residual alignment errors limit achievable resolution. + """ _label = 'refine subtomogram alignment' # --------------------------- DEFINE param functions -------------------------------------------- @@ -140,10 +287,17 @@ def _defineParams(self, form): form.addSection(label='combined rigid-body & elastic alignment') group = form.addGroup('Optical flow parameters', condition='Alignment_refine') - group.addParam('N_GPU', params.IntParam, default=3, important=True, allowsNull=True, + group.addParam('N_GPU', params.IntParam, default=1, important=True, allowsNull=True, label = 'Parallel processes on GPU', help='This parameter indicates the number of volumes that will be processed in parallel' ' (independently). The more powerful your GPU, the higher the number you can choose.') + group.addParam('GPU_list', params.NumericRangeParam, + label="GPU id(s)", + help='Select the GPU id(s) that will be used for optical flow calculation.' + 'Examples: ' + 'You can select a list like 0-4, and it will take the GPUs 0 1 2 3 4' + 'You can also combine different selections like 1, 3-5 and it will take 1, 3, 4, 5', + default='0') group.addParam('pyr_scale', params.FloatParam, default=0.5, label='pyr_scale', allowsNull=True, help='parameter specifying the image scale to build pyramids for each image (pyr_scale < 1). ' @@ -195,7 +349,7 @@ def _defineParams(self, form): help='The maximum shift is a number between 1 and half the size of your volume. ' 'It represents the maximum distance searched in x,y and z directions.') - form.addParallelSection(threads=0, mpi=5) + form.addParallelSection(threads=0, mpi=multiprocessing.cpu_count()//2-1) # --------------------------- INSERT steps functions -------------------------------------------- @@ -371,15 +525,12 @@ def fillMissingWedge(self, num): # print('xmipp_transform_geometry',params) runProgram('xmipp_transform_geometry', params) # Now the STA is aligned, add the missing wedge region to the subtomogram: - # v = open_volume(new_imgPath) v = ImageHandler().read(new_imgPath).getData() I = fft(v) I = fftshift(I) - # v_ave = open_volume(tempdir + '/temp.vol') v_ave = ImageHandler().read(tempdir + '/temp.vol').getData() Iave = fft(v_ave) Iave = fftshift((Iave)) - # Mask = open_volume(fnmask) Mask = ImageHandler().read(fnmask).getData() Mask = np.ones(np.shape(Mask)) - Mask @@ -394,7 +545,6 @@ def fillMissingWedge(self, num): # for debugging, save everything that was aligned in the first iteration if objId == 1: - # v_ave = open_volume(tempdir + '/temp.vol') v_ave = ImageHandler().read(tempdir + '/temp.vol').getData() save_volume(v_ave, self._getExtraPath('aligned_average_with_first_volume.spi')) @@ -494,9 +644,6 @@ def calculateOpticalFlows(self, num): winsize = self.winsize.get() poly_n = self.poly_n.get() poly_sigma = self.poly_sigma.get() - # TODO: the factor1 and 2 can be any value as long as we are using the subtomogram average (gray level values - # are similar. It is not sure if we use an external reference what this should be! This could be normalized in - # future flags = self.flags.get() factor1 = self.factor1.get() factor2 = self.factor2.get() @@ -507,8 +654,11 @@ def calculateOpticalFlows(self, num): # This is a spherical mask with maximum radius mask_size = int(self.getVolumeDimesion()//2) # Parallel processing (finding multiple optical flows at the same time) + GPUids = np.array(getListFromRangeString(self.GPU_list.get())) + gpu_ps = np.tile(GPUids, mdImgs.size()) global segment def segment(objId): + gpu_p = gpu_ps[objId-1] imgPath = mdImgs.getValue(md.MDL_IMAGE, objId) # getting a copy converted to spider format to solve the problem with stacks or mrc files tmp = self._getTmpPath('tmp_' + str(objId) + '.spi') @@ -522,11 +672,12 @@ def segment(objId): if (isfile(path_flowx)): return else: - args = " %s %s %f %d %d %d %d %f %d %d %s %s %s" % (path_vol0, path_vol_i, pyr_scale, levels, winsize, + args = " %s %s %f %d %d %d %d %f %d %d %s %s %s %d" % (path_vol0, path_vol_i, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, factor1, factor2, - path_flowx, path_flowy, path_flowz) + path_flowx, path_flowy, path_flowz, gpu_p) script_path = continuousflex.__path__[0] + '/protocols/utilities/optflow_run.py' command = "python " + script_path + args + command = Plugin.getContinuousFlexCmd(command) check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr, env=None, cwd=None) @@ -548,7 +699,6 @@ def warpByFlow(self, num): if(not(self.KeepFiles.get())): cleanPath(self._getExtraPath() + '/estimated_volumes_' + str(num-1)) estVol_root = self._getExtraPath() + '/estimated_volumes_' + str(num) + '/' - # reference = open_volume(self._getExtraPath('reference' + str(num) + '.spi')) reference = ImageHandler().read(self._getExtraPath('reference' + str(num) + '.spi')).getData() # recount the number of volumes: imgFn = self.imgsFn @@ -558,13 +708,23 @@ def warpByFlow(self, num): for objId in mdImgs: N += 1 + ref_dump = self._getTmpPath('ref_dump.pkl') + joblib.dump(reference, ref_dump) + mdWarped = md.MetaData() for i in range(1, N + 1): print('Warping a copy of the reference volume by the optical flow ', i) flow_i = self.read_optical_flow_by_number(i, op_path=self._getExtraPath() + '/optical_flows_' + str(num) + '/') - warped_i = farneback3d.warp_by_flow(reference, np.float32(flow_i)) + # dumping the optical flow to use it in an outside script + flow_dump = self._getTmpPath('flow_dump.pkl') + joblib.dump(flow_i, flow_dump) warped_path_i = estVol_root + str(i).zfill(6) + '.spi' - save_volume(warped_i, warped_path_i) + args = " %s %s %s" % (ref_dump, flow_dump, warped_path_i) + script_path = continuousflex.__path__[0] + '/protocols/utilities/optflow_warp.py' + command = "python " + script_path + args + command = Plugin.getContinuousFlexCmd(command) + check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr, + env=None, cwd=None) mdWarped.setValue(md.MDL_IMAGE, warped_path_i, mdWarped.addObject()) mdWarped.setValue(md.MDL_ITEM_ID, i, i) warpedVolFn = self._getExtraPath('warped_volumes_' + str(num) + '.xmd') @@ -627,8 +787,8 @@ def combineRefinedAlignment(self, num): shifty_r = MD_refined.getValue(md.MDL_SHIFT_Y, objId) shiftz_r = MD_refined.getValue(md.MDL_SHIFT_Z, objId) - T_o = self.eulerAngles2matrix(rot_o, tilt_o, psi_o, shiftx_o, shifty_o, shiftz_o) - T_r = self.eulerAngles2matrix(rot_r, tilt_r, psi_r, shiftx_r, shifty_r, shiftz_r) + T_o = eulerAngles2matrix(rot_o, tilt_o, psi_o, shiftx_o, shifty_o, shiftz_o) + T_r = eulerAngles2matrix(rot_r, tilt_r, psi_r, shiftx_r, shifty_r, shiftz_r) # 3- multiply the matrices if self.getAngleY() == 90: @@ -641,7 +801,7 @@ def combineRefinedAlignment(self, num): # have missing wedge correction) T = np.matmul(T_o, T_r) - rot_i, tilt_i, psi_i, x_i, y_i, z_i = self.matrix2eulerAngles(T) + rot_i, tilt_i, psi_i, x_i, y_i, z_i = matrix2eulerAngles(T) # Populate the metadata name_i = MD_original.getValue(md.MDL_IMAGE, objId) @@ -731,24 +891,10 @@ def createOutputStep(self, num =0): else: self._defineOutputs(OutputVolumes=partSet) - # --------------------------- INFO functions -------------------------------------------- - def _summary(self): - summary = [] - return summary - - def _citations(self): - return [] - - def _methods(self): - pass - # --------------------------- UTILS functions -------------------------------------------- def read_optical_flow(self, path_flowx, path_flowy, path_flowz): - # x = open_volume(path_flowx) x = ImageHandler().read(path_flowx).getData() - # y = open_volume(path_flowy) y = ImageHandler().read(path_flowy).getData() - # z = open_volume(path_flowz) z = ImageHandler().read(path_flowz).getData() l = np.shape(x) @@ -776,6 +922,7 @@ def _printWarnings(self, *lines): print >> fWarn, l fWarn.close() + # AngleY should never be 90 from now on. However, it can stay here in order someone imports an old STA alignment def getAngleY(self): AlignmentParameters = self.AlignmentParameters.get() MetaDataFile = self.MetaDataFile.get() @@ -794,62 +941,13 @@ def getAngleY(self): def getVolumeDimesion(self): return self.inputVolumes.get().getDimensions()[0] - def matrix2eulerAngles(self, A): - abs_sb = np.sqrt(A[0, 2] * A[0, 2] + A[1, 2] * A[1, 2]) - if (abs_sb > 16 * np.exp(-5)): - gamma = math.atan2(A[1, 2], -A[0, 2]) - alpha = math.atan2(A[2, 1], A[2, 0]) - if (abs(np.sin(gamma)) < np.exp(-5)): - sign_sb = np.sign(-A[0, 2] / np.cos(gamma)) - else: - if np.sin(gamma) > 0: - sign_sb = np.sign(A[1, 2]) - else: - sign_sb = -np.sign(A[1, 2]) - beta = math.atan2(sign_sb * abs_sb, A[2, 2]) - else: - if (np.sign(A[2, 2]) > 0): - alpha = 0 - beta = 0 - gamma = math.atan2(-A[1, 0], A[0, 0]) - else: - alpha = 0 - beta = np.pi - gamma = math.atan2(A[1, 0], -A[0, 0]) - gamma = np.rad2deg(gamma) - beta = np.rad2deg(beta) - alpha = np.rad2deg(alpha) - return alpha, beta, gamma, A[0, 3], A[1, 3], A[2, 3] - - - def eulerAngles2matrix(self, alpha, beta, gamma, shiftx, shifty, shiftz): - A = np.empty([4, 4]) - A.fill(2) - A[3, 3] = 1 - A[3, 0:3] = 0 - A[0, 3] = float(shiftx) - A[1, 3] = float(shifty) - A[2, 3] = float(shiftz) - alpha = float(alpha) - beta = float(beta) - gamma = float(gamma) - sa = np.sin(np.deg2rad(alpha)) - ca = np.cos(np.deg2rad(alpha)) - sb = np.sin(np.deg2rad(beta)) - cb = np.cos(np.deg2rad(beta)) - sg = np.sin(np.deg2rad(gamma)) - cg = np.cos(np.deg2rad(gamma)) - cc = cb * ca - cs = cb * sa - sc = sb * ca - ss = sb * sa - A[0, 0] = cg * cc - sg * sa - A[0, 1] = cg * cs + sg * ca - A[0, 2] = -cg * sb - A[1, 0] = -sg * cc - cg * sa - A[1, 1] = -sg * cs + cg * ca - A[1, 2] = sg * sb - A[2, 0] = sc - A[2, 1] = ss - A[2, 2] = cb - return A \ No newline at end of file + # --------------------------- INFO functions -------------------------------------------- + def _summary(self): + summary = [] + return summary + + def _citations(self): + return ['harastani2022tomoflow','harastani2022continuousflex'] + + def _methods(self): + pass diff --git a/continuousflex/protocols/utilities/OF_plots.py b/continuousflex/protocols/utilities/OF_plots.py index a51c473..813d900 100755 --- a/continuousflex/protocols/utilities/OF_plots.py +++ b/continuousflex/protocols/utilities/OF_plots.py @@ -1,8 +1,6 @@ -import matplotlib -# matplotlib.use('Qt5Agg') +# By Mohamad Harastani + import matplotlib.pyplot as plt -# ['GTK3Agg', 'GTK3Cairo', 'MacOSX', 'nbAgg', 'Qt4Agg', 'Qt4Cairo', 'Qt5Agg', 'Qt5Cairo', 'TkAgg', 'TkCairo', 'WebAgg', -# 'WX', 'WXAgg', 'WXCairo', 'agg', 'cairo', 'pdf', 'pgf', 'ps', 'svg', 'template'] import numpy as np from scipy.signal import resample_poly diff --git a/continuousflex/protocols/utilities/bm4d.py b/continuousflex/protocols/utilities/bm4d.py index c94a0bb..f1b858a 100644 --- a/continuousflex/protocols/utilities/bm4d.py +++ b/continuousflex/protocols/utilities/bm4d.py @@ -1,3 +1,5 @@ +# By Mohamad Harastani + import continuousflex import os import tkinter.messagebox as tk diff --git a/continuousflex/protocols/utilities/bm4d_wrapper.m b/continuousflex/protocols/utilities/bm4d_wrapper.m index abed94c..28bd108 100644 --- a/continuousflex/protocols/utilities/bm4d_wrapper.m +++ b/continuousflex/protocols/utilities/bm4d_wrapper.m @@ -22,7 +22,7 @@ % Proc. SPIE Electronic Imaging 2012, San Francisco, CA, USA, Jan. 2012. -% by Mohamad Harastani (mohamad.harastani@upmc.fr) +% by Mohamad Harastani (mohamad.harastani@igbmc.fr) function bm4d_wrapper(path_vol_in, path_vol_out, distribution, sigma, profile, do_wiener) diff --git a/continuousflex/protocols/utilities/deep_hemnma.py b/continuousflex/protocols/utilities/deep_hemnma.py new file mode 100644 index 0000000..575f4a8 --- /dev/null +++ b/continuousflex/protocols/utilities/deep_hemnma.py @@ -0,0 +1,147 @@ +# Author: Ilyes Hamitouche + +import torch.nn as nn +from torchvision import transforms +import torch.optim as optim +from torch.utils.data import DataLoader +from processing_dh.data import cryodata +from processing_dh.models import deephemnma +import numpy as np +import torch +from torch.utils.data.sampler import SubsetRandomSampler +from torch.utils.tensorboard import SummaryWriter +import sys +def norm(imgs_path, output_path, FLAG, mode, batch_size): + dataset = cryodata(imgs_path, output_path, flag=FLAG, mode = mode, transform=transforms.ToTensor()) + random_seed = 42 + validation_split = .2 + shuffle_dataset = True + + dataset_size = len(dataset) + indices = list(range(dataset_size)) + split = int(np.floor((1-validation_split) * dataset_size)) + + if shuffle_dataset: + np.random.seed(random_seed) + np.random.shuffle(indices) + train_indices, val_indices = indices[:split], indices[split:] + + train_sampler = SubsetRandomSampler(train_indices) + valid_sampler = SubsetRandomSampler(val_indices) + #print('the train set size is: {} images'.format(len(train_sampler))) + #print('the validation set size is: {} images'.format(len(valid_sampler))) + train_loader = DataLoader(dataset, batch_size=batch_size, sampler=train_sampler) + validation_loader = DataLoader(dataset, batch_size=batch_size, sampler=valid_sampler) + sum_, squared_sum_, num_batches = 0, 0, 0 + for img, nm_amplitudes in train_loader: + sum_ += torch.mean(img, dim=[0, 2, 3]) + squared_sum_ += torch.mean(img**2, dim=[0, 2, 3]) + num_batches += 1 + mean = sum_/num_batches + std = (squared_sum_/num_batches - mean**2)**0.5 + return mean, std + +def train(imgs_path, output_path, epochs=400, batch_size=2, lr=1e-4, flag=0, device=0, mode='train'): + + num_epochs = epochs + random_seed = 42 + validation_split = .5 + shuffle_dataset = True + FLAG = '' + if flag==0: + FLAG = 'nma' + elif flag==1: + FLAG = 'ang' + elif flag==2: + FLAG = 'shf' + else: + FLAG = 'all' + DEVICE = '' + if device==0: + DEVICE = 'cuda' + else: + DEVICE = 'cpu' + mean, std = norm(imgs_path, output_path, FLAG, mode, batch_size) + transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((mean), (std))]) + transform1 = transforms.Compose([transforms.ToTensor(), + transforms.RandomRotation((-45, 45)), + transforms.Normalize((mean), (std))]) + dataset1 = cryodata(imgs_path, output_path, flag=FLAG, mode= mode, + transform=transform) + dataset2 = cryodata(imgs_path, output_path, flag=FLAG, mode= mode, + transform=transform1) + transform2 = transforms.Compose([transforms.ToTensor(), + transforms.RandomRotation((-90, 90)), + transforms.Normalize((mean), (std))]) + dataset3 = cryodata(imgs_path, output_path, flag=FLAG, mode= mode, + transform=transform2) + increased_dataset = torch.utils.data.ConcatDataset([dataset1, dataset2, dataset3]) + #dataset = cryodata(imgs_path, output_path, flag=FLAG, mode = mode, transform=transform) + dataset_size = len(increased_dataset) + indices = list(range(dataset_size)) + split = int(np.floor((1-validation_split) * dataset_size)) + + if shuffle_dataset: + np.random.seed(random_seed) + np.random.shuffle(indices) + train_indices, val_indices = indices[:split], indices[split:] + + train_sampler = SubsetRandomSampler(train_indices) + valid_sampler = SubsetRandomSampler(val_indices) + print('the train set size is: {} images'.format(len(train_sampler)//3)) + print('the validation set size is: {} images'.format(len(valid_sampler)//3)) + train_loader = DataLoader(increased_dataset, batch_size=batch_size, sampler=train_sampler) + validation_loader = DataLoader(increased_dataset, batch_size=batch_size, sampler=valid_sampler) + + im, p = next(iter(train_loader)) + if FLAG=='nma': + model = deephemnma(p.shape[1]).to(DEVICE) + elif FLAG=='ang': + model = deephemnma(p.shape[1]).to(DEVICE) + elif FLAG=='shf': + model = deephemnma(p.shape[1]).to(DEVICE) + elif FLAG=='all': + model = deephemnma(p.shape[1]).to(DEVICE) + + optimizer = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=1e-5) + scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', patience=10) + criterion = nn.L1Loss() + writer = SummaryWriter(output_path+'/scalars') + for epoch in range(num_epochs): + + epoch_loss = 0.0 + running_loss = 0.0 + + for img, params in train_loader: + img = img/255. + optimizer.zero_grad() + pred_params = model(img.to(DEVICE), 'train') + l = criterion(params.to(DEVICE), pred_params) + l.backward() + optimizer.step() + running_loss += l.item() + epoch_loss += pred_params.shape[0] * l.item() + print('epoch [{}/{}], loss:{:.4f}' + .format(epoch + 1, num_epochs, l.item() ), end='\r') + valid_loss = 0.0 + with torch.no_grad(): + for img, params in validation_loader: + pred_params = model(img.to(DEVICE), 'validation') + l = criterion(params.to(DEVICE), pred_params) + valid_loss += pred_params.shape[0] * l.item() + + print('epoch [{}/{}], train loss:{:.4f}, validation loss:{:.4f}' + .format(epoch + 1, num_epochs, epoch_loss / len(train_loader.dataset), valid_loss / len(validation_loader.dataset))) + writer.add_scalar('Loss/train', epoch_loss / len(train_loader.dataset), epoch+1) + writer.add_scalar('Loss/validation', valid_loss / len(validation_loader.dataset), epoch+1) + scheduler.step(epoch_loss) + torch.save(model.state_dict(), output_path+'/weights.pth') + +if __name__ == '__main__': + train(sys.argv[1], + sys.argv[2], + int(sys.argv[3]), + int(sys.argv[4]), + float(sys.argv[5]), + int(sys.argv[6]), + int(sys.argv[7])) \ No newline at end of file diff --git a/continuousflex/protocols/utilities/deep_hemnma_infer.py b/continuousflex/protocols/utilities/deep_hemnma_infer.py new file mode 100644 index 0000000..791e6a9 --- /dev/null +++ b/continuousflex/protocols/utilities/deep_hemnma_infer.py @@ -0,0 +1,111 @@ +# Author: Ilyes Hamitouche + +from torchvision import transforms +from torch.utils.data import DataLoader +from processing_dh.data import cryodata +from processing_dh.utils import quater2euler, reverse_min_max +from processing_dh.models import deephemnma +import numpy as np +import torch +from pathlib import Path +import sys +import pwem.emlib.metadata as md +def norm(imgs_path, weights_path, flag, mode, batch_size): + dataset = cryodata(imgs_path, weights_path, flag=flag, mode=mode, transform=transforms.ToTensor()) + train_loader = DataLoader(dataset, batch_size=batch_size) + sum_, squared_sum_, num_batches = 0, 0, 0 + for img, image_name in train_loader: + sum_ += torch.mean(img, dim=[0, 2, 3]) + squared_sum_ += torch.mean(img**2, dim=[0, 2, 3]) + num_batches += 1 + mean = sum_/num_batches + std = (squared_sum_/num_batches - mean**2)**0.5 + return mean, std +def infer(imgs_path, weights_path, output_path, num_modes, batch_size=2, flag=0, device=0, mode='inference'): + FLAG = '' + if flag==0: + FLAG = 'nma' + elif flag==1: + FLAG = 'ang' + elif flag==2: + FLAG = 'shf' + else: + FLAG = 'all' + DEVICE = '' + if device==0: + DEVICE = 'cuda' + else: + DEVICE = 'cpu' + + mean, std = norm(imgs_path, weights_path, flag=FLAG, mode=mode, batch_size=batch_size) + transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((mean), (std))]) + dataset = cryodata(imgs_path, weights_path, flag=FLAG, mode=mode, transform=transform) + + dataset_size = len(dataset) + print('the train set size is: {} images'.format(dataset_size)) + + data_loader = DataLoader(dataset, batch_size=batch_size) + + if FLAG=='nma': + model = deephemnma(3).to(DEVICE) + predictions = np.zeros((dataset_size, num_modes), dtype='float32') + elif FLAG=='ang': + model = deephemnma(4).to(DEVICE) + predictions = np.zeros((dataset_size, 4), dtype='float32') + elif FLAG=='shf': + model = deephemnma(2).to(DEVICE) + predictions = np.zeros((dataset_size, 2), dtype='float32') + elif FLAG=='all': + model = deephemnma(6+num_modes).to(DEVICE) + predictions = np.zeros((dataset_size, 6+num_modes), dtype='float32') + + model.load_state_dict(torch.load(weights_path)) + model.eval() + with torch.no_grad(): + i = 0 + for img, image_name in data_loader: + pred_params = model(img.to(DEVICE), mode) + predictions[i * batch_size:(i + 1) * batch_size, :] = pred_params.cpu() + i+=1 + + + if FLAG=='nma': + min_max_nma = np.loadtxt(str(Path(weights_path).parent) + '/min_max_nma.txt') + nma = reverse_min_max(predictions, min_max_nma[0], min_max_nma[1]) + elif FLAG=='ang': + angles = predictions + euler_angles = [] + for i in range(len(angles)): + euler_angles.append(quater2euler(angles)) + euler_angles = np.array(euler_angles) + elif FLAG=='shf': + min_max_shf = np.loadtxt(str(Path(weights_path).parent) + '/min_max_shf.txt') + shifts = reverse_min_max(predictions, min_max_shf[0], min_max_shf[1]) + elif FLAG=='all': + min_max_nma = np.loadtxt(str(Path(weights_path).parent) + '/min_max_nma.txt') + min_max_shf = np.loadtxt(str(Path(weights_path).parent) + '/min_max_shf.txt') + nma = reverse_min_max(predictions[:,:num_modes], min_max_nma[0], min_max_nma[1]) + angles = predictions[:,num_modes:num_modes+4] + shifts = reverse_min_max(predictions[:,num_modes+4:], min_max_shf[0], min_max_shf[1]) + euler_angles = [] + for i in range(len(angles)): + euler_angles.append(quater2euler(angles[i])) + euler_angles = np.array(euler_angles) + mdImgs = md.MetaData(imgs_path) + imgPath = [] + for objId in mdImgs: + imgPath.append(mdImgs.getValue(md.MDL_IMAGE, objId)) + with open(output_path+'/images.xmd', 'w') as f: + f.write('# XMIPP_STAR_1 * \n # \ndata_noname\nloop_\n _image\n _enabled\n _angleRot\n _angleTilt\n _anglePsi\n _shiftX\n _shiftY\n _nmaDisplacements\n _cost\n _itemId\n') + for i in range(euler_angles.shape[0]): + f.write(imgPath[i]+" 1 {:>12.6} {:>12.6} {:>12.6} {:>12.6} {:>12.6} '{:>12.6} {:>12.6} {:>12.6}' 0.55 {}".format( + euler_angles[i, 0], euler_angles[i, 1], euler_angles[i, 2], shifts[i, 0], + shifts[i, 1], nma[i,0], nma[i,1], nma[i,2], i+1) + '\n') +if __name__ == '__main__': + infer(sys.argv[1], + sys.argv[2], + sys.argv[3], + int(sys.argv[4]), + int(sys.argv[5]), + int(sys.argv[6]), + int(sys.argv[7])) diff --git a/continuousflex/protocols/utilities/dynamo.py b/continuousflex/protocols/utilities/dynamo.py index ea2dcdd..329fcd0 100644 --- a/continuousflex/protocols/utilities/dynamo.py +++ b/continuousflex/protocols/utilities/dynamo.py @@ -7,6 +7,7 @@ import pandas as pd import math + def dynamo_mat(tdrot, tilt, narot, shiftx, shifty, shiftz): tdrot = radians(tdrot) tilt = radians(tilt) @@ -33,8 +34,6 @@ def dynamo_mat(tdrot, tilt, narot, shiftx, shifty, shiftz): m[2,3] = shiftz m[3,3] = 1 - - return m diff --git a/continuousflex/protocols/utilities/genesis_utilities.py b/continuousflex/protocols/utilities/genesis_utilities.py new file mode 100644 index 0000000..b22cf4b --- /dev/null +++ b/continuousflex/protocols/utilities/genesis_utilities.py @@ -0,0 +1,240 @@ +# By Remi Vuillemot + +import numpy as np +from pyworkflow.utils import runCommand +import multiprocessing + +NUMBER_OF_CPU = int(np.min([multiprocessing.cpu_count(),4])) + +EMFIT_NONE = 0 +EMFIT_VOLUMES = 1 +EMFIT_IMAGES = 2 + +FORCEFIELD_CHARMM = 0 +FORCEFIELD_AAGO = 1 +FORCEFIELD_CAGO = 2 + +SIMULATION_MIN = 0 +SIMULATION_MD = 1 +SIMULATION_NMMD = 2 +SIMULATION_REMD = 3 +SIMULATION_RENMMD = 4 + +PROGRAM_ATDYN = 0 +PROGRAM_SPDYN= 1 + +INTEGRATOR_VVERLET = 0 +INTEGRATOR_LEAPFROG = 1 + +IMPLICIT_SOLVENT_GBSA = 0 +IMPLICIT_SOLVENT_NONE = 1 + +TPCONTROL_NONE = 0 +TPCONTROL_LANGEVIN = 1 +TPCONTROL_BERENDSEN = 2 +TPCONTROL_BUSSI = 3 + +ENSEMBLE_NVT = 0 +ENSEMBLE_NVE = 1 +ENSEMBLE_NPT = 2 + +BOUNDARY_NOBC = 0 +BOUNDARY_PBC = 1 + +ELECTROSTATICS_PME = 0 +ELECTROSTATICS_CUTOFF = 1 + +NUCLEIC_NO = 0 +NUCLEIC_RNA =1 +NUCLEIC_DNA = 2 + +RB_PROJMATCH = 0 +RB_WAVELET = 1 + +INPUT_TOPOLOGY = 0 +INPUT_RESTART = 1 +INPUT_NEW_SIM = 2 + +PROJECTION_ANGLE_SAME=0 +PROJECTION_ANGLE_XMIPP=1 +PROJECTION_ANGLE_IMAGE=2 + +PARALLEL_MPI = 0 +PARALLEL_GNU = 1 +PARALLEL_SERIAL = 2 + + +def lastPDBFromDCD(inputPDB,inputDCD, outputPDB): + + # EXTRACT PDB from dcd file + with open("%s_tmp_dcd2pdb.tcl" % outputPDB, "w") as f: + s = "" + s += "mol load pdb %s dcd %s\n" % (inputPDB, inputDCD) + s += "set nf [molinfo top get numframes]\n" + s += "[atomselect top all frame [expr $nf - 1]] writepdb %s\n" % outputPDB + s += "exit\n" + f.write(s) + runCommand("vmd -dispdev text -e %s_tmp_dcd2pdb.tcl" % outputPDB) + + # CLEAN TMP FILES + runCommand("rm -f %s_tmp_dcd2pdb.tcl" % (outputPDB)) + + +def readLogFile(log_file): + with open(log_file,"r") as file: + header = None + dic = {} + for line in file: + if line.startswith("INFO:"): + if header is None: + header = line.split() + for i in range(1,len(header)): + dic[header[i]] = [] + else: + splitline = line.split() + if len(splitline) >= len(header): + for i in range(1,len(header)): + try : + dic[header[i]].append(float(splitline[i])) + except ValueError: + pass + return dic +def dcd2numpyArr(filename): + print("> Reading dcd file %s"%filename) + BYTESIZE = 4 + with open(filename, 'rb') as f: + + # Header + # ---------------- INIT + + start_size = int.from_bytes((f.read(BYTESIZE)), "little") + crd_type = f.read(BYTESIZE).decode('ascii') + nframe = int.from_bytes((f.read(BYTESIZE)), "little") + start_frame = int.from_bytes((f.read(BYTESIZE)), "little") + len_frame = int.from_bytes((f.read(BYTESIZE)), "little") + len_total = int.from_bytes((f.read(BYTESIZE)), "little") + for i in range(5): + f.read(BYTESIZE) + time_step = np.frombuffer(f.read(BYTESIZE), dtype=np.float32) + for i in range(9): + f.read(BYTESIZE) + charmm_version = int.from_bytes((f.read(BYTESIZE)), "little") + + end_size = int.from_bytes((f.read(BYTESIZE)), "little") + + if end_size != start_size: + raise RuntimeError("Can not read dcd file") + + # ---------------- TITLE + start_size = int.from_bytes((f.read(BYTESIZE)), "little") + ntitle = int.from_bytes((f.read(BYTESIZE)), "little") + tilte_rd = f.read(BYTESIZE*20 * ntitle) + try : + title = tilte_rd.encode("ascii") + except AttributeError: + title = str(tilte_rd) + end_size = int.from_bytes((f.read(BYTESIZE)), "little") + + if end_size != start_size: + raise RuntimeError("Can not read dcd file") + + # ---------------- NATOM + start_size = int.from_bytes((f.read(BYTESIZE)), "little") + natom = int.from_bytes((f.read(BYTESIZE)), "little") + end_size = int.from_bytes((f.read(BYTESIZE)), "little") + + if end_size != start_size: + raise RuntimeError("Can not read dcd file") + + # ----------------- DCD COORD + dcd_arr = np.zeros((nframe, natom, 3), dtype=np.float32) + for i in range(nframe): + for j in range(3): + + start_size = int.from_bytes((f.read(BYTESIZE)), "little") + while (start_size != BYTESIZE * natom and start_size != 0): + # print("\n-- UNKNOWN %s -- " % start_size) + + f.read(start_size) + end_size = int.from_bytes((f.read(BYTESIZE)), "little") + if end_size != start_size: + raise RuntimeError("Can not read dcd file") + start_size = int.from_bytes((f.read(BYTESIZE)), "little") + + bin_arr = f.read(BYTESIZE * natom) + if len(bin_arr) == BYTESIZE * natom: + dcd_arr[i, :, j] = np.frombuffer(bin_arr, dtype=np.float32) + else: + break + end_size = int.from_bytes((f.read(BYTESIZE)), "little") + if end_size != start_size: + if i>1: + break + else: + # pass + raise RuntimeError("Can not read dcd file %i %i " % (start_size, end_size)) + + print("\t -- Summary of DCD file -- ") + print("\t\t crd_type : %s"%crd_type) + print("\t\t nframe : %s"%nframe) + print("\t\t len_frame : %s"%len_frame) + print("\t\t len_total : %s"%len_total) + print("\t\t time_step : %s"%time_step) + print("\t\t charmm_version : %s"%charmm_version) + print("\t\t title : %s"%title) + print("\t\t natom : %s"%natom) + print("\t Done \n") + + return dcd_arr + +def numpyArr2dcd(arr, filename, start_frame=1, len_frame=1, time_step=1.0, title=None): + print("> Wrinting dcd file %s"%filename) + BYTESIZE = 4 + nframe, natom, _ = arr.shape + len_total=nframe*len_frame + charmm_version=24 + if title is None: + title = "DCD file generated by Continuous Flex plugin" + ntitle = (len(title)//(20*BYTESIZE)) + 1 + with open(filename, 'wb') as f: + zeroByte = int.to_bytes(0, BYTESIZE, "little") + + # Header + # ---------------- INIT + f.write(int.to_bytes(21*BYTESIZE ,BYTESIZE, "little")) + f.write(b'CORD') + f.write(int.to_bytes(nframe, BYTESIZE, "little")) + f.write(int.to_bytes(start_frame, BYTESIZE, "little")) + f.write(int.to_bytes(len_frame, BYTESIZE, "little")) + f.write(int.to_bytes(len_total, BYTESIZE, "little")) + for i in range(5): + f.write(zeroByte) + f.write(np.float32(time_step).tobytes()) + for i in range(9): + f.write(zeroByte) + f.write(int.to_bytes(charmm_version, BYTESIZE, "little")) + + f.write(int.to_bytes(21*BYTESIZE,BYTESIZE, "little")) + + # ---------------- TITLE + f.write(int.to_bytes((ntitle*20+1)*BYTESIZE ,BYTESIZE, "little")) + f.write(int.to_bytes(ntitle ,BYTESIZE, "little")) + f.write(title.ljust(20*BYTESIZE).encode("ascii")) + f.write(int.to_bytes((ntitle*20+1)*BYTESIZE ,BYTESIZE, "little")) + + # ---------------- NATOM + f.write(int.to_bytes(BYTESIZE ,BYTESIZE, "little")) + f.write(int.to_bytes(natom ,BYTESIZE, "little")) + f.write(int.to_bytes(BYTESIZE ,BYTESIZE, "little")) + + # ----------------- DCD COORD + for i in range(nframe): + for j in range(3): + f.write(int.to_bytes(BYTESIZE*natom, BYTESIZE, "little")) + f.write(np.float32(arr[i, :, j]).tobytes()) + f.write(int.to_bytes(BYTESIZE*natom, BYTESIZE, "little")) + print("\t Done \n") + +def existsCommand(name): + from shutil import which + return which(name) is not None diff --git a/continuousflex/protocols/utilities/mpi_genesis.py b/continuousflex/protocols/utilities/mpi_genesis.py new file mode 100644 index 0000000..8b3a348 --- /dev/null +++ b/continuousflex/protocols/utilities/mpi_genesis.py @@ -0,0 +1,202 @@ +import subprocess +from subprocess import Popen +import sys +import os +import shutil +import time + +print("---------------- MPI GENESIS ------------------") +usage = "USAGE : \n"\ + "\t python mpigenesis.py \n" \ + "\t\t -c, --mpi_command MPI_COMMAND (mpi command to run e.g. \"mpirun -np 1\")\n"\ + "\t\t -p, --num_mpi NUM_MPI (total number of MPI cores available)\n"\ + "\t\t -t, --num_threads NUM_THREADS (Number of OMP threads)\n" \ + "\t\t -i, --inputs GENESIS_INPUT_FILES_PATH (file containing the path to the genesis inputs files to run)\n" \ + "\t\t -o, --outputs GENESIS_LOG_FILES_PATH (file containing the path to the output log files to use)\n" \ + "\t\t -e, --executable GENESIS_EXECUTABLE_PATH (path to genesis executable e.g. /path/to/atdyn)\n" \ + "\t\t [-a, --mpi_argument MPI_ARGUMENT ] (Additional arguments to pass to the MPI command)]\n" \ + "\t\t [-r, --rankdir RANK_DIRECTORY ] (If set, use rankfiles to attribute each run to a core)\n" \ + "\t\t [-cn, --num_core_per_node NUM_CORE_PER_NODE ] (if rankdir is set, defines the number of cores per node)\n" \ + "\t\t [-sn, --num_socket_per_node NUM_SOCKET_PER_NODE ] (if rankdir is set, defines the number of sockets per node)\n" \ + "\t\t [-n, --num_node NUM_NODE ] (if rankdir is set, defines the number of nodes) \n" \ + "\t\t [-l, --localhost ] (If set, use localhost instead of relative host)\n"\ + "\t\t [-f, --first_index FIRST_INDEX] (If set, will skip all the inputs until FIRST_INDEX. 1 start at the first input file)\n"\ + "\t\t [-l, --last_index LAST_INDEX] (If set, will skip all the inputs after LAST_INDEX. -1 ends et the last input file)\n"\ + "\n\t\t -h, --help (Print this usage message)\n" + +mpi_command = "" +num_mpi = 1 +num_threads = 1 +inputs_path = "" +outputs_path="" +executable="" + +mpi_argument=None +localhost=False +use_rankfiles= False +rankdir = "" +num_core_per_node = 1 +num_socket_per_node = 1 +num_node = 1 +first_index = 1 +last_index = -1 + +for i in range(1, len(sys.argv)): + if sys.argv[i] == "-h" or sys.argv[i] == "--help": + print(usage) + exit(0) + if sys.argv[i] == "-c" or sys.argv[i] == "--mpi_command": + mpi_command = sys.argv[i+1] + if sys.argv[i] == "-p" or sys.argv[i] == "--num_mpi": + num_mpi = int(sys.argv[i+1]) + elif sys.argv[i] == "-t" or sys.argv[i] == "--num_threads": + num_threads = int(sys.argv[i+1]) + elif sys.argv[i] == "-i" or sys.argv[i] == "--inputs": + inputs_path = sys.argv[i+1] + elif sys.argv[i] == "-o" or sys.argv[i] == "--outputs": + outputs_path = sys.argv[i+1] + elif sys.argv[i] == "-e" or sys.argv[i] == "--executable": + executable = sys.argv[i+1] + elif sys.argv[i] == "-l" or sys.argv[i] == "--localhost": + localhost = True + elif sys.argv[i] == "-r" or sys.argv[i] == "--rankdir": + rankdir = sys.argv[i + 1] + use_rankfiles= True + elif sys.argv[i] == "-a" or sys.argv[i] == "--mpi_argument": + mpi_argument = sys.argv[i+1] + elif sys.argv[i] == "-cn" or sys.argv[i] == "--num_core_per_node": + num_core_per_node = int(sys.argv[i+1]) + elif sys.argv[i] == "-sn" or sys.argv[i] == "--num_socket_per_node": + num_socket_per_node = int(sys.argv[i+1]) + elif sys.argv[i] == "-n" or sys.argv[i] == "--num_node": + num_node = int(sys.argv[i + 1]) + elif sys.argv[i] == "-f" or sys.argv[i] == "--first_index": + first_index = int(sys.argv[i + 1]) + elif sys.argv[i] == "-l" or sys.argv[i] == "--last_index": + last_index = int(sys.argv[i + 1]) + + +print("Parameters : ") +print("\t mpi_command -> %s"%mpi_command) +print("\t num_mpi -> %s"%num_mpi) +print("\t num_threads -> %s"%num_threads) +print("\t inputs -> %s"%inputs_path) +print("\t outputs -> %s"%outputs_path) +print("\t executable -> %s"%executable) +print("\t first_index -> %i"%first_index) +print("\t last_index -> %i"%last_index) +if mpi_argument is not None: + print("\t mpi_argument -> %s" % mpi_argument ) +if use_rankfiles : + print("\t rankdir -> %s" % rankdir) + print("\t num_node -> %s" % num_node) + print("\t num_core_per_node -> %s" % num_core_per_node) + print("\t num_socket_per_node -> %s" % num_socket_per_node) + print("\t localhost -> %s"%str(localhost)) + +#Read inputs/ outputs +inputs = [] +with open(inputs_path,"r") as f: + for l in f: + inputs.append(l.strip()) +outputs = [] +with open(outputs_path,"r") as f: + for l in f: + outputs.append(l.strip()) +num_run = len(inputs) +if len(outputs) != num_run: + raise RuntimeError("Error: number of inputs and outputs differs : %i != %i"%(num_run, len(outputs))) +if last_index != -1: + num_run = last_index + +num_core_per_socket = num_core_per_node//num_socket_per_node + +if use_rankfiles: + # Clean and rankfile dir + if os.path.exists(rankdir) and len(rankdir): + if os.path.isdir(rankdir): + if os.path.islink(rankdir): + os.remove(rankdir) + else: + shutil.rmtree(rankdir) + else: + os.remove(rankdir) + os.makedirs(rankdir) + # create rank files + rankfiles = [] + for i in range(num_mpi): + A = int( i/num_core_per_node ) + j = int( i%num_core_per_node) + B= int(j/num_core_per_socket) + C= int(j%24) + if localhost: + rank = "rank 0=localhost slot=%i:%i"%(B,C) + else: + rank = "rank 0=+n%i slot=%i:%i"%(A,B,C) + rf = os.path.join(rankdir,"rank_file_%s"%str(i+1).zfill(6)) + with open(rf, "w") as f: + f.write(rank) + rankfiles.append(rf) + +# prepare env +num_complete = 0 +launch_index = first_index -1 +env = os.environ +env["OMP_NUM_THREADS"] = str(num_threads) +process = [None for i in range(num_mpi)] +status = [0 for i in range(num_mpi)] +if mpi_argument is None: + mpi_argument = "" + +# utils functions +def check_complete(): + complete = 0 + for i in range(num_mpi): + p = process[i] + if isinstance(p, subprocess.Popen): + stat = p.poll() + if stat is not None: + if stat != status[i]: + status[i] = stat + complete +=1 + if stat != 0 : + print("Warning : one task returned a non-zero exit") + else: + status[i] = stat + return complete + +def get_free_slot(): + for i in range(num_mpi): + if status[i] is not None: + return i + return -1 + +def print_load(): + print("Task completed : %i / %i"%(num_complete, num_run)) + +print_load() +while (1): + new = check_complete() + num_complete += new + if (num_complete == num_run): + break + if new !=0 : + print_load() + + slot = get_free_slot() + if slot == -1 : + time.sleep(1) + else: + if launch_index < num_run: + if use_rankfiles : + rank_command = "--rankfile %s"%rankfiles[slot] + else: + rank_command = "" + cmd = "%s %s %s %s %s > %s"\ + % (mpi_command, rank_command, mpi_argument, executable, inputs[launch_index], outputs[launch_index]) + print(cmd) + p = Popen(cmd, env=env, shell=True, cwd=os.getcwd()) + launch_index+=1 + process[slot] = p + +print("All task completed") \ No newline at end of file diff --git a/continuousflex/protocols/utilities/mwr_wrapper.m b/continuousflex/protocols/utilities/mwr_wrapper.m index bb2a0de..4eda926 100644 --- a/continuousflex/protocols/utilities/mwr_wrapper.m +++ b/continuousflex/protocols/utilities/mwr_wrapper.m @@ -26,7 +26,7 @@ % https://doi.org/10.1016/j.yjsbx.2019.100013. % (https://www.sciencedirect.com/science/article/pii/S259015241930011X) -% by Mohamad Harastani (mohamad.harastani@upmc.fr) +% by Mohamad Harastani (mohamad.harastani@igbmc.fr) function mwr_wrapper(path_vol_in, path_wedge, path_vol_out, sigma_noise, T, Tb, beta, mask_shifted) diff --git a/continuousflex/protocols/utilities/mwr_wrapper.py b/continuousflex/protocols/utilities/mwr_wrapper.py index 061bf8c..ddc262f 100644 --- a/continuousflex/protocols/utilities/mwr_wrapper.py +++ b/continuousflex/protocols/utilities/mwr_wrapper.py @@ -1,3 +1,4 @@ +# By Mohamad Harastani import continuousflex import os import tkinter.messagebox as tk diff --git a/continuousflex/protocols/utilities/optflow_run.py b/continuousflex/protocols/utilities/optflow_run.py index ef6e54f..b98f0c0 100644 --- a/continuousflex/protocols/utilities/optflow_run.py +++ b/continuousflex/protocols/utilities/optflow_run.py @@ -1,18 +1,27 @@ -from continuousflex.protocols.utilities.spider_files3 import open_volume, save_volume -import farneback3d +# By Mohamad Harastani + +from spider_files3 import open_volume, save_volume + import time import numpy as np import sys +import os def opflow_vols(path_vol0, path_vol1, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, factor1=100, - factor2=100, path_volx='x_OF_3D.vol', path_voly='y_OF_3D.vol', path_volz='z_OF_3D.vol'): + factor2=100, path_volx='x_OF_3D.vol', path_voly='y_OF_3D.vol', path_volz='z_OF_3D.vol', gpu_id=0): # Convention here is in reverse order vol0 = open_volume(path_vol0) vol1 = open_volume(path_vol1) vol0 = vol0 * factor1 vol1 = vol1 * factor2 + os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" + os.environ["CUDA_VISIBLE_DEVICES"] = str(gpu_id) + + import pycuda.autoinit + import farneback3d + optflow = farneback3d.Farneback( pyr_scale=pyr_scale, # Scaling between multi-scale pyramid levels levels=levels, # Number of multi-scale levels @@ -39,7 +48,7 @@ def opflow_vols(path_vol0, path_vol1, pyr_scale, levels, winsize, iterations, po if __name__ == '__main__': - if len(sys.argv) < 9 or len(sys.argv) > 14: + if len(sys.argv) < 9 or len(sys.argv) > 15: print('optical flow will not be calculated due to wrong arguments') else: opflow_vols(sys.argv[1], @@ -54,6 +63,7 @@ def opflow_vols(path_vol0, path_vol1, pyr_scale, levels, winsize, iterations, po int(sys.argv[10]), sys.argv[11], sys.argv[12], - sys.argv[13] + sys.argv[13], + int(sys.argv[14]) ) sys.exit() \ No newline at end of file diff --git a/continuousflex/protocols/utilities/optflow_warp.py b/continuousflex/protocols/utilities/optflow_warp.py new file mode 100644 index 0000000..ee80d62 --- /dev/null +++ b/continuousflex/protocols/utilities/optflow_warp.py @@ -0,0 +1,19 @@ +# By Mohamad Harastani + +from spider_files3 import save_volume +import sys +import farneback3d +import joblib + +def opflow_warp(ref_dump, flow_dump, warped_path_i): + reference = joblib.load(ref_dump) + flow_i = joblib.load(flow_dump) + warped_i = farneback3d.warp_by_flow(reference, flow_i) + save_volume(warped_i, warped_path_i) + + +if __name__ == '__main__': + opflow_warp(sys.argv[1], + sys.argv[2], + sys.argv[3]) + sys.exit() \ No newline at end of file diff --git a/continuousflex/protocols/utilities/par_all36_prot_na.prm b/continuousflex/protocols/utilities/par_all36_prot_na.prm new file mode 100644 index 0000000..3d2d0c8 --- /dev/null +++ b/continuousflex/protocols/utilities/par_all36_prot_na.prm @@ -0,0 +1,4610 @@ +*>>>> CHARMM36 All-Hydrogen Parameter File for Proteins <<<<<<<<<< +*>>>>> Includes phi, psi cross term map (CMAP) correction <<<<<<<< +*>>>>>>>>>>>>>>>>>>>>>>>>>> Feb. 2012 <<<<<<<<<<<<<<<<<<<<<<<<<<<< +* All comments to the CHARMM web site: www.charmm.org +* parameter set discussion forum +* + +!references +! +!Robert B. Best, R.B., Xiao Zhu, X., Shim, J., Lopes, P. +!Mittal, J., Feig, M. and MacKerell, A.D., Jr. Optimization of the +!additive CHARMM all-atom protein force field targeting improved +!sampling of the backbone phi, psi and sidechain chi1 and chi2 +!dihedral angles. In preparation +! +!MacKerell, A.D., Jr., Feig, M. and Brooks, III, C.L. "Improved +!treatment of the protein backbone in empirical force fields," Journal +!of the American Chemical Society, 126: 698-699, 2004 +! +!MacKerell, Jr., A. D.; Bashford, D.; Bellott, M.; Dunbrack Jr., R.L.; +!Evanseck, J.D.; Field, M.J.; Fischer, S.; Gao, J.; Guo, H.; Ha, S.; +!Joseph-McCarthy, D.; Kuchnir, L.; Kuczera, K.; Lau, F.T.K.; Mattos, +!C.; Michnick, S.; Ngo, T.; Nguyen, D.T.; Prodhom, B.; Reiher, III, +!W.E.; Roux, B.; Schlenkrich, M.; Smith, J.C.; Stote, R.; Straub, J.; +!Watanabe, M.; Wiorkiewicz-Kuczera, J.; Yin, D.; Karplus, M. All-atom +!empirical potential for molecular modeling and dynamics Studies of +!proteins. Journal of Physical Chemistry B, 1998, 102, 3586-3616. + +ATOMS +MASS -1 H 1.00800 ! polar H +MASS -1 HC 1.00800 ! N-ter H +MASS -1 HA 1.00800 ! nonpolar H +MASS -1 HP 1.00800 ! aromatic H +MASS -1 HB1 1.00800 ! backbone H +MASS -1 HB2 1.00800 ! aliphatic backbone H, to CT2 +MASS -1 HR1 1.00800 ! his he1, (+) his HG,HD2 +MASS -1 HR2 1.00800 ! (+) his HE1 +MASS -1 HR3 1.00800 ! neutral his HG, HD2 +MASS -1 HS 1.00800 ! thiol hydrogen +MASS -1 HE1 1.00800 ! for alkene; RHC=CR +MASS -1 HE2 1.00800 ! for alkene; H2C=CR +MASS -1 HA1 1.00800 ! alkane, CH, new LJ params (see toppar_all22_prot_aliphatic_c27.str) +MASS -1 HA2 1.00800 ! alkane, CH2, new LJ params (see toppar_all22_prot_aliphatic_c27.str) +MASS -1 HA3 1.00800 ! alkane, CH3, new LJ params (see toppar_all22_prot_aliphatic_c27.str) +MASS -1 C 12.01100 ! carbonyl C, peptide backbone +MASS -1 CA 12.01100 ! aromatic C +MASS -1 CT 12.01100 ! aliphatic sp3 C, new LJ params, no hydrogens, see retinol stream file for parameters +MASS -1 CT1 12.01100 ! aliphatic sp3 C for CH +MASS -1 CT2 12.01100 ! aliphatic sp3 C for CH2 +MASS -1 CT2A 12.01100 ! from CT2 (GLU, HSP chi1/chi2 fitting) 05282010, zhu +MASS -1 CT3 12.01100 ! aliphatic sp3 C for CH3 +MASS -1 CPH1 12.01100 ! his CG and CD2 carbons +MASS -1 CPH2 12.01100 ! his CE1 carbon +MASS -1 CPT 12.01100 ! trp C between rings +MASS -1 CY 12.01100 ! TRP C in pyrrole ring +MASS -1 CP1 12.01100 ! tetrahedral C (proline CA) +MASS -1 CP2 12.01100 ! tetrahedral C (proline CB/CG) +MASS -1 CP3 12.01100 ! tetrahedral C (proline CD) +MASS -1 CC 12.01100 ! carbonyl C, asn,asp,gln,glu,cter,ct2 +MASS -1 CD 12.01100 ! carbonyl C, pres aspp,glup,ct1 +MASS -1 CS 12.01100 ! thiolate carbon +MASS -1 CE1 12.01100 ! for alkene; RHC=CR +MASS -1 CE2 12.01100 ! for alkene; H2C=CR +MASS -1 CAI 12.01100 ! aromatic C next to CPT in trp +MASS -1 N 14.00700 ! proline N +MASS -1 NR1 14.00700 ! neutral his protonated ring nitrogen +MASS -1 NR2 14.00700 ! neutral his unprotonated ring nitrogen +MASS -1 NR3 14.00700 ! charged his ring nitrogen +MASS -1 NH1 14.00700 ! peptide nitrogen +MASS -1 NH2 14.00700 ! amide nitrogen +MASS -1 NH3 14.00700 ! ammonium nitrogen +MASS -1 NC2 14.00700 ! guanidinium nitrogen +MASS -1 NY 14.00700 ! TRP N in pyrrole ring +MASS -1 NP 14.00700 ! Proline ring NH2+ (N-terminal) +MASS -1 O 15.99900 ! carbonyl oxygen +MASS -1 OB 15.99900 ! carbonyl oxygen in acetic acid +MASS -1 OC 15.99900 ! carboxylate oxygen +MASS -1 OH1 15.99900 ! hydroxyl oxygen +MASS -1 OS 15.99940 ! ester oxygen +MASS -1 S 32.06000 ! sulphur +MASS -1 SM 32.06000 ! sulfur C-S-S-C type +MASS -1 SS 32.06000 ! thiolate sulfur + + +BONDS +! +!V(bond) = Kb(b - b0)**2 +! +!Kb: kcal/mole/A**2 +!b0: A +! +!atom type Kb b0 +! +NH2 CT1 240.000 1.4550 ! From LSN NH2-CT2 +! +!Indole/Tryptophan +CA CAI 305.000 1.3750 ! from CA CA +CAI CAI 305.000 1.3750 ! atm, methylindole, fit CCDSS +CPT CA 300.000 1.3600 ! atm, methylindole, fit CCDSS +CPT CAI 300.000 1.3600 ! atm, methylindole, fit CCDSS +CPT CPT 360.000 1.3850 ! atm, methylindole, fit CCDSS +CY CA 350.000 1.3650 ! trj, adm jr., 5/08/91, indole CCDB structure search +CY CAI 350.000 1.3650 ! from CY CA +CY CPT 350.000 1.4300 ! atm, methylindole, fit CDS data +CY CT3 375.000 1.4920 ! atm, methylindole, fit CDS data +CY CT2 375.000 1.4920 ! atm, methylindole, fit CDS data +HP CAI 340.000 1.0800 ! from HP CA +HP CY 350.000 1.0800 ! trp, adm jr., 12/30/91 +NY CA 270.000 1.3700 ! trp, adm jr., 12/30/91 +NY CPT 270.000 1.3700 ! atm, methylindole, from CCDS 1/17/04 +NY H 537.500 0.9760 ! atm, methylindole, 1/17/04 +CA CA 305.000 1.3750 ! ALLOW ARO + ! benzene, JES 8/25/89 +CE1 CE1 440.000 1.3400 ! + ! for butene; from propene, yin/adm jr., 12/95 +CE1 CE2 500.000 1.3420 ! + ! for propene, yin/adm jr., 12/95 +CE1 CT2 365.000 1.5020 ! + ! for butene; from propene, yin/adm jr., 12/95 +CE1 CT3 383.000 1.5040 ! + ! for butene, yin/adm jr., 12/95 +CE2 CE2 510.000 1.3300 ! + ! for ethene, yin/adm jr., 12/95 +CP1 C 250.000 1.4900 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP1 CC 250.000 1.4900 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP1 CD 200.000 1.4900 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP2 CP1 222.500 1.5270 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP2 CP2 222.500 1.5370 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 CP2 222.500 1.5370 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CPH1 CPH1 410.000 1.3600 ! ALLOW ARO + ! histidine, adm jr., 6/27/90 +CT1 C 250.000 1.4900 ! ALLOW ALI PEP POL ARO + ! Ala Dipeptide ab initio calc's (LK) fixed from 10/90 (5/91) +CT1 CC 200.000 1.5220 ! ALLOW POL + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +CT1 CD 200.000 1.5220 ! ALLOW POL + ! adm jr. 5/02/91, acetic acid pure solvent +CT1 CT1 222.500 1.5000 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT2 C 250.000 1.4900 ! ALLOW ALI PEP POL ARO + ! Ala Dipeptide ab initio calc's (LK) fixed from 10/90 (5/91) +CT2 CA 230.000 1.4900 ! ALLOW ALI ARO + ! phe,tyr, JES 8/25/89 +CT2 CC 200.000 1.5220 ! ALLOW POL + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +CT2 CD 200.000 1.5220 ! ALLOW POL + ! adm jr. 5/02/91, acetic acid pure solvent +CT2 CPH1 229.630 1.5000 ! ALLOW ARO + ! his, adm jr., 7/22/89, FC from CT2CT, BL from crystals +CT2 CT1 222.500 1.5380 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT2 CT2 222.500 1.5300 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT3 C 250.000 1.4900 ! ALLOW ALI PEP POL ARO + ! Ala Dipeptide ab initio calc's (LK) fixed from 10/90 (5/91) +CT3 CA 230.000 1.4900 ! ALLOW ALI ARO + ! toluene, adm jr. 3/7/92 +CT3 CC 200.000 1.5220 ! ALLOW POL + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +CT3 CD 200.000 1.5220 ! ALLOW POL + ! adm jr. 5/02/91, acetic acid pure solvent +CT3 CPH1 229.630 1.5000 ! ALLOW ARO + ! his, adm jr., 7/22/89, FC from CT2CT, BL from crystals +CT3 CS 190.000 1.5310 ! ALLOW SUL + ! ethylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +CT3 CT1 222.500 1.5380 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT3 CT2 222.500 1.5280 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT3 CT3 222.500 1.5300 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +H CD 330.000 1.1100 ! ALLOW PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +HA1 CC 317.130 1.1000 ! ALLOW POL + ! adm jr., 5/13/91, formamide geometry and vibrations +HA2 CP2 309.000 1.1110 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA2 CP3 309.000 1.1110 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA2 CS 300.000 1.1110 ! ALLOW SUL + ! methylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +HA3 CS 300.000 1.1110 ! ALLOW SUL + ! methylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +HA1 CT1 309.000 1.1110 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HA2 CT2 309.000 1.1110 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HA3 CT3 322.000 1.1110 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +!HA CY 330.000 1.0800 ! ALLOW ARO + ! JWK 05/14/91 new r0 from indole +HE1 CE1 360.500 1.1000 ! + ! for propene, yin/adm jr., 12/95 +HE2 CE2 365.000 1.1000 ! + ! for ethene, yin/adm jr., 12/95 +HB1 CP1 330.000 1.0800 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HB1 CT1 330.000 1.0800 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HB2 CT2 330.000 1.0800 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +!HB3 CT3 330.000 1.0800 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HP CA 340.000 1.0800 ! ALLOW ARO + ! phe,tyr JES 8/25/89 +HR1 CPH1 375.000 1.0830 ! ALLOW ARO + ! his, adm jr., 6/27/90 +HR1 CPH2 340.000 1.0900 ! ALLOW ARO + ! his, adm jr., 6/28/29 +HR2 CPH2 333.000 1.0700 ! ALLOW ARO + ! his, adm jr., 6/27/90 +HR3 CPH1 365.000 1.0830 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +N C 260.000 1.3000 ! ALLOW PEP POL ARO PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N CP1 320.000 1.4340 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N CP3 320.000 1.4550 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NC2 C 450.000 1.3650 ! ALLOW PEP POL ARO + ! mp2/6-311g** mgua vib. data, adm jr., 1/04 +NC2 CT2 390.000 1.4900 ! ALLOW ALI POL + ! mp2/6-311g** mgua vib. data, adm jr., 1/04 +NC2 CT3 390.000 1.4900 ! ALLOW ALI POL + ! mp2/6-311g** mgua vib. data, adm jr., 1/04 +NC2 HC 455.000 1.0000 ! ALLOW POL + ! 405.0->455.0 GUANIDINIUM (KK) +NH1 C 370.000 1.3450 ! ALLOW PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +NH1 CT1 320.000 1.4300 ! ALLOW ALI PEP POL ARO + ! NMA Gas & Liquid Phase IR Spectra (LK) +NH1 CT2 320.000 1.4300 ! ALLOW ALI PEP POL ARO + ! NMA Gas & Liquid Phase IR Spectra (LK) +NH1 CT3 320.000 1.4300 ! ALLOW ALI PEP POL ARO + ! NMA Gas & Liquid Phase IR Spectra (LK) +NH1 H 440.000 0.9970 ! ALLOW PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +NH1 HC 405.000 0.9800 ! ALLOW PEP POL ARO + ! (DS) +NH2 CC 430.000 1.3600 ! ALLOW PEP POL ARO + ! adm jr. 4/10/91, acetamide +NH2 CT2 240.000 1.4550 + ! from NH2 CT3, neutral glycine, adm jr. +NH2 CT3 240.000 1.4550 ! ALLOW POL + ! methylamine geom/freq, adm jr., 6/2/92 +NH2 H 480.000 1.0000 ! ALLOW POL + ! adm jr. 8/13/90 acetamide geometry and vibrations +NH2 HC 460.000 1.0000 ! ALLOW POL + ! methylamine geom/freq, adm jr., 6/2/92 +NH3 CT1 200.000 1.4800 ! ALLOW ALI POL + ! new stretch and bend; methylammonium (KK 03/10/92) +NH3 CT2 200.000 1.4800 ! ALLOW ALI POL + ! new stretch and bend; methylammonium (KK 03/10/92) +NH3 CT3 200.000 1.4800 ! ALLOW ALI POL + ! new stretch and bend; methylammonium (KK 03/10/92) +NH3 HC 403.000 1.0400 ! ALLOW POL + ! new stretch and bend; methylammonium (KK 03/10/92) +NP CP1 320.000 1.4850 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NP CP3 320.000 1.5020 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NP HC 460.000 1.0060 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NR1 CPH1 400.000 1.3800 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR1 CPH2 400.000 1.3600 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR1 H 466.000 1.0000 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR2 CPH1 400.000 1.3800 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR2 CPH2 400.000 1.3200 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR3 CPH1 380.000 1.3700 ! ALLOW ARO + ! his, adm jr., 6/28/90 +NR3 CPH2 380.000 1.3200 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR3 H 453.000 1.0000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +O C 620.000 1.2300 ! ALLOW PEP POL ARO + ! Peptide geometry, condensed phase (LK) +O CC 650.000 1.2300 ! ALLOW PEP POL ARO + ! adm jr. 4/10/91, acetamide +OB CC 750.000 1.2200 ! ALLOW PEP POL ARO + ! adm jr., 10/17/90, acetic acid vibrations and geom. +OB CD 750.000 1.2200 ! ALLOW PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +OC CA 525.000 1.2600 ! ALLOW PEP POL ARO ION + ! adm jr. 8/27/91, phenoxide +OC CC 525.000 1.2600 ! ALLOW PEP POL ARO ION + ! adm jr. 7/23/91, acetic acid +OC CT2 450.000 1.3300 ! ALLOW ALC + ! ethoxide 6-31+G* geom/freq, adm jr., 6/1/92 +OC CT3 450.000 1.3300 ! ALLOW ALC + ! methoxide 6-31+G* geom/freq, adm jr., 6/1/92 +OH1 CA 334.300 1.4110 ! ALLOW ARO ALC + ! MeOH, EMB 10/10/89, +OH1 CD 230.000 1.4000 ! ALLOW PEP POL ARO ALC + ! adm jr. 5/02/91, acetic acid pure solvent +OH1 CT1 428.000 1.4200 ! ALLOW ALI ALC ARO + ! methanol vib fit EMB 11/21/89 +OH1 CT2 428.000 1.4200 ! ALLOW ALI ALC ARO + ! methanol vib fit EMB 11/21/89 +OH1 CT3 428.000 1.4200 ! ALLOW ALI ALC ARO + ! methanol vib fit EMB 11/21/89 +OH1 H 545.000 0.9600 ! ALLOW ALC ARO + ! EMB 11/21/89 methanol vib fit +OS CD 150.000 1.3340 ! ALLOW POL PEP + ! adm jr. 5/02/91, acetic acid pure solvent +OS CT3 340.000 1.4300 ! ALLOW POL PEP + ! adm jr., 4/05/91, for PRES CT1 from methylacetate +S CT2 198.000 1.8180 ! ALLOW ALI SUL ION + ! fitted to C-S s 9/26/92 (FL) +S CT3 240.000 1.8160 ! ALLOW ALI SUL ION + ! fitted to C-S s 9/26/92 (FL) +S HS 275.000 1.3250 ! ALLOW SUL ION + ! methanethiol pure solvent, adm jr., 6/22/92 +SM CT2 214.000 1.8160 ! ALLOW SUL ION + ! improved CSSC surface in DMDS 5/15/92 (FL) +SM CT3 214.000 1.8160 ! ALLOW SUL ION + ! improved CSSC surface in DMDS 5/15/92 (FL) +SM SM 173.000 2.0290 ! ALLOW SUL ION + ! improved CSSC surface in DMDS 5/15/92 (FL) +SS CS 205.000 1.8360 ! ALLOW SUL + ! methylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +HR1 CD 330.000 1.1100 ! acetaldehyde, benzaldehyde, 3ALP +O CD 720.000 1.2050 ! acetaldehyde, benzaldehyde, 3ALP. from stream/toppar_all27_na_bkb_modifications.str +CT2A CT1 222.500 1.5380 ! from CT2 CT1, Zhu +CT2 CT2A 222.500 1.5300 ! from CT2 CT2, Zhu +CT2A HA2 309.000 1.1110 ! from HA2 CT2, Zhu +CT2A CPH1 229.630 1.5000 ! from CT2 CPH1, Zhu +!ASP, CT2->CT2A +CT2A CC 200.000 1.5220 ! from CT2 CC, jshim +! RESI CYSM and PRES CYSD +CT1 CS 190.000 1.5380 ! from CT3 CS but lengthened; compare CT3 CT2 with CT2 CT1; kevo + +ANGLES +! +!V(angle) = Ktheta(Theta - Theta0)**2 +! +!V(Urey-Bradley) = Kub(S - S0)**2 +! +!Ktheta: kcal/mole/rad**2 +!Theta0: degrees +!Kub: kcal/mole/A**2 (Urey-Bradley) +!S0: A +! +!atom types Ktheta Theta0 Kub S0 +! +H NH2 CT1 50.000 111.00 ! From LSN HC-NH2-CT2 +H NH2 CT2 50.000 111.00 ! From LSN HC-NH2-CT2, Neutral Gly Nterminus +NH2 CT1 CT1 67.700 110.00 ! From LSN NH2-CT2-CT2 +NH2 CT1 CT2 67.700 110.00 ! From LSN NH2-CT2-CT2 +NH2 CT1 CT3 67.700 110.00 ! From LSN NH2-CT2-CT2 +CT1 CD OH1 55.000 110.50 ! From ASPP CT2-CD-OH1 +CT3 CT1 CD 52.000 108.00 ! Ala cter +NH2 CT1 HB1 38.000 109.50 50.00 2.1400 ! From LSN NH2-CT2-HA +NH2 CT1 C 50.000 107.00 ! From ALA Dipep. NH1-CT2-C +NH2 CT2 C 50.000 107.00 ! From ALA Dipep. NH1-CT2-C, Neutral Gly Nterminus + +! +!Indole/Tryptophan +CAI CAI CA 40.000 120.00 35.00 2.41620 ! from CA CA CA +CAI CA CA 40.000 120.00 35.00 2.41620 ! from CA CA CA +CPT CA CA 50.000 113.20 ! atm, methylindole, 1/17/04 +CPT CPT CA 50.000 110.00 ! atm, methylindole, 1/17/04 +CPT CAI CA 50.000 113.20 ! atm, methylindole, 1/17/04 +CPT CPT CAI 50.000 110.00 ! atm, methylindole, 1/17/04 +CPT CY CA 85.000 106.40 25.00 2.26100 ! atm, methylindole, 1/17/04 +CPT NY CA 85.000 112.00 ! atm, methylindole, 1/17/04 +CT2 CY CA 30.000 127.00 ! atm, methylindole, CT3 CY CA +CT2 CY CPT 30.000 126.70 ! atm, methylindole, 1/17/04 +CT3 CY CA 30.000 127.00 ! atm, methylindole, CT3 CY CA +CT3 CY CPT 30.000 126.70 ! atm, methylindole, 1/17/04 +CY CPT CA 130.000 133.50 ! atm, methylindole, 1/17/04 +CY CPT CAI 130.000 133.50 ! atm, methylindole, 1/17/04 +CY CPT CPT 85.000 108.00 ! atm, methylindole, 1/17/04 +CY CT2 CT1 58.350 114.00 ! from TRP crystal, JWK +CY CT2 CT3 58.350 114.00 ! from TRP crystal, JWK +H NY CA 28.000 126.00 ! trp, adm jr., 12/30/91 +H NY CAI 28.000 126.00 ! trp, adm jr., 12/30/91 +H NY CPT 28.000 126.00 ! trp, adm jr., 12/30/91 +HA2 CT2 CY 55.000 109.50 ! atm, methylindole, 1/17/04 +HA3 CT3 CY 55.000 109.50 ! atm, methylindole, 1/17/04 +HP CA CAI 30.000 120.00 22.00 2.15250 ! from HP CA CA +HP CAI CA 30.000 120.00 22.00 2.15250 ! from HP CA CA +HP CA CPT 30.000 122.00 22.00 2.14600 ! trp, adm jr., 12/30/91 +HP CAI CPT 30.000 122.00 22.00 2.14600 ! from HP CA CPT +HP CA CY 32.000 125.00 25.00 2.17300 ! JWK 05/14/91 new theta0 and r0UB from indole +HP CY CA 32.000 126.40 25.00 2.18600 ! trp, adm jr., 12/30/91 +HP CY CPT 32.000 126.40 25.00 2.25500 ! JWK 05/14/91 new theta0 and r0UB from indole +NY CA CY 85.000 110.50 25.00 2.24000 ! trp, adm jr., 12/30/91 +NY CA HP 32.000 125.00 25.00 2.17700 ! JWK 05/14/91 new theta0 and r0UB from indole +NY CPT CA 130.000 129.50 ! atm, methylindole, 1/17/04 +NY CPT CAI 130.000 129.50 ! atm, methylindole, 1/17/04 +NY CPT CPT 95.000 107.40 ! atm, methylindole, 1/17/04 +CA CA CA 40.000 120.00 35.00 2.41620 ! ALLOW ARO + ! JES 8/25/89 +CE1 CE1 CT2 48.00 123.50 ! + ! for 2-butene, yin/adm jr., 12/95 +CE1 CE1 CT3 48.00 123.50 ! + ! for 2-butene, yin/adm jr., 12/95 +CE1 CT2 CT3 32.00 112.20 ! + ! for 1-butene; from propene, yin/adm jr., 12/95 +CE2 CE1 CT2 48.00 126.00 ! + ! for 1-butene; from propene, yin/adm jr., 12/95 +CE2 CE1 CT3 47.00 125.20 ! + ! for propene, yin/adm jr., 12/95 +CP1 N C 60.000 117.0000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP2 CP1 C 52.000 112.3000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP2 CP1 CC 52.000 112.3000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP2 CP1 CD 50.000 112.3000 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP2 CP2 CP1 70.000 108.5000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 CP2 CP2 70.000 108.5000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 N C 60.000 117.0000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 N CP1 100.000 114.2000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 NP CP1 100.000 111.0000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CPH2 NR1 CPH1 130.000 107.5000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +CPH2 NR2 CPH1 130.000 104.0000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +CPH2 NR3 CPH1 145.000 108.0000 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +CT1 CT1 C 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +CT1 CT1 CC 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +CT1 CT1 CD 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 6/27/2012, for Thr with CT1 patch +CT1 CT1 CT1 53.350 111.00 8.00 2.56100 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT1 CT2 CA 51.800 107.5000 ! ALLOW ALI ARO + ! PARALLH19 (JES) +CT1 CT2 CC 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +CT1 CT2 CD 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +CT1 CT2 CPH1 58.350 113.0000 ! ALLOW ARO + ! his, ADM JR., 7/22/89, from CT2CT2CT, U-B omitted +CT1 CT2 CT1 58.350 113.50 11.16 2.56100 ! ALLOW ALI + ! alkane frequencies (MJF), alkane geometries (SF) +CT1 NH1 C 50.000 120.0000 ! ALLOW ALI PEP POL ARO + ! NMA Vib Modes (LK) +CT2 CA CA 45.800 122.3000 ! ALLOW ALI ARO + ! PARALLH19 (JES) +CT2 CPH1 CPH1 45.800 130.0000 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FC=>CT2CA CA,BA=> CRYSTALS +CT2 CT1 C 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +CT2 CT1 CC 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +CT2A CT1 CC 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +CT2 CT1 CD 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +CT2 CT1 CT1 53.350 111.00 8.00 2.56100 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT2 CT2 C 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! from CT2 CT1 C, for lactams, adm jr. +CT2 CT2 CC 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +CT3 CT2 CC 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +CT2 CT2 CD 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +CT2A CT2 CD 52.000 108.0000 ! for GLUP, ZHU +CT2 CT2 CT1 58.350 113.50 11.16 2.56100 ! ALLOW ALI + ! alkane frequencies (MJF), alkane geometries (SF) +CT2 CT2 CT2 58.350 113.60 11.16 2.56100 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT2 CT3 CT1 58.350 113.50 11.16 2.56100 ! ALLOW ALI + ! alkane frequencies (MJF), alkane geometries (SF) +CT2 NC2 C 62.300 120.0000 ! ALLOW ALI POL PEP ARO + ! 107.5->120.0 to make planar Arg (KK) +CT2 NH1 C 50.000 120.0000 ! ALLOW ALI PEP POL ARO + ! NMA Vib Modes (LK) +CT2 OS CD 40.000 109.60 30.00 2.26510 ! ALLOW POL PEP + ! adm jr. 5/02/91, acetic acid pure solvent +CT3 CA CA 45.800 122.3000 ! ALLOW ALI ARO + ! toluene, adm jr., 3/7/92 +CT3 CPH1 CPH1 45.800 130.0000 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FC=>CT2CA CA,BA=> CRYSTALS +CT3 CT1 C 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +CT3 CT1 CC 52.000 108.0000 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/09/92, for ALA cter +CT3 CT1 CT1 53.350 108.50 8.00 2.56100 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT3 CT1 CT2 53.350 114.00 8.00 2.56100 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT3 CT1 CT3 53.350 114.00 8.00 2.56100 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT3 CT2 CA 51.800 107.5000 ! ALLOW ALI ARO + ! ethylbenzene, adm jr., 3/7/92 +CT3 CT2 CPH1 58.350 113.0000 ! ALLOW ARO + ! his, ADM JR., 7/22/89, from CT2CT2CT, U-B omitted +CT3 CT2 CT1 58.350 113.50 11.16 2.56100 ! ALLOW ALI + ! alkane frequencies (MJF), alkane geometries (SF) +CT3 CT2 CT2 58.000 115.00 8.00 2.56100 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT3 CT2 CT3 53.350 114.00 8.00 2.56100 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CT3 NC2 C 62.300 120.0000 ! ALLOW ALI POL PEP ARO + ! methylguanidinium, adm jr., 3/26/92 +CT3 NH1 C 50.000 120.0000 ! ALLOW ALI PEP POL ARO + ! NMA Vib Modes (LK) +CT3 OS CD 40.000 109.60 30.00 2.26510 ! ALLOW POL PEP + ! adm jr. 5/02/91, acetic acid pure solvent +CT3 S CT2 34.000 95.0000 ! ALLOW ALI SUL ION + ! expt. MeEtS, 3/26/92 (FL) +H NH1 C 34.000 123.0000 ! ALLOW PEP POL ARO + ! NMA Vib Modes (LK) +H NH1 CT1 35.000 117.0000 ! ALLOW PEP POL ARO ALI + ! NMA Vibrational Modes (LK) +H NH1 CT2 35.000 117.0000 ! ALLOW PEP POL ARO ALI + ! NMA Vibrational Modes (LK) +H NH1 CT3 35.000 117.0000 ! ALLOW PEP POL ARO ALI + ! NMA Vibrational Modes (LK) +H NH2 CC 50.000 120.0000 ! ALLOW POL PEP ARO + ! his, adm jr. 8/13/90 acetamide geometry and vibrations +H NH2 H 23.000 120.0000 ! ALLOW POL + ! adm jr. 8/13/90 acetamide geometry and vibrations +H NR1 CPH1 30.000 125.50 20.00 2.15000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +H NR1 CPH2 30.000 127.00 20.00 2.14000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +H NR3 CPH1 25.000 126.00 15.00 2.13000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +H NR3 CPH2 25.000 126.00 15.00 2.09000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +H OH1 CA 65.000 108.0000 ! ALLOW ALC ARO + ! JES 8/25/89 phenol +H OH1 CD 55.000 115.0000 ! ALLOW ALC ARO PEP POL + ! adm jr. 5/02/91, acetic acid pure solvent +H OH1 CT1 57.500 106.0000 ! ALLOW ALC ARO ALI + ! methanol vib fit EMB 11/21/89 +H OH1 CT2 57.500 106.0000 ! ALLOW ALC ARO ALI + ! methanol vib fit EMB 11/21/89 +H OH1 CT3 57.500 106.0000 ! ALLOW ALC ARO ALI + ! methanol vib fit EMB 11/21/89 +HA2 CP2 CP1 33.430 110.10 22.53 2.17900 ! ALLOW ALI PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA2 CP2 CP2 26.500 110.10 22.53 2.17900 ! ALLOW ALI PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA2 CP2 CP3 26.500 110.10 22.53 2.17900 ! ALLOW ALI PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA2 CP2 HA2 35.500 109.00 5.40 1.80200 ! ALLOW ALI PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA2 CP3 CP2 26.500 110.10 22.53 2.17900 ! ALLOW ALI PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA2 CP3 HA2 35.500 109.00 5.40 1.80200 ! ALLOW ALI PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA2 CS CT3 34.600 110.10 22.53 2.17900 ! ALLOW SUL + ! ethylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +HA2 CS HA2 35.500 108.40 14.00 1.77500 ! ALLOW SUL + ! methylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +HA3 CS HA3 35.500 108.40 14.00 1.77500 ! ALLOW SUL + ! methylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +HA1 CT1 C 33.000 109.50 30.00 2.16300 ! ALLOW ALI PEP POL ARO + ! alanine dipeptide, LK, replaced, adm jr., 5/09/91 +HA1 CT1 CD 33.000 109.50 30.00 2.16300 ! ALLOW ALI PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +HA1 CT1 CT1 34.500 110.10 22.53 2.17900 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HA1 CT1 CT2 34.500 110.10 22.53 2.17900 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HA1 CT1 CT3 34.500 110.10 22.53 2.17900 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HA1 CT1 HA1 35.500 109.00 5.40 1.80200 ! TEST for test cpd + ! based on HA CT2 HA +HA2 CT2 C 33.000 109.50 30.00 2.16300 ! ALLOW ALI PEP POL ARO + ! alanine dipeptide, LK, replaced, adm jr., 5/09/91 +HA2 CT2 CA 49.300 107.5000 ! ALLOW ALI ARO + ! PARALLH19 (JES) +HA2 CT2 CC 33.000 109.50 30.00 2.16300 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +HA2 CT2 CD 33.000 109.50 30.00 2.16300 ! ALLOW ALI PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +HA2 CT2 CE1 45.00 111.50 ! + ! for 1-butene; from propene, yin/adm jr., 12/95 +HA2 CT2 CPH1 33.430 109.5000 ! ALLOW ARO + ! his, ADM JR., 7/22/89, from CT2CT2HA, U-B OMITTED +HA2 CT2 CT1 26.500 110.10 22.53 2.17900 ! ALLOW ALI + ! alkane frequencies (MJF), alkane geometries (SF) +HA2 CT2 CT2 26.500 110.10 22.53 2.17900 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HA2 CT2 CT3 34.600 110.10 22.53 2.17900 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HA2 CT2 HA2 35.500 109.00 5.40 1.80200 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HA3 CT3 C 33.000 109.50 30.00 2.16300 ! ALLOW ALI PEP POL ARO + ! alanine dipeptide, LK, replaced, adm jr., 5/09/91 +HA3 CT3 CA 49.300 107.5000 ! ALLOW ALI ARO + ! toluene, adm jr. 3/7/92 +HA3 CT3 CC 33.000 109.50 30.00 2.16300 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +HA3 CT3 CD 33.000 109.50 30.00 2.16300 ! ALLOW ALI PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +HA3 CT3 CE1 42.00 111.50 ! + ! for 2-butene, yin/adm jr., 12/95 +HA3 CT3 CPH1 33.430 109.5000 ! ALLOW ARO + ! his, ADM JR., 7/22/89, from CT2CT2HA, U-B OMITTED +HA3 CT3 CS 34.600 110.10 22.53 2.17900 ! ALLOW SUL + ! ethylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +HA3 CT3 CT1 33.430 110.10 22.53 2.17900 ! ALLOW ALI + ! alkane frequencies (MJF), alkane geometries (SF) +HA3 CT3 CT2 34.600 110.10 22.53 2.17900 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HA3 CT3 CT3 37.500 110.10 22.53 2.17900 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HA3 CT3 HA3 35.500 108.40 5.40 1.80200 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +HE1 CE1 CE1 52.00 119.50 ! + ! for 2-butene, yin/adm jr., 12/95 +HE1 CE1 CE2 42.00 118.00 ! + ! for propene, yin/adm jr., 12/95 +HE1 CE1 CT2 40.00 116.00 ! + ! for 1-butene; from propene, yin/adm jr., 12/95 +HE1 CE1 CT3 22.00 117.00 ! + ! for propene, yin/adm jr., 12/95 +HE2 CE2 CE1 45.00 120.50 ! + ! for propene, yin/adm jr., 12/95 +HE2 CE2 CE2 55.50 120.50 ! + ! for ethene, yin/adm jr., 12/95 +HE2 CE2 HE2 19.00 119.00 ! + ! for propene, yin/adm jr., 12/95 +HB1 CP1 C 50.000 112.0000 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HB1 CP1 CC 50.000 112.0000 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HB1 CP1 CD 50.000 112.0000 ! ALLOW PEP POL PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HB1 CP1 CP2 35.000 118.0000 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HB1 CT1 C 50.000 109.5000 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HB1 CT1 CC 50.000 109.5000 ! ALLOW PEP POL + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +HB1 CT1 CD 50.000 109.5000 ! ALLOW PEP POL + ! adm jr. 5/02/91, acetic acid pure solvent +HB1 CT1 CT1 35.000 111.0000 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HB1 CT1 CT2 35.000 111.0000 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HB1 CT1 CT3 35.000 111.0000 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HB2 CT2 C 50.000 109.5000 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HB2 CT2 CC 50.000 109.5000 ! ALLOW PEP POL + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +HB2 CT2 CD 50.000 109.5000 ! ALLOW PEP POL + ! adm jr. 5/02/91, acetic acid pure solvent +HB2 CT2 HB2 36.000 115.0000 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HC NC2 C 49.000 120.0000 ! ALLOW POL PEP ARO + ! 35.3->49.0 GUANIDINIUM (KK) +HC NC2 CT2 40.400 120.0000 ! ALLOW POL ALI + ! 107.5->120.0 to make planar Arg (KK) +HC NC2 CT3 40.400 120.0000 ! ALLOW POL ALI + ! methylguanidinium, adm jr., 3/26/92 +HC NC2 HC 25.000 120.0000 ! ALLOW POL + ! 40.0->25.0 GUANIDINIUM (KK) +HC NH2 CT2 50.000 111.0000 ! ALLOW POL + ! from HC NH2 CT3, neutral glycine, adm jr. +HC NH2 CT3 50.000 111.0000 ! ALLOW POL + ! methylamine geom/freq, adm jr., 6/2/92 +HC NH2 HC 39.000 106.5000 ! ALLOW POL + ! 40.0->25.0 GUANIDINIUM (KK) +HC NH3 CT1 30.000 109.50 20.00 2.07400 ! ALLOW POL ALI + ! new stretch and bend; methylammonium (KK 03/10/92) +HC NH3 CT2 30.000 109.50 20.00 2.07400 ! ALLOW POL ALI + ! new stretch and bend; methylammonium (KK 03/10/92) +HC NH3 CT3 30.000 109.50 20.00 2.07400 ! ALLOW POL ALI + ! new stretch and bend; methylammonium (KK 03/10/92) +HC NH3 HC 44.000 109.5000 ! ALLOW POL + ! new stretch and bend; methylammonium (KK 03/10/92) +HC NP CP1 33.000 109.50 4.00 2.05600 ! ALLOW POL ALI PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HC NP CP3 33.000 109.50 4.00 2.05600 ! ALLOW POL ALI PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HC NP HC 51.000 107.5000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HP CA CA 30.000 120.00 22.00 2.15250 ! ALLOW ARO + ! JES 8/25/89 benzene +HR1 CPH1 CPH1 22.000 130.00 15.00 2.21500 ! ALLOW ARO + ! adm jr., 6/27/90, his +HR3 CPH1 CPH1 25.000 130.00 20.00 2.20000 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HS S CT2 38.800 95.0000 ! ALLOW SUL ION ALI + ! methanethiol pure solvent, adm jr., 6/22/92 +HS S CT3 43.000 95.0000 ! ALLOW SUL ION ALI + ! methanethiol pure solvent, adm jr., 6/22/92 +N C CP1 20.000 112.5000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CT1 20.000 112.5000 ! ALLOW ALI PEP POL ARO PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CT2 20.000 112.5000 ! ALLOW ALI PEP POL ARO PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CT3 20.000 112.5000 ! ALLOW ALI PEP POL ARO PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N CP1 C 50.000 108.2000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N CP1 CC 50.000 108.2000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N CP1 CD 50.000 108.2000 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N CP1 CP2 70.000 110.8000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N CP1 HB1 48.000 112.0000 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N CP3 CP2 70.000 110.5000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N CP3 HA2 48.000 108.0000 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NC2 C NC2 40.000 120.00 70.00 2.31 + ! mp2/6-311g** mgua vib data, adm jr., 1/04 + ! N-N distances: 2.29001, 2.31146, 2.33240 +NC2 CT2 CT2 67.700 107.5000 ! ALLOW ALI POL + ! arg, (DS) +NC2 CT2 HA2 56.500 107.5000 ! ALLOW ALI POL + ! mp2/6-311g** mgua vib data, adm jr., 1/04 +NC2 CT3 HA3 56.5000 107.5000 ! ALLOW ALI POL + ! mp2/6-311g** mgua vib data, adm jr., 1/04 +NH1 C CP1 80.000 116.5000 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH1 C CT1 80.000 116.5000 ! ALLOW ALI PEP POL ARO + ! NMA Vib Modes (LK) +NH1 C CT2 80.000 116.5000 ! ALLOW ALI PEP POL ARO + ! NMA Vib Modes (LK) +NH1 C CT3 80.000 116.5000 ! ALLOW ALI PEP POL ARO + ! NMA Vib Modes (LK) +NH1 CT1 C 50.000 107.0000 ! ALLOW PEP POL ARO ALI + ! Alanine Dipeptide ab initio calc's (LK) +NH1 CT1 CC 50.000 107.0000 ! ALLOW PEP POL ARO ALI + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +NH1 CT1 CD 50.000 107.0000 ! ALLOW PEP POL ARO ALI + ! adm jr. 5/02/91, acetic acid pure solvent +NH1 CT1 CT1 70.000 113.5000 ! ALLOW ALI PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +NH1 CT1 CT2 70.000 113.5000 ! ALLOW ALI PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +NH1 CT1 CT3 70.000 113.5000 ! ALLOW ALI PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +NH1 CT1 HB1 48.000 108.0000 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +NH1 CT2 C 50.000 107.0000 ! ALLOW PEP POL ARO ALI + ! Alanine Dipeptide ab initio calc's (LK) +NH1 CT2 CC 50.000 107.0000 ! ALLOW PEP POL ARO ALI + ! adm jr. 5/20/92, for asn,asp,gln,glu and cters +NH1 CT2 CD 50.000 107.0000 ! ALLOW PEP POL ARO ALI + ! adm jr. 5/02/91, acetic acid pure solvent +NH1 CT2 CT2 70.000 113.5000 ! ALLOW ALI PEP POL ARO + ! from NH1 CT1 CT2, for lactams, adm jr. +NH1 CT2 HA2 51.500 109.5000 ! ALLOW ALI PEP POL ARO + ! from NH1 CT3 HA, for lactams, adm jr. +NH1 CT2 HB2 48.000 108.0000 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +NH1 CT3 HA3 51.500 109.5000 ! ALLOW ALI PEP POL ARO + ! NMA crystal (JCS) +NH2 CC CP1 80.000 112.5000 ! ALLOW ALI PEP POL ARO PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH2 CC CT1 50.000 116.50 50.00 2.45000 ! ALLOW ALI PEP POL ARO + ! adm jr. 8/13/90 acetamide geometry and vibrations +NH2 CC CT2 50.000 116.50 50.00 2.45000 ! ALLOW ALI PEP POL ARO + ! adm jr. 8/13/90 acetamide geometry and vibrations +NH2 CC CT3 50.000 116.50 50.00 2.45000 ! ALLOW ALI PEP POL ARO + ! adm jr. 8/13/90 acetamide geometry and vibrations +NH2 CC HA1 44.000 111.00 50.00 1.98000 ! ALLOW POL + ! adm jr., 5/13/91, formamide geometry and vibrations +NH2 CT2 HB2 38.000 109.50 50.00 2.14000 + !from NH2 CT3 HA, neutral glycine, adm jr. +NH2 CT2 CD 52.000 108.0000 + !from CT2 CT2 CD, neutral glycine, adm jr. +NH2 CT2 CT2 67.700 110.0000 ! ALLOW ALI POL + !from NH3 CT2 CT2, neutral lysine +NH2 CT2 HA2 38.000 109.50 50.00 2.14000 + !from NH2 CT3 HA, neutral lysine +NH2 CT3 HA3 38.000 109.50 50.00 2.14000 ! ALLOW POL + ! methylamine geom/freq, adm jr., 6/2/92 +NH3 CT1 C 43.700 110.0000 ! ALLOW PEP POL ARO ALI + ! new aliphatics, adm jr., 2/3/92 +NH3 CT1 CC 43.700 110.0000 ! ALLOW PEP POL ARO ALI + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +NH3 CT1 CT1 67.700 110.0000 ! ALLOW ALI POL + ! new aliphatics, adm jr., 2/3/92 +NH3 CT1 CT2 67.700 110.0000 ! ALLOW ALI POL + ! new aliphatics, adm jr., 2/3/92 +NH3 CT1 CT3 67.700 110.0000 ! ALLOW ALI POL + ! new aliphatics, adm jr., 2/3/92 +NH3 CT1 HB1 51.500 107.5000 ! ALLOW ALI POL PEP + ! new aliphatics, adm jr., 2/3/92 +NH3 CT2 C 43.700 110.0000 ! ALLOW PEP POL ARO ALI + ! alanine (JCS) +NH3 CT2 CC 43.700 110.0000 ! ALLOW PEP POL ARO ALI + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +NH3 CT2 CD 43.700 110.0000 ! ALLOW PEP POL ARO ALI + ! adm jr. 5/02/91, acetic acid pure solvent +NH3 CT2 CT2 67.700 110.0000 ! ALLOW ALI POL + ! methylammonium +NH3 CT2 CT3 67.700 110.0000 ! ALLOW ALI POL + ! ethylammonium +NH3 CT2 HA2 45.000 107.50 35.00 2.10100 ! ALLOW ALI POL + ! new stretch and bend; methylammonium (KK 03/10/92) +NH3 CT2 HB2 51.500 107.5000 ! ALLOW ALI POL PEP + ! for use on NTER -- from NH3 CT2HA (JCS) -- (LK) +NH3 CT3 HA3 45.000 107.50 35.00 2.10100 ! ALLOW ALI POL + ! new stretch and bend; methylammonium (KK 03/10/92) +NP CP1 C 50.000 106.0000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NP CP1 CC 50.000 106.0000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NP CP1 CD 50.000 106.0000 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NP CP1 CP2 70.000 108.5000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NP CP1 HB1 51.500 107.5000 ! ALLOW ALI POL PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NP CP3 CP2 70.000 108.5000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NP CP3 HA2 51.500 109.1500 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NR1 CPH1 CPH1 130.000 106.0000 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR1 CPH1 CT2 45.800 124.0000 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FC FROM CA CT2CT +NR1 CPH1 CT3 45.800 124.0000 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FC FROM CA CT2CT +NR1 CPH1 HR3 25.000 124.00 20.00 2.14000 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +NR1 CPH2 HR1 25.000 122.50 20.00 2.14000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR2 CPH1 CPH1 130.000 110.0000 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR2 CPH1 CT2 45.800 120.0000 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FC FROM CA CT2CT +NR2 CPH1 HR3 25.000 120.00 20.00 2.14000 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +NR2 CPH2 HR1 25.000 125.00 20.00 2.12000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR2 CPH2 NR1 130.000 112.5000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR3 CPH1 CPH1 145.000 108.0000 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR3 CPH1 CT2 45.800 122.0000 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FC FROM CA CT2CT +NR3 CPH1 HR1 22.000 122.00 15.00 2.18000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR3 CPH2 HR2 32.000 126.00 25.00 2.14000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR3 CPH2 NR3 145.000 108.0000 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +O C CP1 80.000 118.0000 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C CT1 80.000 121.0000 ! ALLOW ALI PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +O C CT2 80.000 121.0000 ! ALLOW ALI PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +O C CT3 80.000 121.0000 ! ALLOW ALI PEP POL ARO + ! Alanine Dipeptide ab initio calc's (LK) +O C H 50.000 121.7000 ! ALLOW PEP POL ARO + ! acetaldehyde (JCS) +O C N 80.000 122.5000 ! ALLOW PRO PEP POL ARO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C NH1 80.000 122.5000 ! ALLOW PEP POL ARO + ! NMA Vib Modes (LK) +O CC CP1 80.000 118.0000 ! ALLOW ALI PEP POL ARO PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O CC CT1 15.000 121.00 50.00 2.44000 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/10/91, acetamide update +O CC CT2 15.000 121.00 50.00 2.44000 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/10/91, acetamide update +O CC CT3 15.000 121.00 50.00 2.44000 ! ALLOW ALI PEP POL ARO + ! adm jr. 4/10/91, acetamide update +O CC HA1 44.000 122.0000 ! ALLOW POL + ! adm jr., 5/13/91, formamide geometry and vibrations +O CC NH2 75.000 122.50 50.00 2.37000 ! ALLOW POL PEP ARO + ! adm jr. 4/10/91, acetamide update +OB CD CP1 70.000 125.00 20.00 2.44200 ! ALLOW ALI PEP POL ARO PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +OB CD CT1 70.000 125.00 20.00 2.44200 ! ALLOW ALI PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +OB CD CT2 70.000 125.00 20.00 2.44200 ! ALLOW ALI PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +OB CD CT3 70.000 125.00 20.00 2.44200 ! ALLOW ALI PEP POL ARO + ! adm jr. 5/02/91, acetic acid pure solvent +OC CA CA 40.000 120.0000 ! ALLOW POL ARO + ! adm jr. 8/27/91, phenoxide +OC CC CP1 40.000 118.00 50.00 2.38800 ! ALLOW ALI PEP POL ARO ION PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +OC CC CT1 40.000 118.00 50.00 2.38800 ! ALLOW ALI PEP POL ARO ION + ! adm jr. 7/23/91, correction, ACETATE (KK) +OC CC CT2 40.000 118.00 50.00 2.38800 ! ALLOW ALI PEP POL ARO ION + ! adm jr. 7/23/91, correction, ACETATE (KK) +OC CC CT3 40.000 118.00 50.00 2.38800 ! ALLOW ALI PEP POL ARO ION + ! adm jr. 7/23/91, correction, ACETATE (KK) +OC CC OC 100.000 124.00 70.00 2.22500 ! ALLOW POL ION PEP ARO + ! adm jr. 7/23/91, correction, ACETATE (KK) +OC CT2 CT3 65.000 122.0000 ! ALLOW ALC + ! ethoxide 6-31+G* geom/freq, adm jr., 6/1/92 +OC CT2 HA2 65.000 118.3000 ! ALLOW ALC + ! ethoxide 6-31+G* geom/freq, adm jr., 6/1/92 +OC CT3 HA3 65.000 118.3000 ! ALLOW ALC + ! methoxide 6-31+G* geom/freq, adm jr., 6/1/92 +OH1 CA CA 45.200 120.0000 ! ALLOW ARO ALC + ! PARALLH19 WITH [122.3] (JES) +OH1 CD CT2 55.000 110.5000 ! ALLOW ALI PEP POL ARO ALC + ! adm jr, 10/17/90, acetic acid vibrations +OH1 CD CT3 55.000 110.5000 ! ALLOW ALI PEP POL ARO ALC + ! adm jr, 10/17/90, acetic acid vibrations +OH1 CD OB 50.000 123.00 210.00 2.26200 ! ALLOW PEP POL ARO ALC + ! adm jr, 10/17/90, acetic acid vibrations +OH1 CT1 CT1 75.700 110.1000 ! ALLOW ALI ALC ARO + ! MeOH, EMB, 10/10/89 +OH1 CT1 CT3 75.700 110.1000 ! ALLOW ALI ALC ARO + ! MeOH, EMB, 10/10/89 +OH1 CT1 HA1 45.900 108.8900 ! ALLOW ALI ALC ARO + ! MeOH, EMB, 10/10/89 +OH1 CT2 CT1 75.700 110.1000 ! ALLOW ALI ALC ARO + ! MeOH, EMB, 10/10/89 +OH1 CT2 CT2 75.700 110.1000 ! ALLOW ALI ALC ARO + ! MeOH, EMB, 10/10/89 +OH1 CT2 CT3 75.700 110.1000 ! ALLOW ALI ALC ARO + ! MeOH, EMB, 10/10/89 +OH1 CT2 HA2 45.900 108.8900 ! ALLOW ALI ALC ARO + ! MeOH, EMB, 10/10/89 +OH1 CT3 HA3 45.900 108.8900 ! ALLOW ALI ALC ARO + ! MeOH, EMB, 10/10/89 +OS CD CP1 55.000 109.00 20.00 2.32600 ! ALLOW POL PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +OS CD CT1 55.000 109.00 20.00 2.32600 ! ALLOW POL PEP + ! adm jr., 4/05/91, for PRES CT1 from methylacetate +OS CD CT2 55.000 109.00 20.00 2.32600 ! ALLOW POL PEP + ! adm jr., 4/05/91, for PRES CT1 from methylacetate +OS CD CT3 55.000 109.00 20.00 2.32600 ! ALLOW POL PEP + ! adm jr., 4/05/91, for PRES CT1 from methylacetate +OS CD OB 90.000 125.90 160.00 2.25760 ! ALLOW PEP POL + ! adm jr. 3/19/92, from lipid methyl acetate +OS CT2 HA2 60.000 109.5000 ! ALLOW PEP POL + ! adm jr. 4/05/91, for PRES CT1 from methyl acetate +OS CT3 HA3 60.000 109.5000 ! ALLOW PEP POL + ! adm jr. 4/05/91, for PRES CT1 from methyl acetate +S CT2 CT1 58.000 112.5000 ! ALLOW ALI SUL ION + ! as in expt.MeEtS & DALC crystal, 5/15/92 +S CT2 CT2 58.000 114.5000 ! ALLOW ALI SUL ION + ! expt. MeEtS, 3/26/92 (FL) +S CT2 CT3 58.000 114.5000 ! ALLOW ALI SUL ION + ! expt. MeEtS, 3/26/92 (FL) +S CT2 HA2 46.100 111.3000 ! ALLOW ALI SUL ION + ! vib. freq. and HF/6-31G* geo. (DTN) 8/24/90 +S CT3 HA3 46.100 111.3000 ! ALLOW ALI SUL ION + ! vib. freq. and HF/6-31G* geo. (DTN) 8/24/90 +SM CT2 CT1 58.000 112.5000 ! ALLOW ALI SUL ION + ! as in expt.MeEtS & DALC crystal, 5/15/92 +SM CT2 CT3 58.000 112.5000 ! ALLOW ALI SUL ION + ! diethyldisulfide, as in expt.MeEtS & DALC crystal, 5/15/92 +SM CT2 HA2 38.000 111.0000 ! ALLOW ALI SUL ION + ! new S-S atom type 8/24/90 +SM CT3 HA3 38.000 111.0000 ! ALLOW ALI SUL ION + ! new S-S atom type 8/24/90 +SM SM CT2 72.500 103.3000 ! ALLOW ALI SUL ION + ! expt. dimethyldisulfide, 3/26/92 (FL) +SM SM CT3 72.500 103.3000 ! ALLOW ALI SUL ION + ! expt. dimethyldisulfide, 3/26/92 (FL) +SS CS CT3 55.000 118.0000 ! ALLOW SUL + ! ethylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +SS CS HA2 40.000 112.3000 ! ALLOW SUL + ! methylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +SS CS HA3 40.000 112.3000 ! ALLOW SUL + ! methylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +O CD HR1 75.000 121.0000 ! acetaldehyde, benzaldehyde, 3ALP, retinal +!For GLU/HSP, Zhu +NH1 CT1 CT2A 70.000 113.5000 ! from NH1 CT1 CT2 +HB1 CT1 CT2A 35.000 111.0000 ! from HB1 CT1 CT2 +CT2A CT1 C 52.000 108.0000 ! from CT2 CT1 C +CT1 CT2A HA2 26.500 110.1000 22.53 2.17900 ! from HA2 CT2 CT1 +CT1 CT2A CT2 58.350 113.5000 11.16 2.56100 ! from CT2 CT2 CT1 +HA2 CT2A HA2 35.500 109.0000 5.40 1.80200 ! from HA2 CT2 HA2 +HA2 CT2A CT2 26.500 110.1000 22.53 2.17900 ! from HA2 CT2 CT2 +CT2A CT2 HA2 26.500 110.1000 22.53 2.17900 ! from HA2 CT2 CT2 +CT2A CT2 CC 52.000 108.0000 ! from CT2 CT2 CC +CT1 CT2A CPH1 58.350 113.0000 ! from CT1 CT2 CPH1 +HA2 CT2A CPH1 33.430 109.5000 ! from HA2 CT2 CPH1 +CT2A CPH1 CPH1 45.800 130.0000 ! from CT2 CPH1 CPH1 +CT2A CPH1 NR3 45.800 122.0000 ! from NR3 CPH1 CT2 +!ASP, CT2->CT2A, jshim +CT1 CT2A CC 52.000 108.0000 ! from CT1 CT2 CC +HA2 CT2A CC 33.000 109.5000 30.00 2.16300 ! from HA2 CT2 CC +OC CC CT2A 40.000 118.0000 50.00 2.38800 ! from OC CC CT2 +NH3 CT1 CT2A 67.700 110.0000 ! from NH3 CT1 CT2 +CT2A CT1 CD 52.000 108.0000 ! from CT2 CT1 CD +! RESI CYSM and PRES CYSD +NH2 CT1 CS 67.700 110.0000 ! from NH2 CT1 CT2 , kevo +CS CT1 C 52.000 108.0000 ! from CT2 CT1 C , kevo +CS CT1 CC 52.000 108.0000 ! from CT2 CT1 CC , kevo +CS CT1 CD 52.000 108.0000 ! from CT2 CT1 CD , kevo +HB1 CT1 CS 35.000 111.0000 ! from HB1 CT1 CT2 , kevo +NH1 CT1 CS 70.000 113.5000 ! from NH1 CT1 CT2 , kevo +NH3 CT1 CS 67.700 110.0000 ! from NH3 CT1 CT2 , kevo +SS CS CT1 55.000 118.0000 ! from SS CS CT3 , kevo +HA2 CS CT1 34.600 110.10 22.53 2.17900 ! from HA2 CS CT3 to be consistent with SS CS CT1, kevo +! PRES SERD +OC CT2 CT1 65.000 122.0000 ! from OC CT2 CT3 , kevo + +DIHEDRALS +! +!V(dihedral) = Kchi(1 + cos(n(chi) - delta)) +! +!Kchi: kcal/mole +!n: multiplicity +!delta: degrees +! +!atom types Kchi n delta +! +!Neutral N terminus +NH2 CT1 C O 0.0000 1 0.00 +NH2 CT2 C O 0.0000 1 0.00 ! Neutral Gly Nterminus +NH2 CT1 C NH1 0.0000 1 0.00 +NH2 CT2 C NH1 0.0000 1 0.00 ! Neutral Gly Nterminus +H NH2 CT1 CT1 0.0000 1 0.00 +H NH2 CT1 C 0.0000 1 0.00 +H NH2 CT2 C 0.0000 1 0.00 ! Neutral Gly Nterminus +H NH2 CT1 HB1 0.1100 3 0.00 ! From LSN HC-NH2-CT2-HA +H NH2 CT2 HB2 0.1100 3 0.00 ! From LSN HC-NH2-CT2-HA, Neutral Gly Nterminus +H NH2 CT1 CT2 0.1100 3 0.00 ! From LSN HC-NH2-CT2-CT2 +H NH2 CT1 CT3 0.1100 3 0.00 ! From LSN HC-NH2-CT2-CT2 +!Indole/Tryptophan +CAI CA CA CAI 3.1000 2 180.00 ! from CA CA CA CA +CA CPT CPT CA 3.0000 2 180.00 ! atm, methylindole, 1/17/04 +CAI CPT CPT CAI 3.0000 2 180.00 ! atm, methylindole, 1/17/04 +CA CY CPT CA 3.0000 2 180.00 ! atm, methylindole, 1/17/04 +CA CY CPT CAI 3.0000 2 180.00 ! atm, methylindole, 1/17/04 +CA NY CPT CA 3.0000 2 180.00 ! atm, methylindole, 1/17/04 +CPT CA CA CA 3.0000 2 180.00 ! JWK 05/14/91 fit to indole +CPT CPT CA CA 3.0000 2 180.00 ! JWK 05/14/91 fit to indole +CA NY CPT CAI 3.0000 2 180.00 ! atm, methylindole, 1/17/04 +CPT CAI CA CA 3.0000 2 180.00 ! JWK 05/14/91 fit to indole +CPT CPT CAI CA 3.0000 2 180.00 ! JWK 05/14/91 fit to indole +CPT CPT CY CA 5.0000 2 180.00 ! atm, methylindole, 1/17/04 +CPT CPT NY CA 6.5000 2 180.00 ! atm, methylindole, 1/17/04 +CT3 CY CPT CA 2.5000 2 180.00 ! atm, methylindole, r6r5 +CT3 CY CPT CAI 2.5000 2 180.00 ! atm, methylindole, r6r5 +CT3 CY CPT CPT 3.0000 2 180.00 ! atm, methylindole, meth +CT2 CY CPT CA 2.5000 2 180.00 ! atm, methylindole, r6r5 +CT2 CY CPT CAI 2.5000 2 180.00 ! atm, methylindole, r6r5 +CT2 CY CPT CPT 3.0000 2 180.00 ! atm, methylindole, meth +CY CA NY CPT 6.0000 2 180.00 ! atm, methylindole, 1/17/04 +CY CPT CA CA 4.0000 2 180.00 ! atm, methylindole, 1/17/04 +CY CPT CPT CA 4.0000 2 180.00 ! atm, methylindole, 1/17/04 +CY CPT CAI CA 4.0000 2 180.00 ! atm, methylindole, 1/17/04 +CY CPT CPT CAI 4.0000 2 180.00 ! atm, methylindole, 1/17/04 +H NY CA CY 0.0500 2 180.00 ! atm, methylindole, 1/17/04 +H NY CPT CA 0.2000 2 180.00 ! atm, methylindole, 1/17/04 +H NY CPT CAI 0.2000 2 180.00 ! atm, methylindole, 1/17/04 +H NY CPT CPT 0.8500 2 180.00 ! atm, methylindole, 1/17/04 +HP CAI CA CA 4.2000 2 180.00 ! from HP CA CA CA +HP CA CA CPT 3.0000 2 180.00 ! JWK 05/14/91 fit to indole +HP CA CPT CPT 3.0000 2 180.00 ! JWK indole 05/14/91 +HP CA CPT CY 4.0000 2 180.00 ! atm, methylindole, 1/17/04 +HP CA CA CAI 4.2000 2 180.00 ! from HP CA CA CA +HP CA CAI CPT 3.0000 2 180.00 ! from HP CA CA CPT +HP CAI CA HP 2.4000 2 180.00 ! from HP CA CA HP +HP CAI CPT CPT 3.0000 2 180.00 ! from HP CA CPT CPT +HP CAI CPT CY 4.0000 2 180.00 ! from HP CA CPT CY, r6r5 +HP CA CY CPT 2.8000 2 180.00 ! adm jr., 12/30/91, for jwk +HP CA CY CT3 1.2000 2 180.00 ! atm, methylindole +HP CA CY CT2 1.2000 2 180.00 ! atm, methylindole +HP CA NY CPT 2.6000 2 180.00 ! adm jr., 12/30/91, for jwk +HP CA NY H 0.4000 2 180.00 ! JWK 05/14/91 fit to indole +HP CY CA HP 1.0000 2 180.00 ! JWK 05/14/91 fit to indole +HP CY CPT CA 2.8000 2 180.00 ! JWK 05/14/91 fit to indole +HP CY CPT CAI 2.8000 2 180.00 ! JWK 05/14/91 fit to indole +HP CY CPT CPT 2.6000 2 180.00 ! JWK 05/14/91 fit to indole +NY CA CY CPT 5.0000 2 180.00 ! atm, methylindole, 1/17/04 +NY CA CY CT3 2.5000 2 180.00 ! atm, methylindole, from NY CA CY CT3 +NY CA CY CT2 2.5000 2 180.00 ! atm, methylindole, from NY CA CY CT3 +NY CA CY HP 3.5000 2 180.00 ! JWK indole 05/14/91 +NY CPT CA CA 3.0000 2 180.00 ! atm, methylindole, 1/17/04, r6r5 +NY CPT CA HP 3.0000 2 180.00 ! JWK 05/14/91 fit to indole, r6r5 +NY CPT CPT CA 4.0000 2 180.00 ! atm, methylindole, 1/17/04, bfly +NY CPT CAI CA 3.0000 2 180.00 ! atm, methylindole, 1/17/04 +NY CPT CAI HP 3.0000 2 180.00 ! JWK 05/14/91 fit to indole, r6r5 +NY CPT CPT CAI 4.0000 2 180.00 ! atm, methylindole, 1/17/04, bfly +NY CPT CPT CY 6.5000 2 180.00 ! JWK 05/14/91 fit to indole, r5 t1 +CT3 CT2 CY CA 0.3800 2 0.00 ! trp, from ethylbenzene, adm jr., 3/7/92 +CT3 CT2 CY CPT 0.2500 2 180.00 ! atm 1/14/04 3-ethylindole +CT3 CT2 CY CPT 0.3000 3 0.00 ! atm 1/14/04 3-ethylindole +HA3 CT3 CY CA 0.0100 3 0.00 ! atm, methylindole, 1/17/04 +HA3 CT3 CY CPT 0.2000 3 0.00 ! atm, methylindole, 1/17/04 +HA2 CT2 CY CA 0.0100 3 0.00 ! atm, methylindole, 1/17/04 +HA2 CT2 CY CPT 0.2000 3 0.00 ! atm, methylindole, 1/17/04 +X CS SS X 0.0000 3 0.20 ! guess + !from methanethiol, HS S CT3 HA + !adm jr., 7/01 +C CT1 NH1 C 0.2000 1 180.00 ! ALLOW PEP + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93c +C CT2 NH1 C 0.2000 1 180.00 ! ALLOW PEP + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93c +C N CP1 C 0.8000 3 0.00 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CA CA CA CA 3.1000 2 180.00 ! ALLOW ARO + ! JES 8/25/89 +!CA CT2 CT1 C 0.0400 3 0.00 ! ALLOW ARO + ! 2.7 kcal/mole CH3 rot in ethylbenzene, adm jr, 3/7/92 +CC CP1 N C 0.8000 3 0.00 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CC CT1 CT2 CA 0.0400 3 0.00 ! ALLOW ARO + ! 2.7 kcal/mole CH3 rot in ethylbenzene, adm jr, 3/7/92 +CC CT1 NH1 C 0.2000 1 180.00 ! ALLOW PEP POL + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93c +!CC CT2 NH1 C 0.2000 1 180.00 ! ALLOW PEP POL +! ! Alanine dipeptide; NMA; acetate; etc. adm jr., 3/3/93c +CC CT2 NH1 C 2.0000 1 180.00 ! ALLOW PEP POL + ! Based on Gly3 data from graf et al, RB 7/1/11 +CD CP1 N C 0.0000 1 180.00 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CD CT1 NH1 C 0.2000 1 180.00 ! ALLOW PEP POL + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93c +!CD CT2 NH1 C 0.2000 1 180.00 ! ALLOW PEP POL +! ! Alanine dipeptide; NMA; acetate; etc. backbon adm jr., 3/3/93c +CD CT2 NH1 C 2.0000 1 180.00 ! ALLOW PEP POL + ! Based on Gly3 data from graf et al, RB 7/1/11 +CE1 CE1 CT3 HA3 0.0300 3 0.00 ! + ! for butene, yin/adm jr., 12/95 +CE2 CE1 CT2 CT3 0.5000 1 180.00 ! + ! 1-butene, adm jr., 2/00 update +CE2 CE1 CT2 CT3 1.3000 3 180.00 ! + ! 1-butene, adm jr., 2/00 update +CE2 CE1 CT2 HA2 0.1200 3 0.00 ! + ! for butene, yin/adm jr., 12/95 +CE2 CE1 CT3 HA3 0.0500 3 180.00 ! + ! for propene, yin/adm jr., 12/95 +CP1 C N CP1 2.7500 2 180.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP1 C N CP1 0.3000 4 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP2 CP1 N C 0.8000 3 0.00 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP2 CP3 N C 0.0000 3 180.00 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP2 CP3 N CP1 0.1000 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP2 CP3 NP CP1 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 N C CP1 2.7500 2 180.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 N C CP1 0.3000 4 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 N CP1 C 0.1000 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 N CP1 CC 0.1000 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 N CP1 CP2 0.1000 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 NP CP1 C 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 NP CP1 CC 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 NP CP1 CD 0.0800 3 0.00 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CP3 NP CP1 CP2 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CPH2 NR1 CPH1 CPH1 14.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +CPH2 NR2 CPH1 CPH1 14.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +CPH2 NR3 CPH1 CPH1 12.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +CT1 C N CP1 2.7500 2 180.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT1 C N CP1 0.3000 4 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT1 C N CP3 2.7500 2 180.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT1 C N CP3 0.3000 4 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT1 C NH1 CT1 1.6000 1 0.00 ! ALLOW PEP + ! Revised to adjust NMA cis/trans energy difference. (LK) +CT1 C NH1 CT1 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +CT1 CT1 NH1 C 1.8000 1 0.00 ! ALLOW PEP + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93c +CT1 NH1 C CP1 1.6000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT1 NH1 C CP1 2.5000 2 180.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT2 C N CP1 2.7500 2 180.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT2 C N CP1 0.3000 4 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT2 C N CP3 2.7500 2 180.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT2 C N CP3 0.3000 4 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT2 C NH1 CT1 1.6000 1 0.00 ! ALLOW PEP + ! Revised to adjust NMA cis/trans energy difference. (LK) +CT2 C NH1 CT1 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +CT2 C NH1 CT2 1.6000 1 0.00 ! ALLOW PEP + ! Revised to adjust NMA cis/trans energy difference. (LK) +CT2 C NH1 CT2 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +CT2 C NH1 CT3 1.6000 1 0.00 ! ALLOW PEP + ! from CT2 C NH1 CT2, adm jr. 10/21/96 +CT2 C NH1 CT3 2.5000 2 180.00 ! ALLOW PEP + ! from CT2 C NH1 CT2, adm jr. 10/21/96 +CT2 CA CA CA 3.1000 2 180.00 ! ALLOW ARO + ! JES 8/25/89 toluene and ethylbenzene +CT2 CPH1 NR1 CPH2 3.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FROM HA CPH1 NR1 CPH2 +CT2 CPH1 NR2 CPH2 3.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FROM HA CPH1 NR2 CPH2 +CT2 CPH1 NR3 CPH2 2.5000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +CT2 CT1 NH1 C 1.8000 1 0.00 ! ALLOW PEP + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93c +CT2 CT2 CPH1 CPH1 0.4000 1 0.00 ! ALLOW ARO + ! 4-methylimidazole 4-21G//6-31G* rot bar. ADM JR., 9/4/89 +!aliphatic chain parameters compatible with the revised side-chain parameters, from all22_carb>>all27_lip>>all31 + ! lower butane gauche conformer +CT2 CT2 CT2 CT2 0.10 2 180.00 ! alkane, 4/98, adm jr. +CT2 CT2 CT2 CT2 0.15 4 0.00 ! alkane, 4/98, adm jr. +CT2 CT2 CT2 CT2 0.10 6 180.00 ! alkane, 4/98, adm jr. +CT2 CT2 CT2 CT3 0.10 2 180.00 ! alkane, 4/98, adm jr. +CT2 CT2 CT2 CT3 0.15 4 0.00 ! alkane, 4/98, adm jr. +CT2 CT2 CT2 CT3 0.10 6 180.00 ! alkane, 4/98, adm jr. +! +CT2 CT2 NH1 C 1.8000 1 0.00 ! ALLOW PEP + ! from CT2 CT1 NH1 C, for lactams, adm jr. +CT2 NH1 C CP1 1.6000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT2 NH1 C CP1 2.5000 2 180.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT2 NH1 C CT1 1.6000 1 0.00 ! ALLOW PEP + ! Revised to adjust NMA cis/trans energy difference. (LK) +CT2 NH1 C CT1 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +CT2 SM SM CT2 1.0000 1 0.00 ! ALLOW ALI SUL ION + ! improved CSSC dihedral in DMDS 5/15/92 (FL) +CT2 SM SM CT2 4.1000 2 0.00 ! ALLOW ALI SUL ION + ! mp 6-311G** dimethyldisulfide, 3/26/92 (FL) +CT2 SM SM CT2 0.9000 3 0.00 ! ALLOW ALI SUL ION + ! improved CSSC dihedral in DMDS 5/15/92 (FL) +CT3 C N CP1 2.7500 2 180.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT3 C N CP1 0.3000 4 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT3 C N CP3 2.7500 2 180.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT3 C N CP3 0.3000 4 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT3 C NH1 CT1 1.6000 1 0.00 ! ALLOW PEP + ! Revised to adjust NMA cis/trans energy difference. (LK) +CT3 C NH1 CT1 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +CT3 C NH1 CT2 1.6000 1 0.00 ! ALLOW PEP + ! for acetylated GLY N-terminus, adm jr. +CT3 C NH1 CT2 2.5000 2 180.00 ! ALLOW PEP + ! for acetylated GLY N-terminus, adm jr. +CT3 C NH1 CT3 1.6000 1 0.00 ! ALLOW PEP + ! Revised to adjust NMA cis/trans energy difference. (LK) +CT3 C NH1 CT3 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +CT3 CA CA CA 3.1000 2 180.00 ! ALLOW ARO + ! toluene, adm jr., 3/7/92 +CT3 CE1 CE2 HE2 5.2000 2 180.00 ! + ! for propene, yin/adm jr., 12/95 +CT3 CPH1 NR1 CPH2 3.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FROM HA CPH1 NR1 CPH2 +CT3 CT1 NH1 C 1.8000 1 0.00 ! ALLOW PEP + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93c +CT3 CT2 CA CA 0.2300 2 180.00 ! ALLOW ARO ALI + ! ethylbenzene ethyl rotation, adm jr. 3/7/92 +CT3 CT2 CPH1 CPH1 0.2000 1 0.00 ! ALLOW ARO + ! 4-ethylimidazole 4-21G rot bar, adm jr. 3/4/92 +CT3 CT2 CPH1 CPH1 0.2700 2 0.00 ! ALLOW ARO + ! 4-ethylimidazole 4-21G rot bar, adm jr. 3/4/92 +CT3 CT2 CPH1 CPH1 0.0000 3 0.00 ! ALLOW ARO + ! 4-ethylimidazole 4-21G rot bar, adm jr. 3/4/92 +CT3 CT2 S CT3 0.2400 1 180.00 ! ALOW ALI SUL ION + ! expt. MeEtS, 3/26/92 (FL) +CT3 CT2 S CT3 0.3700 3 0.00 ! ALOW ALI SUL ION + ! DTN 8/24/90 +CT3 NH1 C CP1 1.6000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT3 NH1 C CP1 2.5000 2 180.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +CT3 NH1 C CT1 1.6000 1 0.00 ! ALLOW PEP + ! Revised to adjust NMA cis/trans energy difference. (LK) +CT3 NH1 C CT1 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +CT3 S CT2 CT2 0.2400 1 180.00 ! ALOW ALI SUL ION + ! expt. MeEtS, 3/26/92 (FL) +CT3 S CT2 CT2 0.3700 3 0.00 ! ALOW ALI SUL ION + ! expt. MeEtS, 3/26/92 (FL) +CT3 SM SM CT3 1.0000 1 0.00 ! ALLOW ALI SUL ION + ! improved CSSC dihedral in DMDS 5/15/92 (FL) +CT3 SM SM CT3 4.1000 2 0.00 ! ALLOW ALI SUL ION + ! mp 6-311G** dimethyldisulfide, 3/26/92 (FL) +CT3 SM SM CT3 0.9000 3 0.00 ! ALLOW ALI SUL ION + ! improved CSSC dihedral in DMDS 5/15/92 (FL) +H NH1 C CP1 2.5000 2 180.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +H NH1 C CT1 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +H NH1 C CT2 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +H NH1 C CT3 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +H NH1 CT1 C 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +H NH1 CT1 CC 0.0000 1 0.00 ! ALLOW PEP POL + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +H NH1 CT1 CD 0.0000 1 0.00 ! ALLOW PEP POL + ! adm jr. 5/02/91, acetic acid pure solvent +H NH1 CT1 CT1 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +H NH1 CT1 CT2 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +H NH1 CT1 CT3 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +H NH1 CT2 C 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +H NH1 CT2 CC 0.0000 1 0.00 ! ALLOW PEP POL + ! Alanine dipeptide; NMA; acetate; etc. backbone param. RLD 3/22/92 +H NH1 CT2 CD 0.0000 1 0.00 ! ALLOW PEP POL + ! adm jr. 5/02/91, acetic acid pure solvent +H NH1 CT2 CT2 0.0000 1 0.00 ! ALLOW PEP + ! from H NH1 CT2 CT3, for lactams, adm jr. +H NH1 CT2 CT3 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +H NH2 CC CT1 1.4000 2 180.00 ! ALLOW PEP POL ARO PRO + ! adm jr. 4/10/91, acetamide update +H NH2 CC CT2 1.4000 2 180.00 ! ALLOW PEP POL ARO PRO + ! adm jr. 4/10/91, acetamide update +H NH2 CC CT3 1.4000 2 180.00 ! ALLOW PEP POL ARO PRO + ! adm jr. 4/10/91, acetamide update +H NH2 CC CP1 2.5000 2 180.00 ! ALLOW PEP POL ARO PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +H NR1 CPH1 CPH1 1.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 7/20/89 +H NR1 CPH1 CT2 1.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 7/22/89, FROM HA CPH1 NR1 H +H NR1 CPH1 CT3 1.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 7/22/89, FROM HA CPH1 NR1 H +H NR3 CPH1 CPH1 1.4000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +H NR3 CPH1 CT2 3.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 7/22/89, FROM HC NR3 CPH1 HA +H NR3 CPH1 CT3 3.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 7/22/89, FROM HC NR3 CPH1 HA +H OH1 CA CA 0.9900 2 180.00 ! ALLOW ARO ALC + ! phenol OH rot bar, 3.37 kcal/mole, adm jr. 3/7/92 +H OH1 CT1 CT3 1.3300 1 0.00 ! ALLOW ALC + ! 2-propanol OH hf/6-31g* torsional surface, adm jr., 3/2/93 +H OH1 CT1 CT3 0.1800 2 0.00 ! ALLOW ALC + ! 2-propanol OH hf/6-31g* torsional surface, adm jr., 3/2/93 +H OH1 CT1 CT3 0.3200 3 0.00 ! ALLOW ALC + ! 2-propanol OH hf/6-31g* torsional surface, adm jr., 3/2/93 +H OH1 CT2 CT2 1.3000 1 0.00 ! ALLOW ALC + ! ethanol OH hf/6-31g* torsional surface, adm jr., 3/2/93 +H OH1 CT2 CT2 0.3000 2 0.00 ! ALLOW ALC + ! ethanol OH hf/6-31g* torsional surface, adm jr., 3/2/93 +H OH1 CT2 CT2 0.4200 3 0.00 ! ALLOW ALC + ! ethanol OH hf/6-31g* torsional surface, adm jr., 3/2/93 +H OH1 CT2 CT3 1.3000 1 0.00 ! ALLOW ALC + ! ethanol OH hf/6-31g* torsional surface, adm jr., 3/2/93 +H OH1 CT2 CT3 0.3000 2 0.00 ! ALLOW ALC + ! ethanol OH hf/6-31g* torsional surface, adm jr., 3/2/93 +H OH1 CT2 CT3 0.4200 3 0.00 ! ALLOW ALC + ! ethanol OH hf/6-31g* torsional surface, adm jr., 3/2/93 +HA1 CC NH2 H 1.4000 2 180.00 ! ALLOW PEP POL + ! adm jr. 4/10/91, acetamide update +HA2 CP3 N C 0.0000 3 180.00 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA2 CP3 N CP1 0.1000 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA2 CP3 NP CP1 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HA1 CT1 CT2 CA 0.0400 3 0.00 ! ALLOW ARO + ! 2.7 kcal/mole CH3 rot in ethylbenzene, adm jr, 3/7/92 +HA2 CT2 CPH1 CPH1 0.0000 3 0.00 ! ALLOW ARO + ! 4-methylimidazole 4-21G//6-31G* rot bar. adm jr., 9/4/89 +HA2 CT2 NH1 C 0.0000 3 0.00 ! ALLOW PEP + ! LK for autogenerate dihe, sp2-methyl, no dihedral potential +HA2 CT2 NH1 H 0.0000 3 0.00 ! ALLOW PEP + ! LK for autogenerate dihe, sp2-methyl, no dihedral potential +HA2 CT2 S CT3 0.2800 3 0.00 ! ALLOW ALI SUL ION + ! DTN 8/24/90 +HA3 CT3 CPH1 CPH1 0.0000 3 0.00 ! ALLOW ARO + ! 4-methylimidazole 4-21G//6-31G* rot bar. adm jr., 9/4/89 +HA3 CT3 CS HA2 0.1600 3 0.00 ! ALLOW SUL + ! ethylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +HA3 CT3 CS HA3 0.1600 3 0.00 ! ALLOW SUL + ! ethylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +HA3 CT3 CT2 CA 0.0400 3 0.00 ! ALLOW ARO + ! 2.7 kcal/mole CH3 rot in ethylbenzene, adm jr, 3/7/92 +HA3 CT3 NH1 C 0.0000 3 0.00 ! ALLOW PEP + ! LK for autogenerate dihe, sp2-methyl, no dihedral potential +HA3 CT3 NH1 H 0.0000 3 0.00 ! ALLOW PEP + ! LK for autogenerate dihe, sp2-methyl, no dihedral potential +HA3 CT3 S CT2 0.2800 3 0.00 ! ALLOW ALI SUL ION + ! DTN 8/24/90 +HE1 CE1 CE1 HE1 1.0000 2 180.00 ! + ! 2-butene, adm jr., 8/98 update +CT3 CE1 CE1 HE1 1.0000 2 180.00 ! + ! 2-butene, adm jr., 8/98 update +HE1 CE1 CE2 HE2 5.2000 2 180.00 ! + ! for propene, yin/adm jr., 12/95 +HE1 CE1 CT2 HA2 0.0000 3 0.00 + ! butene, adm jr., 2/00 update +HE1 CE1 CT2 CT3 0.1200 3 0.00 ! + ! for butene, yin/adm jr., 12/95 +HE1 CE1 CT3 HA3 0.0000 3 0.00 + ! butene, adm jr., 2/00 update +HE2 CE2 CE1 CT2 5.2000 2 180.00 ! + ! for butene, yin/adm jr., 12/95 +HB1 CP1 N C 0.8000 3 0.00 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HB1 CP1 N CP3 0.1000 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HB1 CP1 NP CP3 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HB1 CT1 NH1 C 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HB1 CT1 NH1 H 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HB2 CT2 NH1 C 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HB2 CT2 NH1 H 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +HC NH2 CT2 HB2 0.1100 3 0.00 + !from X CT3 NH2 X, neutral glycine, adm jr. +HC NH2 CT2 CD 0.1100 3 0.00 + !from X CT3 NH2 X, neutral glycine, adm jr. +HC NH2 CT2 CT2 0.1100 3 0.00 + !from X CT3 NH2 X, neutral lysine +HC NH2 CT2 HA2 0.1100 3 0.00 + !from X CT3 NH2 X, neutral lysine +HC NP CP1 C 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HC NP CP1 CC 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HC NP CP1 CD 0.0800 3 0.00 ! ALLOW PRO PEP + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HC NP CP1 CP2 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HC NP CP1 HB1 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HC NP CP3 CP2 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HC NP CP3 HA2 0.0800 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +HP CA CA CA 4.2000 2 180.00 ! ALLOW ARO + ! JES 8/25/89 benzene +HP CA CA CT2 4.2000 2 180.00 ! ALLOW ARO + ! JES 8/25/89 toluene and ethylbenzene +HP CA CA CT3 4.2000 2 180.00 ! ALLOW ARO + ! toluene, adm jr., 3/7/92 +HP CA CA HP 2.4000 2 180.00 ! ALLOW ARO + ! JES 8/25/89 benzene +HR1 CPH1 CPH1 CT2 1.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +HR1 CPH1 CPH1 CT3 1.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +HR1 CPH1 CPH1 HR1 1.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90, his +HR1 CPH1 NR3 CPH2 2.5000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +HR1 CPH1 NR3 H 3.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +HR1 CPH2 NR1 CPH1 3.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +HR1 CPH2 NR1 H 1.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +HR1 CPH2 NR2 CPH1 3.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +HR2 CPH2 NR3 CPH1 3.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +HR2 CPH2 NR3 H 0.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90, YES, 0.0 +HR3 CPH1 CPH1 CT2 2.0000 2 180.00 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HR3 CPH1 CPH1 CT3 2.0000 2 180.00 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HR3 CPH1 CPH1 HR3 2.0000 2 180.00 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HR3 CPH1 NR1 CPH2 3.0000 2 180.00 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HR3 CPH1 NR1 H 1.0000 2 180.00 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HR3 CPH1 NR2 CPH2 3.0000 2 180.00 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HS S CT2 CT3 0.2400 1 0.00 ! ALLOW ALI SUL ION + ! ethanethiol C-C-S-H surface, adm jr., 4/18/93 +HS S CT2 CT3 0.1500 2 0.00 ! ALLOW ALI SUL ION + ! ethanethiol C-C-S-H surface, adm jr., 4/18/93 +HS S CT2 CT3 0.2700 3 0.00 ! ALLOW ALI SUL ION + ! ethanethiol C-C-S-H surface, adm jr., 4/18/93 +HS S CT2 HA2 0.2000 3 0.00 ! ALLOW ALI SUL ION + ! methanethiol pure solvent, adm jr., 6/22/92 +HS S CT3 HA3 0.2000 3 0.00 ! ALLOW ALI SUL ION + ! methanethiol pure solvent, adm jr., 6/22/92 +N C CP1 CP2 0.4000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CP1 CP2 0.6000 2 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CP1 HB1 0.4000 1 180.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CP1 HB1 0.6000 2 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CP1 N 0.3000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CP1 N -0.3000 4 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CT1 CT1 0.0000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CT1 CT2 0.0000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CT1 CT3 0.0000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CT1 HB1 0.0000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CT2 HB2 0.0000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N C CT3 HA3 0.0000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +N CT1 CT2 CA 0.0400 3 0.00 ! ALLOW ARO + ! 2.7 kcal/mole CH3 rot in ethylbenzene, adm jr, 3/7/92 +NH1 C CP1 CP2 0.4000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH1 C CP1 CP2 0.6000 2 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH1 C CP1 HB1 0.4000 1 180.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH1 C CP1 HB1 0.6000 2 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH1 C CP1 N 0.3000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH1 C CP1 N -0.3000 4 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH1 C CT1 CT1 0.0000 1 0.00 ! ALLOW PEP + ! ala dipeptide corrxn for new C VDW Rmin, 4/10/93 (LK) +NH1 C CT1 CT2 0.0000 1 0.00 ! ALLOW PEP + ! ala dipeptide corrxn for new C VDW Rmin, 4/10/93 (LK) +NH1 C CT1 CT3 0.0000 1 0.00 ! ALLOW PEP + ! ala dipeptide corrxn for new C VDW Rmin, 4/10/93 (LK) +NH1 C CT1 HB1 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +NH1 C CT1 NH1 0.6000 1 0.00 ! ALLOW PEP + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93 +NH1 C CT2 CT2 0.0000 1 0.00 ! ALLOW PEP + ! from NH1 C CT1 CT2, for lactams, adm jr. +NH1 C CT2 HA2 0.0000 3 0.00 ! ALLOW PEP + ! LK for autogenerate dihe, sp2-methyl, no dihedral potential +NH1 C CT2 HB2 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +NH1 C CT2 NH1 0.6000 1 0.00 ! ALLOW PEP + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93 +NH1 C CT3 HA3 0.0000 3 0.00 ! ALLOW PEP + ! LK for autogenerate dihe, sp2-methyl, no dihedral potential +NH1 CT1 C N 0.4000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH1 CT2 C N 0.4000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH2 CC CP1 CP2 0.4000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH2 CC CP1 CP2 0.6000 2 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH2 CC CP1 HB1 0.4000 1 180.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH2 CC CP1 HB1 0.6000 2 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH2 CC CP1 N 0.3000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH2 CC CP1 N -0.3000 4 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH2 CC CT2 HA2 0.0000 3 180.00 ! ALLOW POL + ! adm jr., 8/13/90 acetamide geometry and vibrations +NH3 CT1 C N 0.4000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NH3 CT1 C NH1 0.6000 1 0.00 ! ALLOW PEP PRO + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93 +NH3 CT1 CC NH2 0.4000 1 0.00 ! ALLOW PEP PRO + ! Alanine dipeptide; NMA; acetate; etc. backbone param. RLD 3/22/92 +NH3 CT2 C N 0.4000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +!!!NH3 CT2 C NH1 0.4000 1 0.00 ! ALLOW PEP PRO +!!! ! adm jr. 3/24/92, for PRES GLYP +NH3 CT2 C NH1 1.0000 1 0.00 ! ALLOW PEP PRO + ! RB 1/07/11, based on graf et al Gly 3 N-ter J-couplings for PRES GLYP +NH3 CT2 CC NH2 0.4000 1 0.00 ! ALLOW PEP PRO + ! Alanine dipeptide; NMA; acetate; etc. backbone param. RLD 3/22/92 +NP CP1 C N 0.3000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NP CP1 C NH1 0.3000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NP CP1 CC NH2 0.3000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NR1 CPH1 CPH1 CT2 3.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FROM NR1 CPH1 CPH1 HA +NR1 CPH1 CPH1 CT3 3.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FROM NR1 CPH1 CPH1 HA +NR1 CPH1 CPH1 HR3 3.0000 2 180.00 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +NR1 CPH1 CT2 CT2 0.1900 3 0.00 ! ALLOW ARO + ! 4-METHYLIMIDAZOLE 4-21G//6-31G* ROT BAR. ADM JR., 9/4/89 +NR1 CPH1 CT2 CT3 0.1900 3 0.00 ! ALLOW ARO + ! 4-METHYLIMIDAZOLE 4-21G//6-31G* ROT BAR. ADM JR., 9/4/89 +NR1 CPH1 CT2 HA2 0.1900 3 0.00 ! ALLOW ARO + ! 4-METHYLIMIDAZOLE 4-21G//6-31G* ROT BAR. ADM JR., 9/4/89 +NR1 CPH1 CT3 HA3 0.1900 3 0.00 ! ALLOW ARO + ! 4-METHYLIMIDAZOLE 4-21G//6-31G* ROT BAR. ADM JR., 9/4/89 +NR1 CPH2 NR2 CPH1 14.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR2 CPH1 CPH1 CT2 3.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FROM NR2 CPH1 CPH1 HA +NR2 CPH1 CPH1 CT3 3.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/22/89, FROM NR2 CPH1 CPH1 HA +NR2 CPH1 CPH1 HR3 3.0000 2 180.00 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +NR2 CPH1 CPH1 NR1 14.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +!NR2 CPH1 CT2 CT1 0.1900 3 0.00 ! ALLOW ARO + ! HIS CB-CG TORSION, +NR2 CPH1 CT2 CT2 0.1900 3 0.00 ! ALLOW ARO + ! HIS CB-CG TORSION, +NR2 CPH1 CT2 CT3 0.1900 3 0.00 ! ALLOW ARO + ! HIS CB-CG TORSION, +NR2 CPH1 CT2 HA2 0.1900 3 0.00 ! ALLOW ARO + ! 4-METHYLIMIDAZOLE 4-21G//6-31G* ROT BAR. ADM JR., 9/4/89 +NR2 CPH1 CT3 HA3 0.1900 3 0.00 ! ALLOW ARO + ! 4-METHYLIMIDAZOLE 4-21G//6-31G* ROT BAR. ADM JR., 9/4/89 +NR2 CPH2 NR1 CPH1 14.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR2 CPH2 NR1 H 1.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR3 CPH1 CPH1 CT2 2.5000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR3 CPH1 CPH1 CT3 2.5000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR3 CPH1 CPH1 HR1 2.5000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR3 CPH1 CPH1 NR3 12.0000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR3 CPH1 CT2 CT2 0.1900 3 0.00 ! ALLOW ARO + ! 4-METHYLIMIDAZOLE 4-21G//6-31G* ROT BAR. ADM JR., 9/4/89 +NR3 CPH1 CT2 CT3 0.1900 3 0.00 ! ALLOW ARO + ! 4-METHYLIMIDAZOLE 4-21G//6-31G* ROT BAR. ADM JR., 9/4/89 +NR3 CPH1 CT2 HA2 0.1900 3 0.00 ! ALLOW ARO + ! 4-METHYLIMIDAZOLE 4-21G//6-31G* ROT BAR. ADM JR., 9/4/89 +NR3 CPH1 CT3 HA3 0.1900 3 0.00 ! ALLOW ARO + ! 4-METHYLIMIDAZOLE 4-21G//6-31G* ROT BAR. ADM JR., 9/4/89 +NR3 CPH2 NR3 CPH1 12.0000 2 180.00 ! ALLOW ARO + ! his, ADM JR., 7/20/89 +NR3 CPH2 NR3 H 1.4000 2 180.00 ! ALLOW ARO + ! his, adm jr., 6/27/90 +O C CP1 CP2 0.4000 1 180.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C CP1 CP2 0.6000 2 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C CP1 HB1 0.4000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C CP1 HB1 0.6000 2 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C CP1 N -0.3000 4 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C CT1 CT1 1.4000 1 0.00 ! ALLOW PEP + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93c +O C CT1 CT2 1.4000 1 0.00 ! ALLOW PEP + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93c +O C CT1 CT3 1.4000 1 0.00 ! ALLOW PEP + ! ala dipeptide update for new C VDW Rmin, adm jr., 3/3/93c +O C CT1 HB1 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +O C CT1 NH1 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +O C CT1 NH3 0.0000 1 0.00 ! ALLOW PEP PRO + ! Backbone parameter set made complete RLD 8/8/90 +O C CT2 CT2 1.4000 1 0.00 ! ALLOW PEP + ! from O C CT1 CT2, for lactams, adm jr. +O C CT2 HA2 0.0000 3 180.00 ! ALLOW POL + ! adm jr., 8/13/90 acetamide geometry and vibrations +O C CT2 HB2 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +O C CT2 NH1 0.0000 1 0.00 ! ALLOW PEP + ! Alanine Dipeptide ab initio calc's (LK) +O C CT2 NH3 0.0000 1 0.00 ! ALLOW PEP PRO + ! Backbone parameter set made complete RLD 8/8/90 +O C CT3 HA3 0.0000 3 180.00 ! ALLOW POL + ! adm jr., 8/13/90 acetamide geometry and vibrations +O C N CP1 2.7500 2 180.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C N CP1 0.3000 4 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C N CP3 2.7500 2 180.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C N CP3 0.3000 4 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O C NH1 CT1 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +O C NH1 CT2 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +O C NH1 CT3 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +O C NH1 H 2.5000 2 180.00 ! ALLOW PEP + ! Gives appropriate NMA cis/trans barrier. (LK) +O CC CP1 CP2 0.4000 1 180.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O CC CP1 CP2 0.6000 2 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O CC CP1 HB1 0.4000 1 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O CC CP1 HB1 0.6000 2 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O CC CP1 N -0.3000 4 0.00 ! ALLOW PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +O CC CT2 HA2 0.0000 3 180.00 ! ALLOW POL + ! adm jr. 4/05/91, for asn,asp,gln,glu and cters +O CC NH2 H 1.4000 2 180.00 ! ALLOW PEP POL ARO PRO + ! adm jr. 4/10/91, acetamide update +OB CD OS CT2 0.9650 1 180.00 ! ALLOW PEP POL + ! adm jr. 3/19/92, from lipid methyl acetate +OB CD OS CT2 3.8500 2 180.00 ! ALLOW PEP POL + ! adm jr. 3/19/92, from lipid methyl acetate +OB CD OS CT3 0.9650 1 180.00 ! ALLOW PEP POL + ! adm jr. 3/19/92, from lipid methyl acetate +OB CD OS CT3 3.8500 2 180.00 ! ALLOW PEP POL + ! adm jr. 3/19/92, from lipid methyl acetate +OC CA CA CA 3.1000 2 180.00 ! ALLOW ARO + ! adm jr. 8/27/91, phenoxide +OC CA CA HP 4.2000 2 180.00 ! ALLOW ARO + ! adm jr. 8/27/91, phenoxide +OC CC CP1 CP2 0.1600 3 0.00 ! ALLOW PEP PRO POL + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +OC CC CP1 HB1 0.1600 3 0.00 ! ALLOW PEP PRO POL + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +OC CC CP1 N 0.1600 3 0.00 ! ALLOW PEP PRO POL + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +OC CC CP1 NP 0.1600 3 0.00 ! ALLOW PEP PRO POL + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +OC CC CT1 NH3 3.2000 2 180.00 ! ALLOW PEP PRO + ! adm jr. 4/17/94, zwitterionic glycine +OC CC CT2 NH3 3.2000 2 180.00 ! ALLOW PEP PRO + ! adm jr. 4/17/94, zwitterionic glycine +OH1 CA CA CA 3.1000 2 180.00 ! ALLOW ARO + ! JES 8/25/89 phenol +OH1 CA CA HP 4.2000 2 180.00 ! ALLOW ARO + ! JES 8/25/89 phenol +S CT2 CT2 HA2 0.0100 3 0.00 ! ALLOW ALI SUL ION + ! DTN 8/24/90 +SM CT2 CT2 HA2 0.0100 3 0.00 ! ALLOW ALI SUL ION + ! DTN 8/24/90 +SM SM CT2 CT1 0.3100 3 0.00 ! ALLOW SUL ALI + ! S-S for cys-cys, dummy parameter for now ... DTN 9/04/90 +SM SM CT2 CT2 0.3100 3 0.00 ! ALLOW SUL ALI + ! S-S for cys-cys, dummy parameter for now ... DTN 9/04/90 +SM SM CT2 CT3 0.3100 3 0.00 ! ALLOW SUL ALI + ! S-S for cys-cys, dummy parameter for now ... DTN 9/04/90 +SM SM CT2 HA2 0.1580 3 0.00 ! ALLOW ALI SUL ION + ! expt. dimethyldisulfide, 3/26/92 (FL) +SM SM CT3 HA3 0.1580 3 0.00 ! ALLOW ALI SUL ION + ! expt. dimethyldisulfide, 3/26/92 (FL) +SS CS CT3 HA3 0.1500 3 0.00 ! ALLOW SUL + ! ethylthiolate 6-31+G* geom/freq, adm jr., 6/1/92 +X C NC2 X 2.2500 2 180.00 ! ALLOW PEP POL ARO + ! 9.0->2.25 GUANIDINIUM (KK) +X CD OH1 X 2.0500 2 180.00 ! ALLOW PEP POL ARO ALC + ! adm jr, 10/17/90, acetic acid C-Oh rotation barrier +X CD OS X 2.0500 2 180.00 ! ALLOW PEP POL + ! adm jr. 3/19/92, from lipid methyl acetate +X CE1 CE1 X 0.1500 1 0.00 + ! 2-butene, adm jr., 2/00 update +X CE1 CE1 X 8.5000 2 180.00 + ! 2-butene, adm jr., 2/00 update +X CE2 CE2 X 4.9000 2 180.00 ! + ! for ethene, yin/adm jr., 12/95 +X CP1 C X 0.0000 6 180.00 ! ALLOW POL PEP PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +X CP1 CC X 0.0000 6 180.00 ! ALLOW POL PEP + ! changed to 0.0 RLD 5/19/92 +X CP1 CD X 0.0000 6 180.00 ! ALLOW POL PEP + ! Alanine dipeptide; NMA; acetate; etc. backbone param. RLD 3/22/92 +X CP1 CP2 X 0.1400 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +X CP2 CP2 X 0.1600 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +X CP3 CP2 X 0.1400 3 0.00 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +X CT1 CC X 0.0500 6 180.00 ! ALLOW POL PEP + ! For side chains of asp,asn,glu,gln, (n=6) from KK(LK) +X CT1 CD X 0.0000 6 180.00 ! ALLOW POL PEP + ! adm jr. 3/19/92, from lipid methyl acetate +X CT1 CT1 X 0.2000 3 0.00 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +X CT1 CT2 X 0.2000 3 0.00 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +X CT1 CT3 X 0.2000 3 0.00 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +X CT1 NH3 X 0.1000 3 0.00 ! ALLOW ALI POL + ! 0.715->0.10 METHYLAMMONIUM (KK) +X CT1 OH1 X 0.1400 3 0.00 ! ALLOW ALI ALC ARO + ! EMB 11/21/89 methanol vib fit +X CT1 OS X -0.1000 3 0.00 ! ALLOW PEP POL + ! adm jr. 3/19/92, from lipid methyl acetate +X CT2 CA X 0.0000 6 0.00 ! ALLOW ALI ARO + ! toluene, adm jr., 3/7/92 +X CT2 CC X 0.0500 6 180.00 ! ALLOW POL PEP + ! For side chains of asp,asn,glu,gln, (n=6) from KK(LK) +X CT2 CD X 0.0000 6 180.00 ! ALLOW POL PEP + ! adm jr. 3/19/92, from lipid methyl acetate +X CT2 CT2 X 0.1900 3 0.00 ! ALLOW ALI + ! alkane, 4/98, yin and mackerell +X CT2 CT3 X 0.1600 3 0.00 ! ALLOW ALI + ! alkane, 4/98, yin and mackerell +X CT2 NC2 X 0.0000 6 180.00 ! ALLOW ALI POL + ! methylguanidinium, adm jr., 3/26/92 +X CT2 NH3 X 0.1000 3 0.00 ! ALLOW ALI POL + ! 0.715->0.10 METHYLAMMONIUM (KK) +X CT2 OH1 X 0.1400 3 0.00 ! ALLOW ALI ALC ARO + ! EMB 11/21/89 methanol vib fit +X CT2 OS X -0.1000 3 0.00 ! ALLOW PEP POL + ! adm jr. 3/19/92, from lipid methyl acetate +X CT3 CA X 0.0000 6 0.00 ! ALLOW ALI ARO + ! toluene, adm jr., 3/7/92 +X CT3 CC X 0.0500 6 180.00 ! ALLOW POL PEP + ! For side chains of asp,asn,glu,gln, (n=6) from KK(LK) +X CT3 CD X 0.0000 6 180.00 ! ALLOW POL PEP + ! adm jr. 3/19/92, from lipid methyl acetate +X CT3 CT3 X 0.1525 3 0.00 ! ALLOW ALI + ! alkane, 4/98, yin and mackerell +X CT3 NC2 X 0.0000 6 180.00 ! ALLOW ALI POL + ! methylguanidinium, adm jr., 3/26/92 +X CT3 NH2 X 0.1100 3 0.00 ! ALLOW POL + ! methylamine geom/freq, adm jr., 6/2/92 +X CT3 NH3 X 0.0900 3 0.00 ! ALLOW ALI POL + ! fine-tuned to ab initio; METHYLAMMONIUM, KK 03/10/92 +X CT3 OH1 X 0.1400 3 0.00 ! ALLOW ALI ALC ARO + ! EMB 11/21/89 methanol vib fit +X CT3 OS X -0.1000 3 0.00 ! ALLOW PEP POL + ! adm jr. 3/19/92, from lipid methyl acetate + +!chi1/chi2 fitting, Zhu, 2011 +!directly transferred parameters +NH1 CT1 CT1 HA1 0.2000 3 0.00 ! From X CT1 CT1 X +HB1 CT1 CT1 HA1 0.2000 3 0.00 ! From X CT1 CT1 X +HB1 CT1 CT1 CT3 0.2000 3 0.00 ! From X CT1 CT1 X +HA1 CT1 CT1 C 0.2000 3 0.00 ! From X CT1 CT1 X +! +NH1 CT1 CT2 HA2 0.2000 3 0.00 ! From X CT1 CT2 X +HB1 CT1 CT2 HA2 0.2000 3 0.00 ! From X CT1 CT2 X +HB1 CT1 CT2 OH1 0.2000 3 0.00 ! From X CT1 CT2 X +HB1 CT1 CT2 CT2 0.2000 3 0.00 ! From X CT1 CT2 X +HA2 CT2 CT1 C 0.2000 3 0.00 ! From X CT1 CT2 X +HA2 CT2 OH1 H 0.1400 3 0.00 ! From X CT2 OH1 X +! +CT1 CT2 CT2 HA2 0.1900 3 0.00 ! From X CT2 CT2 X +HA2 CT2 CT2 HA2 0.1900 3 0.00 ! From X CT2 CT2 X +HA2 CT2 CT2 CC 0.1900 3 0.00 ! From X CT2 CT2 X +! +HB1 CT1 CT2 S 0.2000 3 0.00 ! From X CT1 CT2 X +!Arg +CT2 CT2 CT2 HA2 0.1900 3 0.00 ! From X CT2 CT2 X +CT2 CT2 CT2 NC2 0.1900 3 0.00 ! From X CT2 CT2 X +CT2 CT2 NC2 HC 0.0000 6 180.00 ! From X CT2 NC2 X +CT2 CT2 NC2 C 0.0000 6 180.00 ! From X CT2 NC2 X +HA2 CT2 CT2 NC2 0.1900 3 0.00 ! From X CT2 CT2 X +CT2 NC2 C NC2 2.2500 2 180.00 ! From X C NC2 X +HA2 CT2 NC2 HC 0.0000 6 180.00 ! From X CT2 NC2 X +HA2 CT2 NC2 C 0.0000 6 180.00 ! From X CT2 NC2 X +NC2 C NC2 HC 2.2500 2 180.00 ! From X C NC2 X +!Asn +HB1 CT1 CT2 CC 0.2000 3 0.00 ! From X CT1 CT2 X +!Trp +HB1 CT1 CT2 CY 0.2000 3 0.00 ! From X CT1 CT2 X +!Asp +HA2 CT2 CC OC 0.0500 6 180.00 ! From X CT2 CC X +!Hsd/Hse +HB1 CT1 CT2 CPH1 0.2000 3 0.00 ! From X CT1 CT2 X +!Ile,Leu,Val +CT1 CT1 CT3 HA3 0.2000 3 0.00 ! From X CT1 CT3 X +CT1 CT1 CT2 HA2 0.2000 3 0.00 ! From X CT1 CT2 X +HB1 CT1 CT1 CT2 0.2000 3 0.00 ! From X CT1 CT1 X +CT1 CT2 CT3 HA3 0.1600 3 0.00 ! From X CT2 CT3 X +HA1 CT1 CT3 HA3 0.2000 3 0.00 ! From X CT1 CT3 X +HA1 CT1 CT2 HA2 0.2000 3 0.00 ! From X CT1 CT2 X +HA1 CT1 CT2 CT3 0.2000 3 0.00 ! From X CT1 CT2 X +CT3 CT1 CT2 HA2 0.2000 3 0.00 ! From X CT1 CT2 X +CT3 CT1 CT2 CT3 0.2000 3 0.00 ! From X CT1 CT2 X +HA3 CT3 CT1 CT2 0.2000 3 0.00 ! From X CT1 CT3 X +HA2 CT2 CT3 HA3 0.1600 3 0.00 ! From X CT2 CT3 X +CT1 CT2 CT1 HA1 0.2000 3 0.00 ! From X CT1 CT2 X +HB1 CT1 CT2 CT1 0.2000 3 0.00 ! From X CT1 CT2 X +CT3 CT1 CT3 HA3 0.2000 3 0.00 ! From X CT1 CT3 X +!Lys +CT2 CT2 CT2 NH3 0.1900 3 0.00 ! From X CT2 CT2 X +CT2 CT2 NH3 HC 0.1000 3 0.00 ! From X CT2 NH3 X +HA2 CT2 CT2 NH3 0.1900 3 0.00 ! From X CT2 CT2 X +HA2 CT2 NH3 HC 0.1000 3 0.00 ! From X CT2 NH3 X +!Tyr/Phe +HB1 CT1 CT2 CA 0.2000 3 0.00 ! From X CT1 CT2 X +HA2 CT2 CA CA 0.0000 6 0.00 ! From X CT2 CA X +!Thr +HB1 CT1 CT1 OH1 0.2000 3 0.00 ! From X CT1 CT1 X +HA1 CT1 OH1 H 0.1400 3 0.00 ! From X CT1 OH1 X +OH1 CT1 CT3 HA3 0.2000 3 0.00 ! From X CT1 CT3 X +!Gln +CT2 CT2 CC O 0.0500 6 180.00 ! From X CT2 CC X +CT2 CT2 CC NH2 0.0500 6 180.00 ! From X CT2 CC X +!Glu +CT2 CT2 CC OC 0.0500 6 180.00 ! From X CT2 CC X +!Glu/Hsp +NH1 CT1 CT2A HA2 0.2000 3 0.00 ! From X CT1 CT2 X +NH3 CT1 CT2A CT2 0.2000 3 0.00 ! From X CT1 CT2 X !N terminus +CT1 CT2A CT2 HA2 0.1900 3 0.00 ! From X CT2 CT2 X +HB1 CT1 CT2A HA2 0.2000 3 0.00 ! From X CT1 CT2 X +HB1 CT1 CT2A CT2 0.2000 3 0.00 ! From X CT1 CT2 X +HA2 CT2A CT1 C 0.2000 3 0.00 ! From X CT1 CT2 X +HA2 CT2A CT1 CC 0.2000 3 0.00 ! RB: added for C-ter Glu +HA2 CT2A CT2 HA2 0.1900 3 0.00 ! From X CT2 CT2 X +HA2 CT2A CT2 CC 0.1900 3 0.00 ! From X CT2 CT2 X +HB1 CT1 CT2A CPH1 0.2000 3 0.00 ! From X CT1 CT2 X +C NH1 CT1 CT2A 1.8000 1 0.00 ! from CT2 CT1 NH1 C +H NH1 CT1 CT2A 0.0000 1 0.00 ! from H NH1 CT1 CT2 +CT2A CT1 C O 1.4000 1 0.00 ! from O C CT1 CT2 +CT2A CT1 C NH1 0.0000 1 0.00 ! NH1 C CT1 CT2 +CT2A CT1 C N 0.0000 1 0.00 ! RB: added for GLU-PRO in UBQ +! Glup +CT1 CT2A CT2 CD 0.1900 3 0.00 ! From X CT2 CT2 X +HA2 CT2A CT2 CD 0.1900 3 0.00 ! From X CT2 CT2 X +CT2A CPH1 CPH1 HR1 1.0000 2 180.00 ! from HR1 CPH1 CPH1 CT2 +CT2A CPH1 CPH1 NR3 2.5000 2 180.00 ! from NR3 CPH1 CPH1 CT2 +CT2A CPH1 NR3 H 3.0000 2 180.00 ! from H NR3 CPH1 CT2 +CT2A CPH1 NR3 CPH2 2.5000 2 180.00 ! from CT2 CPH1 NR3 CPH2 +HA2 CT2A CPH1 CPH1 0.0000 3 0.00 ! from HA2 CT2 CPH1 CPH1 +HA2 CT2A CPH1 NR3 0.1900 3 0.00 ! from NR3 CPH1 CT2 HA2 + +! Fit dihedrals +! Variable cutoff based on QM and weighted in favor of alphaR and EXT (5:5:1) +! Shared dihedrals were fitted simultaneously + +! Group-fitted for Lys/Arg/Gln/Met +C CT1 CT2 CT2 0.3500 1 180.00 +C CT1 CT2 CT2 0.4200 2 180.00 +C CT1 CT2 CT2 1.9100 3 180.00 +CT2 CT2 CT1 NH1 0.8800 1 180.00 +CT2 CT2 CT1 NH1 0.0000 2 180.00 +CT2 CT2 CT1 NH1 1.9000 3 0.00 +CC CT2 CT2 CT1 1.8400 1 180.00 +CC CT2 CT2 CT1 0.8400 2 180.00 +CC CT2 CT2 CT1 0.3900 3 180.00 +CT1 CT2 CT2 CT2 0.6300 1 180.00 +CT1 CT2 CT2 CT2 0.0100 2 0.00 +CT1 CT2 CT2 CT2 0.1500 3 0.00 +CT1 CT2 CT2 S 0.1400 1 180.00 +CT1 CT2 CT2 S 0.5400 2 0.00 +CT1 CT2 CT2 S 0.6900 3 0.00 +! Fitted Asn +C CT1 CT2 CC 1.4100 1 180.00 +C CT1 CT2 CC 1.2900 2 180.00 +C CT1 CT2 CC 0.5900 3 180.00 +CC CT2 CT1 NH1 0.2800 1 180.00 +CC CT2 CT1 NH1 0.5000 2 180.00 +CC CT2 CT1 NH1 0.3800 3 0.00 +CT1 CT2 CC NH2 0.6200 1 180.00 +CT1 CT2 CC NH2 0.6600 2 180.00 +CT1 CT2 CC NH2 0.7200 3 180.00 +CT1 CT2 CC O 0.4200 1 180.00 +CT1 CT2 CC O 0.1500 2 180.00 +CT1 CT2 CC O 0.9500 3 180.00 +! Fitted Asp +C CT1 CT2A CC 1.6100 1 180.00 +C CT1 CT2A CC 1.2900 2 180.00 +C CT1 CT2A CC 0.5900 3 180.00 +CC CT2A CT1 NH1 0.6800 1 180.00 +CC CT2A CT1 NH1 0.1000 2 180.00 +CC CT2A CT1 NH1 0.3800 3 0.00 +CT1 CT2A CC OC 0.8400 1 0.00 +CT1 CT2A CC OC 0.9800 2 180.00 +CT1 CT2A CC OC 1.4600 3 0.00 +! Fitted Cys +CT1 CT2 S HS 0.2000 1 0.00 +CT1 CT2 S HS 0.6500 2 0.00 +CT1 CT2 S HS 0.2200 3 0.00 +C CT1 CT2 S 0.2400 1 180.00 +C CT1 CT2 S 0.7500 2 180.00 +C CT1 CT2 S 1.3500 3 180.00 +NH1 CT1 CT2 S 0.3400 1 0.00 +NH1 CT1 CT2 S 0.5000 2 180.00 +NH1 CT1 CT2 S 1.4300 3 0.00 +! Fitted Glu +CC CT2 CT2A CT1 0.0000 1 180.00 +CC CT2 CT2A CT1 0.3800 2 180.00 +CC CT2 CT2A CT1 0.5900 3 180.00 +C CT1 CT2A CT2 0.1100 1 0.00 +C CT1 CT2A CT2 0.9800 2 180.00 +C CT1 CT2A CT2 1.6000 3 180.00 +CC CT1 CT2A CT2 1.6000 3 180.00 +CT2 CT2A CT1 NH1 0.3000 1 0.00 +CT2 CT2A CT1 NH1 0.3500 2 0.00 +CT2 CT2A CT1 NH1 1.7600 3 0.00 +! Group-fitted for Hsd/Hse +CPH1 CPH1 CT2 CT1 1.7400 1 0.00 +CPH1 CPH1 CT2 CT1 0.1500 2 0.00 +CPH1 CPH1 CT2 CT1 0.7700 3 180.00 +CT1 CT2 CPH1 NR1 1.4900 1 0.00 +CT1 CT2 CPH1 NR1 0.0900 2 180.00 +CT1 CT2 CPH1 NR1 0.7900 3 180.00 +CT1 CT2 CPH1 NR2 1.0900 1 0.00 +CT1 CT2 CPH1 NR2 0.0900 2 0.00 +CT1 CT2 CPH1 NR2 0.6700 3 180.00 +C CT1 CT2 CPH1 0.1800 1 180.00 +C CT1 CT2 CPH1 0.6400 2 180.00 +C CT1 CT2 CPH1 0.8700 3 180.00 +CPH1 CT2 CT1 NH1 0.0000 1 0.00 +CPH1 CT2 CT1 NH1 0.0000 2 180.00 +CPH1 CT2 CT1 NH1 0.9000 3 0.00 +! Fitted Hsp +CPH1 CPH1 CT2A CT1 2.0400 1 0.00 +CPH1 CPH1 CT2A CT1 0.4400 2 0.00 +CPH1 CPH1 CT2A CT1 0.1300 3 180.00 +CT1 CT2A CPH1 NR3 0.5300 1 180.00 +CT1 CT2A CPH1 NR3 0.4200 2 180.00 +CT1 CT2A CPH1 NR3 0.3000 3 180.00 +C CT1 CT2A CPH1 1.7500 1 180.00 +C CT1 CT2A CPH1 0.1300 2 0.00 +C CT1 CT2A CPH1 1.8600 3 180.00 +CPH1 CT2A CT1 NH1 1.0900 1 180.00 +CPH1 CT2A CT1 NH1 0.2200 2 180.00 +CPH1 CT2A CT1 NH1 2.3200 3 0.00 +! Group-fitted for Ile/Thr +CT1 CT1 CT2 CT3 0.3800 1 180.00 +CT1 CT1 CT2 CT3 0.1300 2 180.00 +CT1 CT1 CT2 CT3 0.2900 3 180.00 +C CT1 CT1 CT2 0.1000 1 180.00 +C CT1 CT1 CT2 0.5200 2 180.00 +C CT1 CT1 CT2 0.2900 3 180.00 +CT2 CT1 CT1 NH1 0.1200 1 180.00 +CT2 CT1 CT1 NH1 0.3600 2 180.00 +CT2 CT1 CT1 NH1 0.4100 3 0.00 +! Fitted Leu +CT1 CT2 CT1 CT3 0.0500 1 0.00 +CT1 CT2 CT1 CT3 0.1000 2 180.00 +CT1 CT2 CT1 CT3 0.0100 3 180.00 +C CT1 CT2 CT1 0.3200 1 180.00 +C CT1 CT2 CT1 0.6100 2 180.00 +C CT1 CT2 CT1 0.7200 3 180.00 +CT1 CT2 CT1 NH1 0.4800 1 180.00 +CT1 CT2 CT1 NH1 0.4200 2 180.00 +CT1 CT2 CT1 NH1 0.6500 3 0.00 +! Group-fitted for Phe/Tyr +CA CA CT2 CT1 1.0700 1 0.00 +CA CA CT2 CT1 0.2400 2 180.00 +CA CA CT2 CT1 0.1700 3 180.00 +C CT1 CT2 CA 1.2800 1 180.00 +C CT1 CT2 CA 0.9400 2 180.00 +C CT1 CT2 CA 1.5700 3 180.00 +CA CT2 CT1 NH1 0.5200 1 180.00 +CA CT2 CT1 NH1 0.6200 2 180.00 +CA CT2 CT1 NH1 1.5800 3 0.00 +! Fitted Ser +CT1 CT2 OH1 H 0.0200 1 0.00 +CT1 CT2 OH1 H 0.5600 2 0.00 +CT1 CT2 OH1 H 0.4900 3 0.00 +C CT1 CT2 OH1 0.6500 1 180.00 +C CT1 CT2 OH1 0.2500 2 180.00 +C CT1 CT2 OH1 1.1700 3 180.00 +NH1 CT1 CT2 OH1 0.1800 1 180.00 +NH1 CT1 CT2 OH1 0.1900 2 180.00 +NH1 CT1 CT2 OH1 1.4600 3 0.00 +! Group-fitted for Ile/Thr +CT1 CT1 OH1 H 0.1800 1 0.00 +CT1 CT1 OH1 H 0.0600 2 0.00 +CT1 CT1 OH1 H 0.2500 3 0.00 +C CT1 CT1 OH1 0.7900 1 180.00 +C CT1 CT1 OH1 0.3900 2 180.00 +C CT1 CT1 OH1 0.9900 3 180.00 +NH1 CT1 CT1 OH1 0.0900 1 0.00 +NH1 CT1 CT1 OH1 0.1900 2 180.00 +NH1 CT1 CT1 OH1 0.1700 3 0.00 +! Fitted Trp +CA CY CT2 CT1 0.0300 1 0.00 +CA CY CT2 CT1 0.5500 2 0.00 +CA CY CT2 CT1 0.3900 3 180.00 +CPT CY CT2 CT1 0.3600 1 180.00 +CPT CY CT2 CT1 0.0500 2 0.00 +CPT CY CT2 CT1 0.1900 3 180.00 +C CT1 CT2 CY 1.0900 1 180.00 +C CT1 CT2 CY 0.5000 2 180.00 +C CT1 CT2 CY 1.1700 3 180.00 +CY CT2 CT1 NH1 0.2900 1 180.00 +CY CT2 CT1 NH1 0.6600 2 180.00 +CY CT2 CT1 NH1 1.1700 3 0.00 +! Fitted Val +C CT1 CT1 CT3 0.1400 1 180.00 +C CT1 CT1 CT3 0.2600 2 180.00 +C CT1 CT1 CT3 0.3300 3 180.00 +CT3 CT1 CT1 NH1 0.1800 1 0.00 +CT3 CT1 CT1 NH1 0.0600 2 0.00 +CT3 CT1 CT1 NH1 0.5900 3 0.00 +!ASP, CT2->CT2A, jshim +H NH1 CT2A CC 0.0000 1 0.00 +X CT2A CC X 0.0500 6 180.00 +HB1 CT1 CT2A CC 0.2000 3 0.00 +HA2 CT2A CC OC 0.0500 6 180.00 +NH3 CT1 CT2A HA2 0.2000 3 0.00 +NH3 CT1 CT2A CC 0.2000 3 0.00 +CC CT2A CT1 CC 0.2000 3 0.00 +!termini specific terms +CPH1 CT2A CT1 CC 0.2000 3 0.00 +CPH1 CT2A CT1 NH3 0.2000 3 0.00 +CPH1 CT2A CT1 CD 0.2000 3 0.00 +HA2 CT2A CT1 CD 0.2000 3 0.00 +CT2 CT2A CT1 CD 0.2000 3 0.00 +! RESI CYSM and PRES CYSD +H NH2 CT1 CS 0.1100 3 0.00 ! from H NH2 CT1 CT2 or H NH2 CT1 CT2 , kevo +CS CT1 NH1 C 1.8000 1 0.00 ! from CT2 CT1 NH1 C or CT2A CT1 NH1 C , kevo +H NH1 CT1 CS 0.0000 1 0.00 ! from H NH1 CT1 CT2 or H NH1 CT1 CT2 , kevo +N C CT1 CS 0.0000 1 0.00 ! from N C CT1 CT2 or N C CT1 CT2 , kevo +NH1 C CT1 CS 0.0000 1 0.00 ! from NH1 C CT1 CT2 or NH1 C CT1 CT2 , kevo +O C CT1 CS 1.4000 1 0.00 ! from O C CT1 CT2 or O C CT1 CT2 , kevo +HA2 CS CT1 C 0.2000 3 0.00 ! from HA2 CT2 CT1 C or HA2 CT2A CT1 C , kevo +NH1 CT1 CS HA2 0.2000 3 0.00 ! from NH1 CT1 CT2 HA2 or NH1 CT1 CT2A HA2 , kevo +HB1 CT1 CS HA2 0.2000 3 0.00 ! from HB1 CT1 CT2 HA2 or HB1 CT1 CT2A HA2 , kevo +HB1 CT1 CS SS 0.2000 3 0.00 ! from HB1 CT1 CT2 S or HB1 CT1 CT2A S , kevo +C CT1 CS SS 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +NH1 CT1 CS SS 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +! Termini +NH3 CT1 CS HA2 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +NH3 CT1 CS SS 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +NH2 CT1 CS HA2 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +NH2 CT1 CS SS 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +CC CT1 CS HA2 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +CC CT1 CS SS 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +CD CT1 CS HA2 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +CD CT1 CS SS 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +! PRES SERD +NH1 CT1 CT2 OC 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +NH2 CT1 CT2 OC 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +NH3 CT1 CT2 OC 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +C CT1 CT2 OC 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +CC CT1 CT2 OC 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +CD CT1 CT2 OC 0.2000 3 0.00 ! from X CT1 CT2 X , kevo +HB1 CT1 CT2 OC 0.2000 3 0.00 ! from X CT1 CT2 X , kevo + +IMPROPER +! +!V(improper) = Kpsi(psi - psi0)**2 +! +!Kpsi: kcal/mole/rad**2 +!psi0: degrees +!note that the second column of numbers (0) is ignored +! +!atom types Kpsi psi0 +! +HE2 HE2 CE2 CE2 3.0 0 0.00 ! + ! for ethene, yin/adm jr., 12/95 +HR1 NR1 NR2 CPH2 0.5000 0 0.0000 ! ALLOW ARO + ! his, adm jr., 7/05/90 +HR1 NR2 NR1 CPH2 0.5000 0 0.0000 ! ALLOW ARO + ! his, adm jr., 7/05/90 +HR3 CPH1 NR1 CPH1 0.5000 0 0.0000 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HR3 CPH1 NR2 CPH1 0.5000 0 0.0000 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HR3 CPH1 NR3 CPH1 1.0000 0 0.0000 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HR3 NR1 CPH1 CPH1 0.5000 0 0.0000 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HR3 NR2 CPH1 CPH1 0.5000 0 0.0000 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +N C CP1 CP3 0.0000 0 0.0000 ! ALLOW PRO + ! 6-31g* AcProNH2 and ProNH2 RLD 5/19/92 +NC2 X X C 45.0000 0 0.0000 ! ALLOW PEP POL ARO + ! mp2/6-311g** guan vibrational data, adm jr., 1/04 +C HC HC NC2 0.0 0 0.0 + ! mp2/6-311g** guan vibrational data, adm jr., 1/04 +NC2 X X HC -2.0 0 0.0 + ! mp2/6-311g** guan vibrational data, adm jr., 1/04 +NH1 X X H 20.0000 0 0.0000 ! ALLOW PEP POL ARO + ! NMA Vibrational Modes (LK) +NH2 X X H 4.0000 0 0.0000 ! ALLOW POL + ! adm jr., 8/13/90 acetamide geometry and vibrations +NR1 CPH1 CPH2 H 0.4500 0 0.0000 ! ALLOW ARO + ! his, adm jr., 7/05/90 +NR1 CPH2 CPH1 H 0.4500 0 0.0000 ! ALLOW ARO + ! his, adm jr., 7/05/90 +NR3 CPH1 CPH2 H 1.2000 0 0.0000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +NR3 CPH2 CPH1 H 1.2000 0 0.0000 ! ALLOW ARO + ! his, adm jr., 6/27/90 +O CP1 NH2 CC 45.0000 0 0.0000 ! ALLOW PEP POL PRO + ! 6-31g* AcProNH2 and ProNH2 RLD 5/19/92 +O CT1 NH2 CC 45.0000 0 0.0000 ! ALLOW PEP POL + ! adm jr., 8/13/90 acetamide geometry and vibrations +O CT2 NH2 CC 45.0000 0 0.0000 ! ALLOW PEP POL + ! adm jr., 8/13/90 acetamide geometry and vibrations +O CT3 NH2 CC 45.0000 0 0.0000 ! ALLOW PEP POL + ! adm jr., 8/13/90 acetamide geometry and vibrations +O HA1 NH2 CC 45.0000 0 0.0000 ! ALLOW PEP POL PRO + ! adm jr., 5/13/91, formamide geometry and vibrations +O N CT2 CC 120.0000 0 0.0000 ! ALLOW PEP POL PRO + ! 6-31g* AcProNH2 and ProNH2 RLD 5/19/92 +O NH2 CP1 CC 45.0000 0 0.0000 ! ALLOW PEP POL PRO + ! 6-31g* AcProNH2 and ProNH2 RLD 5/19/92 +O NH2 CT1 CC 45.0000 0 0.0000 ! ALLOW PEP POL + ! adm jr., 8/13/90 acetamide geometry and vibrations +O NH2 CT2 CC 45.0000 0 0.0000 ! ALLOW PEP POL + ! adm jr., 8/13/90 acetamide geometry and vibrations +O NH2 CT3 CC 45.0000 0 0.0000 ! ALLOW PEP POL + ! adm jr., 8/13/90 acetamide geometry and vibrations +O NH2 HA1 CC 45.0000 0 0.0000 ! ALLOW PEP POL + ! adm jr., 5/13/91, formamide geometry and vibrations +O X X C 120.0000 0 0.0000 ! ALLOW PEP POL ARO + ! NMA Vibrational Modes (LK) +OB X X CD 100.0000 0 0.0000 ! ALLOW ALC ARO POL + ! adm jr., 10/17/90, acetic acid vibrations +OC X X CC 96.0000 0 0.0000 ! ALLOW PEP POL ARO ION + ! 90.0->96.0 acetate, single impr (KK) +CC X X CT1 96.0000 0 0.0000 ! ALLOW PEP POL ARO ION + ! 90.0->96.0 acetate, single impr (KK) +CC X X CT2 96.0000 0 0.0000 ! ALLOW PEP POL ARO ION + ! 90.0->96.0 acetate, single impr (KK) +CC X X CT3 96.0000 0 0.0000 ! ALLOW PEP POL ARO ION + ! 90.0->96.0 acetate, single impr (KK) + +CMAP +! 2D grid correction data. +! Finalfix3, Feig/Best/MacKerell 2010 + +! alanine map +C NH1 CT1 C NH1 CT1 C NH1 24 + +! phi = -180.0 + 0.126790 0.768700 0.971260 1.250970 2.121010 + 2.720430 2.089440 1.789790 0.780870 -0.688474 + 1.001130 -2.200520 -4.827670 -4.821447 -4.913223 + -3.591106 -2.766446 -2.784200 -2.454589 -2.346991 + -2.335350 -1.522656 -0.951542 -0.036650 + +! phi = -165.0 + -0.127133 1.377090 1.577020 1.872290 2.398990 + 2.486630 2.436754 1.929070 1.086456 0.643400 + 0.258676 -2.800440 -4.009477 -4.135306 -3.420090 + -2.602140 -2.299128 -1.501241 -1.101780 -0.861434 + -0.640168 -0.207701 -1.076344 -1.122030 + +! phi = -150.0 + 0.084069 1.420317 1.624350 2.047200 2.653910 + 2.716410 2.321416 1.985454 1.557466 2.463293 + -0.225720 -1.815886 -2.583256 -3.006154 -2.551995 + -1.890683 -1.354215 -0.727243 0.068512 -0.225016 + -0.765479 -1.283444 -1.293226 -0.816303 + +! phi = -135.0 + 0.927992 1.521370 2.242218 2.546305 3.111384 + 2.918410 2.460813 2.187970 2.058314 1.852278 + 0.115935 -1.183897 -1.995479 -2.278329 -1.959136 + -1.340467 -0.932949 0.021790 0.313725 -0.517358 + -1.152891 -0.983285 -0.566518 -0.442565 + +! phi = -120.0 + 1.357468 1.959160 2.698894 3.037857 3.698960 + 3.558453 2.639296 2.773853 2.719664 1.627997 + 0.705667 -0.785637 -2.118268 -2.628489 -1.803113 + -0.425969 -0.062320 0.439040 0.910952 -0.546994 + -0.968118 -0.856791 -0.250116 0.449309 + +! phi = -105.0 + 2.045006 2.544424 2.818030 3.088582 3.370620 + 3.551568 3.073520 2.903794 2.956634 2.124759 + 0.906487 -0.823628 -2.090819 -2.241579 -1.456524 + 0.206160 0.082195 0.771710 1.040241 -0.124647 + -0.316550 -0.164333 0.314474 0.733747 + +! phi = -90.0 + 1.451735 2.748481 2.738185 3.156796 3.450028 + 3.344157 3.180200 3.898724 3.335030 2.440579 + 0.912671 -0.606502 -1.511772 -1.620864 -0.962798 + -0.020653 0.415153 0.908250 0.459433 0.145910 + -0.071054 0.017622 0.280839 0.748823 + +! phi = -75.0 + 1.378160 3.345958 2.352424 3.063543 3.814070 + 3.700796 3.580310 4.212293 3.536425 1.693809 + 0.095172 -0.682452 -0.123614 -0.427765 -0.598368 + 0.226352 0.423308 0.301999 0.551890 0.191719 + -0.253585 -0.190548 -0.253412 0.468922 + +! phi = -60.0 + 0.237754 1.229980 1.716960 3.168570 4.208190 + 4.391860 4.276080 3.673107 2.272295 -0.482789 + -0.406695 -0.038919 -0.357600 -0.823341 -0.173146 + 0.139806 0.267796 0.322420 0.309664 -0.666399 + -0.948631 -1.534365 -1.479968 -0.204264 + +! phi = -45.0 + -1.184837 0.078060 2.347410 4.211350 5.376000 + 5.389940 4.380200 2.461506 1.123713 0.107016 + 0.007574 -0.149443 -0.797230 -0.582210 0.082910 + 0.271580 -0.045570 0.379430 0.247770 -0.890956 + -1.582430 -1.954532 -1.980965 -2.000433 + +! phi = -30.0 + -1.174720 1.067030 4.180460 6.741610 6.070770 + 4.806470 2.783340 1.320806 0.765978 -0.008448 + 0.276860 -0.707140 1.314360 1.522590 1.915550 + 2.223490 0.194290 0.534000 0.331780 -1.595147 + -2.849141 -3.550465 -3.277369 -2.655135 + +! phi = -15.0 + 0.293590 5.588070 3.732620 3.217620 3.272450 + 2.517320 1.588700 1.381760 0.856410 0.655170 + 1.616970 0.846920 0.511070 0.740760 1.021020 + 1.616580 -0.342400 0.181770 -0.613920 -2.558037 + -3.786839 -3.807325 -3.155346 -1.749204 + +! phi = 0.0 + 2.832310 0.787990 0.323280 0.479230 0.628600 + 0.976330 1.238750 1.671950 1.645480 2.520340 + 1.606970 0.776350 0.119780 0.070390 0.121170 + -1.569230 -1.213010 -1.846360 -2.744510 -3.792530 + -3.934880 -3.615930 -2.675750 -0.924170 + +! phi = 15.0 + -0.778340 -1.912680 -2.052140 -1.846280 -1.047430 + 0.183400 1.682950 2.223500 1.358370 2.448660 + 1.436920 0.678570 -0.237060 -0.535320 -0.790380 + -2.182580 -3.251140 -4.195110 -4.269270 -3.908210 + -3.455620 -2.773970 1.755370 0.313410 + +! phi = 30.0 + -2.963810 -3.483730 -3.441809 -2.400349 -1.125083 + 0.336200 1.428450 1.394630 0.970370 2.462720 + 1.522430 0.553620 -0.407380 -1.482950 -3.613920 + -4.159810 -4.709721 -4.496271 -3.764540 -2.959140 + -1.963850 -1.071260 -1.599580 -2.445320 + +! phi = 45.0 + -4.021496 -3.836549 -3.365327 -2.334377 -0.984725 + 0.362000 0.814380 0.754110 0.502370 1.903420 + 0.770220 -0.416420 -3.286310 -3.875270 -4.611550 + -5.287977 -5.146239 -4.038627 -2.865450 -2.368170 + -2.860490 -3.416560 -3.666490 -3.595217 + +! phi = 60.0 + -3.353683 -2.984416 -2.317412 -1.240143 -0.257890 + 0.722610 0.668070 0.438130 2.395330 1.632470 + -2.041450 -3.218100 -3.915080 -4.568574 -5.096776 + -5.526955 -5.005312 -3.777879 -2.840678 -3.508820 + -3.756430 -3.640810 -3.451845 -3.342810 + +! phi = 75.0 + -2.248733 -1.641080 -1.010583 0.039656 0.636063 + 0.823710 0.517140 -0.013120 -0.370910 -1.192809 + -2.305650 -3.420580 -4.484960 -5.597237 -5.601264 + -5.727739 -4.740525 -3.819378 -3.685150 -4.151360 + -4.170739 -3.725589 -3.736732 -2.620673 + +! phi = 90.0 + -1.720840 -1.177830 -0.428430 0.277730 0.807900 + 0.803260 0.482510 -0.336900 -0.786270 -1.774070 + -2.793220 -3.828560 -5.211800 -6.294328 -6.617221 + -5.763953 -5.072995 -3.911450 -4.158306 -4.473413 + -4.099325 -3.769822 -3.157300 -2.651694 + +! phi = 105.0 + -1.850640 -1.092420 -0.445020 0.128490 1.005520 + 0.884820 0.485850 -0.218470 -0.857670 -1.682330 + -3.014400 -4.481110 -6.053510 -6.865400 -6.871130 + -5.728240 -3.912230 -4.802110 -5.034640 -4.715990 + -4.600554 -4.086721 -3.274630 -2.410940 + +! phi = 120.0 + -1.969230 -1.116650 -0.540250 -0.150330 0.763520 + 1.038890 0.758480 0.313530 -0.333050 -1.872770 + -3.366270 -5.008260 -6.124810 -7.034830 -6.724320 + -3.700200 -4.510620 -5.185650 -5.361620 -4.847490 + -4.444320 -4.004260 -3.415720 -2.751230 + +! phi = 135.0 + -2.111250 -1.168960 -0.322790 -0.006920 0.316660 + 1.086270 0.939170 0.625340 -0.166360 -1.830310 + -3.469470 -4.946030 -6.112560 -1.915580 -4.047310 + -4.996740 -4.996730 -4.842690 -4.886620 -4.300540 + -4.494620 -4.442210 -4.163570 -3.183510 + +! phi = 150.0 + -1.757590 -0.403620 0.023920 0.362390 0.634520 + 1.264920 1.361360 0.948420 -0.073680 -1.483560 + -3.152820 1.835120 -1.762860 -5.093660 -5.744830 + -5.390070 -4.783930 -4.190630 -4.115420 -4.042280 + -4.125570 -4.028550 -4.026100 -2.937910 + +! phi = 165.0 + -0.810590 -0.071500 0.378890 0.543310 1.277880 + 1.641310 1.698840 1.519950 0.631950 -1.088670 + -2.736530 -0.735240 -4.563830 -6.408350 -5.889450 + -5.141750 -4.194970 -3.666490 -3.843450 -3.555000 + -3.548722 -3.246995 -2.751289 -1.814368 + + +! alanine before proline map + +C NH1 CT1 C NH1 CT1 C N 24 + +! phi = -180.0 + 0.126790 0.768700 0.971260 1.250970 2.121010 + 2.720430 2.089440 1.789790 0.780870 -0.688474 + 1.001130 -2.200520 -4.827670 -4.821447 -4.913223 + -3.591106 -2.766446 -2.784200 -2.454589 -2.346991 + -2.335350 -1.522656 -0.951542 -0.036650 + +! phi = -165.0 + -0.127133 1.377090 1.577020 1.872290 2.398990 + 2.486630 2.436754 1.929070 1.086456 0.643400 + 0.258676 -2.800440 -4.009477 -4.135306 -3.420090 + -2.602140 -2.299128 -1.501241 -1.101780 -0.861434 + -0.640168 -0.207701 -1.076344 -1.122030 + +! phi = -150.0 + 0.084069 1.420317 1.624350 2.047200 2.653910 + 2.716410 2.321416 1.985454 1.557466 2.463293 + -0.225720 -1.815886 -2.583256 -3.006154 -2.551995 + -1.890683 -1.354215 -0.727243 0.068512 -0.225016 + -0.765479 -1.283444 -1.293226 -0.816303 + +! phi = -135.0 + 0.927992 1.521370 2.242218 2.546305 3.111384 + 2.918410 2.460813 2.187970 2.058314 1.852278 + 0.115935 -1.183897 -1.995479 -2.278329 -1.959136 + -1.340467 -0.932949 0.021790 0.313725 -0.517358 + -1.152891 -0.983285 -0.566518 -0.442565 + +! phi = -120.0 + 1.357468 1.959160 2.698894 3.037857 3.698960 + 3.558453 2.639296 2.773853 2.719664 1.627997 + 0.705667 -0.785637 -2.118268 -2.628489 -1.803113 + -0.425969 -0.062320 0.439040 0.910952 -0.546994 + -0.968118 -0.856791 -0.250116 0.449309 + +! phi = -105.0 + 2.045006 2.544424 2.818030 3.088582 3.370620 + 3.551568 3.073520 2.903794 2.956634 2.124759 + 0.906487 -0.823628 -2.090819 -2.241579 -1.456524 + 0.206160 0.082195 0.771710 1.040241 -0.124647 + -0.316550 -0.164333 0.314474 0.733747 + +! phi = -90.0 + 1.451735 2.748481 2.738185 3.156796 3.450028 + 3.344157 3.180200 3.898724 3.335030 2.440579 + 0.912671 -0.606502 -1.511772 -1.620864 -0.962798 + -0.020653 0.415153 0.908250 0.459433 0.145910 + -0.071054 0.017622 0.280839 0.748823 + +! phi = -75.0 + 1.378160 3.345958 2.352424 3.063543 3.814070 + 3.700796 3.580310 4.212293 3.536425 1.693809 + 0.095172 -0.682452 -0.123614 -0.427765 -0.598368 + 0.226352 0.423308 0.301999 0.551890 0.191719 + -0.253585 -0.190548 -0.253412 0.468922 + +! phi = -60.0 + 0.237754 1.229980 1.716960 3.168570 4.208190 + 4.391860 4.276080 3.673107 2.272295 -0.482789 + -0.406695 -0.038919 -0.357600 -0.823341 -0.173146 + 0.139806 0.267796 0.322420 0.309664 -0.666399 + -0.948631 -1.534365 -1.479968 -0.204264 + +! phi = -45.0 + -1.184837 0.078060 2.347410 4.211350 5.376000 + 5.389940 4.380200 2.461506 1.123713 0.107016 + 0.007574 -0.149443 -0.797230 -0.582210 0.082910 + 0.271580 -0.045570 0.379430 0.247770 -0.890956 + -1.582430 -1.954532 -1.980965 -2.000433 + +! phi = -30.0 + -1.174720 1.067030 4.180460 6.741610 6.070770 + 4.806470 2.783340 1.320806 0.765978 -0.008448 + 0.276860 -0.707140 1.314360 1.522590 1.915550 + 2.223490 0.194290 0.534000 0.331780 -1.595147 + -2.849141 -3.550465 -3.277369 -2.655135 + +! phi = -15.0 + 0.293590 5.588070 3.732620 3.217620 3.272450 + 2.517320 1.588700 1.381760 0.856410 0.655170 + 1.616970 0.846920 0.511070 0.740760 1.021020 + 1.616580 -0.342400 0.181770 -0.613920 -2.558037 + -3.786839 -3.807325 -3.155346 -1.749204 + +! phi = 0.0 + 2.832310 0.787990 0.323280 0.479230 0.628600 + 0.976330 1.238750 1.671950 1.645480 2.520340 + 1.606970 0.776350 0.119780 0.070390 0.121170 + -1.569230 -1.213010 -1.846360 -2.744510 -3.792530 + -3.934880 -3.615930 -2.675750 -0.924170 + +! phi = 15.0 + -0.778340 -1.912680 -2.052140 -1.846280 -1.047430 + 0.183400 1.682950 2.223500 1.358370 2.448660 + 1.436920 0.678570 -0.237060 -0.535320 -0.790380 + -2.182580 -3.251140 -4.195110 -4.269270 -3.908210 + -3.455620 -2.773970 1.755370 0.313410 + +! phi = 30.0 + -2.963810 -3.483730 -3.441809 -2.400349 -1.125083 + 0.336200 1.428450 1.394630 0.970370 2.462720 + 1.522430 0.553620 -0.407380 -1.482950 -3.613920 + -4.159810 -4.709721 -4.496271 -3.764540 -2.959140 + -1.963850 -1.071260 -1.599580 -2.445320 + +! phi = 45.0 + -4.021496 -3.836549 -3.365327 -2.334377 -0.984725 + 0.362000 0.814380 0.754110 0.502370 1.903420 + 0.770220 -0.416420 -3.286310 -3.875270 -4.611550 + -5.287977 -5.146239 -4.038627 -2.865450 -2.368170 + -2.860490 -3.416560 -3.666490 -3.595217 + +! phi = 60.0 + -3.353683 -2.984416 -2.317412 -1.240143 -0.257890 + 0.722610 0.668070 0.438130 2.395330 1.632470 + -2.041450 -3.218100 -3.915080 -4.568574 -5.096776 + -5.526955 -5.005312 -3.777879 -2.840678 -3.508820 + -3.756430 -3.640810 -3.451845 -3.342810 + +! phi = 75.0 + -2.248733 -1.641080 -1.010583 0.039656 0.636063 + 0.823710 0.517140 -0.013120 -0.370910 -1.192809 + -2.305650 -3.420580 -4.484960 -5.597237 -5.601264 + -5.727739 -4.740525 -3.819378 -3.685150 -4.151360 + -4.170739 -3.725589 -3.736732 -2.620673 + +! phi = 90.0 + -1.720840 -1.177830 -0.428430 0.277730 0.807900 + 0.803260 0.482510 -0.336900 -0.786270 -1.774070 + -2.793220 -3.828560 -5.211800 -6.294328 -6.617221 + -5.763953 -5.072995 -3.911450 -4.158306 -4.473413 + -4.099325 -3.769822 -3.157300 -2.651694 + +! phi = 105.0 + -1.850640 -1.092420 -0.445020 0.128490 1.005520 + 0.884820 0.485850 -0.218470 -0.857670 -1.682330 + -3.014400 -4.481110 -6.053510 -6.865400 -6.871130 + -5.728240 -3.912230 -4.802110 -5.034640 -4.715990 + -4.600554 -4.086721 -3.274630 -2.410940 + +! phi = 120.0 + -1.969230 -1.116650 -0.540250 -0.150330 0.763520 + 1.038890 0.758480 0.313530 -0.333050 -1.872770 + -3.366270 -5.008260 -6.124810 -7.034830 -6.724320 + -3.700200 -4.510620 -5.185650 -5.361620 -4.847490 + -4.444320 -4.004260 -3.415720 -2.751230 + +! phi = 135.0 + -2.111250 -1.168960 -0.322790 -0.006920 0.316660 + 1.086270 0.939170 0.625340 -0.166360 -1.830310 + -3.469470 -4.946030 -6.112560 -1.915580 -4.047310 + -4.996740 -4.996730 -4.842690 -4.886620 -4.300540 + -4.494620 -4.442210 -4.163570 -3.183510 + +! phi = 150.0 + -1.757590 -0.403620 0.023920 0.362390 0.634520 + 1.264920 1.361360 0.948420 -0.073680 -1.483560 + -3.152820 1.835120 -1.762860 -5.093660 -5.744830 + -5.390070 -4.783930 -4.190630 -4.115420 -4.042280 + -4.125570 -4.028550 -4.026100 -2.937910 + +! phi = 165.0 + -0.810590 -0.071500 0.378890 0.543310 1.277880 + 1.641310 1.698840 1.519950 0.631950 -1.088670 + -2.736530 -0.735240 -4.563830 -6.408350 -5.889450 + -5.141750 -4.194970 -3.666490 -3.843450 -3.555000 + -3.548722 -3.246995 -2.751289 -1.814368 + + +! proline +! mp2/aug-cc-pVDZ//RIMP2/VTZ/VQZ CBS map +C N CP1 C N CP1 C NH1 24 + +! phi = -180 + 2.973500 3.348200 3.062900 2.113400 1.040500 + 0.770600 0.785200 0.263300 -0.479000 -0.583000 + -0.463800 -0.292600 0.000000 0.259100 0.177100 + -0.151200 -0.173500 0.211700 0.348900 -0.135600 + -0.950000 -1.256600 -0.292800 1.560000 + +! phi = -165 + 5.674100 6.011400 5.562700 4.467300 3.390800 + 3.008800 2.848600 2.311200 1.661400 1.468400 + 1.142700 1.437400 2.113200 2.799500 2.989100 + 2.869000 3.016100 3.328500 3.232900 2.547600 + 1.647200 1.422700 2.517100 4.339800 + +! phi = -150 + 6.752800 6.973200 6.444300 5.389800 4.438600 + 4.046000 3.832800 3.442400 3.303500 3.010000 + 2.838100 3.162200 3.778300 4.362800 4.603600 + 4.546200 4.702100 4.837200 4.549500 3.849600 + 3.099200 3.031800 4.060200 5.624800 + +! phi = -135 + 7.627800 8.153400 7.342500 5.893500 4.799200 + 4.433400 4.551500 4.442800 2.222200 0.776300 + 0.790000 2.152300 3.932900 5.274900 5.830800 + 5.988600 5.588500 5.211000 4.918000 4.292100 + 3.495500 3.449800 4.617700 6.311700 + +! phi = -120 + 8.115600 8.477200 7.754300 6.585000 5.537900 + 4.964300 4.929000 4.421200 2.336100 1.257800 + 1.769300 3.359900 5.018000 6.055500 6.217600 + 5.726100 5.512200 5.820200 5.716700 4.872300 + 4.066800 4.094600 5.284900 6.931500 + +! phi = -105 + 9.249700 9.483000 8.668500 7.525300 7.003200 + 6.834600 6.822100 5.287600 3.320600 2.640300 + 3.464800 5.100300 6.537600 6.885600 5.842000 + 5.248700 5.540200 6.652400 7.196700 6.625400 + 5.710100 5.581700 6.651500 8.192800 + +! phi = -90 + 9.335600 9.208000 8.564600 8.010200 7.885100 + 8.212200 8.737100 8.429100 7.306500 6.474200 + 6.651300 7.484700 8.195300 8.295000 7.407200 + 6.529900 6.242000 6.227500 6.347300 6.449700 + 6.404700 6.579300 7.391700 8.570700 + +! phi = -75 + 10.955200 11.455400 11.173300 10.428700 10.062400 + 10.044500 9.279600 6.965100 5.361500 5.102700 + 6.267600 7.871600 8.009800 7.104500 6.616400 + 6.733700 7.504000 8.664700 9.282800 8.795900 + 7.872500 7.612400 8.498100 9.894000 + +! phi = -60 + 8.422900 8.529200 8.608500 9.306400 10.239400 + 11.025900 11.510800 9.283500 7.566000 6.624600 + 7.038700 8.222400 8.786400 8.512000 8.103500 + 7.988200 8.192900 8.291000 8.055600 7.436800 + 6.651800 6.317000 6.802500 7.746300 + +! phi = -45 + 6.913200 7.937400 8.610800 9.316600 9.388500 + 9.408400 8.828800 7.297900 5.456400 4.742700 + 5.793100 7.118800 7.565400 7.598500 7.438700 + 7.512500 7.878100 8.082200 7.642700 6.320500 + 4.680400 3.830500 4.215800 5.435200 + +! phi = -30 + 5.466700 7.116000 8.908800 8.347200 7.413500 + 7.047000 6.031600 4.193100 2.674800 3.023700 + 4.485300 5.451700 6.214900 6.422600 6.229300 + 6.191100 6.488900 6.646400 5.833400 3.751300 + 1.719800 1.064900 1.955800 3.860800 + +! phi = -15 + 3.061500 5.603800 12.179500 6.295200 5.323400 + 4.826500 3.705600 2.461500 2.291600 3.145900 + 3.562100 4.443600 5.337500 5.728800 5.694800 + 5.641600 5.943300 6.169000 4.759500 2.569400 + 1.357100 1.669800 3.212300 5.031900 + +! phi = 0 + 8.085900 8.051100 5.023600 3.450800 2.836100 + 2.192500 1.566200 1.456300 2.039300 1.945200 + 2.188400 2.921300 3.467500 3.543500 3.374500 + 3.472300 4.069900 3.615600 2.082200 0.958600 + 0.792600 1.494200 2.794900 4.853100 + +! phi = 15 + 6.639500 5.177400 3.252300 1.952700 1.078400 + 0.888300 1.505400 2.442300 2.178600 1.578600 + 1.777400 2.395400 2.820200 2.795200 2.662400 + 2.917100 2.562100 1.557900 1.322300 1.631400 + 2.051200 2.555600 3.039100 4.915000 + +! phi = 30 + 7.548800 5.095500 2.747000 0.955200 0.444500 + 1.318700 2.733300 3.223200 2.565500 2.150900 + 2.394400 2.939300 3.266000 3.210000 3.113400 + 2.491300 0.978300 0.815300 1.522700 2.055600 + 2.199900 2.327600 3.474200 7.977800 + +! phi = 45 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 60 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 75 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 90 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 105 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 120 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 135 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 150 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 165 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +!2 adjacent prolines +! mp2/aug-cc-pVDZ//RIMP2/VTZ/VQZ CBS map +C N CP1 C N CP1 C N 24 + +! phi = -180 + 2.973500 3.348200 3.062900 2.113400 1.040500 + 0.770600 0.785200 0.263300 -0.479000 -0.583000 + -0.463800 -0.292600 0.000000 0.259100 0.177100 + -0.151200 -0.173500 0.211700 0.348900 -0.135600 + -0.950000 -1.256600 -0.292800 1.560000 + +! phi = -165 + 5.674100 6.011400 5.562700 4.467300 3.390800 + 3.008800 2.848600 2.311200 1.661400 1.468400 + 1.142700 1.437400 2.113200 2.799500 2.989100 + 2.869000 3.016100 3.328500 3.232900 2.547600 + 1.647200 1.422700 2.517100 4.339800 + +! phi = -150 + 6.752800 6.973200 6.444300 5.389800 4.438600 + 4.046000 3.832800 3.442400 3.303500 3.010000 + 2.838100 3.162200 3.778300 4.362800 4.603600 + 4.546200 4.702100 4.837200 4.549500 3.849600 + 3.099200 3.031800 4.060200 5.624800 + +! phi = -135 + 7.627800 8.153400 7.342500 5.893500 4.799200 + 4.433400 4.551500 4.442800 2.222200 0.776300 + 0.790000 2.152300 3.932900 5.274900 5.830800 + 5.988600 5.588500 5.211000 4.918000 4.292100 + 3.495500 3.449800 4.617700 6.311700 + +! phi = -120 + 8.115600 8.477200 7.754300 6.585000 5.537900 + 4.964300 4.929000 4.421200 2.336100 1.257800 + 1.769300 3.359900 5.018000 6.055500 6.217600 + 5.726100 5.512200 5.820200 5.716700 4.872300 + 4.066800 4.094600 5.284900 6.931500 + +! phi = -105 + 9.249700 9.483000 8.668500 7.525300 7.003200 + 6.834600 6.822100 5.287600 3.320600 2.640300 + 3.464800 5.100300 6.537600 6.885600 5.842000 + 5.248700 5.540200 6.652400 7.196700 6.625400 + 5.710100 5.581700 6.651500 8.192800 + +! phi = -90 + 9.335600 9.208000 8.564600 8.010200 7.885100 + 8.212200 8.737100 8.429100 7.306500 6.474200 + 6.651300 7.484700 8.195300 8.295000 7.407200 + 6.529900 6.242000 6.227500 6.347300 6.449700 + 6.404700 6.579300 7.391700 8.570700 + +! phi = -75 + 10.955200 11.455400 11.173300 10.428700 10.062400 + 10.044500 9.279600 6.965100 5.361500 5.102700 + 6.267600 7.871600 8.009800 7.104500 6.616400 + 6.733700 7.504000 8.664700 9.282800 8.795900 + 7.872500 7.612400 8.498100 9.894000 + +! phi = -60 + 8.422900 8.529200 8.608500 9.306400 10.239400 + 11.025900 11.510800 9.283500 7.566000 6.624600 + 7.038700 8.222400 8.786400 8.512000 8.103500 + 7.988200 8.192900 8.291000 8.055600 7.436800 + 6.651800 6.317000 6.802500 7.746300 + +! phi = -45 + 6.913200 7.937400 8.610800 9.316600 9.388500 + 9.408400 8.828800 7.297900 5.456400 4.742700 + 5.793100 7.118800 7.565400 7.598500 7.438700 + 7.512500 7.878100 8.082200 7.642700 6.320500 + 4.680400 3.830500 4.215800 5.435200 + +! phi = -30 + 5.466700 7.116000 8.908800 8.347200 7.413500 + 7.047000 6.031600 4.193100 2.674800 3.023700 + 4.485300 5.451700 6.214900 6.422600 6.229300 + 6.191100 6.488900 6.646400 5.833400 3.751300 + 1.719800 1.064900 1.955800 3.860800 + +! phi = -15 + 3.061500 5.603800 12.179500 6.295200 5.323400 + 4.826500 3.705600 2.461500 2.291600 3.145900 + 3.562100 4.443600 5.337500 5.728800 5.694800 + 5.641600 5.943300 6.169000 4.759500 2.569400 + 1.357100 1.669800 3.212300 5.031900 + +! phi = 0 + 8.085900 8.051100 5.023600 3.450800 2.836100 + 2.192500 1.566200 1.456300 2.039300 1.945200 + 2.188400 2.921300 3.467500 3.543500 3.374500 + 3.472300 4.069900 3.615600 2.082200 0.958600 + 0.792600 1.494200 2.794900 4.853100 + +! phi = 15 + 6.639500 5.177400 3.252300 1.952700 1.078400 + 0.888300 1.505400 2.442300 2.178600 1.578600 + 1.777400 2.395400 2.820200 2.795200 2.662400 + 2.917100 2.562100 1.557900 1.322300 1.631400 + 2.051200 2.555600 3.039100 4.915000 + +! phi = 30 + 7.548800 5.095500 2.747000 0.955200 0.444500 + 1.318700 2.733300 3.223200 2.565500 2.150900 + 2.394400 2.939300 3.266000 3.210000 3.113400 + 2.491300 0.978300 0.815300 1.522700 2.055600 + 2.199900 2.327600 3.474200 7.977800 + +! phi = 45 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 60 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 75 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 90 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 105 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 120 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 135 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 150 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! phi = 165 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 0.000000 + 0.000000 0.000000 0.000000 0.000000 + +! glycine map +! mp2/aug-cc-pVDZ//RIMP2/VTZ/VQZ CBS map +C NH1 CT2 C NH1 CT2 C NH1 24 + +! phi = -180 + 0.235350 0.182300 0.177200 0.396800 0.859400 + 1.489700 2.092500 2.297700 1.808600 0.696200 + -0.563300 -1.432700 -1.015100 1.426300 -0.564300 + 0.696200 1.808200 2.301700 2.092600 1.489100 + 0.859500 0.396900 0.176900 0.182400 + +! phi = -165 + 0.020100 -0.203800 -0.269700 0.014200 0.620800 + 1.392400 2.046200 2.188200 1.683900 0.688500 + -0.373700 -0.703500 0.837800 3.704000 -0.730100 + 0.594100 1.713100 2.205800 2.026400 1.529800 + 1.027400 0.623800 0.348400 0.182800 + +! phi = -150 + -0.533600 -0.807400 -0.804600 -0.379800 0.365300 + 1.168000 1.641000 1.618100 1.302200 0.615100 + 0.065700 0.738500 2.959500 -2.036600 -0.934600 + 0.407900 1.517000 1.984800 1.833100 1.435200 + 0.995600 0.562200 0.150600 -0.209000 + +! phi = -135 + -1.208500 -1.429400 -1.319200 -0.817500 -0.112400 + 0.454400 0.737600 0.879300 0.850100 0.670300 + 0.943500 -2.651200 -2.829400 -2.199100 -1.065700 + 0.279600 1.322000 1.668300 1.521300 1.193900 + 0.765300 0.246000 -0.315500 -0.823200 + +! phi = -120 + -1.789100 -1.965500 -1.860700 -1.447900 -0.896500 + -0.401000 -0.015100 0.321300 0.634600 0.976300 + -1.977500 -2.883200 -2.848500 -2.137900 -0.960300 + 0.308700 1.098100 1.245300 1.133600 0.881800 + 0.448200 -0.153900 -0.823700 -1.404300 + +! phi = -105 + -2.246700 -2.487000 -2.473700 -2.135600 -1.577700 + -0.980600 -0.429100 0.144700 0.734000 -0.918300 + -2.299200 -2.882200 -2.668600 -1.847100 -0.719800 + 0.107000 0.496000 0.553500 0.584300 0.494000 + 0.098300 -0.529800 -1.237900 -1.840100 + +! phi = -90 + -2.851100 -3.181100 -3.199500 -2.785300 -2.054300 + -1.242900 -0.476500 0.288100 -0.045300 -1.470600 + -2.558800 -2.869400 -2.450300 -1.582200 -0.930800 + -0.426400 -0.022700 0.000000 -0.097400 -0.136100 + -0.439600 -1.038600 -1.741000 -2.373200 + +! phi = -75 + -3.961800 -4.268200 -4.109000 -3.364700 -2.252200 + -1.140400 -0.209800 0.487300 -0.746200 -2.127700 + -2.932100 -2.898500 -2.247900 -1.730400 -1.177200 + -0.448200 0.034900 -0.073300 -0.531600 -0.933300 + -1.360700 -2.009200 -2.745700 -3.424900 + +! phi = -60 + -5.408000 -5.355100 -4.640100 -3.283200 -1.710200 + -0.423800 0.354400 -0.103700 -1.577700 -2.828300 + -3.151200 -2.649200 -2.183000 -1.761200 -0.981700 + -0.174700 0.262600 0.039200 -0.663000 -1.530700 + -2.478200 -3.465600 -4.334200 -5.011200 + +! phi = -45 + -6.093200 -5.298400 -3.816620 -1.922530 -0.196160 + 0.768200 0.568500 -0.831300 -2.343900 -3.037100 + -2.663700 -2.191100 -2.022900 -1.438500 -0.649000 + 0.077000 0.441500 0.257500 -0.491100 -1.820600 + -3.473100 -4.895200 -5.790700 -6.205900 + +! phi = -30 + -5.258225 -3.675795 -1.631110 0.430085 1.496470 + 0.318200 -0.555100 -1.695500 -2.434200 -2.192600 + -1.691300 -1.890000 -1.708500 -1.206300 -0.567400 + 0.054300 0.497200 0.599600 -0.171000 -2.137600 + -4.237000 -5.584100 -6.135100 -6.067000 + +! phi = -15 + -3.161820 -0.902080 1.432450 -1.452885 -1.560780 + -1.665600 -1.783100 -1.755100 -1.329300 -0.731100 + -1.317000 -1.662800 -1.601200 -1.294900 -0.817300 + -0.197100 0.549500 0.850400 -0.689700 -2.819900 + -4.393000 -5.111500 -5.205690 -4.654785 + +! phi = 0 + 0.034035 -2.349860 -3.412065 -3.620070 -3.450950 + -2.875650 -1.787800 -0.541250 0.410450 -0.372500 + -1.126850 -1.498450 -1.608700 -1.498450 -1.126850 + -0.372500 0.410450 -0.541250 -1.787800 -2.875650 + -3.450950 -3.620070 -3.412065 -2.349860 + +! phi = 15 + -3.162345 -4.654785 -5.205690 -5.111500 -4.393000 + -2.819900 -0.689700 0.850400 0.549500 -0.197100 + -0.817300 -1.294900 -1.601200 -1.662800 -1.317000 + -0.731100 -1.329300 -1.755100 -1.783100 -1.665600 + -1.560780 -1.452885 1.432450 -0.902080 + +! phi = 30 + -5.258220 -6.067000 -6.135100 -5.584100 -4.237000 + -2.137600 -0.171000 0.599600 0.497200 0.054300 + -0.567400 -1.206300 -1.708500 -1.890000 -1.691300 + -2.192600 -2.434200 -1.695500 -0.555100 0.318200 + 1.496470 0.430085 -1.631110 -3.675795 + +! phi = 45 + -6.093300 -6.205900 -5.790700 -4.895200 -3.473100 + -1.820600 -0.491100 0.257500 0.441500 0.077000 + -0.649000 -1.438500 -2.022900 -2.191100 -2.663700 + -3.037100 -2.343900 -0.831300 0.568500 0.768200 + -0.196160 -1.922530 -3.816620 -5.298400 + +! phi = 60 + -5.407500 -5.011200 -4.334200 -3.465600 -2.478200 + -1.530700 -0.663000 0.039200 0.262600 -0.174700 + -0.981700 -1.761200 -2.183000 -2.649200 -3.151200 + -2.828300 -1.577700 -0.103700 0.354400 -0.423800 + -1.710200 -3.283200 -4.640100 -5.355100 + +! phi = 75 + -3.961900 -3.424900 -2.745700 -2.009200 -1.360700 + -0.933300 -0.531600 -0.073300 0.034900 -0.448200 + -1.177200 -1.730400 -2.247900 -2.898500 -2.932100 + -2.127700 -0.746200 0.487300 -0.209800 -1.140400 + -2.252200 -3.364700 -4.109000 -4.268200 + +! phi = 90 + -2.854500 -2.373200 -1.741000 -1.038600 -0.439600 + -0.136100 -0.097400 0.000000 -0.022700 -0.426400 + -0.930800 -1.582200 -2.450300 -2.869400 -2.558800 + -1.470600 -0.045300 0.288100 -0.476500 -1.242900 + -2.054300 -2.785300 -3.199500 -3.181100 + +! phi = 105 + -2.246400 -1.840100 -1.237900 -0.529800 0.098300 + 0.494000 0.584300 0.553500 0.496000 0.107000 + -0.719800 -1.847100 -2.668600 -2.882200 -2.299200 + -0.918300 0.734000 0.144700 -0.429100 -0.980600 + -1.577700 -2.135600 -2.473700 -2.487000 + +! phi = 120 + -1.788800 -1.404300 -0.823700 -0.153900 0.448200 + 0.881800 1.133600 1.245300 1.098100 0.308700 + -0.960300 -2.137900 -2.848500 -2.883200 -1.977500 + 0.976300 0.634600 0.321300 -0.015100 -0.401000 + -0.896500 -1.447900 -1.860700 -1.965500 + +! phi = 135 + -1.208900 -0.823200 -0.315500 0.246000 0.765300 + 1.193900 1.521300 1.668300 1.322000 0.279600 + -1.065700 -2.199100 -2.829400 -2.651200 0.943500 + 0.670300 0.850100 0.879300 0.737600 0.454400 + -0.112400 -0.817500 -1.319200 -1.429400 + +! phi = 150 + -0.533400 -0.209000 0.150600 0.562200 0.995600 + 1.435200 1.833100 1.984800 1.517000 0.407900 + -0.934600 -2.036600 2.959500 0.738500 0.065700 + 0.615100 1.302200 1.618100 1.641000 1.168000 + 0.365300 -0.379800 -0.804600 -0.807400 + +! phi = 165 + 0.019900 0.182800 0.348400 0.623800 1.027400 + 1.529800 2.026400 2.205800 1.713100 0.594100 + -0.730100 3.704000 0.837800 -0.703500 -0.373700 + 0.688500 1.683900 2.188200 2.046200 1.392400 + 0.620800 0.014200 -0.269700 -0.203800 + +! glycine before proline map: use glycine map +! mp2/aug-cc-pVDZ//RIMP2/VTZ/VQZ CBS map +C NH1 CT2 C NH1 CT2 C N 24 + +! phi = -180 + 0.235350 0.182300 0.177200 0.396800 0.859400 + 1.489700 2.092500 2.297700 1.808600 0.696200 + -0.563300 -1.432700 -1.015100 1.426300 -0.564300 + 0.696200 1.808200 2.301700 2.092600 1.489100 + 0.859500 0.396900 0.176900 0.182400 + +! phi = -165 + 0.020100 -0.203800 -0.269700 0.014200 0.620800 + 1.392400 2.046200 2.188200 1.683900 0.688500 + -0.373700 -0.703500 0.837800 3.704000 -0.730100 + 0.594100 1.713100 2.205800 2.026400 1.529800 + 1.027400 0.623800 0.348400 0.182800 + +! phi = -150 + -0.533600 -0.807400 -0.804600 -0.379800 0.365300 + 1.168000 1.641000 1.618100 1.302200 0.615100 + 0.065700 0.738500 2.959500 -2.036600 -0.934600 + 0.407900 1.517000 1.984800 1.833100 1.435200 + 0.995600 0.562200 0.150600 -0.209000 + +! phi = -135 + -1.208500 -1.429400 -1.319200 -0.817500 -0.112400 + 0.454400 0.737600 0.879300 0.850100 0.670300 + 0.943500 -2.651200 -2.829400 -2.199100 -1.065700 + 0.279600 1.322000 1.668300 1.521300 1.193900 + 0.765300 0.246000 -0.315500 -0.823200 + +! phi = -120 + -1.789100 -1.965500 -1.860700 -1.447900 -0.896500 + -0.401000 -0.015100 0.321300 0.634600 0.976300 + -1.977500 -2.883200 -2.848500 -2.137900 -0.960300 + 0.308700 1.098100 1.245300 1.133600 0.881800 + 0.448200 -0.153900 -0.823700 -1.404300 + +! phi = -105 + -2.246700 -2.487000 -2.473700 -2.135600 -1.577700 + -0.980600 -0.429100 0.144700 0.734000 -0.918300 + -2.299200 -2.882200 -2.668600 -1.847100 -0.719800 + 0.107000 0.496000 0.553500 0.584300 0.494000 + 0.098300 -0.529800 -1.237900 -1.840100 + +! phi = -90 + -2.851100 -3.181100 -3.199500 -2.785300 -2.054300 + -1.242900 -0.476500 0.288100 -0.045300 -1.470600 + -2.558800 -2.869400 -2.450300 -1.582200 -0.930800 + -0.426400 -0.022700 0.000000 -0.097400 -0.136100 + -0.439600 -1.038600 -1.741000 -2.373200 + +! phi = -75 + -3.961800 -4.268200 -4.109000 -3.364700 -2.252200 + -1.140400 -0.209800 0.487300 -0.746200 -2.127700 + -2.932100 -2.898500 -2.247900 -1.730400 -1.177200 + -0.448200 0.034900 -0.073300 -0.531600 -0.933300 + -1.360700 -2.009200 -2.745700 -3.424900 + +! phi = -60 + -5.408000 -5.355100 -4.640100 -3.283200 -1.710200 + -0.423800 0.354400 -0.103700 -1.577700 -2.828300 + -3.151200 -2.649200 -2.183000 -1.761200 -0.981700 + -0.174700 0.262600 0.039200 -0.663000 -1.530700 + -2.478200 -3.465600 -4.334200 -5.011200 + +! phi = -45 + -6.093200 -5.298400 -3.816620 -1.922530 -0.196160 + 0.768200 0.568500 -0.831300 -2.343900 -3.037100 + -2.663700 -2.191100 -2.022900 -1.438500 -0.649000 + 0.077000 0.441500 0.257500 -0.491100 -1.820600 + -3.473100 -4.895200 -5.790700 -6.205900 + +! phi = -30 + -5.258225 -3.675795 -1.631110 0.430085 1.496470 + 0.318200 -0.555100 -1.695500 -2.434200 -2.192600 + -1.691300 -1.890000 -1.708500 -1.206300 -0.567400 + 0.054300 0.497200 0.599600 -0.171000 -2.137600 + -4.237000 -5.584100 -6.135100 -6.067000 + +! phi = -15 + -3.161820 -0.902080 1.432450 -1.452885 -1.560780 + -1.665600 -1.783100 -1.755100 -1.329300 -0.731100 + -1.317000 -1.662800 -1.601200 -1.294900 -0.817300 + -0.197100 0.549500 0.850400 -0.689700 -2.819900 + -4.393000 -5.111500 -5.205690 -4.654785 + +! phi = 0 + 0.034035 -2.349860 -3.412065 -3.620070 -3.450950 + -2.875650 -1.787800 -0.541250 0.410450 -0.372500 + -1.126850 -1.498450 -1.608700 -1.498450 -1.126850 + -0.372500 0.410450 -0.541250 -1.787800 -2.875650 + -3.450950 -3.620070 -3.412065 -2.349860 + +! phi = 15 + -3.162345 -4.654785 -5.205690 -5.111500 -4.393000 + -2.819900 -0.689700 0.850400 0.549500 -0.197100 + -0.817300 -1.294900 -1.601200 -1.662800 -1.317000 + -0.731100 -1.329300 -1.755100 -1.783100 -1.665600 + -1.560780 -1.452885 1.432450 -0.902080 + +! phi = 30 + -5.258220 -6.067000 -6.135100 -5.584100 -4.237000 + -2.137600 -0.171000 0.599600 0.497200 0.054300 + -0.567400 -1.206300 -1.708500 -1.890000 -1.691300 + -2.192600 -2.434200 -1.695500 -0.555100 0.318200 + 1.496470 0.430085 -1.631110 -3.675795 + +! phi = 45 + -6.093300 -6.205900 -5.790700 -4.895200 -3.473100 + -1.820600 -0.491100 0.257500 0.441500 0.077000 + -0.649000 -1.438500 -2.022900 -2.191100 -2.663700 + -3.037100 -2.343900 -0.831300 0.568500 0.768200 + -0.196160 -1.922530 -3.816620 -5.298400 + +! phi = 60 + -5.407500 -5.011200 -4.334200 -3.465600 -2.478200 + -1.530700 -0.663000 0.039200 0.262600 -0.174700 + -0.981700 -1.761200 -2.183000 -2.649200 -3.151200 + -2.828300 -1.577700 -0.103700 0.354400 -0.423800 + -1.710200 -3.283200 -4.640100 -5.355100 + +! phi = 75 + -3.961900 -3.424900 -2.745700 -2.009200 -1.360700 + -0.933300 -0.531600 -0.073300 0.034900 -0.448200 + -1.177200 -1.730400 -2.247900 -2.898500 -2.932100 + -2.127700 -0.746200 0.487300 -0.209800 -1.140400 + -2.252200 -3.364700 -4.109000 -4.268200 + +! phi = 90 + -2.854500 -2.373200 -1.741000 -1.038600 -0.439600 + -0.136100 -0.097400 0.000000 -0.022700 -0.426400 + -0.930800 -1.582200 -2.450300 -2.869400 -2.558800 + -1.470600 -0.045300 0.288100 -0.476500 -1.242900 + -2.054300 -2.785300 -3.199500 -3.181100 + +! phi = 105 + -2.246400 -1.840100 -1.237900 -0.529800 0.098300 + 0.494000 0.584300 0.553500 0.496000 0.107000 + -0.719800 -1.847100 -2.668600 -2.882200 -2.299200 + -0.918300 0.734000 0.144700 -0.429100 -0.980600 + -1.577700 -2.135600 -2.473700 -2.487000 + +! phi = 120 + -1.788800 -1.404300 -0.823700 -0.153900 0.448200 + 0.881800 1.133600 1.245300 1.098100 0.308700 + -0.960300 -2.137900 -2.848500 -2.883200 -1.977500 + 0.976300 0.634600 0.321300 -0.015100 -0.401000 + -0.896500 -1.447900 -1.860700 -1.965500 + +! phi = 135 + -1.208900 -0.823200 -0.315500 0.246000 0.765300 + 1.193900 1.521300 1.668300 1.322000 0.279600 + -1.065700 -2.199100 -2.829400 -2.651200 0.943500 + 0.670300 0.850100 0.879300 0.737600 0.454400 + -0.112400 -0.817500 -1.319200 -1.429400 + +! phi = 150 + -0.533400 -0.209000 0.150600 0.562200 0.995600 + 1.435200 1.833100 1.984800 1.517000 0.407900 + -0.934600 -2.036600 2.959500 0.738500 0.065700 + 0.615100 1.302200 1.618100 1.641000 1.168000 + 0.365300 -0.379800 -0.804600 -0.807400 + +! phi = 165 + 0.019900 0.182800 0.348400 0.623800 1.027400 + 1.529800 2.026400 2.205800 1.713100 0.594100 + -0.730100 3.704000 0.837800 -0.703500 -0.373700 + 0.688500 1.683900 2.188200 2.046200 1.392400 + 0.620800 0.014200 -0.269700 -0.203800 + +NONBONDED nbxmod 5 atom cdiel fshift vatom vdistance vfswitch - +cutnb 14.0 ctofnb 12.0 ctonnb 10.0 eps 1.0 e14fac 1.0 wmin 1.5 + !adm jr., 2013 correction +! +!V(Lennard-Jones) = Eps,i,j[(Rmin,i,j/ri,j)**12 - 2(Rmin,i,j/ri,j)**6] +! +!epsilon: kcal/mole, Eps,i,j = sqrt(eps,i * eps,j) +!Rmin/2: A, Rmin,i,j = Rmin/2,i + Rmin/2,j +! +!atom ignored epsilon Rmin/2 ignored eps,1-4 Rmin/2,1-4 +! +!carbons +C 0.000000 -0.110000 2.000000 ! ALLOW PEP POL ARO + ! NMA pure solvent, adm jr., 3/3/93 +CA 0.000000 -0.070000 1.992400 ! ALLOW ARO + ! benzene (JES) +CC 0.000000 -0.070000 2.000000 ! ALLOW PEP POL ARO + ! adm jr. 3/3/92, acetic acid heat of solvation +CD 0.000000 -0.070000 2.000000 ! ALLOW POL + ! adm jr. 3/19/92, acetate a.i. and dH of solvation +CE1 0.000000 -0.068000 2.090000 ! + ! for propene, yin/adm jr., 12/95 +CE2 0.000000 -0.064000 2.080000 ! + ! for ethene, yin/adm jr., 12/95 +CP1 0.000000 -0.020000 2.275000 0.000000 -0.010000 1.900000 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CP2 0.000000 -0.055000 2.175000 0.000000 -0.010000 1.900000 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CP3 0.000000 -0.055000 2.175000 0.000000 -0.010000 1.900000 ! ALLOW ALI + ! alkane update, adm jr., 3/2/92 +CPH1 0.000000 -0.050000 1.800000 ! ALLOW ARO + ! adm jr., 10/23/91, imidazole solvation and sublimation +CPH2 0.000000 -0.050000 1.800000 ! ALLOW ARO + ! adm jr., 10/23/91, imidazole solvation and sublimation +CS 0.000000 -0.110000 2.200000 ! ALLOW SUL + ! methylthiolate to water and F.E. of solvation, adm jr. 6/1/92 +CPT 0.000000 -0.099000 1.860000 ! atm, indole vaporization 5/05 +CY 0.000000 -0.073000 1.990000 ! atm, indole vaporization 5/05 +CAI 0.000000 -0.073000 1.990000 ! atm, indole vaporization 5/05 + ! TRP, JWK 08/29/89 +!new alkanes atoms types for conversion to new LJ parameters for c27 +CT 0.0 -0.0200 2.275 0.0 -0.01 1.9 ! +CT1 0.0 -0.0320 2.000 0.0 -0.01 1.9 ! alkane, 4/07, viv and adm jr. +CT2 0.0 -0.0560 2.010 0.0 -0.01 1.9 ! alkane, 4/98, yin, adm jr. +CT2A 0.0 -0.0560 2.010 0.0 -0.01 1.9 ! from CT2 (GLU, HSP), 05282010, zhu +CT3 0.0 -0.0780 2.040 0.0 -0.01 1.9 ! alkane, 4/98, yin, adm jr. +! hydrogens +H 0.000000 -0.046000 0.224500 ! ALLOW PEP POL SUL ARO ALC + ! same as TIP3P hydrogen, adm jr., 7/20/89 +HA 0.000000 -0.022000 1.320000 ! ALLOW PEP ALI POL SUL ARO PRO ALC + ! methane/ethane a.i. and ethane pure solvent, adm jr, 2/3/92 +HB1 0.000000 -0.022000 1.320000 ! + ! methane/ethane a.i. and ethane pure solvent, adm jr, 2/3/92 +HB2 0.000000 -0.028000 1.340000 ! + ! Yin and MacKerell, adm jr., 5/30/02 +HE1 0.000000 -0.031000 1.250000 ! + ! for propene, yin/adm jr., 12/95 +HE2 0.000000 -0.026000 1.260000 ! + ! for ethene, yin/adm jr., 12/95 +!HB 0.000000 -0.022000 1.320000 ! ALLOW PEP ALI POL SUL ARO PRO ALC + ! methane/ethane a.i. and ethane pure solvent, adm jr, 2/3/92 +HC 0.000000 -0.046000 0.224500 ! ALLOW POL + ! new, small polar Hydrogen, see also adm jr. JG 8/27/89 +HP 0.000000 -0.030000 1.358200 0.000000 -0.030000 1.358200 ! ALLOW ARO + ! JES 8/25/89 values from Jorgensen fit to hydration energy +HR1 0.000000 -0.046000 0.900000 ! ALLOW ARO + ! adm jr., 6/27/90, his +HR2 0.000000 -0.046000 0.700000 ! ALLOW ARO + ! adm jr., 6/27/90, his +HR3 0.000000 -0.007800 1.468000 ! ALLOW ARO + ! adm jr., 3/24/92, maintain old aliphatic H VDW params +HS 0.000000 -0.100000 0.450000 ! ALLOW SUL + ! methanethiol pure solvent, adm jr., 6/22/92 +!new alkanes atoms types for conversion to new LJ parameters for c27 (see toppar_all22_prot_aliphatic_c27.str) +HA1 0.0 -0.045 1.3400 ! alkane, viv and adm jr., 4/07 +HA2 0.0 -0.034 1.3400 ! alkane, viv and adm jr., 4/07 +HA3 0.0 -0.024 1.3400 ! alkane, yin and mackerell, 4/98 +!nitrogens +N 0.000000 -0.200000 1.850000 0.000000 -0.000100 1.850000 ! ALLOW PRO + ! 6-31g* AcProNH2, ProNH2, 6-31g*//3-21g AcProNHCH3 RLD 4/23/93 +NC2 0.000000 -0.200000 1.850000 ! ALLOW POL + ! JG 8/27/89; note: NH1 in ARG was changed to NC2. +NH1 0.000000 -0.200000 1.850000 0.000000 -0.200000 1.550000 ! ALLOW PEP POL ARO + ! This 1,4 vdW allows the C5 dipeptide minimum to exist.(LK) +NH2 0.000000 -0.200000 1.850000 ! ALLOW POL + ! adm jr. +NH3 0.000000 -0.200000 1.850000 ! ALLOW POL + ! adm jr. +NP 0.000000 -0.200000 1.850000 ! ALLOW PRO + ! N-terminal proline; from 6-31g* +ProNH2 RLD 9/28/90 +NR1 0.000000 -0.200000 1.850000 ! ALLOW ARO + ! His, adm jr., 9/4/89 +NR2 0.000000 -0.200000 1.850000 ! ALLOW ARO + ! His, adm jr., 9/4/89 +NR3 0.000000 -0.200000 1.850000 ! ALLOW ARO + ! His, adm jr., 9/4/89 +NY 0.000000 -0.200000 1.850000 ! atm, indole vaporization 5/05 +! oxygens +O 0.000000 -0.120000 1.700000 0.000000 -0.120000 1.400000 ! ALLOW PEP POL + ! This 1,4 vdW allows the C5 dipeptide minimum to exist.(LK) +OB 0.000000 -0.120000 1.700000 0.000000 -0.120000 1.400000 ! ALLOW PEP POL ARO + ! adm jr., 10/17/90, acetic acid carbonyl O +OC 0.000000 -0.120000 1.700000 ! ALLOW POL ION + ! JG 8/27/89 +OH1 0.000000 -0.152100 1.770000 ! ALLOW ALC ARO + ! adm jr. 8/14/90, MeOH nonbond and solvent (same as TIP3P) +OS 0.000000 -0.152100 1.770000 ! ALLOW ALC ARO + ! adm jr. 9/17/90, avoid O* wildcard +! sulfurs +S 0.000000 -0.450000 2.000000 ! ALLOW SUL ION + ! adm jr., 3/3/92, methanethiol/ethylmethylsulfide pure solvent +SM 0.000000 -0.380000 1.975000 ! ALLOW SUL ION + ! adm jr., 3/3/92, dimethyldisulphide pure solvent +SS 0.000000 -0.470000 2.200000 ! ALLOW SUL + ! methylthiolate to water and F.E. of solvation, adm jr. 6/1/92 + + +HBOND CUTHB 0.5 ! If you want to do hbond analysis (only), then use + ! READ PARAM APPEND CARD + ! to append hbond parameters from the file: par_hbond.inp + + +ATOMS +MASS -1 HN1 1.00800 ! Nucleic acid amine proton +MASS -1 HN2 1.00800 ! Nucleic acid ring nitrogen proton +MASS -1 HN3 1.00800 ! Nucleic acid aromatic carbon proton +MASS -1 HN4 1.00800 ! Nucleic acid phosphate hydroxyl proton +MASS -1 HN5 1.00800 ! Nucleic acid ribose hydroxyl proton +MASS -1 HN6 1.00800 ! Nucleic acid ribose aliphatic proton +MASS -1 HN7 1.00800 ! Nucleic acid proton (equivalent to protein HA) +MASS -1 HN8 1.00800 ! Bound to CN8 in nucleic acids/model compounds +MASS -1 HN9 1.00800 ! Bound to CN9 in nucleic acids/model compounds +MASS -1 CN1 12.01100 ! Nucleic acid carbonyl carbon +MASS -1 CN1T 12.01100 ! Nucleic acid carbonyl carbon (T/U C2) +MASS -1 CN2 12.01100 ! Nucleic acid aromatic carbon to amide +MASS -1 CN3 12.01100 ! Nucleic acid aromatic carbon +MASS -1 CN3T 12.01100 ! Nucleic acid aromatic carbon, Thy C5 +MASS -1 CN4 12.01100 ! Nucleic acid purine C8 and ADE C2 +MASS -1 CN5 12.01100 ! Nucleic acid purine C4 and C5 +MASS -1 CN5G 12.01100 ! Nucleic acid guanine C5 +MASS -1 CN7 12.01100 ! Nucleic acid carbon (equivalent to protein CT1) +MASS -1 CN7B 12.01100 ! Nucleic acid aliphatic carbon for C1' +MASS -1 CN8 12.01100 ! Nucleic acid carbon (equivalent to protein CT2) +MASS -1 CN8B 12.01100 ! Nucleic acid carbon (equivalent to protein CT2) +MASS -1 CN9 12.01100 ! Nucleic acid carbon (equivalent to protein CT3) +MASS -1 NN1 14.00700 ! Nucleic acid amide nitrogen +MASS -1 NN2 14.00700 ! Nucleic acid protonated ring nitrogen +MASS -1 NN2B 14.00700 ! From NN2, for N9 in GUA different from ADE +MASS -1 NN2U 14.00700 ! Nucleic acid protonated ring nitrogen, ura N3 +MASS -1 NN2G 14.00700 ! Nucleic acid protonated ring nitrogen, gua N1 +MASS -1 NN3 14.00700 ! Nucleic acid unprotonated ring nitrogen +MASS -1 NN3A 14.00700 ! Nucleic acid unprotonated ring nitrogen, ade N1 and N3 +MASS -1 NN3G 14.00700 ! Nucleic acid unprotonated ring nitrogen, gua N3 +MASS -1 NN4 14.00700 ! Nucleic acid purine N7 +MASS -1 NN6 14.00700 ! Nucleic acid sp3 amine nitrogen (equiv to protein nh3) +MASS -1 ON1 15.99940 ! Nucleic acid carbonyl oxygen +MASS -1 ON1C 15.99940 ! Nucleic acid carbonyl oxygen, cyt O2 +MASS -1 ON2 15.99940 ! Nucleic acid phosphate ester oxygen +MASS -1 ON3 15.99940 ! Nucleic acid =O in phosphate +MASS -1 ON4 15.99940 ! Nucleic acid phosphate hydroxyl oxygen +MASS -1 ON5 15.99940 ! Nucleic acid ribose hydroxyl oxygen +MASS -1 ON6 15.99940 ! Nucleic acid deoxyribose ring oxygen +MASS -1 ON6B 15.99940 ! Nucleic acid ribose ring oxygen +MASS -1 P 30.97400 ! phosphorus +MASS -1 P2 30.97400 ! phosphorus, adm, 2011 DNA update + +BONDS +! +!V(bond) = Kb(b - b0)**2 +! +!Kb: kcal/mole/A**2 +!b0: A +! +!atom type Kb b0 +! +!2-(aminobutyl)-1,3-propandiol terms +CN8 NN6 200.000 1.480 ! methylammonium +NN6 HN1 403.000 1.040 ! methylammonium +!abasic deoxynucleoside +ON6 CN8B 260.0 1.420 ! susil +CN8 CN8B 222.50 1.528 ! Alkanes, sacred +! +CN1 CN3 302.0 1.409 !U, adm jr. 11/97 +CN1 CN3T 302.0 1.403 !T, adm jr. 11/97 +CN1 CN5G 302.0 1.360 !G, adm jr. 11/97 +CN1 NN2 380.0 1.367 !C, adm jr. 11/97 +CN1T NN2B 302.0 1.348 !U,T adm jr. 11/97 +CN1 NN2G 340.0 1.396 !G, adm jr. 11/97 +CN1 NN2U 340.0 1.389 !U,T adm jr. 11/97 +CN1T NN2U 340.0 1.383 !U,T adm jr. 11/97 +CN1 NN3 350.0 1.335 !C, adm jr. 11/97 +CN1T ON1 860.0 1.230 !nad/ppi, jjp1/adm jr. 7/95 +CN1 ON1 660.0 1.234 !U,A,G par_a4 adm jr. 10/2/91 +CN1 ON1C 620.0 1.245 !C, adm jr. 10/2/91 +CN2 CN3 320.0 1.406 !C, adm jr. 11/97 +CN2 CN5 360.0 1.358 !A, adm jr. 11/97 +CN2 NN1 360.0 1.366 !C,A,G JWK, adm jr. 10/2/91 +CN2 NN2G 400.0 1.392 !G +CN2 NN3 450.0 1.343 !C +CN2 NN3A 400.0 1.342 !A, adm jr. 11/97 +CN2 NN3G 320.0 1.326 !G, adm jr. 11/97 +CN3 CN3 500.0 1.326 !C,U adm jr. 11/97 +CN3 CN3T 560.0 1.320 !T, adm jr. 11/97 +CN3T CN9 230.0 1.478 !T, adm jr. 11/97 +CN3 HN3 350.0 1.09 !C,U, JWK +CN3T HN3 350.0 1.09 !T, JWK +CN3 NN2 302.0 1.343 !C, adm jr. 11/97 +CN3 NN2B 320.0 1.343 !U,T adm jr. 11/97 +CN4 HN3 380.0 1.09 !G,A, JWK par_a7 9/30/91 +CN4 NN2 320.0 1.374 !A, adm jr. 11/97 +CN4 NN2B 300.0 1.378 !G, adm jr. 11/97 +CN4 NN3A 420.0 1.322 !A, adm jr. 11/97 +CN4 NN4 400.0 1.305 !G,A, adm jr. 11/97 +CN5 CN5 310.0 1.361 !A, adm jr. 11/97 +CN5 CN5G 320.0 1.350 !G, adm jr. 11/97 +CN5 NN2 300.0 1.375 !A, adm jr. 11/97 +CN5 NN2B 302.0 1.375 !G, adm jr. 11/97 +CN5 NN3A 350.0 1.312 !A, JWK par_a8 9/30/91 +CN5 NN3G 350.0 1.315 !G, adm jr. 11/97 +CN5 NN4 310.0 1.355 !A, adm jr. 11/97 +CN5G NN4 310.0 1.365 !G, adm jr. 11/97 +CN8 CN8 222.50 1.528 !Alkanes, sacred +CN8 CN9 222.50 1.528 !Alkanes, sacred +CN8 NN2 400.0 1.460 !9-E-GUA, ADM JR. +CN8 ON5 428.0 1.42 !RIBOSE, MeOH +CN9 HN9 322.0 1.111 !alkanes +CN9 ON2 340.0 1.43 !DMP, ADM Jr. +HN1 NN1 488.0 1.00 !A,C,G, JWK, adm jr. 7/24/91 +HN2 NN2 474.0 1.01 !C,U, JWK +HN2 NN2B 474.0 1.01 !G, adm jr. 11/97 +HN2 NN2G 471.0 1.01 !G, JWK, par_a12 9/30/91 +HN2 NN2U 474.0 1.01 !U, JWK, adm jr. 7/24/91 +HN4 ON4 545.0 0.960 !MP_1, ADM Jr. +ON2 P 270.0 1.60 !DMP, ADM Jr. +ON2 P2 270.0 1.60 !DMP, ADM Jr., adm, 2011 DNA update +ON3 P 580.0 1.48 !DMP, ADM Jr. +ON3 P2 580.0 1.48 !DMP, ADM Jr., adm, 2011 DNA update +ON4 P 237.0 1.58 !MP_1, ADM Jr. +ON4 P2 237.0 1.58 !MP_1, ADM Jr., adm, 2011 DNA update +!NN5 HN1 460.0 1.01 !sugar model, adm jr. +!@@@@@@@@@ Begining of endocyclic bonds for deoxy-ribose @@@@@@@@@ +CN7B ON6 260.0 1.420 ! From exp +CN7B CN8 200.0 1.518 ! From exp +CN7 ON6 240.0 1.446 ! Fom exp. +CN7 CN7 222.5 1.529 ! From exp +CN7 CN8 222.5 1.516 ! From exp. +CN7 CN9 222.5 1.516 ! for 5MET, From alkanes +CN7 HN7 309.0 1.111 !Alkanes, sacred +CN8 HN8 309.0 1.111 !Alkanes, sacred +CN7B HN7 309.0 1.111 ! From CN8 HN7 (NF) +!@@@@@@@@@ End of endocyclic bonds for deoxy-ribose @@@@@@@@@ +!@@@@@@@@@ Begining of endocyclic bonds for ribose @@@@@@@@@ +CN7B ON6B 260.0 1.420 ! From CN7B ON6 +CN7 ON6B 240.0 1.480 ! From CN7 ON6 +CN7B CN7B 200.0 1.450 ! +CN7 CN7B 222.5 1.460 ! Specific to RNA +!@@@@@@@@@ End of endocyclic bonds for ribose @@@@@@@@@ + +!@@@@@@@@@ Begining of exocyclic bonds for deoxy-ribose @@@@@@@@@ +CN7 CN8B 222.5 1.512 ! From exp. +CN8B ON2 320.0 1.44 ! From exp +!CN8B ON5 250.0 1.44 ! From CN8B ON2 +CN8B ON5 428.0 1.42 !From CN8 ON2, adm jr., 8/30/98 +CN7 ON2 310.0 1.433 ! From exp +CN7B ON2 310.0 1.433 ! From exp, for NADPH and bkbmod +!CN7 ON5 250.0 1.420 ! ALLOW ALI ALC ARO +CN7 ON5 428.0 1.42 !From CN8 ON2, adm jr., 8/30/98 +! C1'-N9 (purines)/C1'-N1 (pyrimidines) +CN9 NN2 400.0 1.456 !9-M-A/C, adm jr. +CN8 NN2B 400.0 1.458 !9-M-G/T/U, adm jr. +CN9 NN2B 400.0 1.458 !9-M-G/T/U, adm jr. +CN7B NN2 220.0 1.456 !A/C +CN7B NN2B 220.0 1.458 !G/T/U +! C5'-H in model compounds and DNA +CN8B HN8 309.0 1.111 !Alkanes, sacred +ON5 HN5 545.0 0.960 !RIBOSE, MeOH +!@@@@@@@@@ End of exocyclic bonds for deoxy-ribose @@@@@@@@@ + +!@@@@@@@@@ Begining of exocyclic bonds for ribose @@@@@@@@@ +!CN7B ON5 250.0 1.400 ! From CN7 ON5 +CN7B ON5 428.0 1.400 ! check adm jr., +!FC should be 428.000 based on Meoh +!@@@@@@@@@ End of exocyclic bonds for ribose @@@@@@@@@ + +!@@@@@@@@@ Begining of bonds for nucleotide analogue @@@@@@@@@ +CN8 ON2 340.0 1.44 ! +!@@@@@@@@@ End of bonds for nucleotide analogue @@@@@@@@@ + +ANGLES +! +!V(angle) = Ktheta(Theta - Theta0)**2 +! +!V(Urey-Bradley) = Kub(S - S0)**2 +! +!Ktheta: kcal/mole/rad**2 +!Theta0: degrees +!Kub: kcal/mole/A**2 (Urey-Bradley) +!S0: A +! +!atom types Ktheta Theta0 Kub S0 +! +! angle parameters have been rearranged based on model +! compounds and functional groups. Additional angle +! parameters follow sorted based on the central atom +! +!2-(aminobutyl)-1,3-propandiol terms +CN7 CN8 CN8 58.35 113.60 11.16 2.561 !alkane +CN8 CN7 CN8 58.35 113.60 11.16 2.561 !alkane +CN8 CN8 CN8 58.35 113.60 11.16 2.561 !alkane +HN1 NN6 CN8 30.00 109.50 20.00 2.074 !methylammonium +NN6 CN8 HN8 45.00 107.50 35.00 2.101 !methylammonium +CN7 CN8 ON2 115.00 109.70 !DNA exocyclic angles +NN6 CN8 CN8 67.70 110.00 !methylammonium +HN1 NN6 HN1 44.00 109.50 !methylammonium +!abasic propyl linkage +ON2 CN8 CN8 115.0 109.7 !DNA exocyclic angles +!abasic deoxynucleoside +CN7 ON6 CN8B 110.0 109.0 +ON6 CN8B CN8 90.0 106.0 +CN8B CN8 CN7 80.0 106.0 +ON6 CN8B HN8 45.2 107.24 ! +HN8 CN8B CN8 34.53 110.10 22.53 2.179 ! alkane +HN8 CN8 CN8B 34.53 110.10 22.53 2.179 ! alkane + +! pyrmidines +!@@@@@@@@ Adenine +! ade 6-mem ring +CN2 NN3A CN4 90.0 117.8 !6R) adm jr. 11/97 +NN3A CN4 NN3A 60.0 133.0 !6R) +CN4 NN3A CN5 90.0 110.1 !6R) +CN5 CN5 NN3A 60.0 127.4 !6R) bridgeC4 +CN2 CN5 CN5 60.0 121.0 !6R) bridgeC5 +CN5 CN2 NN3A 60.0 110.7 !6R) +CN5 CN5 NN2 100.0 105.7 !5R) bridgeC4 +CN5 CN5 NN4 100.0 110.0 !5R) bridgeC5 +CN4 NN4 CN5 120.0 104.6 !5R) +NN2 CN4 NN4 100.0 113.4 !5R) +CN4 NN2 CN5 100.0 106.3 !5R) +NN2 CN5 NN3A 100.0 126.9 !bridgeC4 +CN2 CN5 NN4 100.0 129.0 !bridgeC5 +HN3 CN4 NN3A 38.0 113.5 !h2 +NN3A CN2 NN1 50.0 130.7 !n6 +CN5 CN2 NN1 50.0 118.6 ! +CN2 NN1 HN1 40.0 121.5 !h61,h62, C,A,G +HN1 NN1 HN1 31.0 117.0 !C,A,G +NN4 CN4 HN3 39.0 124.8 !h8, G,A +NN2 CN4 HN3 39.0 121.8 ! +CN5 NN2 HN2 30.0 129.4 !h9 +CN4 NN2 HN2 30.0 125.0 ! +!@@@@@@@@ Guanine +! gua 6-mem ring +CN1 NN2G CN2 70.0 131.1 !6R)G, adm jr. 11/97 +NN2G CN2 NN3G 70.0 122.2 !6R) +CN2 NN3G CN5 90.0 109.4 !6R) +CN5G CN5 NN3G 70.0 129.9 !6R) bridgeC4 +CN1 CN5G CN5 70.0 119.6 !6R) bridgeC5 +CN5G CN1 NN2G 70.0 107.8 !6R) +CN5G CN5 NN2B 100.0 104.6 !5R) bridgeC4 +CN5 CN5G NN4 100.0 111.4 !5R) bridgeC5 +CN4 NN4 CN5G 120.0 103.8 !5R) +NN2B CN4 NN4 100.0 113.0 !5R) +CN4 NN2B CN5 100.0 107.2 !5R) +NN2B CN5 NN3G 140.0 125.5 ! bridgeC4 +CN1 CN5G NN4 125.0 129.0 ! bridgeC5 +CN1 NN2G HN2 45.0 113.3 ! h1 +CN2 NN2G HN2 45.0 115.6 ! +NN1 CN2 NN2G 95.0 115.4 ! n2 +NN1 CN2 NN3G 95.0 122.4 ! +NN2G CN1 ON1 50.0 127.5 ! o6 +CN5G CN1 ON1 50.0 124.7 ! +HN3 CN4 NN2B 40.0 122.2 ! h8 (NN4 CN4 HN3 124.8) +CN4 NN2B HN2 30.0 124.6 ! h9 +CN5 NN2B HN2 30.0 129.3 ! +!@@@@@@@@ Cytosine +! cyt 6-mem ring +CN1 NN2 CN3 50.0 124.1 !C, adm jr. 11/97 +NN2 CN1 NN3 50.0 116.8 !C +CN1 NN3 CN2 85.0 119.1 !C +CN3 CN2 NN3 85.0 119.3 !C +CN2 CN3 CN3 85.0 117.8 !C +CN3 CN3 NN2 85.0 122.9 !C +CN1 NN2 HN2 37.0 121.2 !C, h1 +CN3 NN2 HN2 37.0 114.7 !C +NN2 CN1 ON1C 130.0 119.4 !C, o2 +NN3 CN1 ON1C 130.0 123.8 !C +NN3 CN2 NN1 81.0 122.3 !C, n4 +CN3 CN2 NN1 81.0 118.4 !C +CN2 CN3 HN3 38.0 120.1 !C h5 +CN3 CN3 HN3 38.0 122.1 !C,U +HN3 CN3 NN2 44.0 115.0 !C, h6 +!@@@@@@@@ Uracil +! ura 6-mem ring +CN1T NN2B CN3 70.0 122.0 !U, adm jr. 11/97 +NN2B CN1T NN2U 50.0 114.0 !U +CN1T NN2U CN1 50.0 130.2 !U +NN2U CN1 CN3 70.0 112.6 !U +CN1 CN3 CN3 100.0 117.6 !U +CN3 CN3 NN2B 100.0 123.6 !U +CN1T NN2B HN2 40.5 122.0 !U, h1 +CN3 NN2B HN2 32.0 116.0 !U +NN2B CN1T ON1 100.0 121.6 !U, o2 +NN2U CN1T ON1 100.0 124.4 !U +CN1T NN2U HN2 40.5 114.4 !U, h3 +CN1 NN2U HN2 40.5 115.4 !U +NN2U CN1 ON1 100.0 121.9 !U, o4 +CN3 CN1 ON1 100.0 125.5 !U, +CN1 CN3 HN3 30.0 120.3 !U, h5 +HN3 CN3 NN2B 30.0 114.3 !U, h6 +! thymine 6-mem ring (unique from ura) +CN3T CN1 NN2U 70.0 113.5 !T, adm jr. 11/97 +CN1 CN3T CN3 120.0 116.7 !T +CN3T CN3 NN2B 120.0 123.6 !125.3 !T +CN3T CN1 ON1 100.0 124.6 !T, o4 +CN1 CN3T CN9 38.0 118.7 !T, c5 methyl +CN3 CN3T CN9 38.0 124.6 !T +CN3T CN3 HN3 30.0 122.1 !T, h6 +! base to methyl connection +CN1T NN2B CN9 70.0 116.0 !1-M-T/U, adm jr. +CN3 NN2B CN9 70.0 122.0 !1-M-T/U, adm jr. 7/24/91 +CN1 NN2 CN9 70.0 115.4 !1-M-C, adm jr. +CN3 NN2 CN9 70.0 120.5 !1-M-C, adm jr. 7/24/91 +CN5 NN2 CN9 70.0 125.9 !9-M-A, adm jr. +CN4 NN2 CN9 70.0 127.8 !9-M-A, adm jr. +CN5 NN2B CN9 70.0 125.9 !9-M-G, adm jr. +CN4 NN2B CN9 70.0 126.9 !9-M-G, adm jr. +CN5 NN2B CN8 70.0 125.9 !9-E-G, adm jr. +CN4 NN2B CN8 70.0 126.9 !9-E-G, adm jr. +NN2B CN8 CN9 70.0 113.7 !9-E-G, adm jr. +!===== For glycosydic linkage, base to c1' +CN1T NN2B CN7B 45.0 118.4 !U/T, FC from A +CN3 NN2B CN7B 45.0 119.6 !U/T +CN1 NN2 CN7B 45.0 120.0 !C, FC from A +CN3 NN2 CN7B 45.0 115.9 !C +CN5 NN2 CN7B 45.0 126.1 !A +CN4 NN2 CN7B 45.0 127.6 !A +CN5 NN2B CN7B 45.0 126.5 !G +CN4 NN2B CN7B 45.0 126.3 !G +ON6 CN7B NN2 110.0 108.0 !C/A DNA +ON6B CN7B NN2 110.0 112.0 !C/A RNA +CN8 CN7B NN2 110.0 113.7 !C/A +CN7B CN7B NN2 110.0 111.0 !C/A, RNA +ON6 CN7B NN2B 110.0 108.0 !T/U/G (DNA) FC from A +ON6B CN7B NN2B 110.0 112.0 !T/U/G (RNA) FC from A +CN8 CN7B NN2B 110.0 113.7 !T/U/G +CN7B CN7B NN2B 110.0 111.0 !T/U/G, RNA +HN7 CN7B NN2 43.0 111.0 ! +HN7 CN7B NN2B 43.0 111.0 !From HN7 CN7B NN2 +!===== End of glycosydic linkage +! remaining terms ordered based on central atom +CN9 CN8 HN8 34.6 110.10 22.53 2.179 ! Alkanes, sacred +CN9 CN7 HN7 34.6 110.10 22.53 2.179 ! Alkanes, sacred +HN8 CN8 NN2 33.43 110.1 !FOR 9-M-ADE(THY), ADM +HN8 CN8 ON5 45.9 108.89 !RIBOSE, Adm Jr. MeOH +CN3 CN9 HN9 33.43 110.10 22.53 2.179 ! Alkanes, sacred +CN3T CN9 HN9 33.43 110.10 22.53 2.179 ! Alkanes, sacred +CN8 CN9 HN9 34.60 110.10 22.53 2.179 ! Alkanes, sacred +HN9 CN9 CN7 33.43 110.1 22.53 2.179 ! Alkanes, sacred +HN9 CN9 NN2 33.43 110.1 !FOR 9-M-A(T), adm jr. +HN9 CN9 NN2B 33.43 110.1 !FOR 9-M-G(C), adm jr. +HN8 CN8 NN2B 33.43 110.1 !FOR 9-E-G, adm jr. +HN9 CN9 ON2 60.0 109.5 !DMP, ADM Jr. +!HN1 NN5 HN1 39.0 106.0 ! sugar model, adm jr. +CN9 ON2 P 20.0 120.0 35. 2.33 !DMP, ADM Jr. +HN4 ON4 P 30.0 115.0 40.0 2.35 !MP_1, ADM Jr. +HN4 ON4 P2 30.0 115.0 40.0 2.35 !MP_1, ADM Jr. , adm, 2011 DNA update +HN5 ON5 CN8 57.5 106.0 !RIBOSE, Adm Jr. MeOH +HN5 ON5 CN9 57.5 106.0 !RIBOSE, Adm Jr. MeOH +ON2 P ON2 80.0 104.3 !DMP, ADM Jr. +ON2 P2 ON2 80.0 104.3 !DMP, ADM Jr., adm, 2011 DNA update +ON2 P ON4 48.1 108.0 !MP_1, ADM Jr. +ON2 P2 ON4 48.1 108.0 !MP_1, ADM Jr., adm, 2011 DNA update +ON3 P ON4 98.9 108.23 !MP_1, ADM Jr. +ON3 P2 ON4 98.9 108.23 !MP_1, ADM Jr., adm, 2011 DNA update +ON4 P ON4 98.9 104.0 !MP_0, ADM Jr. +ON4 P2 ON4 98.9 104.0 !MP_0, ADM Jr., adm, 2011 DNA update +CN7 CN8 ON5 75.7 110.10 !RIBOSE, adm jr. MeOH +HN9 CN9 HN9 35.500 108.40 5.40 1.802 !alkane update, adm jr. 3/2/92 +!@@@@@@@@@ Beginning of endocyclic valence angles for regular DNA @@@@@@@ +CN7 ON6 CN7B 110.0 108.0 ! NF, 11/97, C4'O4'C1' +ON6 CN7B CN8 90.0 102.0 ! NF, 11/97, C4'O4'C1' +CN7B CN8 CN7 80.00 100.0 ! NF, 11/97, C1'C2'C3' +CN8 CN7 CN7 60.00 102.0 8.0 2.561 !NF, 11/97, C2'C3'C4' +CN9 CN7 CN7 60.00 102.0 8.0 2.561 !for 5MET, adm jr. +CN7 CN7 ON6 100.0 104.0 ! NF, 11/97, C3'C4'O4' +HN7 CN7 ON6 45.2 107.24 ! +HN7 CN7B ON6 45.2 107.24 ! +HN7 CN7 CN7 40.0 108.00 ! +CN7B CN8 HN8 33.4 110.10 22.53 2.179 ! following terms directly +CN8 CN7B HN7 33.4 110.10 22.53 2.179 ! from alkanes +HN7 CN7 CN8 34.5 110.1 22.53 2.179 ! +HN8 CN8 CN7 34.53 110.10 22.53 2.179 ! +HN8 CN8 CN8 34.53 110.10 22.53 2.179 ! +HN8 CN8 HN8 35.5 109.00 5.40 1.802 ! +HN7 CN7 HN7 35.5 109.00 5.40 1.802 ! +!@@@@@@@@@ End of endocyclic valence angles for regular DNA @@@@@@@ + +!@@@@@@@@@ Beginning of endocyclic valence angles for regular RNA @@@@@@@ +CN7 ON6B CN7B 110.0 115.0 ! From CN7 ON6 CN7B +CN7 CN7 ON6B 100.0 110.0 ! From CN7 CN7 ON6 +ON6B CN7B CN7B 90.0 106.0 ! 030998 +CN7B CN7B CN7 110.0 96.0 ! +CN7B CN7 CN7 60.0 100.0 8.00 2.561 !NF, 11/97, C2'C3'C4' +HN7 CN7 ON6B 45.2 107.24 ! +HN7 CN7B ON6B 45.2 107.24 ! +CN7B CN7B HN7 33.4 110.10 22.53 2.179 ! following terms directly +HN7 CN7B HN7 35.5 109.00 5.40 1.802 ! +!@@@@@@@@@ End of endocyclic valence angles for regular RNA @@@@@@@ + +!@@@@@@@@@ Beginning of exocyclic valence angles for regular DNA @@@@@@@ +ON6 CN7 CN8B 90.0 108.2 !NF, 11/97, O4'C4'C5' +ON6 CN7 CN9 90.0 108.2 !for 5MET, adm jr. +CN7 CN7 CN8B 45.0 110.0 !NF, 11/97, C3'C4'C5' +CN8 CN7 CN8B 58.35 113.60 11.16 2.561 ! from alkane, 25P1 +CN7 CN8B ON2 70.0 108.4 !NF, 11/97, C4'C5'O5' +CN7 CN7 ON2 115.0 109.7 !NF, 11/97, C4'C3'O3' +CN7B CN7B ON2 115.0 109.7 !NF, 11/97, C4'C3'O3' for NADPH and bkbmod +CN8 CN7 ON2 115.0 109.7 !NF, 11/97, C2'C3'O3' +CN8B ON2 P 20.0 120.0 35.00 2.33 !NF, 11/97, C5'O5'P +CN8B ON2 P2 20.0 120.0 35.00 2.33 !NF, 11/97, C5'O5'P, adm, 2011 DNA update +CN7 ON2 P 20.0 120.0 35.00 2.33 !NF, 11/97, C3'O3'P +CN7 ON2 P2 20.0 120.0 35.00 2.33 !NF, 11/97, C3'O3'P, adm, 2011 DNA update +CN7B ON2 P 20.0 120.0 35.00 2.33 !NF, 11/97, C3'O3'P, for NADPH and bkbmod +CN7B ON2 P2 20.0 120.0 35.00 2.33 !NF, 11/97, C3'O3'P, for NADPH and bkbmod, adm, 2011 DNA update +! sugar +HN7 CN7 CN8B 34.5 110.1 22.53 2.179 ! From HN7 CN7 CN8 +HN8 CN8B ON2 60.0 109.5 ! From HN7 CN8 ON2 +HN5 ON5 CN8B 57.5 106.0 ! From HN5 ON5 CN8 +HN8 CN8B HN8 35.5 109.0 5.40 1.802 ! Alkanes, sacred +HN8 CN8B CN7 34.53 110.1 22.53 2.179 ! Alkanes, sacred +HN7 CN7 ON2 60.0 109.5 !DMP, adm jr. from HN7 CN8 ON2 +HN7 CN7B ON2 60.0 109.5 !DMP, adm jr. from HN7 CN8 ON2, for NADPH and bkbmod +!===== For 5ter patch: +CN7 CN8B ON5 75.7 110.10 ! From CN7 CN8B ON5 +CN8B CN7 ON5 90.0 108.2 ! phosphoramidate, carbocyclic +HN8 CN8B ON5 45.9 108.89 ! From HN7 CN8 ON5 +!===== For 3ter patch: +ON5 CN7 CN8 75.7 110.0 ! from CHARMM22 +ON5 CN7 CN7 75.7 110.1 ! +HN7 CN7 ON5 60.0 109.5 ! +HN5 ON5 CN7 57.5 109.0 ! +!@@@@@@@@@ End of exocyclic valence angles for regular DNA @@@@@@@ + +!@@@@@@@@@ Beginning of exocyclic valence angles for regular RNA @@@@@@@ +!O4'-C4'-C5' +ON6B CN7 CN8B 90.0 108.2 ! +ON6B CN7 CN9 90.0 108.2 ! for 5MET patch, adm jr. +!O3'-C3'-C2' +ON2 CN7 CN7B 90.0 110.0 ! +ON5 CN7 CN7B 90.0 110.0 ! From ON5 CN7 CN8 +!O2'-C2'-C1' +ON5 CN7B CN7B 80.0 108.4 ! +!O2'-C2'-C3' +ON5 CN7B CN7 90.0 108.0 ! +HN7 CN7B ON5 60.0 109.5 ! +HN5 ON5 CN7B 57.5 109.0 ! +HN7 CN7B CN7 34.53 110.10 22.53 2.179 +HN7 CN7 CN7B 34.53 110.10 22.53 2.179 + +!@@@@@@@@@ End of exocyclic valence angles for regular RNA @@@@@@@ + +!@@@@@@@@@ Beginning of angles for the nucleotide analogue @@@@@@@ +CN8 ON2 P 20.0 120.0 35. 2.33 !DMP, adm jr. +CN8 ON2 P2 20.0 120.0 35. 2.33 !DMP, adm jr., adm 2011 DNA update +!@@@@@@@@@ End of angles for the nucleotide analogue @@@@@@@ +ON2 P ON3 98.9 111.6 !DMP, adm jr. +ON2 P2 ON3 98.9 111.6 !DMP, adm jr., adm, 2011 DNA update +ON3 P ON3 120.0 120.0 !DMP, adm jr. +ON3 P2 ON3 120.0 120.0 !DMP, adm jr., adm, 2011 DNA update +HN8 CN8 ON2 60.0 109.5 !DMP, adm jr. +ON5 P ON3 98.9 111.6 ! From ON2 P ON3 +!------------------------ added for araim ---------------------- +ON6 CN7B CN7 120.0 106.25 ! +CN7B CN7 CN8 58.35 113.6 11.16 2.561 ! + +DIHEDRALS +! +!V(dihedral) = Kchi(1 + cos(n(chi) - delta)) +! +!Kchi: kcal/mole +!n: multiplicity +!delta: degrees +! +!atom types Kchi n delta +!2-(aminobutyl)-1,3-propandiol terms +X CN8 ON2 X -0.10 3 0.0 ! phosphate ester +X CN7 CN8 X 0.20 3 0.0 ! alkane +X CN8 NN6 X 0.10 3 0.0 ! methylammonium +!abasic nucleoside terms - susil +CN7 ON6 CN8B HN8 0.195 1 0.0 +ON6 CN8B CN8 HN8 0.195 1 0.0 +HN7 CN7 ON6 CN8B 0.195 3 0.0 +CN8B CN8 CN7 HN7 0.195 3 0.0 +HN8 CN8B CN8 HN8 0.195 3 0.0 +HN8 CN8B CN8 CN7 0.195 3 0.0 +! c5'-c4'-o4'-c1', exo +CN8B CN7 ON6 CN8B 0.5 5 0.0 ! min at 150 310 max at 25 200 +CN8B CN7 ON6 CN8B 0.1 3 180.0 +CN8B CN7 ON6 CN8B 0.5 1 0.0 +! c1'-c2'-c3'-o3', exo +CN8B CN8 CN7 ON5 0.4 5 0.0 +CN8B CN8 CN7 ON5 0.4 3 0.0 +CN8B CN8 CN7 ON5 0.7 2 0.0 !elevates energy at 0 (c3'endo), adm +CN8B CN8 CN7 ON5 0.5 1 180.0 !elevates energy at 0 (c3'endo), adm +CN8B CN8 CN7 ON2 0.4 5 0.0 !terms for oligonuclotide +CN8B CN8 CN7 ON2 0.4 3 0.0 +CN8B CN8 CN7 ON2 0.7 2 0.0 +CN8B CN8 CN7 ON2 0.5 1 180.0 +! c4'-o4'-c1'-c2', tau0 +CN7 ON6 CN8B CN8 0.6 6 180.0 +CN7 ON6 CN8B CN8 0.6 3 0.0 +! o4'-c1'-c2'-c3', tau1 +ON6 CN8B CN8 CN7 0.7 5 180.0 !lowers 90, shifts c2endo minimum towards 200 +ON6 CN8B CN8 CN7 0.4 4 0.0 !lowers 90, shifts c2endo minimum towards 200 +ON6 CN8B CN8 CN7 0.4 3 180.0 !lowers 90, shifts c2endo minimum towards 200 +! c4'-c3'-c2'-c1', tau2 +CN7 CN7 CN8 CN8B 0.5 4 0.0 +CN7 CN7 CN8 CN8B 0.1 3 0.0 !lowers energy in 150 to 250 range +! c1'-o4'-c4'-c3', tau4 +CN8B ON6 CN7 CN7 0.5 3 0.0 !effects surface in 200-360 region + +! PHOSPHATE +ON2 P2 ON2 CN7 0.90 1 180.0 ! adm, 2011 DNA update new param, zeta, kat2 set +ON2 P2 ON2 CN7 0.40 2 180.0 ! adm, 2011 DNA update new param, zeta, kat2 set +ON2 P2 ON2 CN7 0.20 3 180.0 ! adm, 2011 DNA update new param, zeta, kat2 set +ON2 P ON2 CN7 1.20 1 180.0 !10/97, DMP, adm jr., RNA +ON2 P ON2 CN7 0.10 2 180.0 !10/97, DMP, adm jr., RNA +ON2 P ON2 CN7 0.10 3 180.0 !10/97, DMP, adm jr., RNA +ON2 P ON2 CN7 0.00 6 0.0 !10/97, DMP, adm jr., RNA +ON2 P ON2 CN8 1.20 1 180.0 !10/97, DMP, adm jr. +ON2 P ON2 CN8 0.10 2 180.0 !10/97, DMP, adm jr. +ON2 P ON2 CN8 0.10 3 180.0 !10/97, DMP, adm jr. +ON2 P ON2 CN8 0.00 6 0.0 !10/97, DMP, adm jr. +ON2 P2 ON2 CN8 1.20 1 180.0 !10/97, DMP, adm jr., adm 2011 DNA update +ON2 P2 ON2 CN8 0.10 2 180.0 !10/97, DMP, adm jr., adm 2011 DNA update +ON2 P2 ON2 CN8 0.10 3 180.0 !10/97, DMP, adm jr., adm 2011 DNA update +ON2 P2 ON2 CN8 0.00 6 0.0 !10/97, DMP, adm jr., adm 2011 DNA update +! Added when C5' defined as CN8B (NF 041497): +ON2 P2 ON2 CN8B 1.20 1 180.0 !10/97, DMP, adm jr., adm, 2011 DNA update +ON2 P2 ON2 CN8B 0.10 2 180.0 !10/97, DMP, adm jr., adm, 2011 DNA update +ON2 P2 ON2 CN8B 0.10 3 180.0 !10/97, DMP, adm jr., adm, 2011 DNA update +ON2 P2 ON2 CN8B 0.00 6 0.0 !10/97, DMP, adm jr., adm, 2011 DNA update +ON2 P ON2 CN8B 1.20 1 180.0 !10/97, DMP, adm jr., RNA +ON2 P ON2 CN8B 0.10 2 180.0 !10/97, DMP, adm jr., RNA +ON2 P ON2 CN8B 0.10 3 180.0 !10/97, DMP, adm jr., RNA +ON2 P ON2 CN8B 0.00 6 0.0 !10/97, DMP, adm jr., RNA +ON2 P ON2 CN9 1.20 1 180.0 !dmp +ON2 P ON2 CN9 0.10 2 180.0 !dmp +ON2 P ON2 CN9 0.10 3 180.0 !dmp +ON2 P ON2 CN9 0.00 6 0.0 !dmp +ON2 P2 ON2 CN9 1.20 1 180.0 !dmp, adm, 2011 DNA update +ON2 P2 ON2 CN9 0.10 2 180.0 !dmp, adm, 2011 DNA update +ON2 P2 ON2 CN9 0.10 3 180.0 !dmp, adm, 2011 DNA update +ON2 P2 ON2 CN9 0.00 6 0.0 !dmp, adm, 2011 DNA update +! +ON3 P ON2 CN7 0.10 3 0.0 !dmp,eps, O1P-P-O3'-C3' +ON3 P2 ON2 CN7 0.10 3 0.0 !dmp,eps, O1P-P-O3'-C3', adm, 2011 DNA update +ON3 P ON2 CN7B 0.10 3 0.0 !for NADPH and bkbmod +ON3 P ON2 CN8 0.10 3 0.0 !dmp +ON3 P2 ON2 CN8 0.10 3 0.0 !dmp, adm 2011 DNA update +ON3 P ON2 CN8B 0.10 3 0.0 !dmp,bet, O1P-P-O5'-C5' +ON3 P2 ON2 CN8B 0.10 3 0.0 !dmp,bet, O1P-P-O5'-C5', adm, 2011 DNA update +ON3 P ON2 CN9 0.10 3 0.0 !dmp +ON3 P2 ON2 CN9 0.10 3 0.0 !dmp, adm, 2011 DNA update +! terminal phosphate terms, adm jr. +ON4 P ON2 CN7 0.95 2 0.0 !MP_1, adm jr. +ON4 P ON2 CN7 0.50 3 0.0 !MP_1, adm jr. +ON4 P2 ON2 CN7 0.95 2 0.0 !MP_1, adm jr., adm, 2011 DNA update +ON4 P2 ON2 CN7 0.50 3 0.0 !MP_1, adm jr., adm, 2011 DNA update +ON4 P ON2 CN8 0.95 2 0.0 !MP_1, adm jr. +ON4 P ON2 CN8 0.50 3 0.0 !MP_1, adm jr. +ON4 P ON2 CN8B 0.95 2 0.0 !MP_1, adm jr. +ON4 P ON2 CN8B 0.50 3 0.0 !MP_1, adm jr. +ON4 P2 ON2 CN8B 0.95 2 0.0 !MP_1, adm jr., adm, 2011 DNA update +ON4 P2 ON2 CN8B 0.50 3 0.0 !MP_1, adm jr., adm, 2011 DNA update +ON4 P ON2 CN9 0.95 2 0.0 !MP_1, adm jr. +ON4 P ON2 CN9 0.50 3 0.0 !MP_1, adm jr. +ON4 P2 ON2 CN9 0.95 2 0.0 !MP_1, adm jr., adm, 2011 DNA update +ON4 P2 ON2 CN9 0.50 3 0.0 !MP_1, adm jr., adm, 2011 DNA update +X ON4 P X 0.30 3 0.0 !MP_1, adm jr. +X ON4 P2 X 0.30 3 0.0 !MP_1, adm jr., adm, 2011 DNA update +! When O5' is ON2 (phosphodiester linkage): +P ON2 CN7 HN7 0.000 3 0.0 !dmp,eps, H-C3'-O3'-P +P2 ON2 CN7 HN7 0.000 3 0.0 !dmp,eps, H-C3'-O3'-P, adm, 2011 DNA update +P ON2 CN7B HN7 0.000 3 0.0 !for NADPH and bkbmod +P ON2 CN8B HN8 0.000 3 0.0 !dmp,beta, H-C5'-O5'-P +P2 ON2 CN8B HN8 0.000 3 0.0 !dmp,beta, H-C5'-O5'-P, adm, 2011 DNA update +P ON2 CN8 HN8 0.000 3 0.0 !dmp +P ON2 CN9 HN9 0.000 3 0.0 !dmp +P2 ON2 CN9 HN9 0.000 3 0.0 !dmp, adm, 2011 DNA update +! butane gauche terms +cn9 cn8 cn8 cn9 0.15 1 0.0 +cn9 cn8 cn8 cn8 0.15 1 0.0 +! BASES +! Uracil +NN2B CN1T NN2U CN1 1.5 2 180.0 ! adm jr. 11/97 +CN1T NN2U CN1 CN3 1.5 2 180.0 ! adm jr. 11/97 +NN2U CN1 CN3 CN3 1.5 2 180.0 ! adm jr. 11/97 +CN1 CN3 CN3 NN2B 6.0 2 180.0 ! adm jr. 11/97 +CN3 CN3 NN2B CN1T 1.5 2 180.0 ! adm jr. 11/97 +CN3 NN2B CN1T NN2U 1.5 2 180.0 ! adm jr. 11/97 +HN3 CN3 CN3 HN3 3.0 2 180.0 ! adm jr. 11/97 +HN3 CN3 CN1 ON1 6.0 2 180.0 ! adm jr. 11/97 +ON1 CN1T NN2B HN2 0.0 2 180.0 ! adm jr. 11/97 +ON1 CN1 NN2U HN2 0.0 2 180.0 ! adm jr. 11/97 +ON1 CN1T NN2U HN2 0.0 2 180.0 ! adm jr. 11/97 +HN2 NN2B CN3 HN3 1.5 2 180.0 ! adm jr. 11/97 +NN2B CN1T NN2U HN2 3.8 2 180.0 ! adm jr. 11/97 +CN3 CN1 NN2U HN2 3.8 2 180.0 ! adm jr. 11/97 +CN3 CN3 NN2B HN2 1.6 2 180.0 ! adm jr. 11/97 +NN2U CN1T NN2B HN2 1.6 2 180.0 ! adm jr. 11/97 +!Thymine +CN1T NN2B CN3 CN3T 1.8 2 180.0 ! adm jr. 11/97 +NN2U CN1 CN3T CN3 1.8 2 180.0 ! adm jr. 11/97 +CN1 CN3T CN3 NN2B 3.0 2 180.0 ! adm jr. 11/97 +NN2B CN1 CN3T CN9 5.6 2 180.0 ! adm jr. 11/97 +NN2B CN3 CN3T CN9 5.6 2 180.0 ! adm jr. 11/97 +CN1 CN3T CN9 HN9 0.46 3 0.0 ! adm jr. 11/97 +CN3 CN3T CN9 HN9 0.46 3 0.0 ! adm jr. 11/97 +CN3T CN1 NN2U HN2 4.8 2 180.0 ! adm jr. 11/97 +! Cytosine +CN3 NN2 CN1 NN3 0.6 2 180.0 ! adm jr. 11/97 +NN2 CN1 NN3 CN2 0.6 2 180.0 ! adm jr. 11/97 +CN1 NN3 CN2 CN3 6.0 2 180.0 ! adm jr. 11/97 +NN3 CN2 CN3 CN3 0.6 2 180.0 ! adm jr. 11/97 +CN2 CN3 CN3 NN2 6.0 2 180.0 ! adm jr. 11/97 +CN3 CN3 NN2 CN1 0.6 2 180.0 ! adm jr. 11/97 +NN3 CN2 NN1 HN1 1.0 2 180.0 ! adm jr. 11/97 +CN3 CN2 NN1 HN1 1.0 2 180.0 ! adm jr. 11/97 +NN1 CN2 NN3 CN1 2.0 2 180.0 ! adm jr. 11/97 +NN1 CN2 CN3 CN3 2.0 2 180.0 ! adm jr. 11/97 +NN1 CN2 CN3 HN3 2.0 2 180.0 ! adm jr. 11/97 +ON1C CN1 NN2 HN2 3.0 2 180.0 ! adm jr. 11/97 +ON1C CN1 NN3 CN2 1.6 2 180.0 ! adm jr. 11/97 +ON1C CN1 NN2 CN3 1.6 2 180.0 ! adm jr. 11/97 +NN3 CN2 CN3 HN3 3.4 2 180.0 ! adm jr. 11/97 +NN2 CN3 CN3 HN3 3.4 2 180.0 ! adm jr. 11/97 +CN2 CN3 CN3 HN3 4.6 2 180.0 ! adm jr. 11/97 +CN1 NN2 CN3 HN3 4.6 2 180.0 ! adm jr. 11/97 +X CN2 NN3 X 2.0 2 180.0 ! adm jr. 11/97 +! Adenine +CN2 NN3A CN4 NN3A 1.8 2 180.0 ! adm jr. 11/97, 6-mem +NN3A CN4 NN3A CN5 2.0 2 180.0 ! +CN4 NN3A CN5 CN5 1.8 2 180.0 ! +NN3A CN5 CN5 CN2 2.0 2 180.0 ! treated 2x +CN5 CN5 CN2 NN3A 1.8 2 180.0 ! +CN5 CN2 NN3A CN4 10.0 2 180.0 ! +CN5 CN5 NN4 CN4 6.0 2 180.0 ! 5-mem +CN5 NN4 CN4 NN2 14.0 2 180.0 ! +NN4 CN4 NN2 CN5 6.0 2 180.0 ! +CN4 NN2 CN5 CN5 6.0 2 180.0 ! +NN2 CN5 CN5 NN4 14.0 2 180.0 ! treated 2x +CN2 NN3A CN4 HN3 8.5 2 180.0 ! H2 +CN5 NN3A CN4 HN3 8.5 2 180.0 ! H2 +CN5 NN4 CN4 HN3 5.2 2 180.0 ! H8 +CN5 NN2 CN4 HN3 5.2 2 180.0 ! H8 +CN5 CN5 NN2 HN2 1.2 2 180.0 ! H9 +NN4 CN4 NN2 HN2 1.2 2 180.0 ! H9 +HN2 NN2 CN4 HN3 0.0 2 180.0 ! H8-C-N-H9 +CN4 NN3A CN2 NN1 4.0 2 180.0 ! N6 +CN5 CN5 CN2 NN1 4.0 2 180.0 ! N6 +NN4 CN5 CN2 NN1 0.0 2 180.0 ! N6 +CN5 CN2 NN1 HN1 0.5 2 180.0 ! 6-NH2 +NN3A CN2 NN1 HN1 0.5 2 180.0 ! +! Butterfly motion +NN3A CN5 CN5 NN4 7.0 2 180.0 !A, adm jr. 11/97 +CN2 CN5 CN5 NN2 7.0 2 180.0 !A +NN3A CN2 CN5 NN4 2.0 2 180.0 !A +CN2 CN5 NN4 CN4 2.0 2 180.0 !A +CN4 NN3A CN5 NN2 2.0 2 180.0 !A +NN3A CN5 NN2 CN4 2.0 2 180.0 !A +! Guanine +CN1 NN2G CN2 NN3G 0.2 2 180.0 !adm jr. 11/97, 6-mem +NN2G CN2 NN3G CN5 2.0 2 180.0 ! +CN2 NN3G CN5 CN5G 0.2 2 180.0 ! +NN3G CN5 CN5G CN1 2.0 2 180.0 ! +CN5 CN5G CN1 NN2G 0.2 2 180.0 ! +CN5G CN1 NN2G CN2 0.2 2 180.0 ! +CN5 CN5G NN4 CN4 6.0 2 180.0 !5-mem +CN5G NN4 CN4 NN2B 16.0 2 180.0 ! +NN4 CN4 NN2B CN5 6.0 2 180.0 ! +CN4 NN2B CN5 CN5G 6.0 2 180.0 ! +NN2B CN5 CN5G NN4 10.0 2 180.0 ! +! substitutents +ON1 CN1 CN5G CN5 14.0 2 180.0 !G, O6 +ON1 CN1 CN5G NN4 0.0 2 180.0 ! +ON1 CN1 NN2G CN2 14.0 2 180.0 ! +ON1 CN1 NN2G HN2 0.0 2 180.0 ! +NN1 CN2 NN2G CN1 4.0 2 180.0 !G, N2 +NN1 CN2 NN3G CN5 4.0 2 180.0 ! +NN1 CN2 NN2G HN2 0.0 2 180.0 ! +NN2G CN2 NN1 HN1 1.2 2 180.0 ! +NN3G CN2 NN1 HN1 1.2 2 180.0 ! +HN2 NN2G CN1 CN5G 3.6 2 180.0 !G, H1 +HN2 NN2G CN2 NN3G 3.6 2 180.0 ! +HN3 CN4 NN4 CN5G 5.6 2 180.0 !G, H8 +HN3 CN4 NN2B CN5 5.6 2 180.0 ! +HN3 CN4 NN2B HN2 0.0 2 180.0 ! +HN2 NN2B CN5 CN5G 1.2 2 180.0 !G, H9 +HN2 NN2B CN5 NN3G 1.2 2 180.0 ! +HN2 NN2B CN4 NN4 1.2 2 180.0 ! +! Butterfly motion +NN3G CN5 CN5G NN4 10.0 2 180.0 !adm jr. 11/97 +CN1 CN5G CN5 NN2 10.0 2 180.0 ! +NN2G CN1 CN5G NN4 2.0 2 180.0 ! +CN1 CN5G NN4 CN4 2.0 2 180.0 ! +CN2 NN3G CN5 NN2B 2.0 2 180.0 ! +NN3G CN5 NN2B CN4 2.0 2 180.0 ! +! Wild cards for uracil, thymine and cytosine +X CN1 NN3 X 1.0 2 180.0 ! c22 +X CN1 NN2 X 0.9 2 180.0 ! c22 +X CN1T NN2B X 0.9 2 180.0 ! From X CN1 NN2 X, for thymines +X CN1 NN2G X 0.9 2 180.0 ! c22 +X CN1 NN2U X 0.9 2 180.0 ! c22 +X CN1T NN2U X 0.9 2 180.0 ! c22 +X CN3 NN2 X 1.0 2 180.0 ! c22 +X CN3 NN2B X 1.0 2 180.0 ! From X CN3 NN2 X, for thymines +X CN3 CN3 X 1.0 2 180.0 ! c22 +X CN3 CN3T X 1.0 2 180.0 !T, adm jr. 11/97 +X CN1 CN3 X 1.0 2 180.0 ! c22 +X CN1 CN3T X 1.0 2 180.0 !T, adm jr. 11/97 +X CN2 CN3 X 0.8 2 180.0 ! c22 +! Wild cards for adenine and guanine +X CN1 CN5G X 1.0 2 180.0 ! adm jr. 11/97 +X CN2 NN2G X 1.0 2 180.0 ! +X CN2 CN5 X 1.0 2 180.0 ! +X CN4 NN2 X 1.5 2 180.0 ! +X CN4 NN2B X 1.5 2 180.0 ! From X CN4 NN2 X +X CN4 NN3A X 3.5 2 180.0 ! +X CN4 NN4 X 2.0 2 180.0 ! A,G +X CN5 CN5 X 0.0 2 180.0 ! +X CN5G CN5 X 0.0 2 180.0 ! adm jr. 11/97 +X CN5 NN2 X 1.5 2 180.0 ! +X CN5 NN2B X 1.5 2 180.0 ! From X CN5 NN2 X +X CN5 NN3A X 1.0 2 180.0 ! +X CN5 NN3G X 1.0 2 180.0 ! adm jr. 11/97 +X CN5 NN4 X 1.0 2 180.0 ! +X CN5G NN4 X 1.0 2 180.0 ! adm jr. 11/97 +X CN2 NN3A X 1.0 2 180.0 ! +X CN2 NN3G X 1.0 2 180.0 ! adm jr. 11/97 +! MISC. +CN1 NN2 CN9 HN9 0.19 3 0.0 ! 1-M-C +CN3 NN2 CN9 HN9 0.00 3 0.0 ! 1-M-C +CN4 NN2 CN9 HN9 0.00 3 0.0 ! 9-M-A +CN5 NN2 CN9 HN9 0.19 3 0.0 ! 9-M-A +CN1 NN2B CN9 HN9 0.19 3 0.0 ! 1-M-U +CN1T NN2B CN9 HN9 0.19 3 0.0 ! 1-M-T +CN3 NN2B CN9 HN9 0.00 3 0.0 ! 1-M-T/U +CN4 NN2B CN9 HN9 0.00 3 0.0 ! 9-M-G +CN5 NN2B CN9 HN9 0.19 3 0.0 ! 9-M-G +CN4 NN2B CN8 HN8 0.00 3 0.0 ! 9-E-G +CN5 NN2B CN8 HN8 0.19 3 0.0 ! 9-E-G +CN4 NN2B CN8 CN9 0.00 3 0.0 ! 9-E-G +CN5 NN2B CN8 CN9 0.19 3 0.0 ! 9-E-G +X CN8 CN8 X 0.15 3 0.0 ! Alkanes (0.2 to 0.15) +X CN8 CN9 X 0.15 3 0.0 ! Alkanes (0.2 to 0.15) +!for nadp/nadph, adm jr. +HN7 CN7B CN7B ON2 0.195 3 0.0 !for NADPH and bkbmod +ON2 CN7B CN7B NN2 0.0 3 0.0 !for NADPH and bkbmod + +! sugar, replace with ribose terms 021998 +CN7 CN7B ON6 CN7 0.6 6 180.0 +CN7B CN7 CN7 CN7 0.4 6 0.0 ! good for amplitudes +CN7B CN7 CN7 CN9 0.4 6 0.0 ! good for amplitudes, 5MET +CN7 CN7 CN7 ON6 0.6 6 0.0 +CN7 CN7 CN7B ON6 0.6 6 0.0 +ON2 CN7 CN7 CN7 0.8 6 0.0 ! +ON2 CN7 CN7 CN7 0.4 5 0.0 ! Moves the barrier right +ON2 CN7 CN7 CN7 2.0 3 180.0 ! +! for ndph +ON2 CN7B CN7 CN7 0.8 6 0.0 ! +ON2 CN7B CN7 CN7 0.4 5 0.0 ! Moves the barrier right +ON2 CN7B CN7 CN7 2.0 3 180.0 ! +! +ON5 CN7 CN7 CN7 0.8 6 0.0 ! +ON5 CN7 CN7 CN7 0.4 5 0.0 ! Moves the barrier right +ON5 CN7 CN7 CN7 2.0 3 180.0 ! +ON5 CN7 CN7 ON5 0.0 3 0.0 ! +ON5 CN7 CN7 ON2 0.0 3 0.0 ! +ON2 CN7 CN7B ON6 0.5 6 0.0 !good for amplitudes +ON2 CN7 CN7B ON6 0.3 5 0.0 !impact on amplitudes +ON2 CN7 CN7B ON6 0.6 4 180.0 !increases c2'endo +ON2 CN7 CN7B ON6 0.2 3 0.0 ! +CN7 CN7 CN7 CN8B 0.5 4 180.0 !del lowers 180 deg. + +!%%%%%%% new terms for dna and the deoxyribose-based model compounds %%%%%% +! The following is for: THF3P (model for espilon), THFM3P (model for puckering), +! THF5P (model for gamma and beta), THFCH3IM (model for chi), nucleotide analogue +!@@@@@@ Begining of chi +!============= added for torsion about chi in adenine ============ +!For link from sugar to base: +CN7B NN2 CN4 HN3 0.3 2 180.0 ! NF +CN7B NN2 CN5 CN5 11.0 2 180.0 ! adm jr. +CN7B NN2 CN4 NN4 11.0 2 180.0 ! adm jr. +CN7B NN2 CN4 NN3A 11.0 2 180.0 ! adm jr. +!For chi itself: + !DNA: +ON6 CN7B NN2 CN5 1.1 1 180.0 ! +ON6 CN7B NN2 CN4 1.1 1 0.0 ! NF + !RNA: +ON6B CN7B NN2 CN5 1.1 1 180.0 ! +ON6B CN7B NN2 CN4 1.1 1 0.0 ! + !DNA: +CN8 CN7B NN2 CN5 0.3 3 0.0 ! NF +CN8 CN7B NN2 CN4 0.0 3 180.0 ! NF + !RNA: +CN7B CN7B NN2 CN5 0.3 3 0.0 ! NF +CN7B CN7B NN2 CN4 0.0 3 180.0 ! NF + +HN7 CN7B NN2 CN5 0.0 3 0.0 ! NF +HN7 CN7B NN2 CN4 0.195 3 0.0 ! NF +!@@@@@@ End of chi in adenines + +!============== terms for torsion about chi in cytosines =========== +CN7B NN2 CN3 HN3 0.3 2 180.0 ! NF +CN7B NN2 CN1 ON1C 11.0 2 180.0 ! adm jr. from A +CN7B NN2 CN1 NN3 11.0 2 180.0 ! adm jr. +CN7B NN2 CN3 CN3 11.0 2 180.0 ! adm jr. + !DNA: +ON6 CN7B NN2 CN1 0.0 3 0.0 ! +ON6 CN7B NN2 CN3 1.0 1 0.0 ! NF + !RNA: +ON6B CN7B NN2 CN1 0.0 3 0.0 ! +ON6B CN7B NN2 CN3 1.0 1 0.0 ! + !DNA: +CN8 CN7B NN2 CN1 1.0 3 0.0 ! +CN8 CN7B NN2 CN3 0.0 3 180.0 ! NF 030697 + !RNA: +CN7B CN7B NN2 CN1 1.0 3 0.0 ! +CN7B CN7B NN2 CN3 0.0 3 180.0 ! + +HN7 CN7B NN2 CN1 0.0 3 0.0 ! NF +HN7 CN7B NN2 CN3 0.195 3 0.0 ! NF +!@@@@@@ End of chi in cytosines + +!=========== terms for torsion about chi in uracils/thymines =========== +CN7B NN2B CN3 HN3 0.3 2 180.0 ! NF +CN7B NN2B CN1T ON1 11.0 2 180.0 ! adm jr. from A +CN7B NN2B CN1T NN2U 11.0 2 180.0 ! adm jr. +CN7B NN2B CN3 CN3T 11.0 2 180.0 ! adm jr. + !DNA: +ON6 CN7B NN2B CN1 0.0 3 0.0 ! +ON6 CN7B NN2B CN1T 0.7 3 0.0 ! +ON6 CN7B NN2B CN1T 0.8 1 180.0 ! +ON6 CN7B NN2B CN3 0.9 1 0.0 ! NF + !RNA: +ON6B CN7B NN2B CN1 0.0 3 0.0 ! +ON6B CN7B NN2B CN1T 0.7 3 0.0 ! +ON6B CN7B NN2B CN1T 0.8 1 180.0 ! +ON6B CN7B NN2B CN3 0.9 1 0.0 ! + !DNA: +CN8 CN7B NN2B CN1T 0.2 3 180.0 ! +CN8 CN7B NN2B CN3 0.0 3 180.0 ! NF + !RNA: +CN7B CN7B NN2B CN1T 0.2 3 180.0 ! +CN7B CN7B NN2B CN3 0.0 3 180.0 ! + +HN7 CN7B NN2B CN1T 0.0 3 0.0 ! NF +HN7 CN7B NN2B CN3 0.195 3 0.0 ! NF +!@@@@@@ End of chi in thymines + +!============= added for torsion about chi in guanine ============ +CN7B NN2B CN4 HN3 0.3 2 180.0 ! NF +CN7B NN2B CN4 NN4 11.0 2 180.0 ! adm jr. +CN7B NN2B CN5 CN5G 11.0 2 180.0 ! adm jr. from U +CN7B NN2B CN5 NN3G 11.0 2 180.0 ! adm jr. + !DNA: +ON6 CN7B NN2B CN5 0.2 3 0.0 ! +ON6 CN7B NN2B CN5 1.1 1 180.0 ! +ON6 CN7B NN2B CN4 1.4 1 0.0 ! NF + !RNA: +ON6B CN7B NN2B CN5 0.2 3 0.0 ! +ON6B CN7B NN2B CN5 1.1 1 180.0 ! +ON6B CN7B NN2B CN4 1.4 1 0.0 ! + !DNA: +CN8 CN7B NN2B CN5 0.0 3 0.0 ! NF +CN8 CN7B NN2B CN4 0.0 3 180.0 ! NF 030697 + !RNA: +CN7B CN7B NN2B CN5 0.0 3 0.0 ! NF +CN7B CN7B NN2B CN4 0.0 3 180.0 ! + +HN7 CN7B NN2B CN5 0.0 3 0.0 ! NF +HN7 CN7B NN2B CN4 0.195 3 0.0 ! NF +!@@@@@@ End of chi in guanines +!@@@@@@ link (not chi) between base and sugar for both purines and pyrimidines: + !DNA: +CN7 ON6 CN7B NN2 0.0 3 0.0 +CN7 ON6 CN7B NN2B 0.0 3 0.0 + !RNA: +CN7 ON6B CN7B NN2 0.0 3 0.0 +CN7 ON6B CN7B NN2B 0.0 3 0.0 + !DNA: +CN7 CN8 CN7B NN2 0.0 3 0.0 +CN7 CN8 CN7B NN2B 0.0 3 0.0 +HN8 CN8 CN7B NN2 0.0 3 0.0 +HN8 CN8 CN7B NN2B 0.0 3 0.0 + !RNA: +CN7 CN7B CN7B NN2 0.0 3 0.0 +CN7 CN7B CN7B NN2B 0.0 3 0.0 + !RNA +HN7 CN7B CN7B NN2 0.0 3 0.0 +HN7 CN7B CN7B NN2B 0.0 3 0.0 + +!@@@@@@ Begining of torsions involving exocyclic sugar atoms: +!======= CN7 CN8B ON2 P = C4'-C5'-O5'-P +CN7 CN8B ON2 P 0.2 1 120.0 !bet C4'-C5'-O5'-P, adm jr. +CN7 CN8B ON2 P2 0.2 1 120.0 !bet C4'-C5'-O5'-P, adm jr., adm, 2011 DNA update +! the following differ significantly from the alcohols +! in the protein (based on ethanol), they also differ from other +! NA C-C-OH-H parameters (see below) +! The two following terms have been replaced by their ethanol +! counterpart (NF, 083098) +CN7 CN8B ON5 HN5 1.3300 1 0.00 +CN7 CN8B ON5 HN5 0.1800 2 0.00 +CN7 CN8B ON5 HN5 0.3200 3 0.00 +!======= HN8 CN8B ON2 P = H-C5'-O5'-P )beta +HN8 CN8B ON5 HN5 0.0 3 0.0 !bet +!======== CN7 CN7 CN8B ON2 = C3'-C4'-C5'-O5' +! When O5' is ON2 (phosphodiester linkage): +CN7 CN7 CN8B ON2 0.20 4 180.0 !gam adm jr. +CN7 CN7 CN8B ON2 0.80 3 180.0 !gam C3'-C4'-C5'-O5' +CN7 CN7 CN8B ON2 0.40 2 0.0 !gam +CN7 CN7 CN8B ON2 2.50 1 180.0 !gam +! +CN8 CN7 CN8B ON2 0.2 3 180.0 ! from gam, carbocyclic and 25P1 +! When O5' is ON5 (5TER patch): +CN7 CN7 CN8B ON5 0.20 4 180.0 !gam adm jr. +CN7 CN7 CN8B ON5 0.80 3 180.0 !gam C3'-C4'-C5'-O5' +CN7 CN7 CN8B ON5 0.40 2 0.0 !gam +CN7 CN7 CN8B ON5 2.50 1 180.0 !gam +!======== ON6 CN7 CN8B ON2 = O4'-C4'-C5'-O5' +! When O5' is ON2 (3'-5' phosphodiester linkage) +ON6 CN7 CN8B ON2 3.4 1 180.0 !gam O4'-C4'-C5'-O5',influences +60 +ON6B CN7 CN8B ON2 3.4 1 180.0 !gam, RNA +! When O5' is ON5 (5TER patch): +ON6 CN7 CN8B ON5 3.4 1 180.0 !gam +ON6B CN7 CN8B ON5 3.4 1 180.0 !gam, RNA +!======== HN8 CN8B CN7 CN7 = H-C5'-C4'-H +HN8 CN8B CN7 CN7 0.195 3 0.0 !gam,H-C5'-C4'-H +HN8 CN8B CN7 CN8 0.195 1 0.0 !gam, carbocylic, 25P1 +!======== HN7 CN8B CN7 ON6 = H-C5'-C4'-O4' +HN8 CN8B CN7 ON6 0.195 1 0.0 !gam,H-C5'-C4'-O4' +HN8 CN8B CN7 ON6B 0.195 1 0.0 !gam, RNA +!======== HN7 CN7 CN8B ON2 = H-C4'-C5'-O5' +! When O5' is ON2 (phosphodiester linkage): +HN7 CN7 CN8B ON2 0.195 3 0.0 !gam H-C4'-C5'-O5' +! When O5' is ON5 (5TER patch): +HN7 CN7 CN8B ON5 0.195 3 0.0 !gam +HN8 CN8 CN8 ON6 0.195 1 0.0 !gam,H-C5'-C4'-O4' +! terms for 5MET patch +CN9 CN7 CN7 CN8B 0.5 4 180.0 !cn8 -> cn9 +HN7 CN7 CN9 HN9 0.195 3 0.0 !cn8 -> cn9 +CN7 CN7 CN9 HN9 0.195 3 0.0 !cn8 -> cn9 +ON6 CN7 CN9 HN9 0.195 3 0.0 !cn7 -> cn9 +HN7 CN7 CN7 CN9 0.195 3 0.0 !cn8 -> cn9 +ON2 CN7 CN7 CN9 0.2 4 0.0 !cn8b -> cn9 +ON2 CN7 CN7 CN9 0.8 3 180.0 !cn8b -> cn9 +CN8 CN7 CN7 CN9 0.5 4 180.0 !cn8b -> cn9 + +!======== CN8 CN7 CN7 CN8B = C2'-C3'-C4'-C5' +! This term is well suited to modify the puckering surfaces, in +! particular because it is present in THF5P +CN8 CN7 CN7 CN8B 0.5 4 180.0 !del lowers 180 deg. +CN7B CN7 CN7 CN8B 0.2 4 180.0 !del, RNA +!======== CN8B CN7 CN7 ON2 = C5'-C4'-C3'-O3' +! These terms affect the c2endo/c3endo energy difference +! When O3' is ON2 (3'-5' phosphodiester linkage) +ON2 CN7 CN7 CN8B 0.2 4 0.0 !del +! the following term controls the location of the barrier at ~75 deg. +ON2 CN7 CN7 CN8B 0.8 3 180.0 !del,decreases P [100,250] +! When O3' is ON5 (patch 3TER) +ON5 CN7 CN7 CN8B 0.2 4 0.0 ! +ON5 CN7 CN7 CN8B 0.8 3 180.0 ! +!======== ON6 CN7 CN7 ON2 = O4'-C4'-C3'-O3' +! These terms contribute to delta +! These terms are present in THF3P and THFM3P but not in THF5P +! When O3' is ON2 (3'-5' phosphodiester linkage) +ON2 CN7 CN7 ON6 0.5 6 0.0 !del, good for amplitudes +ON2 CN7 CN7 ON6 0.3 5 0.0 !del, impact on amplitudes +ON2 CN7 CN7 ON6 0.6 4 180.0 !del, increases c2'endo +ON2 CN7 CN7 ON6 0.2 3 0.0 ! +ON2 CN7 CN7 ON6B 0.4 6 0.0 !del, RNA, good for amplitudes +ON2 CN7 CN7 ON6B 0.0 5 0.0 !del, RNA, impact on amplitudes +ON2 CN7 CN7 ON6B 0.0 4 180.0 !del, RNA, increases c2'endo +ON2 CN7 CN7 ON6B 1.6 3 0.0 !del, RNA, increases C2'endo +! for ndph: make identical to ON2 CN7 CN7 ON6B +ON2 CN7B CN7B ON6B 0.4 6 0.0 !del, RNA, good for amplitudes +ON2 CN7B CN7B ON6B 0.0 5 0.0 !del, RNA, impact on amplitudes +ON2 CN7B CN7B ON6B 0.0 4 180.0 !del, RNA, increases c2'endo +ON2 CN7B CN7B ON6B 1.6 3 0.0 !del, RNA, increases C2'endo +! When O3' is ON5 (patch 3TER) +ON5 CN7 CN7 ON6 0.5 6 0.0 ! +ON5 CN7 CN7 ON6 0.3 5 0.0 ! +ON5 CN7 CN7 ON6 0.6 4 180.0 ! +ON5 CN7 CN7 ON6 0.2 3 0.0 ! +ON5 CN7 CN7 ON6B 0.4 6 0.0 !RNA +ON5 CN7 CN7 ON6B 0.0 5 0.0 !RNA +ON5 CN7 CN7 ON6B 0.0 4 180.0 !RNA +ON5 CN7 CN7 ON6B 1.6 3 0.0 !RNA. increases c2'endo + +!======== CN8B CN7 ON6 CN7B = C5'-C4'-O4'-C1' +! This term can be used to adjust the c2'endo/c3'endo +! energy difference in THF5P +CN7B ON6 CN7 CN8B 0.8 3 0.0 ! P [30,80] +CN7B ON6B CN7 CN8B 2.0 3 0.0 ! To lower barrier in RNA +CN7B ON6B CN7 CN9 2.0 3 0.0 ! To lower barrier in RNA, 5MET +!======== ON2 CN7 CN8 CN7B = O3'-C3'-C2'-C1' +! This term can be used to adjust the c2'endo/c3'endo +! When O3' is ON2 +ON2 CN7 CN8 CN7B 0.8 6 0.0 ! +ON2 CN7 CN8 CN7B 0.4 5 0.0 ! Moves the barrier right +ON2 CN7 CN8 CN7B 2.0 3 180.0 ! +ON2 CN7 CN7B CN7B 0.6 6 0.0 ! RNA +ON2 CN7 CN7B CN7B 0.0 5 0.0 ! RNA c2/c3 endo in RNA +ON2 CN7 CN7B CN7B 1.6 3 180.0 ! +!When O3' is ON5 (patch 3TER) +ON5 CN7 CN8 CN7B 0.8 6 0.0 ! +ON5 CN7 CN8 CN7B 0.4 5 0.0 ! +ON5 CN7 CN8 CN7B 2.0 3 180.0 ! +ON5 CN7 CN7B CN7B 0.6 6 0.0 ! RNA, c2/c3 endo +ON5 CN7 CN7B CN7B 0.0 5 0.0 ! RNA +ON5 CN7 CN7B CN7B 1.6 3 180.0 ! RNA +!======== ON2 CN7 CN8 HN8 = O3'-C3'-C2'-H +ON2 CN7 CN8 HN8 0.195 3 0.0 ! +ON5 CN7 CN8 HN8 0.195 3 180.0 ! +ON2 CN7 CN7B HN7 0.195 3 0.0 ! RNA +ON5 CN7 CN7B HN7 0.195 3 180.0 ! RNA +!======== HN7 CN7 CN7 ON2 = H-C4'-C3'-O3' +HN7 CN7 CN7 ON2 0.195 3 0.0 +HN7 CN7 CN7 ON5 0.195 3 0.0 +!======== CN7 CN7 ON2 P = C4'-C3'-O3'-P +CN7 CN7 ON2 P2 0.6 5 0.0 !eps, adm, 2011 DNA update +CN7 CN7 ON2 P2 0.2 4 0.0 !eps, locat of 200 mimima, adm, 2011 DNA update +CN7 CN7 ON2 P2 0.0 3 180.0 !eps, barE beteen minima, adm, 2011 DNA update +CN7 CN7 ON2 P2 0.4 2 0.0 !eps, relE of 200 vs 275 min, adm, 2011 DNA update +CN7 CN7 ON2 P2 1.9 1 180.0 !eps, adm, 2011 DNA update +CN7 CN7 ON2 P 0.6 5 0.0 !eps, RNA +CN7 CN7 ON2 P 0.2 4 0.0 !eps, locat of 200 mimima, RNA +CN7 CN7 ON2 P 0.0 3 180.0 !eps, barE beteen minima, RNA +CN7 CN7 ON2 P 0.4 2 0.0 !eps, relE of 200 vs 275 min, RNA +CN7 CN7 ON2 P 1.9 1 180.0 !eps, RNA +!======== CN8 CN7 ON2 P = C2'-C3'-O3'-P +! This term is involved in epsilon +CN8 CN7 ON2 P 2.5 1 180.0 ! 3-terminal phosphate +CN8 CN7 ON2 P2 1.9 1 180.0 ! adm, 2011 DNA update new param, eps +CN7B CN7 ON2 P 2.5 1 180.0 !eps, RNA +CN7B CN7B ON2 P 2.5 1 180.0 !eps, NADPH and bkbmod +CN7 CN7B ON2 P 2.5 1 180.0 !eps, NADPH and bkbmod +! base on thfalloh +! the following differ significantly from the protein based +! alcohol parameters (based on ethanol, see above) +CN7 CN7 ON5 HN5 0.5 3 0.0 +CN7 CN7 ON5 HN5 0.3 2 180.0 +CN7 CN7 ON5 HN5 1.5 1 0.0 +CN8 CN7 ON5 HN5 0.5 3 0.0 +CN8 CN7 ON5 HN5 1.0 2 180.0 +CN8 CN7 ON5 HN5 0.3 1 0.0 +CN7B CN7 ON5 HN5 0.8 3 0.0 ! RNA +CN7B CN7 ON5 HN5 0.5 1 0.0 ! RNA +! Was simply transfered from HN7 CN7 ON2 P +! adm jr. should convert to alcohol term (see ribose etc) +HN7 CN7 ON5 HN5 0.0 3 0.0 +HN7 CN7 CN8B HN8 0.195 3 0.0 !gam H-C4'-C5'-H +HN7 CN7 CN7 CN8B 0.195 3 0.0 !gam H-C3'-C4'-C5' +!@@@@@@ End of torsions involving exocyclic atoms: +!@@@@@@ Begining of torsions for endocyclic atoms only: +CN8 CN7B ON6 CN7 0.6 6 180.0 !C2'-C1'-O4'-C4' +CN8 CN7 CN7 ON6 1.0 4 0.0 ! adm, 2011 DNA update new param, C2'-C3'-C4'-O4'; lowers c3'endo +CN8 CN7 CN7 ON6 0.3 5 180.0 ! adm, 2011 DNA update new param, C2'-C3'-C4'-O4'; position of minima +CN8 CN7 CN7 ON6 0.3 6 180.0 ! adm, 2011 DNA update new param, C2'-C3'-C4'-O4'; position of minima +CN7B CN7B ON6B CN7 0.0 6 0.0 ! RNA, Lowers barrier +CN7B CN7 CN7 ON6B 0.0 3 0.0 ! RNA +!======== CN7 CN8 CN7B ON6 for nucleosides, transfered from ========= +!======== CN7 CN8 CN8 ON6 from thfoh ============================== +CN7 CN8 CN7B ON6 0.6 6 0.0 ! C3'-C2'-C1'-O4', adjust barrier +CN7 CN7B CN7B ON6B 0.4 6 0.0 ! RNA +!======== C1'-C2'-C3'-C4' ======== +CN7B CN8 CN7 CN7 0.4 6 0.0 ! good for amplitudes +CN7B CN7B CN7 CN7 0.0 6 0.0 ! RNA +!======== CN7 CN7 ON6 CN7B for nucleosides, transfered from ======== +!======== CN7 CN7 ON6 CN8 from thfohch3 ============================ +CN7 CN7 ON6 CN7B 0.6 6 180.0 ! C3'-C4'-O4'-C1' +CN7 CN7 ON6B CN7B 0.0 6 180.0 ! RNA +!======== Directly adjusted with TM3P +HN7 CN7 CN7 CN8 0.0 3 0.0 !puc,H-C3'-C4'-C5' +!======== HN7 CN7 CN7 ON6 = H-C2'-C3'-O4' +HN7 CN7 CN8 CN7B 0.195 3 0.0 !H-C3'-C2'-C1' +HN7 CN7B CN8 CN7 0.195 3 0.0 !H-C1'-C2'-C3' +HN7 CN7 CN7 ON6 0.195 3 180.0 ! useful +HN8 CN8 CN7B ON6 0.195 3 0.0 !H-C2'-C1'-O4' +HN7 CN7 CN7 HN7 0.195 3 0.0 !H-C4'-C3'-H +HN7 CN7B CN8 HN8 0.195 3 0.0 !H-C1'-C2'-H +HN7 CN7 CN8 HN8 0.195 3 0.0 !H-C3'-C2'-H +HN8 CN8 CN7 CN7 0.195 3 0.0 ! useful *cccc* +HN7 CN7 ON6 CN7B 0.195 3 0.0 !H-C3'-C2'-C1' +HN7 CN7B ON6 CN7 0.000 3 0.0 !H-C1'-O4'-C4' +HN7 CN7 CN7 ON6B 0.195 3 180.0 ! RNA +HN9 CN9 CN7 ON6B 0.195 3 180.0 ! RNA, 5MET +HN8 CN8 CN7B ON6B 0.195 3 0.0 ! RNA +HN7 CN7B ON6B CN7 0.000 3 0.0 ! RNA +HN7 CN7 ON6B CN7B 0.195 3 0.0 ! RNA +HN7 CN7 CN7B CN7B 0.195 3 0.0 ! RNA, H-C3'-C2'-C1' +HN7 CN7B CN7B CN7 0.195 3 0.0 ! RNA, H-C1'-C2'-C3' +HN7 CN7B CN7B ON6B 0.195 3 0.0 ! RNA, H-C2'-C1'-O4' +!@@@@@@ End of torsions for endocyclic atoms only + +!@@@@@@ Begining of torsions specifically defined for RNA @@@@@@ +! N9-C1'-C2'-O2': +NN2 CN7B CN7B ON5 0.000 3 0.0 ! Adenine and cytosine +NN2B CN7B CN7B ON5 0.000 3 0.0 ! Guanine and uracil +ON5 CN7B CN7B HN7 0.000 3 0.0 ! +HN7 CN7B CN7B HN7 0.000 3 0.0 ! +CN7 CN7 CN7B ON5 0.000 3 0.0 +ON6B CN7B CN7B ON5 0.000 3 0.0 +ON5 CN7B CN7 ON2 0.000 3 0.0 +! for ndph +ON5 CN7 CN7B ON2 0.000 3 0.0 +ON5 CN7B CN7 ON5 0.000 3 0.0 +HN7 CN7B ON5 HN5 0.000 3 0.0 +!ejd, 2010 RNA update +HN5 ON5 CN7B CN7B 0.000 6 180.0 ! ejd, 2010 RNA update +HN5 ON5 CN7B CN7B 0.400 3 0.0 ! shifts min, ejd, 2010 RNA update +HN5 ON5 CN7B CN7B 0.400 2 0.0 ! ejd, 2010 RNA update +HN5 ON5 CN7B CN7B 0.800 1 0.0 ! height of right barrier and can shift min, ejd, 2010 RNA update +!to C3' +HN5 ON5 CN7B CN7 0.200 3 0.0 ! ejd, 2010 RNA update +HN5 ON5 CN7B CN7 0.000 2 180.0 ! ejd, 2010 RNA update +HN5 ON5 CN7B CN7 2.000 1 0.0 ! height of left side barrier, ejd, 2010 RNA update +!@@@@@@ End of torsions specifically defined for RNA @@@@@@ + +!Collection of parameters that were previously incorrectly categorized or labeled +CN7B ON6 CN7 CN9 0.0 3 0.0 ! added for sugar model compounds +HN7 CN7 CN7B ON5 0.195 3 0.0 ! for nadp/nadph (NOT!), adm jr. +HN7 CN7B CN7 CN7 0.195 3 0.0 ! for nadp/nadph (NOT!), adm jr. +HN7 CN7 CN7 CN7B 0.195 3 0.0 ! for nadp/nadph (NOT!), adm jr. +HN7 CN7 CN7B HN7 0.195 3 0.0 ! for nadp/nadph (NOT!), adm jr. + +IMPROPER +! +!V(improper) = Kpsi(psi - psi0)**2 +! +!Kpsi: kcal/mole/rad**2 +!psi0: degrees +!note that the second column of numbers (0) is ignored +! +!atom types Kpsi psi0 +! +! +HN2 X X NN2 1.0 0 0.0 !C, adm jr. 11/97 +NN2B CN4 CN5 HN2 7.0 0 0.0 !G, adm jr. 11/97 +HN1 X X NN1 4.0 0 0.0 !G, adm jr. 11/97 +NN1 CN2 HN1 HN1 6.0 0 0.0 !A,C adm jr. 11/97 +CN1 X X ON1 90.0 0 0.0 !U +CN1T X X ON1 90.0 0 0.0 !U +CN1 NN2G CN5G ON1 90.0 0 0.0 !G +CN1T NN2B NN2U ON1 110.0 0 0.0 !T/O2, adm jr. 11/97 +CN1 NN2U CN3T ON1 90.0 0 0.0 !T/O4, adm jr. 11/97 +CN1 X X ON1C 80.0 0 0.0 !C, par_32, adm jr. 10/2/91 +CN2 X X NN1 90.0 0 0.0 !C, +CN2 NN3G NN2G NN1 40.0 0 0.0 !G +CN2 NN3A CN5 NN1 40.0 0 0.0 !A +CN2 NN3 CN3 NN1 60.0 0 0.0 !C, +CN9 X X CN3T 14.0 0 0.0 !T, adm jr. 11/97 + +! Wildcards used to minimize memory requirements +NONBONDED NBXMOD 5 ATOM CDIEL FSHIFT VATOM VDISTANCE VFSWITCH - + CUTNB 14.0 CTOFNB 12.0 CTONNB 10.0 EPS 1.0 E14FAC 1.0 WMIN 1.5 +! +!V(Lennard-Jones) = Eps,i,j[(Rmin,i,j/ri,j)**12 - 2(Rmin,i,j/ri,j)**6] +! +!epsilon: kcal/mole, Eps,i,j = sqrt(eps,i * eps,j) +!Rmin/2: A, Rmin,i,j = Rmin/2,i + Rmin/2,j +! +!atom ignored epsilon Rmin/2 ignored eps,1-4 Rmin/2,1-4 +! +HN1 0.0 -0.0460 0.2245 +HN2 0.0 -0.0460 0.2245 +HN3 0.0 -0.046 1.1000 !adm jr. aromatic Hvdw +HN4 0.0 -0.0460 0.2245 +HN5 0.0 -0.0460 0.2245 +HN6 0.0 -0.0220 1.3200 +HN7 0.0 -0.0220 1.3200 +HN8 0.0 -0.0280 1.3400 ! Hydrogen bound to CN8 +HN9 0.0 -0.0240 1.3400 ! Hydrogen bound to CN9 +! +NN1 0.0 -0.20 1.85 +NN2 0.0 -0.20 1.85 +NN2B 0.0 -0.20 1.85 ! From NN2, for N9 in guanines +NN2G 0.0 -0.20 1.85 +NN2U 0.0 -0.20 1.85 +NN3 0.0 -0.20 1.85 +NN3A 0.0 -0.20 1.85 +NN3G 0.0 -0.20 1.85 +NN4 0.0 -0.20 1.85 +NN6 0.0 -0.20 1.85 +! +ON1 0.0 -0.1200 1.70 +ON1C 0.0 -0.1200 1.70 +ON2 0.0 -0.1521 1.77 +ON3 0.0 -0.1200 1.70 +ON4 0.0 -0.1521 1.77 +ON5 0.0 -0.1521 1.77 +ON6 0.0 -0.1521 1.77 +ON6B 0.0 -0.1521 1.77 +! +! base ring C vdw param, 11/14/97, adm jr +CN1 0.0 -0.10 1.9000 +CN1T 0.0 -0.10 1.9000 +CN2 0.0 -0.10 1.9000 +CN3 0.0 -0.09 1.9000 +CN3T 0.0 -0.09 1.9000 ! T, adm jr. +CN4 0.0 -0.075 1.9000 +CN5 0.0 -0.075 1.9000 +CN5G 0.0 -0.075 1.9000 +CN7 0.0 -0.02 2.275 0.0 -0.01 1.90 !equivalent to protein CT1 +CN7B 0.0 -0.02 2.275 0.0 -0.01 1.90 !equivalent to protein CT1 +! alkane optimized terms below, Yin and MacKerell, 1998, JCC, In press +CN8 0.0 -0.0560 2.010 0.0 -0.01 1.90 ! +CN8B 0.0 -0.0560 2.010 0.0 -0.01 1.90 ! +CN9 0.0 -0.0780 2.040 0.0 -0.01 1.90 ! +! +P 0.0 -0.585 2.15 +P2 0.0 -0.585 2.15 + +NBFIX +! Emin Rmin +! (kcal/mol) (A) +! + +HBOND CUTHB 0.5 ! If you want to do hbond analysis (only), then use + ! READ PARAM APPEND CARD + ! to append hbond parameters from the file: par_hbond.inp + +END diff --git a/continuousflex/protocols/utilities/pdb_handler.py b/continuousflex/protocols/utilities/pdb_handler.py new file mode 100644 index 0000000..cbe4d20 --- /dev/null +++ b/continuousflex/protocols/utilities/pdb_handler.py @@ -0,0 +1,410 @@ +# By Remi Vuillemot +import os.path + +import numpy as np +import copy +from Bio.SVDSuperimposer import SVDSuperimposer + +class ContinuousFlexPDBHandler: + + @classmethod + def read_coords(cls, pdb_file): + print("> Reading pdb file %s ..." % pdb_file) + coords = [] + with open(pdb_file, "r") as f: + for line in f: + if 'ATOM' in line: + coords.append([ + line[30:38],line[38:46],line[46:54] + ]) + return np.array(coords).astype(float) + + def __init__(self, pdb_file): + """ + Contructor + :param pdb_file: PDB file + """ + if not os.path.exists(pdb_file): + raise RuntimeError("Could not read PDB file : No such file") + if os.path.getsize(pdb_file) == 0: + raise RuntimeError("Could not read PDB file : file empty") + + atom = [] + atomNum = [] + atomName = [] + resName = [] + resAlter = [] + chainName = [] + resNum = [] + insertion = [] + coords = [] + occ = [] + temp = [] + chainID = [] + elemName = [] + print("> Reading pdb file %s ..." % pdb_file) + with open(pdb_file, "r") as f: + for line in f: + spl = line.split() + if len(spl) > 0: + if (spl[0] == 'ATOM'): # or (hetatm and spl[0] == 'HETATM'): + l = [line[:6], line[6:11], line[12:16], line[16], line[17:21], line[21], line[22:26], + line[26], line[30:38], + line[38:46], line[46:54], line[54:60], line[60:66], line[72:76], line[76:78]] + l = [i.strip() for i in l] + atom.append(l[0]) + atomNum.append(l[1]) + atomName.append(l[2]) + resAlter.append(l[3]) + resName.append(l[4]) + chainName.append(l[5]) + resNum.append(l[6]) + insertion.append(l[7]) + coords.append([float(l[8]), float(l[9]), float(l[10])]) + occ.append(l[11]) + temp.append(l[12]) + chainID.append(l[13]) + elemName.append(l[14]) + + atomNum = np.array(atomNum) + atomNum[np.where(atomNum == "*****")[0]] = "-1" + + self.atom = np.array(atom, dtype=' Writing pdb file %s ..." % file) + with open(file, "w") as file: + past_chainName = self.chainName[0] + past_chainID = self.chainID[0] + for i in range(len(self.atom)): + if past_chainName != self.chainName[i] or past_chainID != self.chainID[i]: + past_chainName = self.chainName[i] + past_chainID = self.chainID[i] + file.write("TER\n") + + atom = self.atom[i].ljust(6) # atom#6s + if self.atomNum[i] == -1 or self.atomNum[i] >= 100000: + atomNum = "99999" # aomnum#5d + else: + atomNum = str(self.atomNum[i]).rjust(5) # aomnum#5d + atomName = self.atomName[i].ljust(4) # atomname$#4s + resAlter = self.resAlter[i].ljust(1) # resAlter#1 + resName = self.resName[i].ljust(4) # resname#1s + chainName = self.chainName[i].rjust(1) # Astring + resNum = str(self.resNum[i]).rjust(4) # resnum + insertion = self.insertion[i].ljust(1) # resnum + coordx = str('%8.3f' % (float(self.coords[i][0]))).rjust(8) # x + coordy = str('%8.3f' % (float(self.coords[i][1]))).rjust(8) # y + coordz = str('%8.3f' % (float(self.coords[i][2]))).rjust(8) # z\ + occ = str('%6.2f' % self.occ[i]).rjust(6) # occ + temp = str('%6.2f' % self.temp[i]).rjust(6) # temp + chainID = str(self.chainID[i]).ljust(4) # elname + elemName = str(self.elemName[i]).rjust(2) # elname + file.write("%s%s %s%s%s%s%s%s %s%s%s%s%s %s%s\n" % ( + atom, atomNum, atomName, resAlter, resName, chainName, resNum, + insertion, coordx, coordy, coordz, occ, temp, chainID, elemName)) + file.write("END\n") + print("\t Done \n") + + def matchPDBatoms(self, reference_pdb, ca_only=False, matchingType=None): + """ + match atoms between the pdb and a reference pdb + :param reference_pdb: ContinuousflexPDBHandler + :param ca_only: True if carbon alph only + :param matchingType: 0= chain first, 1= segment ID first + :return: index of matching atoms + """ + print("> Matching PDBs atoms ...") + n_mols = 2 + + if matchingType == None: + chain_name_list1 = self.get_chain_list(chainType=0) + chain_name_list2 = reference_pdb.get_chain_list(chainType=0) + n_matching_chain_names = sum([i in chain_name_list2 for i in chain_name_list1]) + print("Chains list 1 : "+str(chain_name_list1)) + print("Chains list 1 : "+str(chain_name_list2)) + print("Number of match : "+str(n_matching_chain_names)) + + chain_id_list1 = self.get_chain_list(chainType=1) + chain_id_list2 = reference_pdb.get_chain_list(chainType=1) + n_matching_chain_ids = sum([i in chain_id_list2 for i in chain_id_list1]) + print("Seg list 1 : "+str(chain_id_list1)) + print("Seg list 1 : "+str(chain_id_list1)) + print("Number of match : "+str(n_matching_chain_ids)) + + if n_matching_chain_ids == 0 and n_matching_chain_names == 0 : + raise RuntimeError("No matching chains") + elif n_matching_chain_ids >=n_matching_chain_names: + matchingType = 1 + print("\t Matching segments %s ... "%n_matching_chain_ids) + elif n_matching_chain_ids < n_matching_chain_names: + matchingType = 0 + print("\t Matching chains %s ... "%n_matching_chain_names) + + + ids = [] + ids_idx = [] + for m in [self, reference_pdb]: + id_tmp = [] + id_idx_tmp = [] + for i in range(m.n_atoms): + if (not ca_only) or m.atomName[i] == "CA" or m.atomName[i] == "P": + id_tmp.append("%s_%i_%s_%s" % (m.chainName[i] if matchingType == 0 else m.chainID[i], + m.resNum[i], m.resName[i], m.atomName[i])) + id_idx_tmp.append(i) + ids.append(np.array(id_tmp)) + ids_idx.append(np.array(id_idx_tmp)) + + idx = [] + for i in range(len(ids[0])): + idx_line = [ids_idx[0][i]] + for m in range(1, n_mols): + idx_tmp = np.where(ids[0][i] == ids[m])[0] + if len(idx_tmp) == 1: + idx_line.append(ids_idx[m][idx_tmp[0]]) + elif len(idx_tmp) > 1: + print("\t Warning : One atom in mol#0 is matching several atoms in mol#%i : " % m) + + if len(idx_line) == n_mols: + idx.append(idx_line) + + if len(idx) == 0: + print("\t Warning : No matching coordinates") + + print("\t %i matching atoms " % len(np.array(idx))) + print("\t Done") + + return np.array(idx) + + def alignMol(self, reference_pdb, idx_matching_atoms=None): + print("> Aligning PDB ...") + + if idx_matching_atoms is not None: + c1 = reference_pdb.coords[idx_matching_atoms[:, 1]] + c2 = self.coords[idx_matching_atoms[:, 0]] + else: + c1 = reference_pdb.coords + c2 = self.coords + + rot, tran = self.alignCoords(c1,c2) + self_copy = self.copy() + self_copy.coords = np.dot(self_copy.coords, rot) + tran + print("\t Done \n") + + return self_copy + + @classmethod + def alignCoords(cls, coord_ref, coord): + sup = SVDSuperimposer() + sup.set(coord_ref, coord) + try: + sup.run() + rot, tran = sup.get_rotran() + except np.linalg.LinAlgError: + print("Error while aligning : SVD did not converge") + rot = np.eye(3) + tran = np.zeros(3) + return rot, tran + + def getRMSD(self, reference_pdb, align=False, idx_matching_atoms=None): + if align: + aligned = self.alignMol(reference_pdb=reference_pdb, idx_matching_atoms=idx_matching_atoms) + else: + aligned=self + if idx_matching_atoms is not None: + coord1 = reference_pdb.coords[idx_matching_atoms[:, 1]] + coord2 = aligned.coords[idx_matching_atoms[:, 0]] + else: + coord1 = reference_pdb.coords + coord2 = aligned.coords + return np.sqrt(np.mean(np.square(np.linalg.norm(coord1 - coord2, axis=1)))) + + def select_atoms(self, idx): + self.coords = self.coords[idx] + self.n_atoms = self.coords.shape[0] + self.atom = self.atom[idx] + self.atomNum = self.atomNum[idx] + self.atomName = self.atomName[idx] + self.resName = self.resName[idx] + self.resAlter = self.resAlter[idx] + self.chainName = self.chainName[idx] + self.resNum = self.resNum[idx] + self.insertion = self.insertion[idx] + self.elemName = self.elemName[idx] + self.occ = self.occ[idx] + self.temp = self.temp[idx] + self.chainID = self.chainID[idx] + + def get_chain_list(self, chainType=0): + if chainType == 0: + lst = list(set(self.chainName)) + else: + lst = list(set(self.chainID)) + lst.sort() + return lst + + def get_chain(self, chainName): + if not isinstance(chainName, list): + chainName=[chainName] + chainidx =[] + for i in chainName: + idx = np.where(self.chainName == i)[0] + if len(idx) == 0: + idx= np.where(self.chainID == i)[0] + chainidx = chainidx + list(idx) + return np.array(chainidx) + + def select_chain(self, chainName): + self.select_atoms(self.get_chain(chainName)) + + def copy(self): + return copy.deepcopy(self) + + def remove_alter_atom(self): + idx = [] + for i in range(self.n_atoms): + if self.resAlter[i] != "": + print("!!! Alter residue %s for atom %i"%(self.resName[i], self.atomNum[i])) + if self.resAlter[i] == "A": + idx.append(i) + self.resAlter[i]="" + else: + idx.append(i) + self.select_atoms(idx) + + def remove_hydrogens(self): + idx=[] + for i in range(self.n_atoms): + if not self.atomName[i].startswith("H"): + idx.append(i) + self.select_atoms(idx) + + def alias_atom(self, atomName, atomNew, resName=None): + n_alias = 0 + for i in range(self.n_atoms): + if self.atomName[i] == atomName: + if resName is not None : + if self.resName[i] == resName : + self.atomName[i] = atomNew + n_alias+=1 + else: + self.atomName[i] = atomNew + n_alias+=1 + print("%s -> %s : %i lines changed"%(atomName, atomNew, n_alias)) + + def alias_res(self, resName, resNew): + n_alias=0 + for i in range(self.n_atoms): + if self.resName[i] == resName : + self.resName[i] = resNew + n_alias+=1 + print("%s -> %s : %i lines changed"%(resName ,resNew, n_alias)) + return n_alias + + + def add_terminal_res(self): + aa = ["ALA", "CYS", "ASP", "GLU", "PHE", "GLY", "HIS", "ILE", "LYS", "LEU", "MET", "ASN", "PRO", + "GLN", "ARG", "SER", "THR", "VAL", "TRP", "TYR"] + past_chainName = self.chainName[0] + past_chainID = self.chainID[0] + for i in range(self.n_atoms-1): + if past_chainName != self.chainName[i+1] or past_chainID != self.chainID[i+1]: + if self.resName[i] in aa : + print("End of chain %s ; adding terminal residue to %s %i %s"% + (past_chainID,self.resName[i],self.resNum[i],self.atomName[i])) + resNum = self.resNum[i] + j=0 + while self.resNum[i-j] ==resNum : + self.resName[i - j] += "T" + j+=1 + else: + print("End of chain %s %s %i"% (past_chainID,self.resName[i],self.resNum[i])) + past_chainName = self.chainName[i+1] + past_chainID = self.chainID[i+1] + + + i = self.n_atoms-1 + if self.resName[i] in aa: + print("End of chain %s ; adding terminal residue to %s %i %s" % ( + past_chainID, self.resName[i], self.resNum[i], self.atomName[i])) + resNum = self.resNum[i] + j = 0 + while self.resNum[i - j] == resNum: + self.resName[i - j] += "T" + j += 1 + else: + print("End of chain %s %s %i" % (past_chainID, self.resName[i], self.resNum[i])) + + + def check_res_order(self): + chains = list(set(self.chainID)) + chains.sort() + new_idx = [] + for c in chains: + chain_idx = self.get_chain(c) + resNumlist = list(set(self.resNum[chain_idx])) + resNumlist.sort() + for i in range(len(resNumlist)): + idx = np.where(self.resNum[chain_idx] == resNumlist[i])[0] + new_idx += list(chain_idx[idx]) + self.select_atoms(np.array(new_idx)) + + + def atom_res_reorder(self, chainType=0): + if chainType ==0: + chains = list(set(self.chainName)) + else: + chains = list(set(self.chainID)) + chains.sort() + + # reorder atoms and res + for c in chains: + chain_idx = self.get_chain(c) + resNum = 1 + previousRes = str(self.resNum[chain_idx[0]]) + self.insertion[chain_idx[0]] + for i in range(len(chain_idx)): + currentRes = str(self.resNum[chain_idx[i]]) + self.insertion[chain_idx[i]] + + if currentRes != previousRes: + previousRes = currentRes + resNum +=1 + self.resNum[chain_idx[i]] = resNum + self.atomNum[chain_idx[i]] = i + 1 + + #remove insertions : + for i in range(self.n_atoms) : + self.insertion[i] = " " + + + def allatoms2ca(self): + new_idx = [] + for i in range(self.n_atoms): + if self.atomName[i] == "CA" or self.atomName[i] == "P": + new_idx.append(i) + return np.array(new_idx) + + def center(self): + self.coords -= np.mean(self.coords, axis=0) + diff --git a/continuousflex/protocols/utilities/pdb_parser.py b/continuousflex/protocols/utilities/pdb_parser.py new file mode 100644 index 0000000..ae0ebc8 --- /dev/null +++ b/continuousflex/protocols/utilities/pdb_parser.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python3 +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# m_inout.py - Library for coordinate input and output +# Part of the ModeHunter package, http://modehunter.biomachina.org +# +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# Request to cite published literature: +# +# When using this software in scholarly work please cite the publications(s) +# posted at http://modehunter.biomachina.org/fref.html +# +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# Legal notice: +# +# This software is copyrighted, (c) 2009, by Joseph N. Stember and Willy Wriggers +# under the following terms: +# +# The authors hereby grant permission to use, copy, modify, and re-distribute this +# software and its documentation for any purpose, provided that existing copyright +# notices are retained in all copies and that this notice is included verbatim in +# any distributions. No written agreement, license, or royalty fee is required for +# any of the authorized uses. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, +# INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +# OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE +# AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, +# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +# PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS +# IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +# MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +# +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +import numpy +import sys +import copy + +# global list with chemical element names +element_name = ["H", "HE", "LI", "BE", "B", "C", "N", "O", "F", "NE", + "NA", "MG", "AL", "SI", "P", "S", "CL", "AR", "K", "CA", + "SC", "TI", "V", "CR", "MN", "FE", "CO", "NI", "CU", "ZN"] + +# global list with corresponding atom masses +element_mass = [1.008, 4.003, 6.940, 9.012, 10.810, 12.011, 14.007, 16.000, 18.998, 20.179, + 22.990, 24.305, 26.982, 28.086, 30.974, 32.060, 35.453, 39.948, 39.102, 40.080, + 44.956, 47.880, 50.942, 51.996, 54.938, 55.847, 58.933, 58.700, 63.546, 65.380] + + +# global PDB class with data required structure +class PDB(object): + def __init__(self, recd="ATOM ", serial=1, type=" ", loc=" ", alt=" ", res=" ", chain=" ", seq=1, icode=" ", + x=0.0, y=0.0, z=0.0, occupancy=0.0, beta=0.0, footnote=0, segid=" ", element=" ", charge=" ", + weight=0.0): + self.recd = recd # 1- 6 + self.serial = serial # 7-11 + self.type = type # 13-14 + self.loc = loc # 15-16 + self.alt = alt # 17 + self.res = res # 18-21 + self.chain = chain # 22 + self.seq = seq # 23-26 + self.icode = icode # 27 + self.x = x # 31-38 + self.y = y # 39-46 + self.z = z # 47-54 + self.occupancy = occupancy # 55-60 + self.beta = beta # 61-66 + self.footnote = footnote # 68-70 + self.segid = segid # 73-76 + self.element = element # 77-78 + self.charge = charge # 79-80 + self.weight = weight # mass of atom assigned by read_pdb + + +# functions + +def m_inout_read_pdb(filename): + "Situs 2.x style pdb parser" + + pdb_list = [] + f = open(filename, 'r') + for line in f: + test_recd = line[0:5] + + # if test_recd.upper().strip() == "ATOM" or test_recd.upper() == "HETATM": + if ((test_recd.upper().strip() == "ATOM") or (test_recd.upper().strip() == "HETATM")): + # create new atom and assign standard fields + new_atom = PDB() + new_atom.recd = test_recd + try: + new_atom.serial = int(line[4:11]) + except: + pass + try: + new_atom.type = line[12:14] + except: + pass + try: + new_atom.loc = line[14:16] + except: + pass + try: + new_atom.alt = line[16] + except: + pass + try: + new_atom.res = line[17:21] + except: + pass + try: + new_atom.chain = line[21] + except: + pass + try: + new_atom.seq = int(line[22:26]) + except: + pass + try: + new_atom.icode = line[26] + except: + pass + try: + new_atom.x = float(line[30:38]) + except: + pass + try: + new_atom.y = float(line[38:46]) + except: + pass + try: + new_atom.z = float(line[46:54]) + except: + pass + try: + new_atom.occupancy = float(line[54:60]) + except: + pass + try: + new_atom.beta = float(line[60:66]) + except: + pass + try: + new_atom.footnote = int(line[67:70]) + except: + pass + try: + new_atom.segid = line[72:76] + except: + pass + try: + new_atom.element = line[76:78] + except: + pass + try: + new_atom.charge = line[78:80] + except: + pass + # compute robust Situs 2.x style mass weight and append atom + if (new_atom.type == "QV" and new_atom.loc == "OL") or (new_atom.type == "QP" and new_atom.loc == "DB"): + new_atom.weight = 0.0 # codebook vectors have zero mass + elif (new_atom.type == "DE" and new_atom.loc == "NS"): + new_atom.weight = new_atom.occupancy # volumetric map density mass assigned from occupancy field + elif (new_atom.type.lstrip()[0] == "H"): + new_atom.weight = element_mass[0] # quick hack for hydrogens, may return false positives for Hg, Hf, Ho + elif (new_atom.type.strip in element_name): + new_atom.weight = element_mass[element_name.index(new_atom.type.strip)] # standard element + elif (new_atom.type.strip()[0] in element_name): + new_atom.weight = element_mass[ + element_name.index(new_atom.type.strip()[0])] # catches frequent elements, C N O P S + else: + # Slavica: Mass of other atoms (eg, 1H,2H,3H, 1HH1, 2HH1, 1HD2, 2HD2 etc) to be incorporated later + # print "Warning: atom %i: unable to identify atom type %s, assigning carbon mass" % (len(pdb_list)+1,new_atom.type) + new_atom.weight = element_mass[5] + pdb_list.append(new_atom) + + f.close() + return pdb_list + + +def m_inout_write_pdb(pdb_list, filename, remarks): + "pdb writer, Situs 2.x convention, renumbering atoms" + + f = open(filename, 'w') + f.write("REMARKS " + remarks + "\n") + + for i in range(len(pdb_list)): + f.write(pdb_list[i].recd.strip()[:6].ljust(6)) + # renumber atoms, ignoring .serial + if ((i + 1) // 100000 == 0): + f.write("%5d" % (i + 1)) + else: + f.write("%05d" % (i + 1 - ((i + 1) // 100000) * 100000)) + f.write(" ") + f.write(pdb_list[i].type.strip()[:2].rjust(2)) + f.write(pdb_list[i].loc.strip()[:2].ljust(2)) + f.write(pdb_list[i].alt.strip()[:1].ljust(1)) + if (len(pdb_list[i].res) < 4): + f.write(pdb_list[i].res.strip().rjust(3)) + f.write(" ") + else: + f.write(pdb_list[i].res[:4]) + f.write(pdb_list[i].chain.strip()[:1].ljust(1)) + f.write("%4d" % pdb_list[i].seq) + f.write(pdb_list[i].icode.strip()[:1].ljust(1)) + f.write(" ") + f.write("%8.3f" % pdb_list[i].x) + f.write("%8.3f" % pdb_list[i].y) + f.write("%8.3f" % pdb_list[i].z) + f.write("%6.2f" % pdb_list[i].occupancy) + f.write("%6.2f" % pdb_list[i].beta) + f.write(" ") + f.write("%3d" % pdb_list[i].footnote) + f.write(" ") + f.write(pdb_list[i].segid.strip()[:4].ljust(4)) + f.write(pdb_list[i].element.strip()[:2].rjust(2)) + f.write(pdb_list[i].charge.strip()[:2].rjust(2)) + f.write("\n") + f.close() + + +def m_inout_write_pdb_sampled(pdb_name, filename, step, thr_mass): + "pdb writer, Situs 2.x convention, renumbering atoms" + + f = open(filename, 'w') + + pdb_list = m_inout_read_pdb(pdb_name) + + for i in range(0, len(pdb_list), step): + if pdb_list[i].beta > thr_mass: + f.write(pdb_list[i].recd.strip()[:6].ljust(6)) + # renumber atoms, ignoring .serial + if ((i + 1) // 100000 == 0): + f.write("%5d" % (i + 1)) + else: + f.write("%05d" % (i + 1 - ((i + 1) // 100000) * 100000)) + f.write(" ") + f.write(pdb_list[i].type.strip()[:2].rjust(2)) + f.write(pdb_list[i].loc.strip()[:2].ljust(2)) + f.write(pdb_list[i].alt.strip()[:1].ljust(1)) + if (len(pdb_list[i].res) < 4): + f.write(pdb_list[i].res.strip().rjust(3)) + f.write(" ") + else: + f.write(pdb_list[i].res[:4]) + f.write(pdb_list[i].chain.strip()[:1].ljust(1)) + f.write("%4d" % pdb_list[i].seq) + f.write(pdb_list[i].icode.strip()[:1].ljust(1)) + f.write(" ") + f.write("%8.3f" % pdb_list[i].x) + f.write("%8.3f" % pdb_list[i].y) + f.write("%8.3f" % pdb_list[i].z) + f.write("%6.2f" % pdb_list[i].occupancy) + f.write("%6.2f" % pdb_list[i].beta) + f.write(" ") + f.write("%3d" % pdb_list[i].footnote) + f.write(" ") + f.write(pdb_list[i].segid.strip()[:4].ljust(4)) + f.write(pdb_list[i].element.strip()[:2].rjust(2)) + f.write(pdb_list[i].charge.strip()[:2].rjust(2)) + f.write("\n") + f.close() + + +def m_inout_carbon_alphas(pdb_list): + "return 0-based indices of carbon alphas in pdb_list" + + cas = [] + for i in range(len(pdb_list)): + if (pdb_list[i].type == " C" and pdb_list[i].loc == "A "): + cas.append(i) + return cas + + +def m_inout_import_coords(filename): + "get x y z coords from PDB file" + coords = numpy.array([]) + pdb_list = m_inout_read_pdb(filename) + for i in numpy.arange(len(pdb_list)): + coords = numpy.append(coords, [pdb_list[i].x, pdb_list[i].y, pdb_list[i].z]) + return coords + + +def m_inout_import_bfact(filename): + "get Bfactor from PDB file" + bfact = numpy.array([]) + pdb_list = m_inout_read_pdb(filename) + for i in numpy.arange(len(pdb_list)): + bfact = numpy.append(bfact, [pdb_list[i].beta]) + return bfact \ No newline at end of file diff --git a/continuousflex/protocols/utilities/processing_dh/__init__.py b/continuousflex/protocols/utilities/processing_dh/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/continuousflex/protocols/utilities/processing_dh/data/__init__.py b/continuousflex/protocols/utilities/processing_dh/data/__init__.py new file mode 100644 index 0000000..d257e61 --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/data/__init__.py @@ -0,0 +1 @@ +from .cryoem_data import cryodata \ No newline at end of file diff --git a/continuousflex/protocols/utilities/processing_dh/data/cryoem_data.py b/continuousflex/protocols/utilities/processing_dh/data/cryoem_data.py new file mode 100644 index 0000000..d953cb2 --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/data/cryoem_data.py @@ -0,0 +1,107 @@ +import glob + +import numpy as np +from torch.utils.data import Dataset +from ..utils import spi2array, eul2quat, min_max +import torch +import pwem.emlib.metadata as md +class cryodata(Dataset): + + def __init__(self, path, output_path, flag='nma', mode = 'train', transform=None): + self.path = path + self.flag = flag + self.mode = mode + self.transform = transform + mdImgs = md.MetaData(self.path) + if mode == 'train': + rot = [] + tilt = [] + psi = [] + nma = [] + shift_x = [] + shift_y = [] + imgPath = [] + for objId in mdImgs: + imgPath.append(mdImgs.getValue(md.MDL_IMAGE, objId)) + rot.append(mdImgs.getValue(md.MDL_ANGLE_ROT, objId)) + tilt.append(mdImgs.getValue(md.MDL_ANGLE_TILT, objId)) + psi.append(mdImgs.getValue(md.MDL_ANGLE_PSI, objId)) + shift_x.append(mdImgs.getValue(md.MDL_SHIFT_X, objId)) + shift_y.append(mdImgs.getValue(md.MDL_SHIFT_Y, objId)) + nma.append(mdImgs.getValue(md.MDL_NMA, objId)) + self.images_Path = imgPath + rot_ = torch.tensor(rot) + tilt_ = torch.tensor(tilt) + psi_ = torch.tensor(psi) + shiftx = torch.tensor(shift_x) + shifty = torch.tensor(shift_y) + + self.angles = torch.column_stack((rot_, tilt_, psi_)) + self.quaternions = torch.zeros((self.angles.shape[0], 4), dtype=torch.float32) + for i in range(len(self.angles)): + self.quaternions[i, :] = torch.tensor(eul2quat(self.angles, i)) + self.shifts, min_shf, max_shf = min_max(torch.column_stack((shiftx, shifty))) + self.amplitudes, min_nma, max_nma = min_max(torch.tensor(nma, dtype=torch.float32)) + + min_max_nma = torch.row_stack((min_nma, max_nma)) + min_max_shf = torch.row_stack((min_shf, max_shf)) + np.savetxt(output_path + '/min_max_nma.txt', min_max_nma.numpy()) + np.savetxt(output_path + '/min_max_shf.txt', min_max_shf.numpy()) + elif self.mode=='inference': + imgPath = [] + for objId in mdImgs: + imgPath.append(mdImgs.getValue(md.MDL_IMAGE, objId)) + self.images_Path = imgPath + else: + pass + + + + def __len__(self): + return len(self.images_Path) + + def __getitem__(self, item): + if self.mode == 'train': + if self.flag == 'nma': + amplitudes = self.amplitudes[item] + image_name = self.images_Path[item] + spi_array = spi2array(image_name) + if self.transform: + spi_array = self.transform(spi_array) + amplitudes = torch.tensor(amplitudes) + return spi_array, amplitudes + elif self.flag == 'ang': + angles = self.quaternions[item] + image_name = self.images_Path[item] + spi_array = spi2array(image_name) + if self.transform: + spi_array = self.transform(spi_array) + angles = torch.tensor(angles) + return spi_array, angles, image_name + elif self.flag == 'shf': + shifts = self.shifts[item] + image_name = self.images_Path[item] + spi_array = spi2array(image_name) + if self.transform: + spi_array = self.transform(spi_array) + shifts = torch.tensor(shifts) + return spi_array, shifts + elif self.flag=='all': + amplitudes = self.amplitudes[item] + angles = self.quaternions[item] + shifts = self.shifts[item] + image_name = self.images_Path[item] + spi_array = spi2array(image_name) + if self.transform: + spi_array = self.transform(spi_array) + amplitudes = torch.tensor(amplitudes) + angles = torch.tensor(angles) + shifts = torch.tensor(shifts) + params = torch.cat([amplitudes, angles, shifts]) + return spi_array, params + elif self.mode == 'inference': + image_name = self.images_Path[item] + spi_array = spi2array(image_name) + if self.transform: + spi_array = self.transform(spi_array) + return spi_array, image_name diff --git a/continuousflex/protocols/utilities/processing_dh/models/__init__.py b/continuousflex/protocols/utilities/processing_dh/models/__init__.py new file mode 100644 index 0000000..42420ed --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/models/__init__.py @@ -0,0 +1,5 @@ +from .resnet import ResNet +from .mlp import mlp +from .resnet import Bottleneck, BasicBlock +from .deep_hemnma import deephemnma +from .losses import loss diff --git a/continuousflex/protocols/utilities/processing_dh/models/deep_hemnma.py b/continuousflex/protocols/utilities/processing_dh/models/deep_hemnma.py new file mode 100644 index 0000000..465b5e5 --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/models/deep_hemnma.py @@ -0,0 +1,33 @@ +import torch.nn as nn +import torch +from . import ResNet, mlp, Bottleneck, BasicBlock +#from utils import projectPDB_NP, normalize, torch_normalize, quater2euler + + + +class deephemnma(nn.Module): + def __init__(self, output): + super(deephemnma, self).__init__() + self.output = output + self.resnet = ResNet(BasicBlock, [3, 4, 6, 3]) + self.mlp = mlp(output) + """ + def forward(self, x, pdb, mode = 'train'): + resnet = self.resnet(x) + flat = torch.flatten(resnet, start_dim=1) + mlp = self.mlp(flat) + if mode == 'train': + proj_imgs = torch.ones_like(x) + for i in range(mlp.shape[0]): + mlp_ = quater2euler(mlp[i,:]) + proj_imgs[i] = torch_normalize(projectPDB_NP(pdb.to('cpu'), 128, 2.96, 1, mlp_[0].to('cpu'), mlp_[1].to('cpu'), mlp_[2].to('cpu'), 0, 0, 0)) + return mlp, proj_imgs.to('cuda:0') + elif mode == 'inference': + return mlp + """ + def forward(self, x, mode = 'train'): + resnet = self.resnet(x) + flat = torch.flatten(resnet, start_dim=1) + mlp = self.mlp(flat) + return mlp + diff --git a/continuousflex/protocols/utilities/processing_dh/models/losses.py b/continuousflex/protocols/utilities/processing_dh/models/losses.py new file mode 100644 index 0000000..cb9c76b --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/models/losses.py @@ -0,0 +1,49 @@ +import torch +import torch.nn.functional as F +import numpy as np + + +def loss(*args): + inp_img = args[0] + pred_img = args[1] + inp = args[2] + pred = args[3] + + l1 = L1(inp, pred) + cc_loss = cc(inp_img, pred_img) + + loss = l1+cc_loss + return loss + +def mse(*args): + input_image = args[0] + projected_image = args[1] + loss = F.mse_loss(input_image, projected_image) + return loss + + + +def cc(img1, img2, reduction = 'mean'): + img1 = img1 - torch.mean(img1, dim = (1, 2))[...,None, None] + img2 = img2 - torch.mean(img2, dim = (1, 2))[...,None, None] + cc = torch.sum(img1*img2, dim = (1,2)) + p1 = torch.sqrt(torch.sum(img1*img1, dim=(1,2))) + p2 = torch.sqrt(torch.sum(img2*img2, dim=(1,2))) + ncc = cc/(p1*p2) + if reduction == 'mean': + res = torch.mean(ncc) + return res + elif reduction == 'sum': + res = torch.sum(ncc) + return res + else: + raise ValueError('Unknown flag, you must select reduce or sum for loss redeuction mode') + + + +def L1(*args): + input = args[0] + infer = args[1] + loss = F.l1_loss(input, infer) + return loss + diff --git a/continuousflex/protocols/utilities/processing_dh/models/mlp.py b/continuousflex/protocols/utilities/processing_dh/models/mlp.py new file mode 100644 index 0000000..f052e4e --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/models/mlp.py @@ -0,0 +1,23 @@ +import torch.nn as nn + +class mlp(nn.Module): + def __init__(self, output): + super(mlp, self).__init__() + + hidden_dims = [512,1000, 512, 128] + modules = [] + for i in range(len(hidden_dims)-1): + modules.append(nn.Sequential(nn.Linear(hidden_dims[i], hidden_dims[i+1]), + nn.LayerNorm(hidden_dims[i+1]), + nn.GELU(), + + )) + self.mlp_ = nn.Sequential(*modules) + + self.output_layer = nn.Linear(hidden_dims[-1], output) + + def forward(self, x): + mlp_ = self.mlp_(x) + elu = nn.ELU() + output_layer = elu(self.output_layer(mlp_)) + return output_layer diff --git a/continuousflex/protocols/utilities/processing_dh/models/resnet.py b/continuousflex/protocols/utilities/processing_dh/models/resnet.py new file mode 100644 index 0000000..cfc3e9a --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/models/resnet.py @@ -0,0 +1,238 @@ +import torch +import torch.nn as nn +from torch import Tensor +from typing import Type, Any, Callable, Union, List, Optional + + +def conv3x3(in_planes: int, out_planes: int, stride: int = 1, groups: int = 1, dilation: int = 1) -> nn.Conv2d: + """3x3 convolution with padding""" + return nn.Conv2d( + in_planes, + out_planes, + kernel_size=3, + stride=stride, + padding=dilation, + groups=groups, + bias=False, + dilation=dilation, + ) + + +def conv1x1(in_planes: int, out_planes: int, stride: int = 1) -> nn.Conv2d: + """1x1 convolution""" + return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False) + + +class BasicBlock(nn.Module): + expansion: int = 1 + + def __init__( + self, + inplanes: int, + planes: int, + stride: int = 1, + downsample: Optional[nn.Module] = None, + groups: int = 1, + base_width: int = 64, + dilation: int = 1, + norm_layer: Optional[Callable[..., nn.Module]] = None, + ) -> None: + super().__init__() + if norm_layer is None: + norm_layer = nn.BatchNorm2d + if groups != 1 or base_width != 64: + raise ValueError("BasicBlock only supports groups=1 and base_width=64") + if dilation > 1: + raise NotImplementedError("Dilation > 1 not supported in BasicBlock") + # Both self.conv1 and self.downsample layers downsample the input when stride != 1 + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = norm_layer(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = norm_layer(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x: Tensor) -> Tensor: + identity = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + identity = self.downsample(x) + + out += identity + out = self.relu(out) + + return out + + +class Bottleneck(nn.Module): + expansion: int = 4 + + def __init__( + self, + inplanes: int, + planes: int, + stride: int = 1, + downsample: Optional[nn.Module] = None, + groups: int = 1, + base_width: int = 64, + dilation: int = 1, + norm_layer: Optional[Callable[..., nn.Module]] = None, + ) -> None: + super().__init__() + if norm_layer is None: + norm_layer = nn.BatchNorm2d + width = int(planes * (base_width / 64.0)) * groups + # Both self.conv2 and self.downsample layers downsample the input when stride != 1 + self.conv1 = conv1x1(inplanes, width) + self.bn1 = norm_layer(width) + self.conv2 = conv3x3(width, width, stride, groups, dilation) + self.bn2 = norm_layer(width) + self.conv3 = conv1x1(width, planes * self.expansion) + self.bn3 = norm_layer(planes * self.expansion) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x: Tensor) -> Tensor: + identity = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + identity = self.downsample(x) + + out += identity + out = self.relu(out) + + return out + + +class ResNet(nn.Module): + def __init__( + self, + block: Type[Union[BasicBlock, Bottleneck]], + layers: List[int], + zero_init_residual: bool = False, + groups: int = 1, + width_per_group: int = 64, + replace_stride_with_dilation: Optional[List[bool]] = None, + norm_layer: Optional[Callable[..., nn.Module]] = None, + ) -> None: + super().__init__() + if norm_layer is None: + norm_layer = nn.BatchNorm2d + self._norm_layer = norm_layer + + self.inplanes = 64 + self.dilation = 1 + if replace_stride_with_dilation is None: + # each element in the tuple indicates if we should replace + # the 2x2 stride with a dilated convolution instead + replace_stride_with_dilation = [False, False, False] + if len(replace_stride_with_dilation) != 3: + raise ValueError( + "replace_stride_with_dilation should be None " + f"or a 3-element tuple, got {replace_stride_with_dilation}" + ) + self.groups = groups + self.base_width = width_per_group + self.conv1 = nn.Conv2d(1, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False) + self.bn1 = norm_layer(self.inplanes) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2, dilate=replace_stride_with_dilation[0]) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2, dilate=replace_stride_with_dilation[1]) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2, dilate=replace_stride_with_dilation[2]) + self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity="relu") + elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + + if zero_init_residual: + for m in self.modules(): + if isinstance(m, Bottleneck): + nn.init.constant_(m.bn3.weight, 0) # type: ignore[arg-type] + elif isinstance(m, BasicBlock): + nn.init.constant_(m.bn2.weight, 0) # type: ignore[arg-type] + + def _make_layer( + self, + block: Type[Union[BasicBlock, Bottleneck]], + planes: int, + blocks: int, + stride: int = 1, + dilate: bool = False, + ) -> nn.Sequential: + norm_layer = self._norm_layer + downsample = None + previous_dilation = self.dilation + if dilate: + self.dilation *= stride + stride = 1 + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + conv1x1(self.inplanes, planes * block.expansion, stride), + norm_layer(planes * block.expansion), + ) + + layers = [] + layers.append( + block( + self.inplanes, planes, stride, downsample, self.groups, self.base_width, previous_dilation, norm_layer + ) + ) + self.inplanes = planes * block.expansion + for _ in range(1, blocks): + layers.append( + block( + self.inplanes, + planes, + groups=self.groups, + base_width=self.base_width, + dilation=self.dilation, + norm_layer=norm_layer, + ) + ) + + return nn.Sequential(*layers) + + def _forward_impl(self, x: Tensor) -> Tensor: + # See note [TorchScript super()] + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + x = self.layer4(x) + + x = self.avgpool(x) + + return x + + def forward(self, x: Tensor) -> Tensor: + return self._forward_impl(x) \ No newline at end of file diff --git a/continuousflex/protocols/utilities/processing_dh/utils/__init__.py b/continuousflex/protocols/utilities/processing_dh/utils/__init__.py new file mode 100644 index 0000000..6d63a36 --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/utils/__init__.py @@ -0,0 +1,8 @@ +from .metadata import read_file +from .metadata import min_max, standardization, reverse_min_max, reverse_standardization +from .spi_reader import spi2array, normalize, torch_normalize +from .spi_reader import read_from_list, read_from_directory +from .pdb_reader import read_pdb, parse_pdb +from .euler2quaternion import eul2quat, quater2euler +from .projection import projectPDB2Image +from .projection import projectPDB_NP diff --git a/continuousflex/protocols/utilities/processing_dh/utils/edit_file.py b/continuousflex/protocols/utilities/processing_dh/utils/edit_file.py new file mode 100644 index 0000000..30f9574 --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/utils/edit_file.py @@ -0,0 +1,20 @@ +import os +import glob +import numpy as np + +def edit(path): + with open(path, 'r') as f: + lines = f.readlines() + for i in range(len(lines)): + if i < 13: + pass + else: + lines[i] = lines[i].replace(lines[i][0:72], 'synthimages_set/img'+lines[i][0:6]+'.spi') + with open('../images.xmd', 'w') as output: + for i in range(len(lines)): + output.write(lines[i]) + output.close() + + + +edit('../images.xmd') diff --git a/continuousflex/protocols/utilities/processing_dh/utils/euler2quaternion.py b/continuousflex/protocols/utilities/processing_dh/utils/euler2quaternion.py new file mode 100644 index 0000000..81d9d03 --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/utils/euler2quaternion.py @@ -0,0 +1,62 @@ +import numpy as np +from math import cos, sin, atan2, acos, radians, degrees +import torch +def eul2quat(arr, i): + rot = radians(arr[i,0]) + tilt = radians(arr[i,1]) + psi = radians(arr[i,2]) + + quaternion = [(cos(rot/2)*cos(tilt/2)*cos(psi/2))-(sin(rot/2)*cos(tilt/2)*sin(psi/2)), + (cos(rot/2)*sin(tilt/2)*sin(psi/2))-(sin(rot/2)*sin(tilt/2)*cos(psi/2)), + (cos(rot/2)*sin(tilt/2)*cos(psi/2))+(sin(rot/2)*sin(tilt/2)*sin(psi/2)), + (cos(rot/2)*cos(tilt/2)*sin(psi/2))+(sin(rot/2)*cos(tilt/2)*cos(psi/2))] + return quaternion + + + +def quater2euler(arr): + qw = arr[0] + qx = arr[1] + qy = arr[2] + qz = arr[3] + + tilt = (qw**2)-(qx**2)-(qy**2)+(qz**2) + if tilt > 1: + tilt = 1.0 + elif tilt <-1: + tilt = -1.0 + else: + pass + + euler = [degrees(atan2(2*((qy*qz)-(qw*qx)),2*((qx*qz)+(qw*qy)))), + degrees(acos(tilt)), + degrees(atan2(2*((qy*qz)+(qw*qx)),-2*((qx*qz)-(qw*qy))))] + + return euler + + +def quat2rotm(arr): + + q0 = arr[0] + q1 = arr[1] + q2 = arr[2] + q3 = arr[3] + + I = np.array([[1,0,0],[0,1,0],[0,0,1]]) + A = np.array([[0, -q3, q2],[q3, 0, -q1],[-q2, q1, 0]]) + + rot_mat = I + 2 * q0 * A + 2 * A * A + return rot_mat + +""" +a = np.array([[134.81444 , 131.236146, 356.849227],[90, 90, 90]], dtype='float32') + +example = eul2quat(a,0) +print("quaternions ",example) + + +example2 = quater2euler(example) + +print("angles in degrees",example2) +""" + diff --git a/continuousflex/protocols/utilities/processing_dh/utils/metadata.py b/continuousflex/protocols/utilities/processing_dh/utils/metadata.py new file mode 100644 index 0000000..3d7984f --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/utils/metadata.py @@ -0,0 +1,145 @@ +""" +This file reads, cleans an 'xmd' file and +create a dataframe and a numpy array that +contains only the normal modes amplitudes +""" + +import re +import numpy as np +from math import cos, sin, radians +from .euler2quaternion import eul2quat +import torch + +def header(path): + num_chars = 20 + head = 0 + with open(path, 'r') as f: + lines = f.readlines() + for line in lines: + if len(line) < num_chars: + head+=1 + else: + pass + return head + +def read_file(path): + head = header(path) + f = open(path, 'r') + file_list = f.readlines() + column_names = [col.replace('\n', '') for col in file_list[4:head]] + for i in range(head): + file_list.pop(0) + return file_list, column_names + + +def create_array(path, flag='nma'): + file_list, column_names = read_file(path) + columns = len(list(filter(None,re.split("\s|'", file_list[0])))) + num_modes = columns-(len(column_names)-1) + nma_index = column_names.index(' _nmaDisplacements') + for i in range(num_modes): + column_names.insert(nma_index, 'mode '+str(num_modes - i)) + column_names.remove(' _nmaDisplacements') + img_index = column_names.index(' _image') + rot_index = column_names.index(' _angleRot') + tilt_index = column_names.index(' _angleTilt') + psi_index = column_names.index(' _anglePsi') + shiftx_index = column_names.index(' _shiftX') + shifty_index = column_names.index(' _shiftY') + + for i in range(len(file_list)): + file_list[i] = file_list[i].replace('\n', ' ') + file_list[i] = list(filter(None, re.split("\s|'",file_list[i]))) + + data_array=np.reshape(file_list,(len(file_list),columns)) + img_names=data_array[:,img_index] + nm_amplitudes = data_array[:, nma_index: nma_index+num_modes].astype('float32') + nm_amplitudes, nma_min, nma_max = min_max(nm_amplitudes) + angles = data_array[:, [rot_index, tilt_index, psi_index]].astype('float32') + shifts = data_array[:, [shiftx_index, shifty_index]].astype('float32') + shifts, shf_min, shf_max = min_max(shifts) + quaternions = np.zeros((angles.shape[0], 4), dtype='float32') + for i in range(len(angles)): + quaternions[i,:] = eul2quat(angles, i) + if flag=='nma': + print("Number of Normal Modes detected is: ",num_modes) + return nm_amplitudes, nma_min, nma_max, img_names + elif flag=='ang': + return quaternions, img_names + elif flag=='shf': + return shifts, shf_min, shf_max, img_names + else: + raise ValueError('Unknown flag, you must select nma for Normal mode amplitudes, ang for euler angles, shf for shifts (X and Y)') + + +def min_max(arr): + _min = torch.min(arr, dim=0) + _max = torch.max(arr, dim=0) + arr = (arr - _min[0]) / (_max[0] - _min[0]) + return arr, _min[0], _max[0] + + +def standardization(arr, params: bool = False, num_modes: int = 3): + _mean = [] + _mu = [] + num_params = 0 + if params: + num_params = num_modes + 5 + else: + num_params = num_modes + for i in range(num_params): + _mean.append(np.mean(arr[:, i])) + _mu.append(np.std(arr[:, i])) + for i in range(num_params): + for j in range(len(arr)): + tmp = arr[j, i] + arr[j, i] = (tmp-_mean[i])/_mu[i] + return arr, _mean, _mu + +def reverse_min_max(arr, _min, _max): + """ + This function rescale back the target values to its original range + it rescaled it back and put it in a list then reshape it to an array + of the same shape as the input + Parameters + ---------- + arr : numpy array float32 + a numpy array for example (100,3). + + Returns + ------- + rescaled_output : numpy array float32 + rescaled_output: a numpy array of the same shape as input for + example (100, 3). + + """ + return (arr * (_max - _min)) + _min + +def reverse_standardization(arr, _mean, _mu, params: bool = False, num_modes:int =3): + num_params = 0 + if params: + num_params = num_modes + 5 + else: + num_params = num_modes + rescaled_list = [] + for i in range(len(arr)): + for j in range(params): + rescaled_list.append((arr[i,j]*_mu[j])+_mean[j]) + rescaled_output = np.array(rescaled_list).reshape((len(arr), num_params)) + return rescaled_output + + + +def rotation_matrix(euler_angles): + rot = radians(euler_angles[0]) + tilt = radians(euler_angles[1]) + psi = radians(euler_angles[2]) + rot_mat = np.array([[(cos(rot)*cos(tilt)*cos(psi))-(sin(rot)*sin(psi)), + (-cos(psi)*sin(rot))-(cos(rot)*cos(tilt)*sin(psi)), + (cos(rot)*sin(tilt))], + [(cos(rot)*sin(psi))+(cos(tilt)*cos(psi)*sin(rot)), + (cos(rot)*cos(psi))-(cos(tilt)*sin(rot)*sin(psi)), + (sin(rot)*sin(tilt))], + [-cos(psi)*sin(tilt), sin(psi)*sin(tilt),cos(tilt)]]) + + return rot_mat diff --git a/continuousflex/protocols/utilities/processing_dh/utils/pdb_reader.py b/continuousflex/protocols/utilities/processing_dh/utils/pdb_reader.py new file mode 100644 index 0000000..b4fc6aa --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/utils/pdb_reader.py @@ -0,0 +1,68 @@ +import numpy as np +from sklearn.preprocessing import StandardScaler + +def read_pdb(path, ca = False): + with open(path, 'r') as f: + lines = f.readlines() + pdb_list = [] + for line in lines: + line = line[:38] + " " + line[38:] + line = line[:47] + " " + line[47:] + line = line[:62] + " " + line[62:] + if ca: + if line.startswith("ATOM") and " CA " in line: + line = line.split() + pdb_list.append(line[6:9]) + else: + pass + else: + if line.startswith("ATOM"): + line = line.split() + pdb_list.append(line[6:9]) + else: + pass + + # pythonic way + #lines = [line.split for line in lines] + #lines = [line for line in lines if "ATOM" in line] + #if ca: + # lines = [line for line in lines if " CA " in line] + #lines + pdb_array = np.array(pdb_list, dtype='float32') + coords = pdb_array + return coords + +def parse_pdb(path, atom_p, i): + """ + ---------- + This function generates the predicted pdb. + + Parameters + ---------- + path : string path to the reference structure. + atom_p: numpy array of the predicted atom positions. + + Returns + ------- + """ + with open(path, 'r') as f: + lines = f.readlines() + lines = [line for line in lines if 'ATOM' in line] + atom = [line[0:4] for line in lines] + serial = ['{:>7}'.format(line[4:12].strip()) for line in lines] + atom_name = ['{:>4}'.format(line[12:17].strip()) for line in lines] + loc_ind = ['{:>5}'.format(line[17:20].strip()) for line in lines] + residue_name = ['{:>2}'.format(line[21:22].strip()) for line in lines] + chain_id = ['{:>4}'.format(line[23:28].strip()) for line in lines] + occupancy = ['{:>6}'.format(line[56:60].strip()) for line in lines] + temperature = ['{:>6}'.format(line[60:67].strip()) for line in lines] + elem_symb = ['{:>12}'.format(line[77:80].strip()) for line in lines] + with open('synth'+str(i)+'.pdb','w') as f: + for i in range(len(lines)): + pos = '{:>12.6}{:>8.6}{:>8.5}'.format(atom_p[i,0],atom_p[i,1],atom_p[i,2]) + line = atom[i]+serial[i]+atom_name[i]+loc_ind[i]+residue_name[i]+chain_id[i]+\ + pos+occupancy[i]+temperature[i]+elem_symb[i]+'\n' + f.write(line) + +def standard_pdb(coords): + return (coords-np.mean(coords,axis=(0)))/np.std(coords,axis=(0)) diff --git a/continuousflex/protocols/utilities/processing_dh/utils/projection.py b/continuousflex/protocols/utilities/processing_dh/utils/projection.py new file mode 100644 index 0000000..9cc8e4c --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/utils/projection.py @@ -0,0 +1,233 @@ +import numpy as np +from struct import pack +import torch +import multiprocessing as multiprocessing + +def readPDB(fnIn): + with open(fnIn) as f: + lines = f.readlines() + return lines + + +def PDB2List(lines): + newlines = [] + for line in lines: + if line.startswith("ATOM "): + try: + x = float(line[30:38]) + y = float(line[38:46]) + z = float(line[46:54]) + newline = [x, y, z] + newlines.append(newline) + except: + pass + return newlines + + +def pdb_to_array(fnIn): + return torch.Tensor(PDB2List(readPDB(fnIn))) + + +def euler_matrix(rot, tilt, psi): + from math import sin, cos, radians + t1 = -torch.deg2rad(psi) + t2 = -torch.deg2rad(tilt) + t3 = -torch.deg2rad(rot) + a11 = torch.cos(t1) * torch.cos(t2) * torch.cos(t3) - torch.sin(t1) * torch.sin(t3) + a12 = -torch.cos(t3) * torch.sin(t1) - torch.cos(t1) * torch.cos(t2) * torch.sin(t3) + a13 = torch.cos(t1) * torch.sin(t2) + a21 = torch.cos(t1) * torch.sin(t3) + torch.cos(t2) * torch.cos(t3) * torch.sin(t1) + a22 = torch.cos(t1) * torch.cos(t3) - torch.cos(t2) * torch.sin(t1) * torch.sin(t3) + a23 = torch.sin(t1) * torch.sin(t2) + a31 = -torch.cos(t3) * torch.sin(t2) + a32 = torch.sin(t2) * torch.sin(t3) + a33 = torch.cos(t2) + T = torch.tensor([[a11, a12, a13], [a21, a22, a23], [a31, a32, a33]]) + return T + + +def projectPDBPixel(pdb_coordinates, s, t, sigma): + # Auxilary function, not meant to be used standalone + row_size, column_size = pdb_coordinates.shape + ng = row_size + # print(row_size,column_size) + sum_of_gaussians = 0 + sl_v = pdb_coordinates[:,0] + tl_v = pdb_coordinates[:,1] + s_v = torch.ones_like(sl_v)*s + t_v = torch.ones_like(tl_v)*t + + exp_arg = -((s_v-sl_v)**2 + (t_v-tl_v)**2)/(2*sigma**2) + exp_vec = torch.exp(exp_arg) + return torch.sum(exp_vec, dim = 2) +def projectPDB_NP(PDB, size, sampling_rate =1, sigma=1, rot=0, tilt=0, psi=0, shift_x=0, shift_y=0, shift_z=0): + #T = torch.linalg.inv(euler_matrix(torch.tensor(rot, dtype=torch.float), torch.tensor(tilt, dtype=torch.float), torch.tensor(psi, dtype=torch.float))) + #PDB = torch.matmul(PDB, T)/sampling_rate + PDB = PDB/sampling_rate + shifts = torch.ones_like(PDB) + shifts[:, 0] = shifts[:, 0] * shift_x + shifts[:, 1] = shifts[:, 1] * shift_y + shifts[:, 2] = shifts[:, 2] * shift_z + PDB += shifts + + PDB = (PDB - torch.mean(PDB) ) + + projection = torch.zeros([size, size]) + + limit = int(size/2) + l = torch.arange(-limit, limit, 1) + y, x = torch.meshgrid(l, l) + x = x.unsqueeze(2) + xx = x.repeat(1,1,PDB.shape[0]) + y = y.unsqueeze(2) + yy = y.repeat(1,1,PDB.shape[0]) + res = projectPDBPixel(PDB, xx, yy, sigma) + return res + +def projectPDB2Image(PDB, size, sampling_rate =1, sigma=1, rot=0, tilt=0, psi=0, shift_x=0, shift_y=0, shift_z=0): + # This function gives the same views as xmipp_phantom_project, however, it performs the projection by representing + # atoms by 3D Gaussians + + # PDB: array of atomic coordinates + # size: image size that you want + # sampling rate: the sampling rate on the image + # sigma: the Gaussian size for each atom (here the projection is with fixed Gaussian) + # rot, tilt, psi: Euler angles of the view + # shift_x, shift_y, shift_z: the shifting applied to the atomic structure before projection + T = torch.linalg.inv(euler_matrix(torch.tensor(rot, dtype=torch.float), torch.tensor(tilt, dtype=torch.float), torch.tensor(psi, dtype=torch.float))) + PDB = torch.matmul(PDB, T.to('cpu')) / sampling_rate + shifts = torch.ones_like(PDB) + shifts[:, 0] = shifts[:, 0] * shift_x + shifts[:, 1] = shifts[:, 1] * shift_y + shifts[:, 2] = shifts[:, 2] * shift_z + PDB += shifts + + # projection = np.zeros([size, size]) + limit = int(size/2) + l = torch.arange(-limit, limit, 1) + x, y = torch.meshgrid(l, l) + xv = torch.reshape(x, (-1,)) + yv = torch.reshape(y, (-1,)) + ps = [(xv[i], yv[i]) for i in range(len(xv))] + + global segment + def segment(p): + return projectPDBPixel(PDB, p[0], p[1], sigma) + with multiprocessing.Pool(20) as pool: + values = pool.map(segment,ps) + values = torch.reshape(list(values),[size,size]) + return values + + +def PDBVoxel(pdb_coordinates,r, s, t, sigma, sampling_rate): + # Auxilary function, not meant to be used standalone + row_size, column_size = pdb_coordinates.shape + ng = row_size + # print(row_size,column_size) + rl_v = pdb_coordinates[:,0]/sampling_rate + sl_v = pdb_coordinates[:,1]/sampling_rate + tl_v = pdb_coordinates[:,2]/sampling_rate + r_v = np.ones_like(rl_v)*r + s_v = np.ones_like(sl_v)*s + t_v = np.ones_like(tl_v)*t + exp_arg = -((r_v-rl_v)**2 + (s_v-sl_v)**2 + (t_v-tl_v)**2)/(2*sigma**2) + exp_vec = np.exp(exp_arg) + return np.sum(exp_vec) + + +def PDB2Volume(PDB, volume_size, sigma, sampling_rate): + # This function gives the same as xmipp_volume_from_pdb, however, it represents atoms by 3D Gaussians + + # PDB: array of atomic coordinates + # volume_size: output volume size + # sampling rate: the sampling rate + # sigma: the Gaussian size for each atom + + limit = int(volume_size/2) + z, y, x = np.mgrid[-limit:limit, -limit:limit, -limit:limit] + xv = np.reshape(x, -1) + yv = np.reshape(y, -1) + zv = np.reshape(z, -1) + ps = [(xv[i], yv[i], zv[i]) for i in range(len(xv))] + + global segment + + def segment(p): + return PDBVoxel(PDB, p[0], p[1], p[2], sigma, sampling_rate) + with multiprocessing.Pool(processes = 8) as pool: + values = pool.map(segment,ps) + values = np.reshape(list(values),[volume_size,volume_size,volume_size]) + return values + + +def save_volume(vol, filename): + vol = np.float32(vol) + # From the spider format: + labels = {i - 1: v for i, v in [ + (1, 'NZ'), + (2, 'NY'), + (3, 'IREC'), + (5, 'IFORM'), + (6, 'IMAMI'), + (7, 'FMAX'), + (8, 'FMIN'), + (9, 'AV'), + (10, 'SIG'), + (12, 'NX'), + (13, 'LABREC'), + (14, 'IANGLE'), + (15, 'PHI'), + (16, 'THETA'), + (17, 'GAMMA'), + (18, 'XOFF'), + (19, 'YOFF'), + (20, 'ZOFF'), + (21, 'SCALE'), + (22, 'LABBYT'), + (23, 'LENBYT'), + (24, 'ISTACK/MAXINDX'), + (26, 'MAXIM'), + (27, 'IMGNUM'), + (28, 'LASTINDX'), + (31, 'KANGLE'), + (32, 'PHI1'), + (33, 'THETA1'), + (34, 'PSI1'), + (35, 'PHI2'), + (36, 'THETA2'), + (37, 'PSI2'), + (38, 'PIXSIZ'), + (39, 'EV'), + (40, 'PROJ'), + (41, 'MIC'), + (42, 'NUM'), + (43, 'GLONUM'), + (101, 'PSI3'), + (102, 'THETA3'), + (103, 'PHI3'), + (104, 'LANGLE')]} + + # Inverse. + locations = {v: k for k, v in labels.items()} + """Save volume vol into a file, with the spider format.""" + nx, ny, nz = vol.shape + fields = [0.0] * nx + values = { + 'NZ': nz, 'NY': ny, + 'IREC': 3, # number of records (including header records) + 'IFORM': 3, # 3D volume + 'FMAX': vol.max(), 'FMIN': vol.min(), + 'AV': vol.mean(), 'SIG': vol.std(), + 'NX': nx, + 'LABREC': 1, # number of records in file header (label) + 'SCALE': 1, + 'LABBYT': 4 * nx, # number of bytes in header + 'LENBYT': 4 * nx, # record length in bytes (only 1 in our header) + } + for label, value in values.items(): + fields[locations[label]] = float(value) + header = pack('%df' % nx, *fields) + with open(filename, 'wb') as f: + f.write(header) + vol.tofile(f) + diff --git a/continuousflex/protocols/utilities/processing_dh/utils/spi_reader.py b/continuousflex/protocols/utilities/processing_dh/utils/spi_reader.py new file mode 100644 index 0000000..706edc2 --- /dev/null +++ b/continuousflex/protocols/utilities/processing_dh/utils/spi_reader.py @@ -0,0 +1,74 @@ +""" +This file reads and displays SPIDER +'single' image using PIL (pillow) module + +""" + +# import PIL module +from PIL import Image +import glob as glob +import numpy as np +import matplotlib.pyplot as plt +#import mrcfile +from tqdm import tqdm +import torch +from pwem.emlib.image import ImageHandler + +""" +def spi2array(f_name) -> object: + spi_image = Image.open(f_name, 'r') + spi_array = np.array(spi_image, dtype='float32') + spi_array = normalize(spi_array) + return spi_array +""" +def spi2array(f_name) -> object: + spi_array = ImageHandler().read(f_name).getData() + return spi_array + + +# read SPIDER dataset from directory +def read_from_directory(dataset_path) -> object: + spi_dataset = [] + for img_path in glob.glob(dataset_path + '/*.spi'): + spi_dataset.append(spi2array(img_path)) + return spi_dataset + + +# read SPIDER dataset from list +def read_from_list(xmd_path, img_name_list): + spi_dataset = [] + for img_path in img_name_list: + spi_dataset.append(spi2array(str(xmd_path) + '/' + img_path)) + return spi_dataset + + +# show SPIDER image format +def imshow(spi_image): + plt.imshow(spi_image) + plt.show() + return + +def normalize(spi_array): + _sdv = np.std(spi_array) + _mean = np.mean(spi_array) + _min = np.min(spi_array) + _max = np.max(spi_array) + spi_array = (spi_array)/max(_max, np.abs(_min)) + #spi_array = (spi_array - _mean) / _sdv + #spi_array = (spi_array - _min) / (_max - _min) + return spi_array + + +def torch_normalize(spi_array): + _sdv = torch.std(spi_array) + _mean = torch.mean(spi_array) + _min = torch.min(spi_array) + _max = torch.max(spi_array) + spi_array = (spi_array - _min) / (_max - _min) + return spi_array + +""" +def mrc_stack_reader(path): + mrc = mrcfile.mmap(path, mode='r+') + return mrc +""" diff --git a/continuousflex/protocols/utilities/tombox.py b/continuousflex/protocols/utilities/tombox.py index 5fe5c1b..aaca86f 100644 --- a/continuousflex/protocols/utilities/tombox.py +++ b/continuousflex/protocols/utilities/tombox.py @@ -1,3 +1,5 @@ +# By Mohamad Harastani + # This function converts a TomBox table (motive list) into xmipp (scipion) metadata file # given a metadata input containing a list of the subtomograms from pwem.emlib import metadata as md diff --git a/continuousflex/protocols/utilities/top_all36_prot_na.rtf b/continuousflex/protocols/utilities/top_all36_prot_na.rtf new file mode 100644 index 0000000..e2772db --- /dev/null +++ b/continuousflex/protocols/utilities/top_all36_prot_na.rtf @@ -0,0 +1,2663 @@ +*>>>>>>>>CHARMM36 All-Hydrogen Topology File for Proteins <<<<<< +*>>>>> Includes phi, psi cross term map (CMAP) correction <<<<<<< +*>>>>>>>>>>>>>>>>>>>>>>>>>> May 2011 <<<<<<<<<<<<<<<<<<<<<<<<<<<< +* All comments to the CHARMM web site: www.charmm.org +* parameter set discussion forum +* +36 1 + +!references +! +!Robert B. Best, R.B., Xiao Zhu, X., Shim, J., Lopes, P. +!Mittal, J., Feig, M. and MacKerell, A.D., Jr. "Optimization of the +!additive CHARMM all-atom protein force field targeting improved +!sampling of the backbone phi, psi and sidechain chi1 and chi2 +!dihedral angles," JCTC, 8: 3257-3273, 2013, PMC3549273 + +!MacKerell, A.D., Jr., Feig, M. and Brooks, III, C.L. "Improved +!treatment of the protein backbone in empirical force fields," Journal +!of the American Chemical Society, 126: 698-699, 2004 +! +!MacKerell, Jr., A. D.; Bashford, D.; Bellott, M.; Dunbrack Jr., R.L.; +!Evanseck, J.D.; Field, M.J.; Fischer, S.; Gao, J.; Guo, H.; Ha, S.; +!Joseph-McCarthy, D.; Kuchnir, L.; Kuczera, K.; Lau, F.T.K.; Mattos, +!C.; Michnick, S.; Ngo, T.; Nguyen, D.T.; Prodhom, B.; Reiher, III, +!W.E.; Roux, B.; Schlenkrich, M.; Smith, J.C.; Stote, R.; Straub, J.; +!Watanabe, M.; Wiorkiewicz-Kuczera, J.; Yin, D.; Karplus, M. All-atom +!empirical potential for molecular modeling and dynamics Studies of +!proteins. Journal of Physical Chemistry B, 1998, 102, 3586-3616. +! + +MASS -1 H 1.00800 ! polar H +MASS -1 HC 1.00800 ! N-ter H +MASS -1 HA 1.00800 ! nonpolar H +MASS -1 HP 1.00800 ! aromatic H +MASS -1 HB1 1.00800 ! backbone H +MASS -1 HB2 1.00800 ! aliphatic backbone H, to CT2 +MASS -1 HR1 1.00800 ! his he1, (+) his HG,HD2 +MASS -1 HR2 1.00800 ! (+) his HE1 +MASS -1 HR3 1.00800 ! neutral his HG, HD2 +MASS -1 HS 1.00800 ! thiol hydrogen +MASS -1 HE1 1.00800 ! for alkene; RHC=CR +MASS -1 HE2 1.00800 ! for alkene; H2C=CR +MASS -1 HA1 1.00800 ! alkane, CH, new LJ params (see toppar_all22_prot_aliphatic_c27.str) +MASS -1 HA2 1.00800 ! alkane, CH2, new LJ params (see toppar_all22_prot_aliphatic_c27.str) +MASS -1 HA3 1.00800 ! alkane, CH3, new LJ params (see toppar_all22_prot_aliphatic_c27.str) +MASS -1 C 12.01100 ! carbonyl C, peptide backbone +MASS -1 CA 12.01100 ! aromatic C +MASS -1 CT 12.01100 ! aliphatic sp3 C, new LJ params, no hydrogens +MASS -1 CT1 12.01100 ! aliphatic sp3 C for CH +MASS -1 CT2 12.01100 ! aliphatic sp3 C for CH2 +MASS -1 CT2A 12.01100 ! from CT2 (asp, glu, hsp chi1/chi2 fitting) +MASS -1 CT3 12.01100 ! aliphatic sp3 C for CH3 +MASS -1 CPH1 12.01100 ! his CG and CD2 carbons +MASS -1 CPH2 12.01100 ! his CE1 carbon +MASS -1 CPT 12.01100 ! trp C between rings +MASS -1 CY 12.01100 ! TRP C in pyrrole ring +MASS -1 CP1 12.01100 ! tetrahedral C (proline CA) +MASS -1 CP2 12.01100 ! tetrahedral C (proline CB/CG) +MASS -1 CP3 12.01100 ! tetrahedral C (proline CD) +MASS -1 CC 12.01100 ! carbonyl C, asn,asp,gln,glu,cter,ct2 +MASS -1 CD 12.01100 ! carbonyl C, pres aspp,glup,ct1 +MASS -1 CS 12.01100 ! thiolate carbon +MASS -1 CE1 12.01100 ! for alkene; RHC=CR +MASS -1 CE2 12.01100 ! for alkene; H2C=CR +MASS -1 CAI 12.01100 ! aromatic C next to CPT in trp +MASS -1 N 14.00700 ! proline N +MASS -1 NR1 14.00700 ! neutral his protonated ring nitrogen +MASS -1 NR2 14.00700 ! neutral his unprotonated ring nitrogen +MASS -1 NR3 14.00700 ! charged his ring nitrogen +MASS -1 NH1 14.00700 ! peptide nitrogen +MASS -1 NH2 14.00700 ! amide nitrogen +MASS -1 NH3 14.00700 ! ammonium nitrogen +MASS -1 NC2 14.00700 ! guanidinium nitrogen +MASS -1 NY 14.00700 ! TRP N in pyrrole ring +MASS -1 NP 14.00700 ! Proline ring NH2+ (N-terminal) +MASS -1 O 15.99900 ! carbonyl oxygen +MASS -1 OB 15.99900 ! carbonyl oxygen in acetic acid +MASS -1 OC 15.99900 ! carboxylate oxygen +MASS -1 OH1 15.99900 ! hydroxyl oxygen +MASS -1 OS 15.99940 ! ester oxygen +MASS -1 S 32.06000 ! sulphur +MASS -1 SM 32.06000 ! sulfur C-S-S-C type +MASS -1 SS 32.06000 ! thiolate sulfur + +DECL -CA +DECL -C +DECL -O +DECL +N +DECL +HN +DECL +CA +DEFA FIRS NTER LAST CTER +AUTO ANGLES DIHE PATCH + +RESI ALA 0.00 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | HB1 +ATOM HA HB1 0.09 ! | / +GROUP ! HA-CA--CB-HB2 +ATOM CB CT3 -0.27 ! | \ +ATOM HB1 HA3 0.09 ! | HB3 +ATOM HB2 HA3 0.09 ! O=C +ATOM HB3 HA3 0.09 ! | +GROUP ! +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA N HN N CA +BOND C CA C +N CA HA CB HB1 CB HB2 CB HB3 +DOUBLE O C +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +ACCEPTOR O C +IC -C CA *N HN 1.3551 126.4900 180.0000 115.4200 0.9996 +IC -C N CA C 1.3551 126.4900 180.0000 114.4400 1.5390 +IC N CA C +N 1.4592 114.4400 180.0000 116.8400 1.3558 +IC +N CA *C O 1.3558 116.8400 180.0000 122.5200 1.2297 +IC CA C +N +CA 1.5390 116.8400 180.0000 126.7700 1.4613 +IC N C *CA CB 1.4592 114.4400 123.2300 111.0900 1.5461 +IC N C *CA HA 1.4592 114.4400 -120.4500 106.3900 1.0840 +IC C CA CB HB1 1.5390 111.0900 177.2500 109.6000 1.1109 +IC HB1 CA *CB HB2 1.1109 109.6000 119.1300 111.0500 1.1119 +IC HB1 CA *CB HB3 1.1109 109.6000 -119.5800 111.6100 1.1114 + +RESI ARG 1.00 +GROUP +ATOM N NH1 -0.47 ! | HH11 +ATOM HN H 0.31 ! HN-N | +ATOM CA CT1 0.07 ! | HB1 HG1 HD1 HE NH1-HH12 +ATOM HA HB1 0.09 ! | | | | | //(+) +GROUP ! HA-CA--CB--CG--CD--NE--CZ +ATOM CB CT2 -0.18 ! | | | | \ +ATOM HB1 HA2 0.09 ! | HB2 HG2 HD2 NH2-HH22 +ATOM HB2 HA2 0.09 ! O=C | +GROUP ! | HH21 +ATOM CG CT2 -0.18 +ATOM HG1 HA2 0.09 +ATOM HG2 HA2 0.09 +GROUP +ATOM CD CT2 0.20 +ATOM HD1 HA2 0.09 +ATOM HD2 HA2 0.09 +ATOM NE NC2 -0.70 +ATOM HE HC 0.44 +ATOM CZ C 0.64 +ATOM NH1 NC2 -0.80 +ATOM HH11 HC 0.46 +ATOM HH12 HC 0.46 +ATOM NH2 NC2 -0.80 +ATOM HH21 HC 0.46 +ATOM HH22 HC 0.46 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB CD CG NE CD CZ NE +BOND NH2 CZ N HN N CA +BOND C CA C +N CA HA CB HB1 +BOND CB HB2 CG HG1 CG HG2 CD HD1 CD HD2 +BOND NE HE NH1 HH11 NH1 HH12 NH2 HH21 NH2 HH22 +DOUBLE O C CZ NH1 +IMPR N -C CA HN C CA +N O +IMPR CZ NH1 NH2 NE +IMPR NH1 HH11 HH12 CZ +IMPR NH2 HH21 HH22 CZ +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HE NE +DONOR HH11 NH1 +DONOR HH12 NH1 +DONOR HH21 NH2 +DONOR HH22 NH2 +ACCEPTOR O C +IC -C CA *N HN 1.3496 122.4500 180.0000 116.6700 0.9973 +IC -C N CA C 1.3496 122.4500 180.0000 109.8600 1.5227 +IC N CA C +N 1.4544 109.8600 180.0000 117.1200 1.3511 +IC +N CA *C O 1.3511 117.1200 180.0000 121.4000 1.2271 +IC CA C +N +CA 1.5227 117.1200 180.0000 124.6700 1.4565 +IC N C *CA CB 1.4544 109.8600 123.6400 112.2600 1.5552 +IC N C *CA HA 1.4544 109.8600 -117.9300 106.6100 1.0836 +IC N CA CB CG 1.4544 110.7000 180.0000 115.9500 1.5475 +IC CG CA *CB HB1 1.5475 115.9500 120.0500 106.4000 1.1163 +IC CG CA *CB HB2 1.5475 115.9500 -125.8100 109.5500 1.1124 +IC CA CB CG CD 1.5552 115.9500 180.0000 114.0100 1.5384 +IC CD CB *CG HG1 1.5384 114.0100 125.2000 108.5500 1.1121 +IC CD CB *CG HG2 1.5384 114.0100 -120.3000 108.9600 1.1143 +IC CB CG CD NE 1.5475 114.0100 180.0000 107.0900 1.5034 +IC NE CG *CD HD1 1.5034 107.0900 120.6900 109.4100 1.1143 +IC NE CG *CD HD2 1.5034 107.0900 -119.0400 111.5200 1.1150 +IC CG CD NE CZ 1.5384 107.0900 180.0000 123.0500 1.3401 +IC CZ CD *NE HE 1.3401 123.0500 180.0000 113.1400 1.0065 +IC CD NE CZ NH1 1.5034 123.0500 180.0000 118.0600 1.3311 +IC NE CZ NH1 HH11 1.3401 118.0600 -178.2800 120.6100 0.9903 +IC HH11 CZ *NH1 HH12 0.9903 120.6100 171.1900 116.2900 1.0023 +IC NH1 NE *CZ NH2 1.3311 118.0600 178.6400 122.1400 1.3292 +IC NE CZ NH2 HH21 1.3401 122.1400 -174.1400 119.9100 0.9899 +IC HH21 CZ *NH2 HH22 0.9899 119.9100 166.1600 116.8800 0.9914 + +RESI ASN 0.00 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | HB1 OD1 HD21 (cis to OD1) +ATOM HA HB1 0.09 ! | | || / +GROUP ! HA-CA--CB--CG--ND2 +ATOM CB CT2 -0.18 ! | | \ +ATOM HB1 HA2 0.09 ! | HB2 HD22 (trans to OD1) +ATOM HB2 HA2 0.09 ! O=C +GROUP ! | +ATOM CG CC 0.55 +ATOM OD1 O -0.55 +GROUP +ATOM ND2 NH2 -0.62 +ATOM HD21 H 0.32 +ATOM HD22 H 0.30 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB ND2 CG +BOND N HN N CA C CA C +N +BOND CA HA CB HB1 CB HB2 ND2 HD21 ND2 HD22 +DOUBLE C O CG OD1 +IMPR N -C CA HN C CA +N O +IMPR CG ND2 CB OD1 CG CB ND2 OD1 +IMPR ND2 CG HD21 HD22 ND2 CG HD22 HD21 +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HD21 ND2 +DONOR HD22 ND2 +ACCEPTOR OD1 CG +ACCEPTOR O C +IC -C CA *N HN 1.3480 124.0500 180.0000 114.4900 0.9992 +IC -C N CA C 1.3480 124.0500 180.0000 105.2300 1.5245 +IC N CA C +N 1.4510 105.2300 180.0000 117.3800 1.3467 +IC +N CA *C O 1.3467 117.3800 180.0000 120.3200 1.2282 +IC CA C +N +CA 1.5245 117.3800 180.0000 124.8800 1.4528 +IC N C *CA CB 1.4510 105.2300 121.1800 113.0400 1.5627 +IC N C *CA HA 1.4510 105.2300 -115.5200 107.6300 1.0848 +IC N CA CB CG 1.4510 110.9100 180.0000 114.3000 1.5319 +IC CG CA *CB HB1 1.5319 114.3000 119.1700 107.8200 1.1120 +IC CG CA *CB HB2 1.5319 114.3000 -123.7400 110.3400 1.1091 +IC CA CB CG OD1 1.5627 114.3000 180.0000 122.5600 1.2323 +IC OD1 CB *CG ND2 1.2323 122.5600 -179.1900 116.1500 1.3521 +IC CB CG ND2 HD21 1.5319 116.1500 -179.2600 117.3500 0.9963 +IC HD21 CG *ND2 HD22 0.9963 117.3500 178.0200 120.0500 0.9951 + +RESI ASP -1.00 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | HB1 OD1 +ATOM HA HB1 0.09 ! | | // +GROUP ! HA-CA--CB--CG +ATOM CB CT2A -0.28 ! | | \ +ATOM HB1 HA2 0.09 ! | HB2 OD2(-) +ATOM HB2 HA2 0.09 ! O=C +ATOM CG CC 0.62 ! | +ATOM OD1 OC -0.76 +ATOM OD2 OC -0.76 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB OD2 CG +BOND N HN N CA C CA C +N +BOND CA HA CB HB1 CB HB2 +DOUBLE O C CG OD1 +IMPR N -C CA HN C CA +N O +IMPR CG CB OD2 OD1 +CMAP -C N CA C N CA C +N +DONOR HN N +ACCEPTOR OD1 CG +ACCEPTOR OD2 CG +ACCEPTOR O C +IC -C CA *N HN 1.3465 125.3100 180.0000 112.9400 0.9966 +IC -C N CA C 1.3465 125.3100 180.0000 105.6300 1.5315 +IC N CA C +N 1.4490 105.6300 180.0000 117.0600 1.3478 +IC +N CA *C O 1.3478 117.0600 180.0000 120.7100 1.2330 +IC CA C +N +CA 1.5315 117.0600 180.0000 125.3900 1.4484 +IC N C *CA CB 1.4490 105.6300 122.3300 114.1000 1.5619 +IC N C *CA HA 1.4490 105.6300 -116.4000 106.7700 1.0841 +IC N CA CB CG 1.4490 111.1000 180.0000 112.6000 1.5218 +IC CG CA *CB HB1 1.5218 112.6000 119.2200 109.2300 1.1086 +IC CG CA *CB HB2 1.5218 112.6000 -121.6100 110.6400 1.1080 +IC CA CB CG OD1 1.5619 112.6000 180.0000 117.9900 1.2565 +IC OD1 CB *CG OD2 1.2565 117.9900 -170.2300 117.7000 1.2541 + +RESI CYS 0.00 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | HB1 +ATOM HA HB1 0.09 ! | | +GROUP ! HA-CA--CB--SG +ATOM CB CT2 -0.11 ! | | \ +ATOM HB1 HA2 0.09 ! | HB2 HG1 +ATOM HB2 HA2 0.09 ! O=C +ATOM SG S -0.23 ! | +ATOM HG1 HS 0.16 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA SG CB N HN N CA +BOND C CA C +N CA HA CB HB1 +BOND CB HB2 SG HG1 +DOUBLE O C +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HG1 SG +ACCEPTOR O C +IC -C CA *N HN 1.3479 123.9300 180.0000 114.7700 0.9982 +IC -C N CA C 1.3479 123.9300 180.0000 105.8900 1.5202 +IC N CA C +N 1.4533 105.8900 180.0000 118.3000 1.3498 +IC +N CA *C O 1.3498 118.3000 180.0000 120.5900 1.2306 +IC CA C +N +CA 1.5202 118.3000 180.0000 124.5000 1.4548 +IC N C *CA CB 1.4533 105.8900 121.7900 111.9800 1.5584 +IC N C *CA HA 1.4533 105.8900 -116.3400 107.7100 1.0837 +IC N CA CB SG 1.4533 111.5600 180.0000 113.8700 1.8359 +IC SG CA *CB HB1 1.8359 113.8700 119.9100 107.2400 1.1134 +IC SG CA *CB HB2 1.8359 113.8700 -125.3200 109.8200 1.1124 +IC CA CB SG HG1 1.5584 113.8700 176.9600 97.1500 1.3341 + +RESI GLN 0.00 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | HB1 HG1 OE1 HE21 (cis to OE1) +ATOM HA HB1 0.09 ! | | | || / +GROUP ! HA-CA--CB--CG--CD--NE2 +ATOM CB CT2 -0.18 ! | | | \ +ATOM HB1 HA2 0.09 ! | HB2 HG2 HE22 (trans to OE1) +ATOM HB2 HA2 0.09 ! O=C +GROUP ! | +ATOM CG CT2 -0.18 +ATOM HG1 HA2 0.09 +ATOM HG2 HA2 0.09 +GROUP +ATOM CD CC 0.55 +ATOM OE1 O -0.55 +GROUP +ATOM NE2 NH2 -0.62 +ATOM HE21 H 0.32 +ATOM HE22 H 0.30 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB CD CG NE2 CD +BOND N HN N CA C CA +BOND C +N CA HA CB HB1 CB HB2 CG HG1 +BOND CG HG2 NE2 HE21 NE2 HE22 +DOUBLE O C CD OE1 +IMPR N -C CA HN C CA +N O +IMPR CD NE2 CG OE1 CD CG NE2 OE1 +IMPR NE2 CD HE21 HE22 NE2 CD HE22 HE21 +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HE21 NE2 +DONOR HE22 NE2 +ACCEPTOR OE1 CD +ACCEPTOR O C +IC -C CA *N HN 1.3477 123.9300 180.0000 114.4500 0.9984 +IC -C N CA C 1.3477 123.9300 180.0000 106.5700 1.5180 +IC N CA C +N 1.4506 106.5700 180.0000 117.7200 1.3463 +IC +N CA *C O 1.3463 117.7200 180.0000 120.5900 1.2291 +IC CA C +N +CA 1.5180 117.7200 180.0000 124.3500 1.4461 +IC N C *CA CB 1.4506 106.5700 121.9100 111.6800 1.5538 +IC N C *CA HA 1.4506 106.5700 -116.8200 107.5300 1.0832 +IC N CA CB CG 1.4506 111.4400 180.0000 115.5200 1.5534 +IC CG CA *CB HB1 1.5534 115.5200 120.9300 106.8000 1.1147 +IC CG CA *CB HB2 1.5534 115.5200 -124.5800 109.3400 1.1140 +IC CA CB CG CD 1.5538 115.5200 180.0000 112.5000 1.5320 +IC CD CB *CG HG1 1.5320 112.5000 118.6900 110.4100 1.1112 +IC CD CB *CG HG2 1.5320 112.5000 -121.9100 110.7400 1.1094 +IC CB CG CD OE1 1.5534 112.5000 180.0000 121.5200 1.2294 +IC OE1 CG *CD NE2 1.2294 121.5200 179.5700 116.8400 1.3530 +IC CG CD NE2 HE21 1.5320 116.8400 -179.7200 116.8600 0.9959 +IC HE21 CD *NE2 HE22 0.9959 116.8600 -178.9100 119.8300 0.9943 + +RESI GLU -1.00 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | HB1 HG1 OE1 +ATOM HA HB1 0.09 ! | | | // +GROUP ! HA-CA--CB--CG--CD +ATOM CB CT2A -0.18 ! | | | \ +ATOM HB1 HA2 0.09 ! | HB2 HG2 OE2(-) +ATOM HB2 HA2 0.09 ! O=C +GROUP ! | +ATOM CG CT2 -0.28 +ATOM HG1 HA2 0.09 +ATOM HG2 HA2 0.09 +ATOM CD CC 0.62 +ATOM OE1 OC -0.76 +ATOM OE2 OC -0.76 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB CD CG OE2 CD +BOND N HN N CA C CA +BOND C +N CA HA CB HB1 CB HB2 CG HG1 +BOND CG HG2 +DOUBLE O C CD OE1 +IMPR N -C CA HN C CA +N O +IMPR CD CG OE2 OE1 +CMAP -C N CA C N CA C +N +DONOR HN N +ACCEPTOR OE1 CD +ACCEPTOR OE2 CD +ACCEPTOR O C +IC -C CA *N HN 1.3471 124.4500 180.0000 113.9900 0.9961 +IC -C N CA C 1.3471 124.4500 180.0000 107.2700 1.5216 +IC N CA C +N 1.4512 107.2700 180.0000 117.2500 1.3501 +IC +N CA *C O 1.3501 117.2500 180.0000 121.0700 1.2306 +IC CA C +N +CA 1.5216 117.2500 180.0000 124.3000 1.4530 +IC N C *CA CB 1.4512 107.2700 121.9000 111.7100 1.5516 +IC N C *CA HA 1.4512 107.2700 -118.0600 107.2600 1.0828 +IC N CA CB CG 1.4512 111.0400 180.0000 115.6900 1.5557 +IC CG CA *CB HB1 1.5557 115.6900 121.2200 108.1600 1.1145 +IC CG CA *CB HB2 1.5557 115.6900 -123.6500 109.8100 1.1131 +IC CA CB CG CD 1.5516 115.6900 180.0000 115.7300 1.5307 +IC CD CB *CG HG1 1.5307 115.7300 117.3800 109.5000 1.1053 +IC CD CB *CG HG2 1.5307 115.7300 -121.9600 111.0000 1.1081 +IC CB CG CD OE1 1.5557 115.7300 180.0000 114.9900 1.2590 +IC OE1 CG *CD OE2 1.2590 114.9900 -179.1000 120.0800 1.2532 + +RESI GLY 0.00 +!GROUP +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! N-H +ATOM CA CT2 -0.02 ! | +ATOM HA1 HB2 0.09 ! | +ATOM HA2 HB2 0.09 ! HA1-CA-HA2 +GROUP ! | +ATOM C C 0.51 ! | +ATOM O O -0.51 ! C=O + ! | +BOND N HN N CA C CA +BOND C +N CA HA1 CA HA2 +DOUBLE O C +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +ACCEPTOR O C +IC -C CA *N HN 1.3475 122.8200 180.0000 115.6200 0.9992 +IC -C N CA C 1.3475 122.8200 180.0000 108.9400 1.4971 +IC N CA C +N 1.4553 108.9400 180.0000 117.6000 1.3479 +IC +N CA *C O 1.3479 117.6000 180.0000 120.8500 1.2289 +IC CA C +N +CA 1.4971 117.6000 180.0000 124.0800 1.4560 +IC N C *CA HA1 1.4553 108.9400 117.8600 108.0300 1.0814 +IC N C *CA HA2 1.4553 108.9400 -118.1200 107.9500 1.0817 +PATCHING FIRS GLYP + +RESI HSD 0.00 ! neutral HIS, proton on ND1 +GROUP +ATOM N NH1 -0.47 ! | HD1 HE1 +ATOM HN H 0.31 ! HN-N | / +ATOM CA CT1 0.07 ! | HB1 ND1--CE1 +ATOM HA HB1 0.09 ! | | / || +GROUP ! HA-CA--CB--CG || +ATOM CB CT2 -0.09 ! | | \\ || +ATOM HB1 HA2 0.09 ! | HB2 CD2--NE2 +ATOM HB2 HA2 0.09 ! O=C | +ATOM ND1 NR1 -0.36 ! | HD2 +ATOM HD1 H 0.32 +ATOM CG CPH1 -0.05 +GROUP +ATOM CE1 CPH2 0.25 +ATOM HE1 HR1 0.13 +ATOM NE2 NR2 -0.70 +ATOM CD2 CPH1 0.22 +ATOM HD2 HR3 0.10 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB ND1 CG CE1 ND1 +BOND NE2 CD2 N HN N CA +BOND C CA C +N CA HA CB HB1 +BOND CB HB2 ND1 HD1 CD2 HD2 CE1 HE1 +DOUBLE O C CG CD2 CE1 NE2 +IMPR ND1 CG CE1 HD1 CD2 CG NE2 HD2 CE1 ND1 NE2 HE1 +IMPR ND1 CE1 CG HD1 CD2 NE2 CG HD2 CE1 NE2 ND1 HE1 +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HD1 ND1 +ACCEPTOR NE2 +ACCEPTOR O C +IC -C CA *N HN 1.3475 123.2700 180.0000 115.2100 0.9988 +IC -C N CA C 1.3475 123.2700 180.0000 107.7000 1.5166 +IC N CA C +N 1.4521 107.7000 180.0000 117.5700 1.3509 +IC +N CA *C O 1.3509 117.5700 180.0000 120.2400 1.2273 +IC CA C +N +CA 1.5166 117.5700 180.0000 123.7200 1.4545 +IC N C *CA CB 1.4521 107.7000 122.4600 109.9900 1.5519 +IC N C *CA HA 1.4521 107.7000 -117.4900 107.3700 1.0830 +IC N CA CB CG 1.4521 112.1200 180.0000 114.0500 1.5041 +IC CG CA *CB HB1 1.5041 114.0500 121.1700 109.0100 1.1118 +IC CG CA *CB HB2 1.5041 114.0500 -122.3600 109.5300 1.1121 +IC CA CB CG ND1 1.5519 114.0500 90.0000 124.1000 1.3783 +IC ND1 CB *CG CD2 1.3783 124.1000 -171.2900 129.6000 1.3597 +IC CB CG ND1 CE1 1.5041 124.1000 -173.2100 107.0300 1.3549 +IC CB CG CD2 NE2 1.5041 129.6000 171.9900 110.0300 1.3817 +IC NE2 ND1 *CE1 HE1 1.3166 111.6300 -179.6300 123.8900 1.0932 +IC CE1 CG *ND1 HD1 1.3549 107.0300 -174.6500 126.2600 1.0005 +IC NE2 CG *CD2 HD2 1.3817 110.0300 -177.8500 129.6300 1.0834 + +RESI HSE 0.00 ! neutral His, proton on NE2 +GROUP +ATOM N NH1 -0.47 ! | HE1 +ATOM HN H 0.31 ! HN-N __ / +ATOM CA CT1 0.07 ! | HB1 ND1--CE1 +ATOM HA HB1 0.09 ! | | / | +GROUP ! HA-CA--CB--CG | +ATOM CB CT2 -0.08 ! | | \\ | +ATOM HB1 HA2 0.09 ! | HB2 CD2--NE2 +ATOM HB2 HA2 0.09 ! O=C | \ +ATOM ND1 NR2 -0.70 ! | HD2 HE2 +ATOM CG CPH1 0.22 +ATOM CE1 CPH2 0.25 +ATOM HE1 HR1 0.13 +GROUP +ATOM NE2 NR1 -0.36 +ATOM HE2 H 0.32 +ATOM CD2 CPH1 -0.05 +ATOM HD2 HR3 0.09 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB ND1 CG +BOND NE2 CD2 N HN N CA +BOND C CA C +N NE2 CE1 CA HA CB HB1 +BOND CB HB2 NE2 HE2 CD2 HD2 CE1 HE1 +DOUBLE O C CD2 CG CE1 ND1 +IMPR NE2 CD2 CE1 HE2 CD2 CG NE2 HD2 CE1 ND1 NE2 HE1 +IMPR NE2 CE1 CD2 HE2 CD2 NE2 CG HD2 CE1 NE2 ND1 HE1 +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HE2 NE2 +ACCEPTOR ND1 +ACCEPTOR O C +IC -C CA *N HN 1.3472 124.1600 180.0000 114.3600 0.9991 +IC -C N CA C 1.3472 124.1600 180.0000 106.4300 1.5166 +IC N CA C +N 1.4532 106.4300 180.0000 116.9700 1.3446 +IC +N CA *C O 1.3446 116.9700 180.0000 120.6800 1.2290 +IC CA C +N +CA 1.5166 116.9700 180.0000 124.9500 1.4505 +IC N C *CA CB 1.4532 106.4300 123.5200 111.6700 1.5578 +IC N C *CA HA 1.4532 106.4300 -116.4900 107.0800 1.0833 +IC N CA CB CG 1.4532 112.8200 180.0000 116.9400 1.5109 +IC CG CA *CB HB1 1.5109 116.9400 119.8000 107.9100 1.1114 +IC CG CA *CB HB2 1.5109 116.9400 -124.0400 109.5000 1.1101 +IC CA CB CG ND1 1.5578 116.9400 90.0000 120.1700 1.3859 +IC ND1 CB *CG CD2 1.3859 120.1700 -178.2600 129.7100 1.3596 +IC CB CG ND1 CE1 1.5109 120.1700 -179.2000 105.2000 1.3170 +IC CB CG CD2 NE2 1.5109 129.7100 178.6600 105.8000 1.3782 +IC NE2 ND1 *CE1 HE1 1.3539 111.7600 179.6900 124.5800 1.0929 +IC CE1 CD2 *NE2 HE2 1.3539 107.1500 -178.6900 125.8600 0.9996 +IC NE2 CG *CD2 HD2 1.3782 105.8000 -179.3500 129.8900 1.0809 + +RESI HSP 1.00 ! Protonated His +GROUP +ATOM N NH1 -0.47 ! | HD1 HE1 +ATOM HN H 0.31 ! HN-N | / +ATOM CA CT1 0.07 ! | HB1 ND1--CE1 +ATOM HA HB1 0.09 ! | | / || +GROUP ! HA-CA--CB--CG || +ATOM CB CT2A -0.05 ! | | \\ || +ATOM HB1 HA2 0.09 ! | HB2 CD2--NE2(+) +ATOM HB2 HA2 0.09 ! O=C | \ +ATOM CD2 CPH1 0.19 ! | HD2 HE2 +ATOM HD2 HR1 0.13 +ATOM CG CPH1 0.19 +GROUP +ATOM NE2 NR3 -0.51 +ATOM HE2 H 0.44 +ATOM ND1 NR3 -0.51 +ATOM HD1 H 0.44 +ATOM CE1 CPH2 0.32 +ATOM HE1 HR2 0.18 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB ND1 CG CE1 ND1 +BOND NE2 CD2 N HN N CA +BOND C CA C +N CA HA CB HB1 +BOND CB HB2 ND1 HD1 NE2 HE2 CD2 HD2 CE1 HE1 +DOUBLE O C CD2 CG NE2 CE1 +IMPR ND1 CG CE1 HD1 ND1 CE1 CG HD1 +IMPR NE2 CD2 CE1 HE2 NE2 CE1 CD2 HE2 +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HD1 ND1 +DONOR HE2 NE2 +ACCEPTOR O C +IC -C CA *N HN 1.3489 123.9300 180.0000 118.8000 1.0041 +IC -C N CA C 1.3489 123.9300 180.0000 112.0300 1.5225 +IC N CA C +N 1.4548 112.0300 180.0000 116.4900 1.3464 +IC +N CA *C O 1.3464 116.4900 180.0000 121.2000 1.2284 +IC CA C +N +CA 1.5225 116.4900 180.0000 124.2400 1.4521 +IC N C *CA CB 1.4548 112.0300 125.1300 109.3800 1.5533 +IC N C *CA HA 1.4548 112.0300 -119.2000 106.7200 1.0832 +IC N CA CB CG 1.4548 112.2500 180.0000 114.1800 1.5168 +IC CG CA *CB HB1 1.5168 114.1800 122.5000 108.9900 1.1116 +IC CG CA *CB HB2 1.5168 114.1800 -121.5100 108.9700 1.1132 +IC CA CB CG ND1 1.5533 114.1800 90.0000 122.9400 1.3718 +IC ND1 CB *CG CD2 1.3718 122.9400 -165.2600 128.9300 1.3549 +IC CB CG ND1 CE1 1.5168 122.9400 -167.6200 108.9000 1.3262 +IC CB CG CD2 NE2 1.5168 128.9300 167.1300 106.9300 1.3727 +IC NE2 ND1 *CE1 HE1 1.3256 108.5000 178.3900 125.7600 1.0799 +IC CE1 CD2 *NE2 HE2 1.3256 108.8200 -172.9400 125.5200 1.0020 +IC CE1 CG *ND1 HD1 1.3262 108.9000 171.4900 126.0900 1.0018 +IC NE2 CG *CD2 HD2 1.3727 106.9300 -174.4900 128.4100 1.0867 + +RESI ILE 0.00 +GROUP +ATOM N NH1 -0.47 ! | HG21 HG22 +ATOM HN H 0.31 ! HN-N | / +ATOM CA CT1 0.07 ! | CG2--HG23 +ATOM HA HB1 0.09 ! | / +GROUP ! HA-CA--CB-HB HD1 +ATOM CB CT1 -0.09 ! | \ / +ATOM HB HA1 0.09 ! | CG1--CD--HD2 +GROUP ! O=C / \ \ +ATOM CG2 CT3 -0.27 ! | HG11 HG12 HD3 +ATOM HG21 HA3 0.09 +ATOM HG22 HA3 0.09 +ATOM HG23 HA3 0.09 +GROUP +ATOM CG1 CT2 -0.18 +ATOM HG11 HA2 0.09 +ATOM HG12 HA2 0.09 +GROUP +ATOM CD CT3 -0.27 +ATOM HD1 HA3 0.09 +ATOM HD2 HA3 0.09 +ATOM HD3 HA3 0.09 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG1 CB CG2 CB CD CG1 +BOND N HN N CA C CA C +N +BOND CA HA CB HB CG1 HG11 CG1 HG12 CG2 HG21 +BOND CG2 HG22 CG2 HG23 CD HD1 CD HD2 CD HD3 +DOUBLE O C +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +ACCEPTOR O C +IC -C CA *N HN 1.3470 124.1600 180.0000 114.1900 0.9978 +IC -C N CA C 1.3470 124.1600 180.0000 106.3500 1.5190 +IC N CA C +N 1.4542 106.3500 180.0000 117.9700 1.3465 +IC +N CA *C O 1.3465 117.9700 180.0000 120.5900 1.2300 +IC CA C +N +CA 1.5190 117.9700 180.0000 124.2100 1.4467 +IC N C *CA CB 1.4542 106.3500 124.2200 112.9300 1.5681 +IC N C *CA HA 1.4542 106.3500 -115.6300 106.8100 1.0826 +IC N CA CB CG1 1.4542 112.7900 180.0000 113.6300 1.5498 +IC CG1 CA *CB HB 1.5498 113.6300 114.5500 104.4800 1.1195 +IC CG1 CA *CB CG2 1.5498 113.6300 -130.0400 113.9300 1.5452 +IC CA CB CG2 HG21 1.5681 113.9300 -171.3000 110.6100 1.1100 +IC HG21 CB *CG2 HG22 1.1100 110.6100 119.3500 110.9000 1.1102 +IC HG21 CB *CG2 HG23 1.1100 110.6100 -120.0900 110.9700 1.1105 +IC CA CB CG1 CD 1.5681 113.6300 180.0000 114.0900 1.5381 +IC CD CB *CG1 HG11 1.5381 114.0900 122.3600 109.7800 1.1130 +IC CD CB *CG1 HG12 1.5381 114.0900 -120.5900 108.8900 1.1141 +IC CB CG1 CD HD1 1.5498 114.0900 -176.7800 110.3100 1.1115 +IC HD1 CG1 *CD HD2 1.1115 110.3100 119.7500 110.6500 1.1113 +IC HD1 CG1 *CD HD3 1.1115 110.3100 -119.7000 111.0200 1.1103 + +RESI LEU 0.00 +GROUP +ATOM N NH1 -0.47 ! | HD11 HD12 +ATOM HN H 0.31 ! HN-N | / +ATOM CA CT1 0.07 ! | HB1 CD1--HD13 +ATOM HA HB1 0.09 ! | | / +GROUP ! HA-CA--CB--CG-HG +ATOM CB CT2 -0.18 ! | | \ +ATOM HB1 HA2 0.09 ! | HB2 CD2--HD23 +ATOM HB2 HA2 0.09 ! O=C | \ +GROUP ! | HD21 HD22 +ATOM CG CT1 -0.09 +ATOM HG HA1 0.09 +GROUP +ATOM CD1 CT3 -0.27 +ATOM HD11 HA3 0.09 +ATOM HD12 HA3 0.09 +ATOM HD13 HA3 0.09 +GROUP +ATOM CD2 CT3 -0.27 +ATOM HD21 HA3 0.09 +ATOM HD22 HA3 0.09 +ATOM HD23 HA3 0.09 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB CD1 CG CD2 CG +BOND N HN N CA C CA C +N +BOND CA HA CB HB1 CB HB2 CG HG CD1 HD11 +BOND CD1 HD12 CD1 HD13 CD2 HD21 CD2 HD22 CD2 HD23 +DOUBLE O C +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +ACCEPTOR O C +IC -C CA *N HN 1.3474 124.3100 180.0000 114.2600 0.9979 +IC -C N CA C 1.3474 124.3100 180.0000 106.0500 1.5184 +IC N CA C +N 1.4508 106.0500 180.0000 117.9300 1.3463 +IC +N CA *C O 1.3463 117.9300 180.0000 120.5600 1.2299 +IC CA C +N +CA 1.5184 117.9300 180.0000 124.2600 1.4467 +IC N C *CA CB 1.4508 106.0500 121.5200 112.1200 1.5543 +IC N C *CA HA 1.4508 106.0500 -116.5000 107.5700 1.0824 +IC N CA CB CG 1.4508 111.1900 180.0000 117.4600 1.5472 +IC CG CA *CB HB1 1.5472 117.4600 120.9800 107.1700 1.1145 +IC CG CA *CB HB2 1.5472 117.4600 -124.6700 108.9800 1.1126 +IC CA CB CG CD1 1.5543 117.4600 180.0000 110.4800 1.5361 +IC CD1 CB *CG CD2 1.5361 110.4800 120.0000 112.5700 1.5360 +IC CD1 CD2 *CG HG 1.5361 110.2600 120.0000 108.0200 1.1168 +IC CB CG CD1 HD11 1.5472 110.4800 177.3300 110.5400 1.1111 +IC HD11 CG *CD1 HD12 1.1111 110.5400 119.9600 110.6200 1.1112 +IC HD11 CG *CD1 HD13 1.1111 110.5400 -119.8500 110.6900 1.1108 +IC CB CG CD2 HD21 1.5472 112.5700 178.9600 110.3200 1.1116 +IC HD21 CG *CD2 HD22 1.1116 110.3200 119.7100 111.6900 1.1086 +IC HD21 CG *CD2 HD23 1.1116 110.3200 -119.6100 110.4900 1.1115 + +RESI LYS 1.00 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | HB1 HG1 HD1 HE1 HZ1 +ATOM HA HB1 0.09 ! | | | | | / +GROUP ! HA-CA--CB--CG--CD--CE--NZ--HZ2 +ATOM CB CT2 -0.18 ! | | | | | \ +ATOM HB1 HA2 0.09 ! | HB2 HG2 HD2 HE2 HZ3 +ATOM HB2 HA2 0.09 ! O=C +GROUP ! | +ATOM CG CT2 -0.18 +ATOM HG1 HA2 0.09 +ATOM HG2 HA2 0.09 +GROUP +ATOM CD CT2 -0.18 +ATOM HD1 HA2 0.09 +ATOM HD2 HA2 0.09 +GROUP +ATOM CE CT2 0.21 +ATOM HE1 HA2 0.05 +ATOM HE2 HA2 0.05 +ATOM NZ NH3 -0.30 +ATOM HZ1 HC 0.33 +ATOM HZ2 HC 0.33 +ATOM HZ3 HC 0.33 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB CD CG CE CD NZ CE +BOND N HN N CA C CA +BOND C +N CA HA CB HB1 CB HB2 CG HG1 +BOND CG HG2 CD HD1 CD HD2 CE HE1 CE HE2 +DOUBLE O C +BOND NZ HZ1 NZ HZ2 NZ HZ3 +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HZ1 NZ +DONOR HZ2 NZ +DONOR HZ3 NZ +ACCEPTOR O C +IC -C CA *N HN 1.3482 123.5700 180.0000 115.1100 0.9988 +IC -C N CA C 1.3482 123.5700 180.0000 107.2900 1.5187 +IC N CA C +N 1.4504 107.2900 180.0000 117.2700 1.3478 +IC +N CA *C O 1.3478 117.2700 180.0000 120.7900 1.2277 +IC CA C +N +CA 1.5187 117.2700 180.0000 124.9100 1.4487 +IC N C *CA CB 1.4504 107.2900 122.2300 111.3600 1.5568 +IC N C *CA HA 1.4504 107.2900 -116.8800 107.3600 1.0833 +IC N CA CB CG 1.4504 111.4700 180.0000 115.7600 1.5435 +IC CG CA *CB HB1 1.5435 115.7600 120.9000 107.1100 1.1146 +IC CG CA *CB HB2 1.5435 115.7600 -124.4800 108.9900 1.1131 +IC CA CB CG CD 1.5568 115.7600 180.0000 113.2800 1.5397 +IC CD CB *CG HG1 1.5397 113.2800 120.7400 109.1000 1.1138 +IC CD CB *CG HG2 1.5397 113.2800 -122.3400 108.9900 1.1143 +IC CB CG CD CE 1.5435 113.2800 180.0000 112.3300 1.5350 +IC CE CG *CD HD1 1.5350 112.3300 122.2500 108.4100 1.1141 +IC CE CG *CD HD2 1.5350 112.3300 -121.5900 108.1300 1.1146 +IC CG CD CE NZ 1.5397 112.3300 180.0000 110.4600 1.4604 +IC NZ CD *CE HE1 1.4604 110.4600 119.9100 110.5100 1.1128 +IC NZ CD *CE HE2 1.4604 110.4600 -120.0200 110.5700 1.1123 +IC CD CE NZ HZ1 1.5350 110.4600 179.9200 110.0200 1.0404 +IC HZ1 CE *NZ HZ2 1.0404 110.0200 120.2700 109.5000 1.0402 +IC HZ1 CE *NZ HZ3 1.0404 110.0200 -120.1300 109.4000 1.0401 + +RESI MET 0.00 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | HB1 HG1 HE1 +ATOM HA HB1 0.09 ! | | | | +GROUP ! HA-CA--CB--CG--SD--CE--HE3 +ATOM CB CT2 -0.18 ! | | | | +ATOM HB1 HA2 0.09 ! | HB2 HG2 HE2 +ATOM HB2 HA2 0.09 ! O=C +GROUP ! | +ATOM CG CT2 -0.14 +ATOM HG1 HA2 0.09 +ATOM HG2 HA2 0.09 +ATOM SD S -0.09 +ATOM CE CT3 -0.22 +ATOM HE1 HA3 0.09 +ATOM HE2 HA3 0.09 +ATOM HE3 HA3 0.09 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB SD CG CE SD +BOND N HN N CA C CA C +N +BOND CA HA CB HB1 CB HB2 CG HG1 CG HG2 +BOND CE HE1 CE HE2 CE HE3 +DOUBLE O C +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +ACCEPTOR O C +IC -C CA *N HN 1.3478 124.2100 180.0000 114.3900 0.9978 +IC -C N CA C 1.3478 124.2100 180.0000 106.3100 1.5195 +IC N CA C +N 1.4510 106.3100 180.0000 117.7400 1.3471 +IC +N CA *C O 1.3471 117.7400 180.0000 120.6400 1.2288 +IC CA C +N +CA 1.5195 117.7400 180.0000 124.5200 1.4471 +IC N C *CA CB 1.4510 106.3100 121.6200 111.8800 1.5546 +IC N C *CA HA 1.4510 106.3100 -116.9800 107.5700 1.0832 +IC N CA CB CG 1.4510 111.2500 180.0000 115.9200 1.5460 +IC CG CA *CB HB1 1.5460 115.9200 120.5600 106.9000 1.1153 +IC CG CA *CB HB2 1.5460 115.9200 -124.8000 109.3800 1.1129 +IC CA CB CG SD 1.5546 115.9200 180.0000 110.2800 1.8219 +IC SD CB *CG HG1 1.8219 110.2800 120.5000 110.3400 1.1106 +IC SD CB *CG HG2 1.8219 110.2800 -121.1600 109.6400 1.1119 +IC CB CG SD CE 1.5460 110.2800 180.0000 98.9400 1.8206 +IC CG SD CE HE1 1.8219 98.9400 -179.4200 110.9100 1.1111 +IC HE1 SD *CE HE2 1.1111 110.9100 119.9500 111.0300 1.1115 +IC HE1 SD *CE HE3 1.1111 110.9100 -119.9500 111.0900 1.1112 + +RESI PHE 0.00 +GROUP +ATOM N NH1 -0.47 ! | HD1 HE1 +ATOM HN H 0.31 ! HN-N | | +ATOM CA CT1 0.07 ! | HB1 CD1--CE1 +ATOM HA HB1 0.09 ! | | // \\ +GROUP ! HA-CA--CB--CG CZ--HZ +ATOM CB CT2 -0.18 ! | | \ __ / +ATOM HB1 HA2 0.09 ! | HB2 CD2--CE2 +ATOM HB2 HA2 0.09 ! O=C | | +GROUP ! | HD2 HE2 +ATOM CG CA 0.00 +GROUP +ATOM CD1 CA -0.115 +ATOM HD1 HP 0.115 +GROUP +ATOM CE1 CA -0.115 +ATOM HE1 HP 0.115 +GROUP +ATOM CZ CA -0.115 +ATOM HZ HP 0.115 +GROUP +ATOM CD2 CA -0.115 +ATOM HD2 HP 0.115 +GROUP +ATOM CE2 CA -0.115 +ATOM HE2 HP 0.115 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB CD2 CG CE1 CD1 +BOND CZ CE2 N HN +BOND N CA C CA C +N CA HA +BOND CB HB1 CB HB2 CD1 HD1 CD2 HD2 CE1 HE1 +DOUBLE O C CD1 CG CZ CE1 CE2 CD2 +BOND CE2 HE2 CZ HZ +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +ACCEPTOR O C +IC -C CA *N HN 1.3476 123.8900 180.0000 114.4700 0.9987 +IC -C N CA C 1.3476 123.8900 180.0000 106.3800 1.5229 +IC N CA C +N 1.4504 106.3800 180.0000 117.6500 1.3483 +IC +N CA *C O 1.3483 117.6500 180.0000 120.4900 1.2287 +IC CA C +N +CA 1.5229 117.6500 180.0000 124.1000 1.4523 +IC N C *CA CB 1.4504 106.3800 122.4900 112.4500 1.5594 +IC N C *CA HA 1.4504 106.3800 -115.6300 107.0500 1.0832 +IC N CA CB CG 1.4504 111.6300 180.0000 112.7600 1.5109 +IC CG CA *CB HB1 1.5109 112.7600 118.2700 109.1000 1.1119 +IC CG CA *CB HB2 1.5109 112.7600 -123.8300 111.1100 1.1113 +IC CA CB CG CD1 1.5594 112.7600 90.0000 120.3200 1.4059 +IC CD1 CB *CG CD2 1.4059 120.3200 -177.9600 120.7600 1.4062 +IC CB CG CD1 CE1 1.5109 120.3200 -177.3700 120.6300 1.4006 +IC CE1 CG *CD1 HD1 1.4006 120.6300 179.7000 119.6500 1.0814 +IC CB CG CD2 CE2 1.5109 120.7600 177.2000 120.6200 1.4002 +IC CE2 CG *CD2 HD2 1.4002 120.6200 -178.6900 119.9900 1.0811 +IC CG CD1 CE1 CZ 1.4059 120.6300 -0.1200 119.9300 1.4004 +IC CZ CD1 *CE1 HE1 1.4004 119.9300 -179.6900 120.0100 1.0808 +IC CZ CD2 *CE2 HE2 1.4000 119.9600 -179.9300 119.8700 1.0811 +IC CE1 CE2 *CZ HZ 1.4004 119.9800 179.5100 119.9700 1.0807 + +RESI PRO 0.00 +GROUP ! HD1 HD2 +ATOM N N -0.29 ! | \ / +ATOM CD CP3 0.00 ! N---CD HG1 ATOM CA CP1 0.02 +ATOM HD1 HA2 0.09 ! | \ / +ATOM HD2 HA2 0.09 ! | CG +ATOM CA CP1 0.02 ! | / \ +ATOM HA HB1 0.09 ! HA-CA--CB HG2 +GROUP ! | / \ +ATOM CB CP2 -0.18 ! | HB1 HB2 +ATOM HB1 HA2 0.09 ! O=C +ATOM HB2 HA2 0.09 ! | +GROUP +ATOM CG CP2 -0.18 +ATOM HG1 HA2 0.09 +ATOM HG2 HA2 0.09 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND C CA C +N +BOND N CA CA CB CB CG CG CD N CD +BOND HA CA HG1 CG HG2 CG HD1 CD HD2 CD HB1 CB HB2 CB +DOUBLE O C +IMPR N -C CA CD +IMPR C CA +N O +CMAP -C N CA C N CA C +N +ACCEPTOR O C +IC -C CA *N CD 1.3366 122.9400 178.5100 112.7500 1.4624 +IC -C N CA C 1.3366 122.9400 -76.1200 110.8600 1.5399 +IC N CA C +N 1.4585 110.8600 180.0000 114.7500 1.3569 +IC +N CA *C O 1.3569 114.7500 177.1500 120.4600 1.2316 +IC CA C +N +CA 1.5399 116.1200 180.0000 124.8900 1.4517 +IC N C *CA CB 1.4585 110.8600 113.7400 111.7400 1.5399 +IC N C *CA HA 1.4585 110.8600 -122.4000 109.0900 1.0837 +IC N CA CB CG 1.4585 102.5600 31.6100 104.3900 1.5322 +IC CA CB CG CD 1.5399 104.3900 -34.5900 103.2100 1.5317 +IC CA CG *CB HB1 1.4585 102.5600 120.0000 109.0200 1.1131 +IC CA CG *CB HB2 1.4585 102.5600 -120.0000 109.0200 1.1131 +IC CB CD *CG HG1 1.5399 104.3900 120.0000 112.9500 1.1077 +IC CB CD *CG HG2 1.5399 104.3900 -120.0000 109.2200 1.1143 +IC N CG *CD HD1 1.5322 103.2100 120.0000 110.0300 1.1137 +IC N CG *CD HD2 1.5322 103.2100 -120.0000 110.0000 1.1144 +PATCHING FIRS PROP + +RESI SER 0.00 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | HB1 +ATOM HA HB1 0.09 ! | | +GROUP ! HA-CA--CB--OG +ATOM CB CT2 0.05 ! | | \ +ATOM HB1 HA2 0.09 ! | HB2 HG1 +ATOM HB2 HA2 0.09 ! O=C +ATOM OG OH1 -0.66 ! | +ATOM HG1 H 0.43 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA OG CB N HN N CA +BOND C CA C +N CA HA CB HB1 +BOND CB HB2 OG HG1 +DOUBLE O C +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HG1 OG +ACCEPTOR OG +ACCEPTOR O C +IC -C CA *N HN 1.3474 124.3700 180.0000 114.1800 0.9999 +IC -C N CA C 1.3474 124.3700 180.0000 105.8100 1.5166 +IC N CA C +N 1.4579 105.8100 180.0000 117.7200 1.3448 +IC +N CA *C O 1.3448 117.7200 180.0000 120.2500 1.2290 +IC CA C +N +CA 1.5166 117.7200 180.0000 124.6300 1.4529 +IC N C *CA CB 1.4579 105.8100 124.7500 111.4000 1.5585 +IC N C *CA HA 1.4579 105.8100 -115.5600 107.3000 1.0821 +IC N CA CB OG 1.4579 114.2800 180.0000 112.4500 1.4341 +IC OG CA *CB HB1 1.4341 112.4500 119.3200 108.1000 1.1140 +IC OG CA *CB HB2 1.4341 112.4500 -123.8600 110.3800 1.1136 +IC CA CB OG HG1 1.5585 112.4500 165.9600 107.0800 0.9655 + +RESI THR 0.00 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | OG1--HG1 +ATOM HA HB1 0.09 ! | / +GROUP ! HA-CA--CB-HB +ATOM CB CT1 0.14 ! | \ +ATOM HB HA1 0.09 ! | CG2--HG21 +ATOM OG1 OH1 -0.66 ! O=C / \ +ATOM HG1 H 0.43 ! | HG21 HG22 +GROUP +ATOM CG2 CT3 -0.27 +ATOM HG21 HA3 0.09 +ATOM HG22 HA3 0.09 +ATOM HG23 HA3 0.09 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA OG1 CB CG2 CB N HN +BOND N CA C CA C +N CA HA +BOND CB HB OG1 HG1 CG2 HG21 CG2 HG22 CG2 HG23 +DOUBLE O C +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HG1 OG1 +ACCEPTOR OG1 +ACCEPTOR O C +IC -C CA *N HN 1.3471 124.1200 180.0000 114.2600 0.9995 +IC -C N CA C 1.3471 124.1200 180.0000 106.0900 1.5162 +IC N CA C +N 1.4607 106.0900 180.0000 117.6900 1.3449 +IC +N CA *C O 1.3449 117.6900 180.0000 120.3000 1.2294 +IC CA C +N +CA 1.5162 117.6900 180.0000 124.6600 1.4525 +IC N C *CA CB 1.4607 106.0900 126.4600 112.7400 1.5693 +IC N C *CA HA 1.4607 106.0900 -114.9200 106.5300 1.0817 +IC N CA CB OG1 1.4607 114.8100 180.0000 112.1600 1.4252 +IC OG1 CA *CB HB 1.4252 112.1600 116.3900 106.1100 1.1174 +IC OG1 CA *CB CG2 1.4252 112.1600 -124.1300 115.9100 1.5324 +IC CA CB OG1 HG1 1.5693 112.1600 -179.2800 105.4500 0.9633 +IC CA CB CG2 HG21 1.5693 115.9100 -173.6500 110.8500 1.1104 +IC HG21 CB *CG2 HG22 1.1104 110.8500 119.5100 110.4100 1.1109 +IC HG21 CB *CG2 HG23 1.1104 110.8500 -120.3900 111.1100 1.1113 + +RESI TRP 0.00 +GROUP +ATOM N NH1 -0.47 ! | HE3 +ATOM HN H 0.31 ! HN-N | +ATOM CA CT1 0.07 ! | HB1 CE3 +ATOM HA HB1 0.09 ! | | / \\ +GROUP ! HA-CA--CB---CG-----CD2 CZ3-HZ3 +ATOM CB CT2 -0.18 ! | | || || | +ATOM HB1 HA2 0.09 ! | HB2 CD1 CE2 CH2-HH2 +ATOM HB2 HA2 0.09 ! O=C / \ / \ // +GROUP ! | HD1 NE1 CZ2 +ATOM CG CY -0.03 ! | | +ATOM CD1 CA -0.15 ! HE1 HZ2 +ATOM HD1 HP 0.22 +ATOM NE1 NY -0.51 +ATOM HE1 H 0.37 +ATOM CE2 CPT 0.24 +ATOM CD2 CPT 0.11 +ATOM CE3 CAI -0.25 +ATOM HE3 HP 0.17 +ATOM CZ3 CA -0.20 +ATOM HZ3 HP 0.14 +ATOM CZ2 CAI -0.27 +ATOM HZ2 HP 0.16 +ATOM CH2 CA -0.14 +ATOM HH2 HP 0.14 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB CD2 CG NE1 CD1 +BOND CZ2 CE2 +BOND N HN N CA C CA C +N +BOND CZ3 CH2 CD2 CE3 NE1 CE2 CA HA CB HB1 +BOND CB HB2 CD1 HD1 NE1 HE1 CE3 HE3 CZ2 HZ2 +BOND CZ3 HZ3 CH2 HH2 +DOUBLE O C CD1 CG CE2 CD2 CZ3 CE3 CH2 CZ2 +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HE1 NE1 +ACCEPTOR O C +IC -C CA *N HN 1.3482 123.5100 180.0000 115.0200 0.9972 +IC -C N CA C 1.3482 123.5100 180.0000 107.6900 1.5202 +IC N CA C +N 1.4507 107.6900 180.0000 117.5700 1.3505 +IC +N CA *C O 1.3505 117.5700 180.0000 121.0800 1.2304 +IC CA C +N +CA 1.5202 117.5700 180.0000 124.8800 1.4526 +IC N C *CA CB 1.4507 107.6900 122.6800 111.2300 1.5560 +IC N C *CA HA 1.4507 107.6900 -117.0200 106.9200 1.0835 +IC N CA CB CG 1.4507 111.6800 180.0000 115.1400 1.5233 +IC CG CA *CB HB1 1.5233 115.1400 119.1700 107.8400 1.1127 +IC CG CA *CB HB2 1.5233 115.1400 -124.7300 109.8700 1.1118 +IC CA CB CG CD2 1.5560 115.1400 90.0000 123.9500 1.4407 +IC CD2 CB *CG CD1 1.4407 123.9500 -172.8100 129.1800 1.3679 +IC CD1 CG CD2 CE2 1.3679 106.5700 -0.0800 106.6500 1.4126 +IC CG CD2 CE2 NE1 1.4407 106.6500 0.1400 107.8700 1.3746 +IC CE2 CG *CD2 CE3 1.4126 106.6500 179.2100 132.5400 1.4011 +IC CE2 CD2 CE3 CZ3 1.4126 120.8000 -0.2000 118.1600 1.4017 +IC CD2 CE3 CZ3 CH2 1.4011 118.1600 0.1000 120.9700 1.4019 +IC CE3 CZ3 CH2 CZ2 1.4017 120.9700 0.0100 120.8700 1.4030 +IC CZ3 CD2 *CE3 HE3 1.4017 118.1600 -179.6200 121.8400 1.0815 +IC CH2 CE3 *CZ3 HZ3 1.4019 120.9700 -179.8200 119.4500 1.0811 +IC CZ2 CZ3 *CH2 HH2 1.4030 120.8700 -179.9200 119.5700 1.0811 +IC CE2 CH2 *CZ2 HZ2 1.3939 118.4200 179.8700 120.0800 1.0790 +IC CD1 CE2 *NE1 HE1 1.3752 108.8100 177.7800 124.6800 0.9767 +IC CG NE1 *CD1 HD1 1.3679 110.1000 178.1000 125.4300 1.0820 + +RESI TYR 0.00 +GROUP +ATOM N NH1 -0.47 ! | HD1 HE1 +ATOM HN H 0.31 ! HN-N | | +ATOM CA CT1 0.07 ! | HB1 CD1--CE1 +ATOM HA HB1 0.09 ! | | // \\ +GROUP ! HA-CA--CB--CG CZ--OH +ATOM CB CT2 -0.18 ! | | \ __ / \ +ATOM HB1 HA2 0.09 ! | HB2 CD2--CE2 HH +ATOM HB2 HA2 0.09 ! O=C | | +GROUP ! | HD2 HE2 +ATOM CG CA 0.00 +GROUP +ATOM CD1 CA -0.115 +ATOM HD1 HP 0.115 +GROUP +ATOM CE1 CA -0.115 +ATOM HE1 HP 0.115 +GROUP +ATOM CZ CA 0.11 +ATOM OH OH1 -0.54 +ATOM HH H 0.43 +GROUP +ATOM CD2 CA -0.115 +ATOM HD2 HP 0.115 +GROUP +ATOM CE2 CA -0.115 +ATOM HE2 HP 0.115 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG CB CD2 CG CE1 CD1 +BOND CZ CE2 OH CZ +BOND N HN N CA C CA C +N +BOND CA HA CB HB1 CB HB2 CD1 HD1 CD2 HD2 +BOND CE1 HE1 CE2 HE2 OH HH +DOUBLE O C CD1 CG CE1 CZ CE2 CD2 +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +DONOR HH OH +ACCEPTOR OH +ACCEPTOR O C +IC -C CA *N HN 1.3476 123.8100 180.0000 114.5400 0.9986 +IC -C N CA C 1.3476 123.8100 180.0000 106.5200 1.5232 +IC N CA C +N 1.4501 106.5200 180.0000 117.3300 1.3484 +IC +N CA *C O 1.3484 117.3300 180.0000 120.6700 1.2287 +IC CA C +N +CA 1.5232 117.3300 180.0000 124.3100 1.4513 +IC N C *CA CB 1.4501 106.5200 122.2700 112.3400 1.5606 +IC N C *CA HA 1.4501 106.5200 -116.0400 107.1500 1.0833 +IC N CA CB CG 1.4501 111.4300 180.0000 112.9400 1.5113 +IC CG CA *CB HB1 1.5113 112.9400 118.8900 109.1200 1.1119 +IC CG CA *CB HB2 1.5113 112.9400 -123.3600 110.7000 1.1115 +IC CA CB CG CD1 1.5606 112.9400 90.0000 120.4900 1.4064 +IC CD1 CB *CG CD2 1.4064 120.4900 -176.4600 120.4600 1.4068 +IC CB CG CD1 CE1 1.5113 120.4900 -175.4900 120.4000 1.4026 +IC CE1 CG *CD1 HD1 1.4026 120.4000 178.9400 119.8000 1.0814 +IC CB CG CD2 CE2 1.5113 120.4600 175.3200 120.5600 1.4022 +IC CE2 CG *CD2 HD2 1.4022 120.5600 -177.5700 119.9800 1.0813 +IC CG CD1 CE1 CZ 1.4064 120.4000 -0.1900 120.0900 1.3978 +IC CZ CD1 *CE1 HE1 1.3978 120.0900 179.6400 120.5800 1.0799 +IC CZ CD2 *CE2 HE2 1.3979 119.9200 -178.6900 119.7600 1.0798 +IC CE1 CE2 *CZ OH 1.3978 120.0500 -178.9800 120.2500 1.4063 +IC CE1 CZ OH HH 1.3978 119.6800 175.4500 107.4700 0.9594 + +RESI VAL 0.00 +GROUP +ATOM N NH1 -0.47 ! | HG11 HG12 +ATOM HN H 0.31 ! HN-N | / +ATOM CA CT1 0.07 ! | CG1--HG13 +ATOM HA HB1 0.09 ! | / +GROUP ! HA-CA--CB-HB +ATOM CB CT1 -0.09 ! | \ +ATOM HB HA1 0.09 ! | CG2--HG21 +GROUP ! O=C / \ +ATOM CG1 CT3 -0.27 ! | HG21 HG22 +ATOM HG11 HA3 0.09 +ATOM HG12 HA3 0.09 +ATOM HG13 HA3 0.09 +GROUP +ATOM CG2 CT3 -0.27 +ATOM HG21 HA3 0.09 +ATOM HG22 HA3 0.09 +ATOM HG23 HA3 0.09 +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA CG1 CB CG2 CB N HN +BOND N CA C CA C +N CA HA +BOND CB HB CG1 HG11 CG1 HG12 CG1 HG13 CG2 HG21 +BOND CG2 HG22 CG2 HG23 +DOUBLE O C +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +ACCEPTOR O C +IC -C CA *N HN 1.3482 124.5700 180.0000 114.4100 0.9966 +IC -C N CA C 1.3482 124.5700 180.0000 105.5400 1.5180 +IC N CA C +N 1.4570 105.5400 180.0000 117.8300 1.3471 +IC +N CA *C O 1.3471 117.8300 180.0000 120.7000 1.2297 +IC CA C +N +CA 1.5180 117.8300 180.0000 124.0800 1.4471 +IC N C *CA CB 1.4570 105.5400 122.9500 111.2300 1.5660 +IC N C *CA HA 1.4570 105.5400 -117.2400 107.4600 1.0828 +IC N CA CB CG1 1.4570 113.0500 180.0000 113.9700 1.5441 +IC CG1 CA *CB CG2 1.5441 113.9700 123.9900 112.1700 1.5414 +IC CG1 CA *CB HB 1.5441 113.9700 -119.1700 107.5700 1.1178 +IC CA CB CG1 HG11 1.5660 113.9700 177.8300 110.3000 1.1114 +IC HG11 CB *CG1 HG12 1.1114 110.3000 119.2500 111.6700 1.1097 +IC HG11 CB *CG1 HG13 1.1114 110.3000 -119.4900 110.7000 1.1110 +IC CA CB CG2 HG21 1.5660 112.1700 -177.7800 110.7100 1.1108 +IC HG21 CB *CG2 HG22 1.1108 110.7100 120.0800 110.5600 1.1115 +IC HG21 CB *CG2 HG23 1.1108 110.7100 -119.5500 111.2300 1.1098 + +RESI ALAD 0.00 ! Alanine dipeptide +GROUP +ATOM CL CT3 -0.27 +ATOM HL1 HA3 0.09 +ATOM HL2 HA3 0.09 +ATOM HL3 HA3 0.09 +GROUP +ATOM CLP C 0.51 +ATOM OL O -0.51 +GROUP +ATOM NL NH1 -0.47 +ATOM HL H 0.31 +ATOM CA CT1 0.07 +ATOM HA HB1 0.09 +GROUP +ATOM CB CT3 -0.27 ! HL1 OL OR HR1 +ATOM HB1 HA3 0.09 ! \ || HL HA || HR / +ATOM HB2 HA3 0.09 ! \ || | | || | / +ATOM HB3 HA3 0.09 ! HL2---CL--CLP--NL--CA--CRP--NR---CR---HR2 +GROUP ! / | \ +ATOM CRP C 0.51 ! / HB1--CB--HB3 \ +ATOM OR O -0.51 ! HL3 | HR3 +GROUP ! HB2 +ATOM NR NH1 -0.47 +ATOM HR H 0.31 +ATOM CR CT3 -0.11 +ATOM HR1 HA3 0.09 +ATOM HR2 HA3 0.09 +ATOM HR3 HA3 0.09 + +BOND CL CLP CLP NL NL CA +BOND CA CRP CRP NR NR CR +DOUBLE CLP OL CRP OR +BOND NL HL NR HR +BOND CA HA CA CB +BOND CL HL1 CL HL2 CL HL3 +BOND CB HB1 CB HB2 CB HB3 +BOND CR HR1 CR HR2 CR HR3 +IMPR CLP CL NL OL NL CLP CA HL +IMPR CRP CA NR OR NR CRP CR HR + +CMAP CLP NL CA CRP NL CA CRP NR + +ic clp nl ca crp 0.0 0.0 180.0 0.0 0.0 ! Phi +ic ca clp *nl hl 0.0 0.0 180.0 0.0 0.0 +ic hl nl ca crp 0.0 0.0 0.0 0.0 0.0 +ic nl ca crp nr 0.0 0.0 180.0 0.0 0.0 ! Psi +ic ca nr *crp or 0.0 0.0 180.0 0.0 0.0 +ic nl ca crp or 0.0 0.0 0.0 0.0 0.0 +ic cl clp nl ca 0.0 0.0 180.0 0.0 0.0 ! Omega Left +ic nl cl *clp ol 0.0 0.0 180.0 0.0 0.0 +ic ol clp nl ca 0.0 0.0 0.0 0.0 0.0 +ic ca crp nr cr 0.0 0.0 180.0 0.0 0.0 ! Omega Right +ic crp cr *nr hr 0.0 0.0 180.0 0.0 0.0 +ic ca crp nr hr 0.0 0.0 180.0 0.0 0.0 +ic nl crp *ca ha 0.0 0.0 240.0 0.0 0.0 +ic nl crp *ca cb 0.0 0.0 120.0 0.0 0.0 +ic hl1 cl clp nl 0.0 0.0 180.0 0.0 0.0 +ic hl2 cl clp nl 0.0 0.0 60.0 0.0 0.0 +ic hl3 cl clp ol 0.0 0.0 120.0 0.0 0.0 +ic ha ca cb hb1 0.0 0.0 180.0 0.0 0.0 +ic nl ca cb hb2 0.0 0.0 180.0 0.0 0.0 +ic crp ca cb hb3 0.0 0.0 180.0 0.0 0.0 +ic crp nr cr hr1 0.0 0.0 180.0 0.0 0.0 +ic crp nr cr hr2 0.0 0.0 60.0 0.0 0.0 +ic hr nr cr hr3 0.0 0.0 120.0 0.0 0.0 +ic ca clp *nl hl 0.0 0.0 180.0 0.0 0.0 +ic ca nr *crp or 0.0 0.0 180.0 0.0 0.0 +ic hb1 hb2 *cb hb3 0.0 0.0 120.0 0.0 0.0 +ic hl1 hl2 *cl hl3 0.0 0.0 240.0 0.0 0.0 +ic hr1 hr2 *cr hr3 0.0 0.0 240.0 0.0 0.0 +ic ha ca nl hl 0.0 0.0 240.0 0.0 0.0 +patch first none last none + +PRES NTER 1.00 ! standard N-terminus +GROUP ! use in generate statement +ATOM N NH3 -0.30 ! +ATOM HT1 HC 0.33 ! HT1 +ATOM HT2 HC 0.33 ! (+)/ +ATOM HT3 HC 0.33 ! --CA--N--HT2 +ATOM CA CT1 0.21 ! | \ +ATOM HA HB1 0.10 ! HA HT3 +DELETE ATOM HN +BOND HT1 N HT2 N HT3 N +DONOR HT1 N +DONOR HT2 N +DONOR HT3 N +IC HT1 N CA C 0.0000 0.0000 180.0000 0.0000 0.0000 +IC HT2 CA *N HT1 0.0000 0.0000 120.0000 0.0000 0.0000 +IC HT3 CA *N HT2 0.0000 0.0000 120.0000 0.0000 0.0000 + +PRES GLYP 1.00 ! Glycine N-terminus +GROUP ! use in generate statement +ATOM N NH3 -0.30 ! +ATOM HT1 HC 0.33 ! HA1 HT1 +ATOM HT2 HC 0.33 ! | (+)/ +ATOM HT3 HC 0.33 ! --CA--N--HT2 +ATOM CA CT2 0.13 ! | \ +ATOM HA1 HB2 0.09 ! HA2 HT3 +ATOM HA2 HB2 0.09 ! +DELETE ATOM HN +BOND HT1 N HT2 N HT3 N +DONOR HT1 N +DONOR HT2 N +DONOR HT3 N +IC HT1 N CA C 0.0000 0.0000 180.0000 0.0000 0.0000 +IC HT2 CA *N HT1 0.0000 0.0000 120.0000 0.0000 0.0000 +IC HT3 CA *N HT2 0.0000 0.0000 120.0000 0.0000 0.0000 + +PRES PROP 1.00 ! Proline N-Terminal +GROUP ! use in generate statement +ATOM N NP -0.07 ! HA +ATOM HN1 HC 0.24 ! | +ATOM HN2 HC 0.24 ! -CA HN1 +ATOM CD CP3 0.16 ! / \ / +ATOM HD1 HA2 0.09 ! N(+) +ATOM HD2 HA2 0.09 ! / \ +ATOM CA CP1 0.16 ! -CD HN2 +ATOM HA HB1 0.09 ! | \ +BOND HN1 N HN2 N ! HD1 HD2 +DONOR HN1 N +DONOR HN2 N +IC HN1 CA *N CD 0.0000 0.0000 120.0000 0.0000 0.0000 +IC HN2 CA *N HN1 0.0000 0.0000 120.0000 0.0000 0.0000 + +PRES ACE 0.00 ! acetylated N-terminus + ! do NOT use to create dipeptides, see ACED +GROUP ! use in generate statement +ATOM CAY CT3 -0.27 ! +ATOM HY1 HA3 0.09 ! HY1 HY2 HY3 +ATOM HY2 HA3 0.09 ! \ | / +ATOM HY3 HA3 0.09 ! CAY +GROUP ! | +ATOM CY C 0.51 ! CY=OY +ATOM OY O -0.51 ! | + ! +BOND CY CAY CY N CAY HY1 CAY HY2 CAY HY3 +DOUBLE OY CY +IMPR CY CAY N OY +IMPR N CY CA HN +CMAP CY N CA C N CA C +N +ACCEPTOR OY CY +IC CY N CA C 0.0000 0.0000 -60.0000 0.0000 0.0000 +IC CY CA *N HN 0.0000 0.0000 180.0000 0.0000 0.0000 +IC CAY CY N CA 0.0000 0.0000 180.0000 0.0000 0.0000 +IC N CAY *CY OY 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OY CY CAY HY1 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OY CY CAY HY2 0.0000 0.0000 60.0000 0.0000 0.0000 +IC OY CY CAY HY3 0.0000 0.0000 -60.0000 0.0000 0.0000 + +PRES ACED 0.00 ! acetylated N-terminus (to create dipeptide) +GROUP ! use in generate statement +ATOM CAY CT3 -0.27 ! +ATOM HY1 HA3 0.09 ! HY1 HY2 HY3 +ATOM HY2 HA3 0.09 ! \ | / +ATOM HY3 HA3 0.09 ! CAY +GROUP ! | +ATOM CY C 0.51 ! CY=OY +ATOM OY O -0.51 ! | + ! +BOND CY CAY CY N CAY HY1 CAY HY2 CAY HY3 +DOUBLE OY CY +IMPR CY CAY N OY +IMPR N CY CA HN +CMAP CY N CA C N CA C NT +ACCEPTOR OY CY +IC CY N CA C 0.0000 0.0000 -60.0000 0.0000 0.0000 +IC CY CA *N HN 0.0000 0.0000 180.0000 0.0000 0.0000 +IC CAY CY N CA 0.0000 0.0000 180.0000 0.0000 0.0000 +IC N CAY *CY OY 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OY CY CAY HY1 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OY CY CAY HY2 0.0000 0.0000 60.0000 0.0000 0.0000 +IC OY CY CAY HY3 0.0000 0.0000 -60.0000 0.0000 0.0000 + +PRES ACP 0.00 ! acetylated N-terminus for proline + ! do NOT use to create dipeptide, see ACPD +GROUP ! use in generate statement +ATOM CAY CT3 -0.27 ! +ATOM HY1 HA3 0.09 ! HY1 HY2 HY3 +ATOM HY2 HA3 0.09 ! \ | / +ATOM HY3 HA3 0.09 ! CAY +GROUP ! | +ATOM CY C 0.51 ! CY=OY +ATOM OY O -0.51 ! | + ! +BOND CY CAY CY N CAY HY1 CAY HY2 CAY HY3 +DOUBLE OY CY +IMPR CY CAY N OY +IMPR N CY CA CD +CMAP CY N CA C N CA C +N +ACCEPTOR OY CY +IC CY N CA C 0.0000 0.0000 -60.0000 0.0000 0.0000 +IC CY CA *N CD 0.0000 0.0000 180.0000 0.0000 0.0000 +IC CAY CY N CA 0.0000 0.0000 180.0000 0.0000 0.0000 +IC N CAY *CY OY 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OY CY CAY HY1 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OY CY CAY HY2 0.0000 0.0000 60.0000 0.0000 0.0000 +IC OY CY CAY HY3 0.0000 0.0000 -60.0000 0.0000 0.0000 + +PRES ACPD 0.00 ! acetylated N-terminus for proline (to create dipeptide) +GROUP ! use in generate statement +ATOM CAY CT3 -0.27 ! +ATOM HY1 HA3 0.09 ! HY1 HY2 HY3 +ATOM HY2 HA3 0.09 ! \ | / +ATOM HY3 HA3 0.09 ! CAY +GROUP ! | +ATOM CY C 0.51 ! CY=OY +ATOM OY O -0.51 ! | + ! +BOND CY CAY CY N CAY HY1 CAY HY2 CAY HY3 +DOUBLE OY CY +IMPR CY CAY N OY +IMPR N CY CA CD +CMAP CY N CA C N CA C NT +ACCEPTOR OY CY +IC CY N CA C 0.0000 0.0000 -60.0000 0.0000 0.0000 +IC CY CA *N CD 0.0000 0.0000 180.0000 0.0000 0.0000 +IC CAY CY N CA 0.0000 0.0000 180.0000 0.0000 0.0000 +IC N CAY *CY OY 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OY CY CAY HY1 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OY CY CAY HY2 0.0000 0.0000 60.0000 0.0000 0.0000 +IC OY CY CAY HY3 0.0000 0.0000 -60.0000 0.0000 0.0000 + +PRES NNEU 0.00 ! neutral N-terminus; charges from LSN +GROUP ! use in generate statement +ATOM N NH2 -0.96 ! +ATOM HT1 H 0.34 ! HT1 +ATOM HT2 H 0.34 ! / + ! --CA--N--HT2 +ATOM CA CT1 0.19 ! | ! change to CT2 for neutral N terminal glycine +ATOM HA HB1 0.09 ! HA ! change to HA1 and HB2 and add HA2 atom for N terminal glycine +DELETE ATOM HN +BOND HT1 N HT2 N +DONOR HT1 N +DONOR HT2 N +IC HT1 N CA C 0.0000 0.0000 180.0000 0.0000 0.0000 +IC HT2 CA *N HT1 0.0000 0.0000 120.0000 0.0000 0.0000 + +PRES NGNE 0.00 ! neutral N-terminal glycine; charges from LSN +GROUP ! use in generate statement +ATOM N NH2 -0.96 ! +ATOM HT1 H 0.34 ! HA1 HT1 +ATOM HT2 H 0.34 ! | / + ! --CA--N--HT2 +ATOM CA CT2 0.10 ! | ! change to CT2 for neutral N terminal glycine +ATOM HA1 HB2 0.09 ! HA2 ! change to HA1 and HB2 and add HA2 atom for N terminal glycine +ATOM HA2 HB2 0.09 ! HA2 ! change to HA1 and HB2 and add HA2 atom for N terminal glycine +DELETE ATOM HN +BOND HT1 N HT2 N +DONOR HT1 N +DONOR HT2 N +IC HT1 N CA C 0.0000 0.0000 180.0000 0.0000 0.0000 +IC HT2 CA *N HT1 0.0000 0.0000 120.0000 0.0000 0.0000 + +PRES CTER -1.00 ! standard C-terminus +GROUP ! use in generate statement +ATOM C CC 0.34 ! OT2(-) +ATOM OT1 OC -0.67 ! / +ATOM OT2 OC -0.67 ! -C +DELETE ATOM O ! \\ +BOND C OT2 ! OT1 +DOUBLE C OT1 +IMPR C CA OT2 OT1 +ACCEPTOR OT1 C +ACCEPTOR OT2 C +IC N CA C OT2 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OT2 CA *C OT1 0.0000 0.0000 180.0000 0.0000 0.0000 + +PRES CNEU 0.00 ! protonated (neutral) C-terminu, charges from ASPP +GROUP ! use in generate statement; C reduced to balance charges +ATOM C CD 0.72 ! OT2-HT2 +ATOM OT1 OB -0.55 ! / +ATOM OT2 OH1 -0.61 ! -C +ATOM HT2 H 0.44 ! \\ +DELETE ATOM O ! OT1 +BOND C OT2 OT2 HT2 +DOUBLE C OT1 +IMPR C CA OT2 OT1 +ACCEPTOR OT1 C +ACCEPTOR OT2 C +IC N CA C OT2 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OT2 CA *C OT1 0.0000 0.0000 180.0000 0.0000 0.0000 +IC CA C OT2 HT2 0.0000 0.0000 180.0000 0.0000 0.0000 + +PRES PCTE 0.00 ! protonated C-terminus (previously CTP) +GROUP ! use in generate statement +ATOM C CD 0.72 ! OT2--HT2 +ATOM OT1 OB -0.55 ! / +ATOM OT2 OH1 -0.61 ! -C +ATOM HT2 H 0.44 ! \\ +DELETE ATOM O ! OT1 +BOND C OT2 OT2 HT2 ! +DOUBLE C OT1 +IMPR C CA OT2 OT1 +ACCEPTOR OT1 C +IC N CA C OT2 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OT2 CA *C OT1 0.0000 0.0000 180.0000 0.0000 0.0000 +IC CA C OT2 HT2 0.0000 0.0000 180.0000 0.0000 0.0000 + +PRES CT1 0.00 ! methylated C-terminus from methyl acetate +GROUP ! use in generate statement +ATOM N NH1 -0.47 ! don't use with Gly or Pro +ATOM HN H 0.31 ! OT1 +ATOM CA CT1 0.17 ! | // +ATOM HA HB1 0.09 ! -N--CA--C HT1 +ATOM C CD 0.63 ! | | \ / +ATOM OT1 OB -0.52 ! HN HA OT2--CT--HT2 +ATOM OT2 OS -0.34 ! \ +ATOM CT CT3 -0.14 ! HT3 +ATOM HT1 HA3 0.09 ! +ATOM HT2 HA3 0.09 ! +ATOM HT3 HA3 0.09 ! +DELETE ATOM O +BOND C OT2 OT2 CT +BOND CT HT1 CT HT2 CT HT3 +DOUBLE C OT1 +IMPR C CA OT2 OT1 +ACCEPTOR OT1 C +ACCEPTOR OT2 C +IC N CA C OT2 0.0000 0.0000 180.0000 0.0000 0.0000 +IC OT2 CA *C OT1 0.0000 0.0000 180.0000 0.0000 0.0000 +IC CA C OT2 CT 0.0000 0.0000 180.0000 0.0000 0.0000 +IC C OT2 CT HT1 0.0000 0.0000 0.0000 0.0000 0.0000 +IC C OT2 CT HT2 0.0000 0.0000 120.0000 0.0000 0.0000 +IC C OT2 CT HT3 0.0000 0.0000 240.0000 0.0000 0.0000 + +PRES CT2 0.00 ! amidated C-terminus +GROUP ! use in generate statement +ATOM C CC 0.55 ! +ATOM O O -0.55 ! | +GROUP ! O=C +ATOM NT NH2 -0.62 ! | +ATOM HT1 H 0.32 ! NT +ATOM HT2 H 0.30 ! / \ +BOND C NT ! HT1 HT2 (HT1 is cis to O) +BOND NT HT1 NT HT2 ! +IMPR C NT CA O C CA NT O +IMPR NT C HT1 HT2 NT C HT2 HT1 +DONOR HT1 NT +DONOR HT2 NT +IC N CA C O 0.0000 0.0000 180.0000 0.0000 0.0000 +IC NT CA *C O 0.0000 0.0000 180.0000 0.0000 0.0000 +IC CA C NT HT1 0.0000 0.0000 180.0000 0.0000 0.0000 +IC HT1 C *NT HT2 0.0000 0.0000 180.0000 0.0000 0.0000 + +PRES CT3 0.00 ! N-Methylamide C-terminus +GROUP ! use in generate statement +ATOM C C 0.51 ! +ATOM O O -0.51 ! | +GROUP ! C=O +ATOM NT NH1 -0.47 ! | +ATOM HNT H 0.31 ! NT-HNT +ATOM CAT CT3 -0.11 ! | +ATOM HT1 HA3 0.09 ! HT1-CAT-HT3 +ATOM HT2 HA3 0.09 ! | +ATOM HT3 HA3 0.09 ! HT2 + ! +BOND C NT NT HNT NT CAT CAT HT1 CAT HT2 CAT HT3 +IMPR NT C CAT HNT C CA NT O +CMAP -C N CA C N CA C NT +!CMAP CY N CA C N CA C NT +DONOR HNT NT +IC N CA C NT 0.0000 0.0000 180.0000 0.0000 0.0000 +IC NT CA *C O 0.0000 0.0000 180.0000 0.0000 0.0000 +IC C CAT *NT HNT 0.0000 0.0000 180.0000 0.0000 0.0000 +IC CA C NT CAT 0.0000 0.0000 180.0000 0.0000 0.0000 +IC C NT CAT HT1 0.0000 0.0000 60.0000 0.0000 0.0000 +IC C NT CAT HT2 0.0000 0.0000 180.0000 0.0000 0.0000 +IC C NT CAT HT3 0.0000 0.0000 -60.0000 0.0000 0.0000 + +PRES ASPP 0.00 ! patch for protonated aspartic acid, proton on od2 + ! via acetic acid, use in a patch statement and + ! follow with AUTOgenerate ANGLes DIHEdrals command +GROUP +ATOM CB CT2 -0.21 ! +ATOM HB1 HA2 0.09 ! HB1 OD1 +ATOM HB2 HA2 0.09 ! | // +ATOM CG CD 0.75 ! -CB--CG +ATOM OD1 OB -0.55 ! | \ +ATOM OD2 OH1 -0.61 ! HB2 OD2-HD2 +ATOM HD2 H 0.44 ! +BOND OD2 HD2 +DONOR HD2 OD2 +IC HD2 OD2 CG OD1 0.0000 0.0000 0.0000 0.0000 0.0000 + +PRES GLUP 0.00 ! patch for protonated glutamic acid, proton on oe2 + ! via acetic acid, use in a patch statement and + ! follow with AUTOgenerate ANGLes DIHEdrals command +GROUP +ATOM CG CT2 -0.21 ! +ATOM HG1 HA2 0.09 ! HG1 OE1 +ATOM HG2 HA2 0.09 ! | // +ATOM CD CD 0.75 ! -CG--CD +ATOM OE1 OB -0.55 ! | \ +ATOM OE2 OH1 -0.61 ! HG2 OE2-HE2 +ATOM HE2 H 0.44 ! +BOND OE2 HE2 +DONOR HE2 OE2 +IC HE2 OE2 CD OE1 0.0000 0.0000 0.0000 0.0000 0.0000 + +PRES LSN 0.00 ! patch for neutral lysine based on methylamine + ! use in a patch statement + ! follow with AUTOgenerate ANGLes DIHEdrals command +!delete atom and reassign charges +DELETE ATOM HZ3 +GROUP +ATOM CE CT2 0.13 +ATOM HE1 HA2 0.075 +ATOM HE2 HA2 0.075 +ATOM NZ NH2 -0.96 +ATOM HZ1 HC 0.34 +ATOM HZ2 HC 0.34 + +RESI CYM -1.00 ! Anionic Cysteine + ! Thiolate form based on RESI MES1 & ES1 (adm jr.) + ! in toppar_*_prot_model.str +! Foloppe, N., J. Sagemark, K. Nordstrand, K.D. Berndt, and L. Nilsson +! (2001). J. Mol. Biol. 310:449-470. +! Ported to CHARMM36 by kevo and beta hydrogens changed +! from HA to HA2 based on other AA and RESI ES1 +GROUP +ATOM N NH1 -0.47 ! | +ATOM HN H 0.31 ! HN-N +ATOM CA CT1 0.07 ! | HB1 +ATOM HA HB1 0.09 ! | | - +GROUP ! HA-CA--CB--SG (thiolate) +ATOM CB CS -0.38 ! | | +ATOM HB1 HA2 0.09 ! | HB2 +ATOM HB2 HA2 0.09 ! O=C +ATOM SG SS -0.80 ! | +GROUP +ATOM C C 0.51 +ATOM O O -0.51 +BOND CB CA SG CB N HN N CA +BOND O C C CA C +N CA HA CB HB1 CB HB2 +IMPR N -C CA HN C CA +N O +CMAP -C N CA C N CA C +N +DONOR HN N +ACCEPTOR O C +! IC table copied by kevo from RESI CYS +IC -C CA *N HN 1.3479 123.9300 180.0000 114.7700 0.9982 +IC -C N CA C 1.3479 123.9300 180.0000 105.8900 1.5202 +IC N CA C +N 1.4533 105.8900 180.0000 118.3000 1.3498 +IC +N CA *C O 1.3498 118.3000 180.0000 120.5900 1.2306 +IC CA C +N +CA 1.5202 118.3000 180.0000 124.5000 1.4548 +IC N C *CA CB 1.4533 105.8900 121.7900 111.9800 1.5584 +IC N C *CA HA 1.4533 105.8900 -116.3400 107.7100 1.0837 +IC N CA CB SG 1.4533 111.5600 180.0000 113.8700 1.8359 +IC SG CA *CB HB1 1.8359 113.8700 119.9100 107.2400 1.1134 +IC SG CA *CB HB2 1.8359 113.8700 -125.3200 109.8200 1.1124 + +PRES CYSD -1.00 ! patch to deprotonate cysteine by kevo +DELETE ATOM HG1 ! from RESI ES1 in toppar_*_prot_model.str +ATOM CB CS -0.38 +ATOM HB1 HA2 0.09 +ATOM HB2 HA2 0.09 +ATOM SG SS -0.80 +! Doesn't require AUTOgenerate. + +PRES SERD -1.00 ! patch to deprotonate serine by kevo +DELETE ATOM HG1 ! from RESI ETO in toppar_*_prot_model.str +ATOM CB CT2 -0.30 +ATOM HB1 HA2 0.11 +ATOM HB2 HA2 0.11 +ATOM OG OC -0.92 +! That's all, folks! Doesn't even need AUTOgenerate. + +PRES LINK 0.00 ! linkage for IMAGES or for joining segments + ! 1 refers to previous (N terminal) + ! 2 refers to next (C terminal) + ! use in a patch statement + ! follow with AUTOgenerate ANGLes DIHEdrals command +BOND 1C 2N +!the need for the explicit specification of angles and dihedrals in +!patches linking images has not been tested +!ANGLE 1C 2N 2CA 1CA 1C 2N +!ANGLE 1O 1C 2N 1C 2N 2HN +!DIHE 1C 2N 2CA 2C 1C 2N 2CA 2HA 1C 2N 2CA 2CB +!DIHE 1HA 1CA 1C 2N 1N 1CA 1C 2N 1CB 1CA 1C 2N +!DIHE 1CA 1C 2N 2HN 1CA 1C 2N 2CA +!DIHE 1O 1C 2N 2HN 1O 1C 2N 2CA +IMPR 2N 1C 2CA 2HN 1C 1CA 2N 1O +IC 1N 1CA 1C 2N 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 2N 1CA *1C 1O 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1CA 1C 2N 2CA 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1C 2N 2CA 2C 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1C 2CA *2N 2HN 0.0000 0.0000 180.0000 0.0000 0.0000 + +PRES DISU -0.36 ! patch for disulfides. Patch must be 1-CYS and 2-CYS. + ! use in a patch statement + ! follow with AUTOgenerate ANGLes DIHEdrals command +GROUP +ATOM 1CB CT2 -0.10 ! +ATOM 1SG SM -0.08 ! 2SG--2CB-- +GROUP ! / +ATOM 2SG SM -0.08 ! -1CB--1SG +ATOM 2CB CT2 -0.10 ! +DELETE ATOM 1HG1 +DELETE ATOM 2HG1 +BOND 1SG 2SG +IC 1CA 1CB 1SG 2SG 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1CB 1SG 2SG 2CB 0.0000 0.0000 90.0000 0.0000 0.0000 +IC 1SG 2SG 2CB 2CA 0.0000 0.0000 180.0000 0.0000 0.0000 + +PRES HS2 0.00 ! Patch for neutral His, move proton from ND1 to NE2 + ! use in a patch statement + ! follow with AUTOgenerate ANGLes DIHEdrals command +GROUP +ATOM CE1 CPH2 0.25 ! HE1 +ATOM HE1 HR1 0.13 ! / +ATOM ND1 NR2 -0.70 ! HB1 ND1--CE1 +ATOM CG CPH1 0.22 ! | / | +ATOM CB CT2 -0.08 ! -CB--CG | +ATOM HB1 HA2 0.09 ! | \ | +ATOM HB2 HA2 0.09 ! HB2 CD2--NE2 +GROUP ! | \ +ATOM NE2 NR1 -0.36 ! HD2 HE2 +ATOM HE2 H 0.32 +ATOM CD2 CPH1 -0.05 +ATOM HD2 HR3 0.09 +DELETE ATOM HD1 +DELETE ACCE NE2 +BOND NE2 HE2 +IMPR NE2 CD2 CE1 HE2 NE2 CE1 CD2 HE2 +DONOR HE2 NE2 +ACCEPTOR ND1 +IC CE1 CD2 *NE2 HE2 0.0000 0.0000 180.0000 0.0000 0.0000 + +! patches for cyclic peptides +PRES LIG1 0.00000 ! linkage for cyclic peptide + ! 1 refers to the C terminus which is a glycine + ! 2 refers to the N terminus + ! use in a patch statement, perform initial + ! generation using first NONE last NONE + ! follow with AUTOgenerate ANGLes DIHEdrals command +BOND 1C 2N +IMPR 2N 1C 2CA 2HN 1C 1CA 2N 1O +IC 1N 1CA 1C 2N 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 2N 1CA *1C 1O 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1CA 1C 2N 2CA 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1C 2N 2CA 2C 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1C 2CA *2N 2HN 0.0000 0.0000 180.0000 0.0000 0.0000 + +PRES LIG2 0.00000 ! linkage for cyclic peptide + ! 1 refers to the C terminus + ! 2 refers to the N terminus which is a glycine + ! use in a patch statement, perform initial + ! generation using first NONE last NONE + ! follow with AUTOgenerate ANGLes DIHEdrals command +BOND 1C 2N +IMPR 2N 1C 2CA 2HN 1C 1CA 2N 1O +IC 1N 1CA 1C 2N 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 2N 1CA *1C 1O 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1CA 1C 2N 2CA 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1C 2N 2CA 2C 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1C 2CA *2N 2HN 0.0000 0.0000 180.0000 0.0000 0.0000 + +PRES LIG3 0.00000 ! linkage for cyclic peptide + ! 1 refers to the C terminus which is a glycine + ! 2 refers to the N terminus which is a glycine + ! use in a patch statement, perform initial + ! generation using first NONE last NONE + ! follow with AUTOgenerate ANGLes DIHEdrals command +BOND 1C 2N +IMPR 2N 1C 2CA 2HN 1C 1CA 2N 1O +IC 1N 1CA 1C 2N 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 2N 1CA *1C 1O 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1CA 1C 2N 2CA 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1C 2N 2CA 2C 0.0000 0.0000 180.0000 0.0000 0.0000 +IC 1C 2CA *2N 2HN 0.0000 0.0000 180.0000 0.0000 0.0000 + + +* \\\\ CHARMM36 All-Hydrogen Nucleic Acid Topology File //// +* Alexander D. MacKerell Jr. and coworkers +* April 2011 +* All comments to the CHARMM web site: www.charmm.org +* parameter set discussion forum +* +36 1 + +!updated 2016/8. see toppar_all.history. + +!2010/2011 additions +! ejd, 2010 RNA update +! adm, 2011 DNA update +! For DNA update, new atom type required for P of DNA. This required +! replication of a number of parameters and the creation of new +! patches, DEOX and DEO5, to convert RNA to DNA, such that previous +! CHARMM scripts to generate DNA will no longer work. Note that the +! atom type change to P3 ONLY applies to the phosphodester linkage in +! DNA and NOT to terminal phosphates, DMP etc. +! + +!example of new generate/patch combination to generate DNA +! +!read sequence card +!* 1bna, strand 1 +!* +!3 +!cyt gua cyt +! +!generate a first 5ter last 3ter setup warn +! +!patch deo5 a 1 setup warn !special patch for 5-terminal deoxy residue +!patch deox a 2 setup warn !new patch to convert RNA to DNA +!patch deox a 3 setup warn !no special patch required for 3-terminal deoxy residue +! +!autogenerate angles dihedrals !Use of AUTOGENERATE is essential + +! +!references +! +!NUCLEIC ACIDS +! +!Denning, E.J., Priyakumar, U.D., Nilsson, L., and MacKerell Jr., A.D., +!“Impact of 2’-hydroxyl sampling on the conformational properties of +!RNA: Update of the CHARMM all-atom additive force field for RNA,” +!JCC, 32: 1929-1943, 2011, PMC3082605 +! +!Hart, K., Foloppe, N., Baker, C.M., Denning, E.J., Nilsson, L. +!and MacKerell Jr., A.D. “Optimization of the CHARMM additive force +!field for DNA: Improved treatment of the BI/BII conformational +!equilibrium,” JCTC, 8:348–362, 2012, PMC3285246 +! + +!Foloppe, N. and MacKerell, Jr., A.D. "All-Atom Empirical Force Field for +!Nucleic Acids: 1) Parameter Optimization Based on Small Molecule and +!Condensed Phase Macromolecular Target Data. JCC, 2000, 21: 86-104. +! +!MacKerell, Jr., A.D. and Banavali, N. "All-Atom Empirical Force Field for +!Nucleic Acids: 2) Application to Molecular Dynamics Simulations of DNA +!and RNA in Solution. JCC, 2000, 21: 105-120. +! + + +MASS -1 HN1 1.00800 H ! Nucleic acid amine proton +MASS -1 HN2 1.00800 H ! Nucleic acid ring nitrogen proton +MASS -1 HN3 1.00800 H ! Nucleic acid aromatic carbon proton +MASS -1 HN4 1.00800 H ! Nucleic acid phosphate hydroxyl proton +MASS -1 HN5 1.00800 H ! Nucleic acid ribose hydroxyl proton +MASS -1 HN6 1.00800 H ! Nucleic acid ribose aliphatic proton +MASS -1 HN7 1.00800 H ! Nucleic acid proton (equivalent to protein HA) +MASS -1 HN8 1.00800 H ! Bound to CN8 in nucleic acids/model compounds +MASS -1 HN9 1.00800 H ! Bound to CN9 in nucleic acids/model compounds +MASS -1 CN1 12.01100 C ! Nucleic acid carbonyl carbon +MASS -1 CN1T 12.01100 C ! Nucleic acid carbonyl carbon (T/U C2) +MASS -1 CN2 12.01100 C ! Nucleic acid aromatic carbon to amide +MASS -1 CN3 12.01100 C ! Nucleic acid aromatic carbon +MASS -1 CN3T 12.01100 C ! Nucleic acid aromatic carbon, Thy C5 +MASS -1 CN4 12.01100 C ! Nucleic acid purine C8 and ADE C2 +MASS -1 CN5 12.01100 C ! Nucleic acid purine C4 and C5 +MASS -1 CN5G 12.01100 C ! Nucleic acid guanine C5 +MASS -1 CN7 12.01100 C ! Nucleic acid carbon (equivalent to protein CT1) +MASS -1 CN7B 12.01100 C ! Nucleic acid aliphatic carbon for C1' +MASS -1 CN8 12.01100 C ! Nucleic acid carbon (equivalent to protein CT2) +MASS -1 CN8B 12.01100 C ! Nucleic acid carbon (equivalent to protein CT2) +MASS -1 CN9 12.01100 C ! Nucleic acid carbon (equivalent to protein CT3) +MASS -1 NN1 14.00700 N ! Nucleic acid amide nitrogen +MASS -1 NN2 14.00700 N ! Nucleic acid protonated ring nitrogen +MASS -1 NN2B 14.00700 N ! From NN2, for N9 in GUA different from ADE +MASS -1 NN2U 14.00700 N ! Nucleic acid protonated ring nitrogen, ura N3 +MASS -1 NN2G 14.00700 N ! Nucleic acid protonated ring nitrogen, gua N1 +MASS -1 NN3 14.00700 N ! Nucleic acid unprotonated ring nitrogen +MASS -1 NN3A 14.00700 N ! Nucleic acid unprotonated ring nitrogen, ade N1 and N3 +MASS -1 NN3G 14.00700 N ! Nucleic acid unprotonated ring nitrogen, gua N3 +MASS -1 NN4 14.00700 N ! Nucleic acid purine N7 +MASS -1 NN6 14.00700 N ! Nucleic acid sp3 amine nitrogen (equiv to protein nh3) +MASS -1 ON1 15.99940 O ! Nucleic acid carbonyl oxygen +MASS -1 ON1C 15.99940 O ! Nucleic acid carbonyl oxygen, cyt O2 +MASS -1 ON2 15.99940 O ! Nucleic acid phosphate ester oxygen +MASS -1 ON3 15.99940 O ! Nucleic acid =O in phosphate +MASS -1 ON4 15.99940 O ! Nucleic acid phosphate hydroxyl oxygen +MASS -1 ON5 15.99940 O ! Nucleic acid ribose hydroxyl oxygen +MASS -1 ON6 15.99940 O ! Nucleic acid deoxyribose ring oxygen +MASS -1 ON6B 15.99940 O ! Nucleic acid ribose ring oxygen +MASS -1 P 30.97400 P ! phosphorus +MASS -1 P2 30.97400 P ! phosphorus, adm, 2011 DNA update + +DECL +P +DECL +O1P +DECL +O2P +DECL +O5' +DECL -O3' + +DEFA FIRS none LAST none +AUTOGENERATE ANGLES DIHEDRALS PATCH + +RESI GUA -1.00 ! O6 +ATOM P P 1.50 ! || +ATOM O1P ON3 -0.78 ! C6 +ATOM O2P ON3 -0.78 ! / \ +ATOM O5' ON2 -0.57 ! H1-N1 C5--N7\\ +ATOM C5' CN8B -0.08 ! | || C8-H8 +ATOM H5' HN8 0.09 ! C2 C4--N9/ +ATOM H5'' HN8 0.09 ! / \\ / \ +GROUP ! H21-N2 N3 \ +ATOM C4' CN7 0.16 ! | \ +ATOM H4' HN7 0.09 ! H22 \ +ATOM O4' ON6B -0.50 ! \ +ATOM C1' CN7B 0.16 ! O1P H5' H4' O4' \ +ATOM H1' HN7 0.09 ! | | \ / \ \ +GROUP ! -P-O5'-C5'---C4' C1' +ATOM N9 NN2B -0.02 ! | | \ / \ +ATOM C4 CN5 0.26 ! O2P H5'' C3'--C2' H1' +ATOM N2 NN1 -0.68 ! / \ / \ +ATOM H21 HN1 0.32 ! O3' H3' O2' H2'' +ATOM H22 HN1 0.35 ! | | +ATOM N3 NN3G -0.74 ! H2' +ATOM C2 CN2 0.75 +ATOM N1 NN2G -0.34 +ATOM H1 HN2 0.26 +ATOM C6 CN1 0.54 +ATOM O6 ON1 -0.51 +ATOM C5 CN5G 0.00 +ATOM N7 NN4 -0.60 +ATOM C8 CN4 0.25 +ATOM H8 HN3 0.16 +GROUP +ATOM C2' CN7B 0.14 +ATOM H2'' HN7 0.09 +ATOM O2' ON5 -0.66 +ATOM H2' HN5 0.43 +GROUP +ATOM C3' CN7 0.01 +ATOM H3' HN7 0.09 +ATOM O3' ON2 -0.57 +BOND P O1P P O2P P O5' +BOND O5' C5' C5' C4' C4' O4' C4' C3' O4' C1' +BOND C1' N9 C1' C2' N9 C4 N9 C8 C4 N3 +BOND C2 N2 C2 N1 N2 H21 +BOND N2 H22 N1 H1 N1 C6 C6 C5 +BOND C5 N7 C2' C3' C3' O3' O3' +P +BOND C2' O2' O2' H2' +BOND C1' H1' C2' H2'' C3' H3' C4' H4' C5' H5' +BOND C5' H5'' C8 H8 +DOUBLE C2 N3 C4 C5 N7 C8 C6 O6 +IMPR C2 N3 N1 N2 C6 N1 C5 O6 N2 H21 C2 H22 +DONO H21 N2 +DONO H22 N2 +DONO H1 N1 +DONO H2' O2' +ACCE O6 C6 +ACCE N3 +ACCE N7 +ACCE O1P P +ACCE O2P P +ACCE O2' +ACCE O3' +ACCE O4' +ACCE O5' +! Chi and sugar-phosphate backbone in B-DNA like conformation +BILD -O3' P O5' C5' 1.6001 101.45 -46.90 119.00 1.4401 !alpha +BILD -O3' O5' *P O1P 1.6001 101.45 -115.82 109.74 1.4802 +BILD -O3' O5' *P O2P 1.6001 101.45 115.90 109.80 1.4801 +BILD P O5' C5' C4' 1.5996 119.00 -146.00 110.04 1.5160 !beta +BILD O5' C5' C4' C3' 1.4401 108.83 60.00 116.10 1.5284 !gamma +BILD C5' C4' C3' O3' 1.5160 116.10 140.00 115.12 1.4212 !delta +BILD C4' C3' O3' +P 1.5284 111.92 155.00 119.05 1.6001 !epsilon +BILD C3' O3' +P +O5' 1.4212 119.05 -95.20 101.45 1.5996 !zeta +BILD O4' C3' *C4' C5' 1.4572 104.06 -120.04 116.10 1.5160 +BILD C2' C4' *C3' O3' 1.5284 100.16 -124.08 115.12 1.4212 +BILD C4' C3' C2' C1' 1.5284 100.16 -30.00 102.04 1.5251 !puck +BILD C3' C2' C1' N9 1.5284 101.97 147.80 113.71 1.4896 +BILD O4' C1' N9 C4 1.5251 113.71 -97.2 125.59 1.3783 !chi +BILD C1' C4 *N9 C8 1.4896 125.59 -179.99 106.0 1.374 +BILD C4 N9 C8 N7 1.377 106.0 0.0 113.5 1.304 +BILD C8 N9 C4 C5 1.374 106.0 0.0 105.6 1.377 +BILD N9 C5 *C4 N3 1.377 105.6 180.0 128.4 1.355 +BILD C5 C4 N3 C2 1.377 128.4 0.0 111.8 1.327 +BILD C4 N3 C2 N1 1.355 111.8 0.0 124.0 1.375 +BILD N1 N3 *C2 N2 1.375 124.0 180.0 119.7 1.341 +BILD N3 C2 N2 H21 1.327 119.7 180.0 127.0 1.01 +BILD H21 C2 *N2 H22 1.01 127.0 -180.0 116.5 1.01 +BILD N3 C2 N1 C6 1.327 124.0 0.0 124.9 1.393 +BILD C6 C2 *N1 H1 1.393 124.9 180.0 117.4 1.03 +BILD C5 N1 *C6 O6 1.415 111.7 180.0 120.0 1.239 +BILD N9 N7 *C8 H8 0.0 0.0 180.0 0.0 0.0 +BILD C1' C3' *C2' O2' 1.5284 102.04 -114.67 110.81 1.4212 +BILD H2' O2' C2' C3' 0.9600 114.97 148.63 111.92 1.5284 +BILD O4' C2' *C1' H1' 0.0 0.0 -115.0 0.0 0.0 +BILD C1' C3' *C2' H2'' 0.0 0.0 115.0 0.0 0.0 +BILD C2' C4' *C3' H3' 0.0 0.0 115.0 0.0 0.0 +BILD C3' O4' *C4' H4' 0.0 0.0 -115.0 0.0 0.0 +BILD C4' O5' *C5' H5' 0.0 0.0 -115.0 0.0 0.0 +BILD C4' O5' *C5' H5'' 0.0 0.0 115.0 0.0 0.0 + + +RESI ADE -1.00 ! H61 H62! +ATOM P P 1.50 ! \ / +ATOM O1P ON3 -0.78 ! N6 +ATOM O2P ON3 -0.78 ! | +ATOM O5' ON2 -0.57 ! C6 +ATOM C5' CN8B -0.08 ! // \ +ATOM H5' HN8 0.09 ! N1 C5--N7\\ +ATOM H5'' HN8 0.09 ! | || C8-H8 +GROUP ! C2 C4--N9/ +ATOM C4' CN7 0.16 ! / \\ / \ +ATOM H4' HN7 0.09 ! H2 N3 \ +ATOM O4' ON6B -0.50 ! \ +ATOM C1' CN7B 0.16 ! \ +ATOM H1' HN7 0.09 ! \ +GROUP ! O1P H5' H4' O4' \ +ATOM N9 NN2 -0.05 ! | | \ / \ \ +ATOM C5 CN5 0.28 ! -P-O5'-C5'---C4' C1' +ATOM N7 NN4 -0.71 ! | | \ / \ +ATOM C8 CN4 0.34 ! O2P H5'' C3'--C2' H1' +ATOM H8 HN3 0.12 ! / \ / \ +ATOM N1 NN3A -0.74 ! O3' H3' O2' H2'' +ATOM C2 CN4 0.50 ! | | +ATOM H2 HN3 0.13 ! H2' +ATOM N3 NN3A -0.75 +ATOM C4 CN5 0.43 +ATOM C6 CN2 0.46 +ATOM N6 NN1 -0.77 +ATOM H61 HN1 0.38 +ATOM H62 HN1 0.38 +GROUP +ATOM C2' CN7B 0.14 +ATOM H2'' HN7 0.09 +ATOM O2' ON5 -0.66 +ATOM H2' HN5 0.43 +GROUP +ATOM C3' CN7 0.01 +ATOM H3' HN7 0.09 +ATOM O3' ON2 -0.57 +BOND P O1P P O2P P O5' +BOND O5' C5' C5' C4' C4' O4' C4' C3' O4' C1' +BOND C1' N9 C1' C2' N9 C4 N9 C8 C4 N3 +BOND C2 N1 C6 N6 +BOND N6 H61 N6 H62 C6 C5 C5 N7 +BOND C2' C3' C2' O2' O2' H2' C3' O3' O3' +P +BOND C1' H1' C2' H2'' C3' H3' C4' H4' C5' H5' +BOND C5' H5'' C8 H8 C2 H2 +DOUBLE N1 C6 C2 N3 C4 C5 N7 C8 +IMPR N6 C6 H61 H62 C6 N1 C5 N6 +DONO H61 N6 +DONO H62 N6 +DONO H2' O2' +ACCE N3 +ACCE N7 +ACCE N1 +ACCE O1P P +ACCE O2P P +ACCE O2' +ACCE O3' +ACCE O4' +ACCE O5' +BILD -O3' P O5' C5' 1.6001 101.45 -46.90 119.00 1.4401 !alpha +BILD -O3' O5' *P O1P 1.6001 101.45 -115.82 109.74 1.4802 +BILD -O3' O5' *P O2P 1.6001 101.45 115.90 109.80 1.4801 +BILD P O5' C5' C4' 1.5996 119.00 -146.00 110.04 1.5160 !beta +BILD O5' C5' C4' C3' 1.4401 108.83 60.00 116.10 1.5284 !gamma +BILD C5' C4' C3' O3' 1.5160 116.10 140.00 115.12 1.4212 !delta +BILD C4' C3' O3' +P 1.5284 111.92 155.00 119.05 1.6001 !epsilon +BILD C3' O3' +P +O5' 1.4212 119.05 -95.20 101.45 1.5996 !zeta +BILD O4' C3' *C4' C5' 1.4572 104.06 -120.04 116.10 1.5160 +BILD C2' C4' *C3' O3' 1.5284 100.16 -124.08 115.12 1.4212 +BILD C4' C3' C2' C1' 1.5284 100.16 -30.00 102.04 1.5251 !puck +BILD C3' C2' C1' N9 1.5284 101.97 147.80 113.71 1.4896 +BILD O4' C1' N9 C4 1.5251 113.71 -97.2 125.59 1.3783 !chi +BILD C1' C4 *N9 C8 1.4896 125.97 -179.94 106.0 1.367 +BILD C4 N9 C8 N7 1.376 106.0 0.0 113.6 1.312 +BILD C8 N9 C4 C5 1.367 106.0 0.0 105.6 1.382 +BILD C8 N7 C5 C6 0.0 0.0 180.0 0.0 0.0 +BILD N7 C5 C6 N1 0.0 0.0 180.0 0.0 0.0 +BILD C5 C6 N1 C2 0.0 0.0 0.0 0.0 0.0 +BILD N9 C5 *C4 N3 1.376 105.6 -180.0 126.9 1.342 +BILD C5 N1 *C6 N6 1.409 117.6 -180.0 121.2 1.337 +BILD N1 C6 N6 H61 1.337 121.2 0.0 119.0 1.01 +BILD H61 C6 *N6 H62 1.01 119.0 180.0 119.00 1.01 +BILD C5 N1 *C6 N6 1.409 117.6 -180.0 119.0 1.337 +BILD N1 C6 N6 H61 1.337 119.0 0.0 119.0 1.01 +BILD H61 C6 *N6 H62 1.01 119.0 180.0 121.00 1.01 +BILD N9 N7 *C8 H8 0.0 0.0 180.0 0.0 0.0 +BILD N1 N3 *C2 H2 0.0 0.0 180.0 0.0 0.0 +BILD C1' C3' *C2' O2' 1.5284 102.04 -114.67 110.81 1.4212 +BILD H2' O2' C2' C3' 0.9600 114.97 148.63 111.92 1.5284 +BILD O4' C2' *C1' H1' 0.0 0.0 -115.0 0.0 0.0 +BILD C1' C3' *C2' H2'' 0.0 0.0 115.0 0.0 0.0 +BILD C2' C4' *C3' H3' 0.0 0.0 115.0 0.0 0.0 +BILD C3' O4' *C4' H4' 0.0 0.0 -115.0 0.0 0.0 +BILD C4' O5' *C5' H5' 0.0 0.0 -115.0 0.0 0.0 +BILD C4' O5' *C5' H5'' 0.0 0.0 115.0 0.0 0.0 + +RESI CYT -1.00 +ATOM P P 1.50 ! +ATOM O1P ON3 -0.78 ! H42 H41 +ATOM O2P ON3 -0.78 ! \ / +ATOM O5' ON2 -0.57 ! N4 +ATOM C5' CN8B -0.08 ! | +ATOM H5' HN8 0.09 ! C4 +ATOM H5'' HN8 0.09 ! / \\ +GROUP ! H5-C5 N3 +ATOM C4' CN7 0.16 ! || | +ATOM H4' HN7 0.09 ! H6-C6 C2 +ATOM O4' ON6B -0.50 ! \ / \\ +ATOM C1' CN7B 0.16 ! N1 O2 +ATOM H1' HN7 0.09 ! \ +GROUP ! \ +ATOM N1 NN2 -0.13 ! \ +ATOM C6 CN3 0.05 ! O1P H5' H4' O4' \ +ATOM H6 HN3 0.17 ! | | \ / \ \ +ATOM C5 CN3 -0.13 ! -P-O5'-C5'---C4' C1' +ATOM H5 HN3 0.07 ! | | \ / \ +ATOM C2 CN1 0.52 ! O2P H5'' C3'--C2' H1' +ATOM O2 ON1C -0.49 ! / \ / \ +ATOM N3 NN3 -0.66 ! O3' H3' O2' H2'' +ATOM C4 CN2 0.65 ! | | +ATOM N4 NN1 -0.75 ! H2' +ATOM H41 HN1 0.37 +ATOM H42 HN1 0.33 +GROUP +ATOM C2' CN7B 0.14 +ATOM H2'' HN7 0.09 +ATOM O2' ON5 -0.66 +ATOM H2' HN5 0.43 +GROUP +ATOM C3' CN7 0.01 +ATOM H3' HN7 0.09 +ATOM O3' ON2 -0.57 +BOND P O1P P O2P P O5' +BOND O5' C5' C5' C4' C4' O4' C4' C3' O4' C1' +BOND C1' N1 C1' C2' N1 C2 N1 C6 +BOND C2 N3 C4 N4 N4 H41 N4 H42 +BOND C4 C5 C2' C3' C3' O3' O3' +P +BOND C2' O2' O2' H2' +BOND C1' H1' C2' H2'' C3' H3' C4' H4' C5' H5' +BOND C5' H5'' C5 H5 C6 H6 +DOUBLE C2 O2 C5 C6 N3 C4 +IMPR C2 N1 N3 O2 C4 N3 C5 N4 +IMPR N4 C4 H41 H42 +DONO H42 N4 +DONO H2' O2' +DONO H41 N4 +ACCE O2 C2 +ACCE N3 +ACCE O1P P +ACCE O2P P +ACCE O2' +ACCE O3' +ACCE O4' +ACCE O5' + +BILD -O3' P O5' C5' 1.6001 101.45 -46.90 119.00 1.4401 !alpha +BILD -O3' O5' *P O1P 1.6001 101.45 -115.82 109.74 1.4802 +BILD -O3' O5' *P O2P 1.6001 101.45 115.90 109.80 1.4801 +BILD P O5' C5' C4' 1.5996 119.00 -146.00 110.04 1.5160 !beta +BILD O5' C5' C4' C3' 1.4401 108.83 60.00 116.10 1.5284 !gamma +BILD C5' C4' C3' O3' 1.5160 116.10 140.00 115.12 1.4212 !delta +BILD C4' C3' O3' +P 1.5284 111.92 155.00 119.05 1.6001 !epsilon +BILD C3' O3' +P +O5' 1.4212 119.05 -95.20 101.45 1.5996 !zeta +BILD O4' C3' *C4' C5' 1.4572 104.06 -120.04 116.10 1.5160 +BILD C2' C4' *C3' O3' 1.5284 100.16 -124.08 115.12 1.4212 +BILD C4' C3' C2' C1' 1.5284 100.16 -30.00 102.04 1.5251 +BILD C3' C2' C1' N1 1.5284 101.97 147.89 113.71 1.4896 +BILD O4' C1' N1 C2 1.5251 113.71 -97.2 125.59 1.3783 !chi +BILD C1' C2 *N1 C6 1.4896 117.79 -180.00 120.6 1.364 +BILD C2 N1 C6 C5 1.399 120.6 0.0 121.0 1.337 +BILD C6 N1 C2 N3 1.364 120.6 0.0 118.9 1.356 +BILD N1 N3 *C2 O2 1.399 118.9 180.0 121.9 1.237 +BILD N1 C2 N3 C4 1.399 118.9 0.0 120.0 1.334 +BILD C5 N3 *C4 N4 1.426 121.8 180.00 118.9 1.337 +BILD N3 C4 N4 H41 1.337 117.9 0.00 118.9 1.01 +BILD H41 C4 *N4 H42 1.01 118.9 180.00 120.7 1.01 +BILD C6 C4 *C5 H5 0.0 0.0 180.0 0.0 0.0 +BILD N1 C5 *C6 H6 0.0 0.0 180.0 0.0 0.0 +BILD C1' C3' *C2' O2' 1.5284 102.04 -114.67 110.81 1.4212 +BILD H2' O2' C2' C3' 0.9600 114.97 148.63 111.92 1.5284 +BILD O4' C2' *C1' H1' 0.0 0.0 -115.0 0.0 0.0 +BILD C1' C3' *C2' H2'' 0.0 0.0 115.0 0.0 0.0 +BILD C2' C4' *C3' H3' 0.0 0.0 115.0 0.0 0.0 +BILD C3' O4' *C4' H4' 0.0 0.0 -115.0 0.0 0.0 +BILD C4' O5' *C5' H5' 0.0 0.0 -115.0 0.0 0.0 +BILD C4' O5' *C5' H5'' 0.0 0.0 115.0 0.0 0.0 + +RESI THY -1.00 ! H51 O4 +ATOM P P 1.50 ! | || +ATOM O1P ON3 -0.78 ! H52-C5M C4 H3 +ATOM O2P ON3 -0.78 ! | \ / \ / +ATOM O5' ON2 -0.57 ! H53 C5 N3 +ATOM C5' CN8B -0.08 ! || | +ATOM H5' HN8 0.09 ! H6-C6 C2 +ATOM H5'' HN8 0.09 ! \ / \\ +GROUP ! N1 O2 +ATOM C4' CN7 0.16 ! \ +ATOM H4' HN7 0.09 ! \ +ATOM O4' ON6B -0.50 ! \ +ATOM C1' CN7B 0.16 ! O1P H5' H4' O4' \ +ATOM H1' HN7 0.09 ! | | \ / \ \ +GROUP ! -P-O5'-C5'---C4' C1' +ATOM N1 NN2B -0.34 ! | | \ / \ +ATOM C6 CN3 0.17 ! O2P H5'' C3'--C2' H1' +ATOM H6 HN3 0.17 ! / \ / \ +ATOM C2 CN1T 0.51 ! O3' H3' O2' H2'' +ATOM O2 ON1 -0.41 ! | | +ATOM N3 NN2U -0.46 ! H2' +ATOM H3 HN2 0.36 ! +ATOM C4 CN1 0.50 ! +ATOM O4 ON1 -0.45 ! +ATOM C5 CN3T -0.15 +ATOM C5M CN9 -0.11 +ATOM H51 HN9 0.07 +ATOM H52 HN9 0.07 +ATOM H53 HN9 0.07 +GROUP +ATOM C2' CN7B 0.14 +ATOM H2'' HN7 0.09 +ATOM O2' ON5 -0.66 +ATOM H2' HN5 0.43 +GROUP +ATOM C3' CN7 0.01 +ATOM H3' HN7 0.09 +ATOM O3' ON2 -0.57 +BOND P O1P P O2P P O5' +BOND O5' C5' C5' C4' C4' O4' C4' C3' O4' C1' +BOND C1' N1 C1' C2' N1 C2 N1 C6 +BOND C2 N3 N3 H3 N3 C4 C4 C5 +BOND C5 C5M C2' C3' C3' O3' O3' +P +BOND C2' O2' O2' H2' +BOND C1' H1' C2' H2'' C3' H3' C4' H4' C5' H5' +BOND C5' H5'' C6 H6 C5M H51 C5M H52 C5M H53 +DOUBLE C2 O2 C4 O4 C5 C6 +IMPR C2 N1 N3 O2 C4 N3 C5 O4 C5 C4 C6 C5M +DONO H3 N3 +DONO H2' O2' +ACCE O2 C2 +ACCE O4 C4 +ACCE O1P P +ACCE O2P P +ACCE O2' +ACCE O3' +ACCE O4' +ACCE O5' + +BILD -O3' P O5' C5' 1.6001 101.45 -46.90 119.00 1.4401 !alpha +BILD -O3' O5' *P O1P 1.6001 101.45 -115.82 109.74 1.4802 +BILD -O3' O5' *P O2P 1.6001 101.45 115.90 109.80 1.4801 +BILD P O5' C5' C4' 1.5996 119.00 -146.00 110.04 1.5160 !beta +BILD O5' C5' C4' C3' 1.4401 108.83 60.00 116.10 1.5284 +BILD C5' C4' C3' O3' 1.5160 116.10 140.00 115.12 1.4212 +BILD C4' C3' O3' +P 1.5284 111.92 155.00 119.05 1.6001 +BILD C3' O3' +P +O5' 1.4212 119.05 -95.20 101.45 1.5996 +BILD O4' C3' *C4' C5' 1.4572 104.06 -120.04 116.10 1.5160 +BILD C2' C4' *C3' O3' 1.5284 100.16 -124.08 115.12 1.4212 +BILD C4' C3' C2' C1' 1.5284 100.16 -30.00 102.04 1.5251 +BILD C3' C2' C1' N1 1.5284 101.97 147.89 113.71 1.4896 +BILD O4' C1' N1 C2 1.5251 113.71 -97.2 125.59 1.3783 !chi +BILD C1' C2 *N1 C6 1.4896 117.06 -179.96 122.08 1.3704 +BILD C2 N1 C6 C5 1.3746 122.08 -0.02 121.23 1.3432 +BILD C6 N1 C2 N3 1.3704 122.08 0.06 115.38 1.3813 +BILD N1 N3 *C2 O2 1.3746 115.38 -179.95 121.70 1.2191 +BILD N1 C2 N3 C4 1.3746 115.38 -0.07 126.46 1.3795 +BILD C5 N3 *C4 O4 1.4439 114.07 179.98 120.59 1.2327 +BILD C2 C4 *N3 H3 1.3813 126.46 180.00 116.77 1.0900 +BILD C4 C6 *C5 C5M 1.4439 120.78 -179.94 121.63 1.5000 +BILD N1 C5 *C6 H6 0.0 0.0 180.0 0.0 0.0 +BILD C6 C5 C5M H51 0.0 0.0 0.0 0.0 0.0 +BILD C5 H51 *C5M H52 0.0 0.0 115.0 0.0 0.0 +BILD H51 H52 *C5M H53 0.0 0.0 -115.0 0.0 0.0 +BILD C1' C3' *C2' O2' 1.5284 102.04 -114.67 110.81 1.4212 +BILD H2' O2' C2' C3' 0.9600 114.97 148.63 111.92 1.5284 +BILD O4' C2' *C1' H1' 0.0 0.0 -115.0 0.0 0.0 +BILD C1' C3' *C2' H2'' 0.0 0.0 115.0 0.0 0.0 +BILD C2' C4' *C3' H3' 0.0 0.0 115.0 0.0 0.0 +BILD C3' O4' *C4' H4' 0.0 0.0 -115.0 0.0 0.0 +BILD C4' O5' *C5' H5' 0.0 0.0 -115.0 0.0 0.0 +BILD C4' O5' *C5' H5'' 0.0 0. 115.0 0.0 0.0 + +RESI URA -1.00 ! O4 +ATOM P P 1.50 ! || +ATOM O1P ON3 -0.78 ! C4 H3 +ATOM O2P ON3 -0.78 ! / \ / +ATOM O5' ON2 -0.57 ! H5-C5 N3 +ATOM C5' CN8B -0.08 ! || | +ATOM H5' HN8 0.09 ! H6-C6 C2 +ATOM H5'' HN8 0.09 ! \ / \\ +GROUP ! N1 O2 +ATOM C4' CN7 0.16 ! \ +ATOM H4' HN7 0.09 ! \ +ATOM O4' ON6B -0.50 ! \ +ATOM C1' CN7B 0.16 ! O1P H5' H4' O4' \ +ATOM H1' HN7 0.09 ! | | \ / \ \ +GROUP ! -P-O5'-C5'---C4' C1' +ATOM N1 NN2B -0.34 ! | | \ / \ +ATOM C6 CN3 0.20 ! O2P H5'' C3'--C2' H1' +ATOM H6 HN3 0.14 ! / \ / \ +ATOM C2 CN1T 0.55 ! O3' H3' O2' H2'' +ATOM O2 ON1 -0.45 ! | | +ATOM N3 NN2U -0.46 ! H2' +ATOM H3 HN2 0.36 ! +ATOM C4 CN1 0.53 ! +ATOM O4 ON1 -0.48 ! +ATOM C5 CN3 -0.15 ! +ATOM H5 HN3 0.10 ! +GROUP +ATOM C2' CN7B 0.14 +ATOM H2'' HN7 0.09 +ATOM O2' ON5 -0.66 +ATOM H2' HN5 0.43 +GROUP +ATOM C3' CN7 0.01 +ATOM H3' HN7 0.09 +ATOM O3' ON2 -0.57 +BOND P O1P P O2P P O5' +BOND O5' C5' C5' C4' C4' O4' C4' C3' O4' C1' +BOND C1' N1 C1' C2' N1 C2 N1 C6 +BOND C2 N3 N3 H3 N3 C4 C4 C5 +BOND C2' C3' C3' O3' O3' +P +BOND C2' O2' O2' H2' +BOND C1' H1' C2' H2'' C3' H3' C4' H4' C5' H5' +BOND C5' H5'' C5 H5 C6 H6 +DOUBLE C2 O2 C4 O4 C5 C6 +IMPR C2 N1 N3 O2 C4 N3 C5 O4 +DONO H3 N3 +DONO H2' O2' +ACCE O2 C2 +ACCE O4 C4 +ACCE O1P P +ACCE O2P P +ACCE O2' +ACCE O3' +ACCE O4' +ACCE O5' +BILD -O3' P O5' C5' 1.6001 101.45 -39.25 119.00 1.4401 +BILD -O3' O5' *P O1P 1.6001 101.45 -115.82 109.74 1.4802 +BILD -O3' O5' *P O2P 1.6001 101.45 115.90 109.80 1.4801 +BILD P O5' C5' C4' 1.5996 119.00 -151.39 110.04 1.5160 +BILD O5' C5' C4' C3' 1.4401 108.83 -179.85 116.10 1.5284 +BILD C5' C4' C3' O3' 1.5160 116.10 76.70 115.12 1.4212 +BILD C4' C3' O3' +P 1.5284 111.92 159.13 119.05 1.6001 +BILD C3' O3' +P +O5' 1.4212 119.05 -98.86 101.45 1.5996 +BILD O4' C3' *C4' C5' 1.4572 104.06 -120.04 116.10 1.5160 +BILD C2' C4' *C3' O3' 1.5284 100.16 -124.08 115.12 1.4212 +BILD C4' C3' C2' C1' 1.5284 100.16 39.58 102.04 1.5251 +BILD C3' C2' C1' N1 1.5284 101.97 144.39 113.71 1.4896 +BILD O4' C1' N1 C2 1.5251 113.71 -96.0 117.06 1.3746 +BILD C1' C2 *N1 C6 1.4896 117.06 -180.0 121.3 1.379 +BILD C2 N1 C6 C5 1.379 121.3 0.0 122.8 1.338 +BILD C6 N1 C2 N3 1.380 121.3 0.0 114.8 1.373 +BILD N1 N3 *C2 O2 1.379 114.8 -180.0 122.0 1.218 +BILD N1 C2 N3 C4 1.379 114.8 0.0 127.0 1.383 +BILD C5 N3 *C4 O4 1.440 114.7 180.0 119.8 1.227 +BILD C2 C4 *N3 H3 1.373 127.0 180.0 116.5 1.03 +BILD C6 C4 *C5 H5 0.0 0.0 180.0 0.0 0.0 +BILD N1 C5 *C6 H6 0.0 0.0 180.0 0.0 0.0 +BILD C1' C3' *C2' O2' 1.5284 102.04 -114.67 110.81 1.4212 +BILD H2' O2' C2' C3' 0.9600 114.97 148.63 111.92 1.5284 +BILD O4' C2' *C1' H1' 0.0 0.0 -115.0 0.0 0.0 +BILD C1' C3' *C2' H2'' 0.0 0.0 115.0 0.0 0.0 +BILD C2' C4' *C3' H3' 0.0 0.0 115.0 0.0 0.0 +BILD C3' O4' *C4' H4' 0.0 0.0 -115.0 0.0 0.0 +BILD C4' O5' *C5' H5' 0.0 0.0 -115.0 0.0 0.0 +BILD C4' O5' *C5' H5'' 0.0 0.0 115.0 0.0 0.0 + +! NOTE the option to regenerate all angles and dihedrals allows +! the explicit inclusion of the THET and DIHE terms to be omitted +! even if the PRES is used in a PATCH statement. It is important to +! inspect the patches prior to use to determine if they should be used +! in a GENErate or PATCh statement and/or if the AUTOgeneration of +! angles and dihedrals is required. +! see AUTOgen ANGLes DIHEdrals in STRUCTURE section of the +! documentation + +PRES DEO5 0.00 ! Patch to make the 5-terminal nucleotide into DEOXYribose +DELETE ATOM O2' ! Follow with AUTOGENERATE ANGLES DIHEDRALS + +GROUP ! To correct O4' atom type in DNA (NF) +ATOM C4' CN7 0.16 ! +ATOM H4' HN7 0.09 ! +ATOM O4' ON6 -0.50 ! +ATOM C1' CN7B 0.16 ! +ATOM H1' HN7 0.09 ! +GROUP +ATOM C2' CN8 -0.18 +ATOM H2' HN8 0.09 +ATOM H2'' HN8 0.09 + +BOND C2' H2' +BILD C1' C3' *C2' H2' 0.0 0.0 -115.0 0.0 0.0 + +PRES DEOX 1.50 ! Patch to make non 5-terminal DEOXyribose nucleotides +DELETE ATOM O2' ! Follow with AUTOGENERATE ANGLES DIHEDRALS + +ATOM P P2 1.50 ! switch type P to type P2 as required to apply + ! 2011 DNA update to zeta in DNA only +GROUP ! To correct O4' atom type in DNA (NF) +ATOM C4' CN7 0.16 ! +ATOM H4' HN7 0.09 ! +ATOM O4' ON6 -0.50 ! +ATOM C1' CN7B 0.16 ! +ATOM H1' HN7 0.09 ! +GROUP +ATOM C2' CN8 -0.18 +ATOM H2' HN8 0.09 +ATOM H2'' HN8 0.09 + +BOND C2' H2' +BILD C1' C3' *C2' H2' 0.0 0.0 -115.0 0.0 0.0 + +PRES DEOS 1.50 ! Patch to convert a single nucleotide in an RNA strand to deoxy + ! for non 5-terminal DEOXyribose nucleotides + ! Do NOT use with patch deox +DELETE ATOM O2' ! Follow with AUTOGENERATE ANGLES DIHEDRALS + +GROUP ! To correct O4' atom type in DNA (NF) +ATOM C4' CN7 0.16 ! +ATOM H4' HN7 0.09 ! +ATOM O4' ON6 -0.50 ! +ATOM C1' CN7B 0.16 ! +ATOM H1' HN7 0.09 ! +GROUP +ATOM C2' CN8 -0.18 +ATOM H2' HN8 0.09 +ATOM H2'' HN8 0.09 + +ATOM +P P2 1.50 ! convert i+1 phosphorous to P2 for DNA + +BOND C2' H2' +BILD C1' C3' *C2' H2' 0.0 0.0 -115.0 0.0 0.0 + +PRES DEOR 3.00 ! Patch to maintain a single RNA nucleotide in a DNA oligonucleotide + ! Note that patch should be invoked once all the DEOX patches + ! for the strand have been called + ! +ATOM P P2 1.50 ! switch type P to type P2 as required for DNA in i-1 nucleotide +ATOM +P P 1.50 ! revert i+1 phosphorous from P2 to P type for RNA + +PRES 5TER 0.00 ! 5'-terminal HYDROXYL patch, from MeOH + ! use in generate statement +GROUP +ATOM H5T HN5 0.43 +ATOM O5' ON5 -0.66 +ATOM C5' CN8B 0.05 +ATOM H5' HN8 0.09 +ATOM H5'' HN8 0.09 +! +DELETE ATOM P +DELETE ATOM O1P +DELETE ATOM O2P +! +BOND H5T O5' +DONO H5T O5' +BILD H5T O5' C5' C4' 0.0000 0.00 180.00 0.00 0.0000 + +PRES 5MET 0.00 ! 5'-ribose METHYL patch + ! use in generate statement, doesn't work with DEOx patches +GROUP +ATOM C5' CN9 -0.27 +ATOM H5' HN9 0.09 +ATOM H5'' HN9 0.09 +ATOM H53' HN9 0.09 ! Can't use ''' and avoid conflict with THY +! +DELETE ATOM O5' +DELETE ATOM P +DELETE ATOM O1P +DELETE ATOM O2P +! +BOND C5' H53' +IC C3' C4' C5' H53' 0.0000 0.00 180.00 0.00 0.0000 +IC H53' C4' *C5' H5' 0.0000 0.00 120.00 0.00 0.0000 +IC H53' C4' *C5' H5'' 0.0000 0.00 -120.00 0.00 0.0000 + +PRES 5PHO -1.00 ! 5'terminal PHOSPHATE patch + ! use in generate statement +GROUP +ATOM C5' CN8B -0.08 +ATOM H5' HN8 0.09 +ATOM H5'' HN8 0.09 +ATOM P P 1.50 +ATOM O1P ON3 -0.82 +ATOM O2P ON3 -0.82 +ATOM O5' ON2 -0.62 +ATOM O5T ON4 -0.68 +ATOM H5T HN4 0.34 +BOND O5T P H5T O5T +DONO H5T O5T +! Built in B-DNA-like conformation (NF) +BILD C4' C5' O5' P 0.0000 000.00 -146.00 000.00 0.0000 +BILD C5' O5' P O5T 0.0000 000.00 -46.90 000.00 0.0000 +BILD O5T O5' *P O1P 0.0000 000.00 -115.82 000.00 0.0000 +BILD O5T O5' *P O2P 0.0000 000.00 115.90 000.00 0.0000 +BILD H5T O5T P O5' 0.0000 000.00 -95.20 000.00 0.0000 + +PRES 5POM -1.00 ! 5'terminal Methyl-Phosphate patch + ! use in generate statement +GROUP +ATOM C5' CN8B -0.08 +ATOM H5' HN8 0.09 +ATOM H5'' HN8 0.09 +ATOM P P 1.50 +ATOM O1P ON3 -0.78 +ATOM O2P ON3 -0.78 +ATOM O5' ON2 -0.57 +ATOM O5T ON2 -0.57 +ATOM C5T CN9 -0.17 +ATOM H5T1 HN9 0.09 +ATOM H5T2 HN9 0.09 +ATOM H5T3 HN9 0.09 + +BOND O5T P O5T C5T C5T H5T1 C5T H5T2 +BOND C5T H5T3 +!DONO H5T O5T +! Built in B-DNA-like conformation (NF) +BILD C4' C5' O5' P 0.0000 000.00 -146.00 000.00 0.0000 +BILD C5' O5' P O5T 0.0000 000.00 -46.90 000.00 0.0000 +BILD O5T O5' *P O1P 0.0000 000.00 -115.82 000.00 0.0000 +BILD O5T O5' *P O2P 0.0000 000.00 115.90 000.00 0.0000 +BILD C5T O5T P O5' 0.0000 000.00 -95.20 000.00 0.0000 +BILD H5T1 C5T O5T P 0.0000 000.00 180.20 000.00 0.0000 +BILD H5T2 C5T O5T P 0.0000 000.00 60.00 000.00 0.0000 +BILD H5T3 C5T O5T P 0.0000 000.00 -60.00 000.00 0.0000 + +PRES 3TER 0.00 ! 3'terminal HYDROXYL patch, from MeOH + ! use in generate statement +GROUP +ATOM C3' CN7 0.14 +ATOM H3' HN7 0.09 +ATOM O3' ON5 -0.66 +ATOM H3T HN5 0.43 +BOND O3' H3T +DONO H3T O3' +BILD H3T O3' C3' C4' 0.9600 114.97 148.63 111.92 1.5284 + +PRES 3PHO -1.00 ! 3'terminal PHOSPHATE patch + ! use in generate statement +GROUP +ATOM C3' CN7 0.01 +ATOM H3' HN7 0.09 +ATOM P3 P 1.50 +ATOM O1P3 ON3 -0.82 +ATOM O2P3 ON3 -0.82 +ATOM O3' ON2 -0.62 +ATOM O3T ON4 -0.68 +ATOM H3T HN4 0.34 +BOND O3' P3 P3 O1P3 P3 O2P3 P3 O3T O3T H3T +DONO H3T O3T +ACCE O3T +ACCE O1P3 +ACCE O2P3 +! Build in B-DNA-like conformation (NF) +BILD C4' C3' O3' P3 0.0000 000.00 155.00 000.00 0.0000 +BILD C3' O3' P3 O3T 0.0000 000.00 -95.20 000.00 0.0000 +BILD O3T O3' *P3 O1P3 0.0000 000.00 -115.82 000.00 0.0000 +BILD O3T O3' *P3 O2P3 0.0000 000.00 115.90 000.00 0.0000 +BILD H3T O3T P3 O3' 0.0000 000.00 -46.90 000.00 0.0000 + +PRES 3POM -1.00 ! 3'terminal Methyl Phosphate patch + ! use in generate statement +! To build model compound with OPO3-CH3 at the 3' end (nicolas) +GROUP +ATOM C3' CN7 0.01 +ATOM H3' HN7 0.09 +ATOM P3 P 1.50 +ATOM O1P3 ON3 -0.78 +ATOM O2P3 ON3 -0.78 +ATOM O3' ON2 -0.57 +ATOM O3T ON2 -0.57 +ATOM C3T CN9 -0.17 +ATOM H3T1 HN9 0.09 +ATOM H3T2 HN9 0.09 +ATOM H3T3 HN9 0.09 + +BOND O3' P3 P3 O1P3 P3 O2P3 P3 O3T O3T C3T +BOND C3T H3T1 C3T H3T2 C3T H3T3 +ACCE O3' +ACCE O5' +ACCE O1P3 +ACCE O2P3 +BILD C4' C3' O3' P3 0.0000 000.00 155.00 000.00 0.0000 +BILD C3' O3' P3 O3T 0.0000 000.00 -95.22 000.00 0.0000 +BILD O3T O3' *P3 O1P3 0.0000 000.00 -115.82 000.00 0.0000 +BILD O3T O3' *P3 O2P3 0.0000 000.00 115.90 000.00 0.0000 +BILD C3T O3T P3 O3' 0.0000 000.00 -46.90 000.00 0.0000 +BILD H3T1 C3T O3T P3 0.0000 000.00 180.00 000.00 0.0000 +BILD H3T2 C3T O3T P3 0.0000 000.00 60.00 000.00 0.0000 +BILD H3T3 C3T O3T P3 0.0000 000.00 -60.00 000.00 0.0000 + +PRES 3PO3 -2.00 ! 3'terminal PHOSPHATE patch + ! use in generate statement + ! Added by Nicolas, to be consistent with model componds +GROUP +ATOM C3' CN7 -0.09 +ATOM H3' HN7 0.09 +ATOM P3 P 1.10 +ATOM O3' ON2 -0.40 +ATOM O1P3 ON3 -0.90 +ATOM O2P3 ON3 -0.90 +ATOM O3P3 ON3 -0.90 +BOND O3' P3 P3 O1P3 P3 O2P3 P3 O3P3 +ACCE O1P3 +ACCE O2P3 +ACCE O3P3 +BILD C4' C3' O3' P3 0.0000 000.00 180.00 000.00 0.0000 +BILD C3' O3' P3 O3P3 0.0000 000.00 -39.52 000.00 0.0000 +BILD O3P3 O3' *P3 O1P3 0.0000 000.00 -115.82 000.00 0.0000 +BILD O3P3 O3' *P3 O2P3 0.0000 000.00 115.90 000.00 0.0000 +BILD O3' P3 O3P3 O3T 0.0000 000.00 180.00 000.00 0.0000 +BILD P3 O3P3 O3T H3T 0.0000 000.00 180.00 000.00 0.0000 + +PRES DELB 0.00 ! patch to delete all possible base atoms + ! of Cyt,Gua,Ade,Thy and Ura + ! +!note: error messages will be obtained due to atoms not present in +!residue being "deleted" by this patch +!cyt section +DELE ATOM N1 +DELE ATOM C6 +DELE ATOM H6 +DELE ATOM C2 +DELE ATOM O2 +DELE ATOM N3 +DELE ATOM C4 +DELE ATOM N4 +DELE ATOM H41 +DELE ATOM H42 +DELE ATOM C5 +DELE ATOM H5 +!gua section +DELE ATOM N9 +DELE ATOM H1 +DELE ATOM N2 +DELE ATOM H21 +DELE ATOM H22 +DELE ATOM O6 +DELE ATOM N7 +DELE ATOM C8 +DELE ATOM H8 +!ade section +DELE ATOM H2 +DELE ATOM N6 +DELE ATOM H61 +DELE ATOM H62 +!thy/ura section +DELE ATOM H3 +DELE ATOM O4 +DELE ATOM C5M +DELE ATOM H51 +DELE ATOM H52 +DELE ATOM H53 + +PRES CY35 0.0 ! patch to make a cyclic 3'-5' nucleotide + ! use AUTOGEN ANGLE DIHE after this patch +BOND O3' P ! but before water-generation + +PRES LKNA 0.0 ! Patch to join to nucleic acid segments (eg for IMAGES) + ! eg: patch sega 10 segb 1 + ! sega should have std 3' (gene sega ... last none) + ! segb should have std 5' (gene segb ... first none) + ! USE AUTOgen ANGL DIHE after this patch, + ! but before water-generation +BOND 1O3' 2P +IC 1O3' 2P 2O5' 2C5' 1.6001 101.45 -39.25 119.00 1.4401 +IC 1O3' 2O5' *2P 2O1P 1.6001 101.45 -115.82 109.74 1.4802 +IC 1O3' 2O5' *2P 2O2P 1.6001 101.45 115.90 109.80 1.4801 +IC 1C4' 1C3' 1O3' 2P 1.5284 111.92 159.13 119.05 1.6001 +IC 1C3' 1O3' 2P 2O5' 1.4212 119.05 -98.86 101.45 1.5996 + +end + diff --git a/continuousflex/protocols/utilities/toppar_water_ions.str b/continuousflex/protocols/utilities/toppar_water_ions.str new file mode 100644 index 0000000..62c64a3 --- /dev/null +++ b/continuousflex/protocols/utilities/toppar_water_ions.str @@ -0,0 +1,335 @@ +* Toplogy and parameter information for water and ions. +* + +!Testcase +!test_water_ions.inp + +! IMPORTANT NOTE: this file contains NBFixes between carboxylates and sodium, +! which will only apply if the main files containing carboxylate atom types +! have been read in first! + +!references +! +!TIP3P water model +! +!W.L. Jorgensen; J.Chandrasekhar; J.D. Madura; R.W. Impey; +!M.L. Klein; "Comparison of simple potential functions for +!simulating liquid water", J. Chem. Phys. 79 926-935 (1983). +! +!IONS +! +!Ions from Roux and coworkers +! +!Beglov, D. and Roux, B., Finite Representation of an Infinite +!Bulk System: Solvent Boundary Potential for Computer Simulations, +!Journal of Chemical Physics, 1994, 100: 9050-9063 +! +!ZINC +! +!Stote, R.H. and Karplus, M. Zinc Binding in Proteins and +!Solution: A Simple but Accurate Nonbonded Representation, PROTEINS: +!Structure, Function, and Genetics 23:12-31 (1995) + +!test "append" to determine if previous toppar files have been read and +!add append to "read rtf card" if true +set nat ?NATC +set app +!We're exploiting what is arguably a bug in the parser. On the left hand side, +!the quotes have priority, so NAT is correctly substituted. On the right hand +!side, the ? has priority and NATC" (sic) is not a valid substitution... +if "@NAT" ne "?NATC" if @nat ne 0 set app append + +read rtf card @app +* Topology for water and ions +* +31 1 + +MASS -1 HT 1.00800 H ! TIPS3P WATER HYDROGEN +MASS -1 HX 1.00800 H ! hydroxide hydrogen +MASS -1 OT 15.99940 O ! TIPS3P WATER OXYGEN +MASS -1 OX 15.99940 O ! hydroxide oxygen +MASS -1 LIT 6.94100 LI ! Lithium ion +MASS -1 SOD 22.98977 NA ! Sodium Ion +MASS -1 MG 24.30500 MG ! Magnesium Ion +MASS -1 POT 39.09830 K ! Potassium Ion +MASS -1 CAL 40.08000 CA ! Calcium Ion +MASS -1 RUB 85.46780 RB ! Rubidium Ion +MASS -1 CES 132.90545 CS ! Cesium Ion +MASS -1 BAR 137.32700 BA ! Barium Ion +MASS -1 ZN 65.37000 ZN ! zinc (II) cation +MASS -1 CAD 112.41100 CD ! cadmium (II) cation +MASS -1 CLA 35.45000 CL ! Chloride Ion + +default first none last none + +RESI TIP3 0.000 ! tip3p water model, generate using noangle nodihedral +GROUP +ATOM OH2 OT -0.834 +ATOM H1 HT 0.417 +ATOM H2 HT 0.417 +BOND OH2 H1 OH2 H2 H1 H2 ! the last bond is needed for shake +ANGLE H1 OH2 H2 ! required +DONOR H1 OH2 +DONOR H2 OH2 +ACCEPTOR OH2 +PATCHING FIRS NONE LAST NONE + +RESI TP3M 0.000 ! "mmff" water model, as an analog of tip3p +GROUP +ATOM OH2 OT -0.834 ! these charges are replaced by the mmff setup +ATOM H1 HT 0.417 ! these charges are replaced by the mmff setup +ATOM H2 HT 0.417 ! these charges are replaced by the mmff setup +BOND OH2 H1 OH2 H2 ! omits the H1-H2 bond, which is needed for shake with tip3p +ANGLE H1 OH2 H2 ! required +DONOR H1 OH2 +DONOR H2 OH2 +ACCEPTOR OH2 +PATCHING FIRS NONE LAST NONE + +RESI OH -1.00 ! hydroxide ion by adm.jr. +GROUP +ATOM O1 OX -1.32 +ATOM H1 HX 0.32 +BOND O1 H1 +DONOR H1 O1 +ACCEPTOR O1 + +! Ion parameters from Benoit Roux and Coworkers +! As of 8/10 new NBFIX terms required +! +RESI LIT 1.00 ! Lithium Ion +GROUP +ATOM LIT LIT 1.00 +PATCHING FIRST NONE LAST NONE + +RESI SOD 1.00 ! Sodium Ion +GROUP +ATOM SOD SOD 1.00 +PATCHING FIRST NONE LAST NONE + +RESI MG 2.00 ! Magnesium Ion +GROUP +ATOM MG MG 2.00 +PATCHING FIRST NONE LAST NONE + +RESI POT 1.00 ! Potassium Ion +GROUP +ATOM POT POT 1.00 +PATCHING FIRST NONE LAST NONE + +RESI CAL 2.00 ! Calcium Ion +GROUP +ATOM CAL CAL 2.00 +PATCHING FIRST NONE LAST NONE + +RESI RUB 1.00 ! Rubidium Ion +GROUP +ATOM RUB RUB 1.00 +PATCHING FIRST NONE LAST NONE + +RESI CES 1.00 ! Cesium Ion +GROUP +ATOM CES CES 1.00 +PATCHING FIRST NONE LAST NONE + +RESI BAR 2.00 ! Barium Ion +GROUP +ATOM BAR BAR 2.00 +PATCHING FIRST NONE LAST NONE + +RESI ZN2 2.00 ! Zinc (II) cation, Roland Stote +GROUP +ATOM ZN ZN 2.00 +PATCHING FIRST NONE LAST NONE + +RESI CD2 2.00 ! Cadmium (II) cation +GROUP +ATOM CD CAD 2.00 +PATCHING FIRST NONE LAST NONE + +RESI CLA -1.00 ! Chloride Ion +GROUP +ATOM CLA CLA -1.00 +PATCHING FIRST NONE LAST NONE + +END + +read para card flex @app +* Parameters for water and ions +* + +ATOMS +MASS -1 HT 1.00800 ! TIPS3P WATER HYDROGEN +MASS -1 HX 1.00800 ! hydroxide hydrogen +MASS -1 OT 15.99940 ! TIPS3P WATER OXYGEN +MASS -1 OX 15.99940 ! hydroxide oxygen +MASS -1 LIT 6.94100 ! Lithium ion +MASS -1 SOD 22.98977 ! Sodium Ion +MASS -1 MG 24.30500 ! Magnesium Ion +MASS -1 POT 39.09830 ! Potassium Ion +MASS -1 CAL 40.08000 ! Calcium Ion +MASS -1 RUB 85.46780 ! Rubidium Ion +MASS -1 CES 132.90545 ! Cesium Ion +MASS -1 BAR 137.32700 ! Barium Ion +MASS -1 ZN 65.37000 ! zinc (II) cation +MASS -1 CAD 112.41100 ! cadmium (II) cation +MASS -1 CLA 35.45000 ! Chloride Ion + +BONDS +! +!V(bond) = Kb(b - b0)**2 +! +!Kb: kcal/mole/A**2 +!b0: A +! +!atom type Kb b0 +! +HT HT 0.0 1.5139 ! from TIPS3P geometry (for SHAKE w/PARAM) +HT OT 450.0 0.9572 ! from TIPS3P geometry +OX HX 545.0 0.9700 ! hydroxide ion + +ANGLES +! +!V(angle) = Ktheta(Theta - Theta0)**2 +! +!V(Urey-Bradley) = Kub(S - S0)**2 +! +!Ktheta: kcal/mole/rad**2 +!Theta0: degrees +!Kub: kcal/mole/A**2 (Urey-Bradley) +!S0: A +! +!atom types Ktheta Theta0 Kub S0 +! +HT OT HT 55.0 104.52 ! FROM TIPS3P GEOMETRY + +DIHEDRALS +! +!V(dihedral) = Kchi(1 + cos(n(chi) - delta)) +! +!Kchi: kcal/mole +!n: multiplicity +!delta: degrees +! +!atom types Kchi n delta +! + + +! +IMPROPER +! +!V(improper) = Kpsi(psi - psi0)**2 +! +!Kpsi: kcal/mole/rad**2 +!psi0: degrees +!note that the second column of numbers (0) is ignored +! +!atom types Kpsi psi0 +! + +NONBONDED nbxmod 5 atom cdiel fshift vatom vdistance vfswitch - +cutnb 14.0 ctofnb 12.0 ctonnb 10.0 eps 1.0 e14fac 1.0 wmin 1.5 + +!TIP3P LJ parameters +HT 0.0 -0.046 0.2245 +OT 0.0 -0.1521 1.7682 + +!for hydroxide +OX 0.000000 -0.120000 1.700000 ! ALLOW POL ION + ! JG 8/27/89 +HX 0.000000 -0.046000 0.224500 ! ALLOW PEP POL SUL ARO ALC + ! same as TIP3P hydrogen, adm jr., 7/20/89 + +!ions +LIT 0.0 -0.00233 1.2975 ! Lithium + ! From S Noskov, target ddG(Li-Na) was 23-26.0 kcal/mol (see JPC B, Lamoureux&Roux,2006) +SOD 0.0 -0.0469 1.41075 ! new CHARMM Sodium + ! ddG of -18.6 kcal/mol with K+ from S. Noskov +MG 0.0 -0.0150 1.18500 ! Magnesium + ! B. Roux dA = -441.65 +POT 0.0 -0.0870 1.76375 ! Potassium + ! D. Beglovd and B. Roux, dA=-82.36+2.8 = -79.56 kca/mol +CAL 0.0 -0.120 1.367 ! Calcium + ! S. Marchand and B. Roux, dA = -384.8 kcal/mol +RUB 0.0000 -0.15 1.90 ! Rubidium + ! delta A with respect to POT is +6.0 kcal/mol in bulk water +CES 0.0 -0.1900 2.100 ! Cesium + ! delta A with respect to POT is +12.0 kcal/mol +BAR 0.0 -0.150 1.890 ! Barium + ! B. Roux, dA = dA[calcium] + 64.2 kcal/mol +ZN 0.000000 -0.250000 1.090000 ! Zinc + ! RHS March 18, 1990 +CAD 0.000000 -0.120000 1.357000 ! Cadmium + ! S. Marchand and B. Roux, from delta delta G +CLA 0.0 -0.150 2.27 ! Chloride + ! D. Beglovd and B. Roux, dA=-83.87+4.46 = -79.40 kcal/mol + +NBFIX +! Emin Rmin +! (kcal/mol) (A) +SOD CLA -0.083875 3.731 ! From osmotic pressure calibration, J. Phys.Chem.Lett. 1:183-189 +POT CLA -0.114236 4.081 ! From osmotic pressure calibration, J. Phys.Chem.Lett. 1:183-189 +END + +! The following section contains NBFixes for sodium interacting with +! carboxylate oxygens of various CHARMM force fields. It will generate +! level -1 warnings whenever any of these force fields have not been +! read prior to the current stream file. Since we don't want to force +! the user to always read all the force fields, we're suppressing the +! warnings. The only side effect is that you will have "most severe +! warning was at level 0" at the end of your output. Also note that +! the user is responsible for reading the current file last if they +! want the NBFixes to apply. A more elegant solution would require new +! features to be added to CHARMM. +! parallel fix, to avoid duplicated messages in the log +set para +if ?NUMNODE gt 1 set para node 0 + +set wrn ?WRNLEV +! Some versions of CHARMM don't seem to initialize wrnlev... +if "@WRN" eq "?WRNLEV" set wrn 5 +set bom ?bomlev +WRNLEV -1 @PARA +BOMLEV -1 @PARA +read para card flex append +* NBFix between carboxylate and sodium +* + +! These NBFixes will only apply if the main files have been read in first!!! +NBFIX + +!new SOD NBFIX values +! Simulations of Anionic Lipid Membranes: Development of Interaction-Specific +! Ion Parameters and Validation using NMR Data. +! Venable, R.M.; Luo, Y,; Gawrisch, K.; Roux, B.; Pastor, R.W. +! J. Phys. Chem. B 2013, 117 (35), pp 10183–10192. DOI: 10.1021/jp401512z +! +! prot +SOD OC -0.07502 3.23 ! osmotic P; carboxylate =O +SOD OS -0.07502 3.13 ! POPC optim.; ester =O +!! NA +!SOD ON3 -0.07502 3.16 ! POPC optim.; phosphate =O UNVALIDATED +LIT ON3 -0.0167 3.1775 ! Savelyev and MacKerell, JPCB 2015 +!! lipid +SOD OCL -0.07502 3.23 ! osmotic P; carboxylate =O +SOD OBL -0.07502 3.13 ! POPC optim.; ester =O +SOD O2L -0.07502 3.16 ! POPC optim.; phosphate =O +!! carb +SOD OC2D2 -0.07502 3.23 ! osmotic P; carboxylate =O +SOD OC2DP -0.07502 3.16 ! POPC optim.; phosphate =O +!! CGenFF +SOD OG2D2 -0.07502 3.23 ! osmotic P; carboxylate =O +! OG2D1 in CGenFF shared between esters, amides, aldehydes,... +!SOD OG2D1 -0.07502 3.13 ! POPC optim.; ester =O +SOD OG2P1 -0.07502 3.16 ! POPC optim.; phosphate =O +! Chloride +CLA LIT -0.0187 3.6875 ! Savelyev and MacKerell, JPCB 2015 +CLA SOD -0.0839 3.7310 ! Savelyev and MacKerell, JPCB 2015 +CLA POT -0.1142 4.0810 ! Savelyev and MacKerell, JPCB 2015 + +END +BOMLEV @bom @PARA +WRNLEV @wrn @PARA + +return + diff --git a/continuousflex/protocols/utilities/umap_run.py b/continuousflex/protocols/utilities/umap_run.py new file mode 100644 index 0000000..ce3903a --- /dev/null +++ b/continuousflex/protocols/utilities/umap_run.py @@ -0,0 +1,46 @@ +# By Mohamad Harastani and Remi Vuillemot + +from umap import UMAP +import sys +from joblib import load, dump +import numba +import numpy as np + +@numba.njit() +def rmsd(a,b): + natoms = len(a) //3 + return np.sqrt(np.mean( + np.square(a[:natoms] - b[:natoms]) + + np.square(a[natoms:(natoms*2)] - b[natoms:(natoms*2)]) + + np.square(a[(natoms*2):(natoms*3)] - b[(natoms*2):(natoms*3)]) + )) + +def umap_run(n_component, n_neigbors, n_epocks, pkl_pdbs, pkl_pca, pkl_out,low_memory=True, metric_rmsd=False): + pdbs_matrix = load(pkl_pdbs) + if metric_rmsd: + metric = rmsd + mat_reshape = pdbs_matrix.reshape(pdbs_matrix.shape[0],pdbs_matrix.shape[1],pdbs_matrix.shape[2]) + mat_reshape = np.transpose(mat_reshape, axis=(0,2,1)) + pdbs_matrix = mat_reshape.reshape(pdbs_matrix.shape[0],pdbs_matrix.shape[1]*pdbs_matrix.shape[2]) + else: + metric= "euclidean" + umap = UMAP(n_components=n_component, n_neighbors=n_neigbors, n_epochs=n_epocks,low_memory=low_memory, + metric=metric).fit(pdbs_matrix) + Y = umap.transform(pdbs_matrix) + dump(umap, pkl_pca) + np.savetxt(pkl_out, Y) + +if __name__ == '__main__': + + print("inputs : ") + for i in sys.argv : + print(i) + umap_run(int(sys.argv[1]), + int(sys.argv[2]), + int(sys.argv[3]), + sys.argv[4], + sys.argv[5], + sys.argv[6], + bool(int(sys.argv[7])), + bool(int(sys.argv[8]))) + sys.exit() diff --git a/continuousflex/smog2.yaml b/continuousflex/smog2.yaml new file mode 100644 index 0000000..090d2ab --- /dev/null +++ b/continuousflex/smog2.yaml @@ -0,0 +1,10 @@ +channels: + - bioconda + - eumetsat + +dependencies: + - perl + - perl-xml-simple + - perl-xml-libxml + - java-jdk + - perl-pdl diff --git a/continuousflex/templates/mdspace.json.template b/continuousflex/templates/mdspace.json.template new file mode 100644 index 0000000..4cf0363 --- /dev/null +++ b/continuousflex/templates/mdspace.json.template @@ -0,0 +1,344 @@ +MDSPACE basic workflow example +[ + { + "object.className": "ProtImportPdb", + "object.id": "129", + "object.label": "Import PDB", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "inputPdbData": 0, + "pdbId": null, + "pdbFile": null + }, + { + "object.className": "ProtGenerateTopology", + "object.id": "204", + "object.label": "C-Alpha Go model", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 1, + "forcefield": 2, + "reorderResidues": false, + "reorderType": false, + "inputPDB": "3394.output" + }, + { + "object.className": "FlexProtGenesis", + "object.id": "392", + "object.label": "Energy Min", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 1, + "inputType": 0, + "forcefield": 0, + "inputTOP": null, + "inputPRM": null, + "inputRTF": null, + "inputPSF": null, + "inputSTR": "", + "centerPDB": false, + "simulationType": 0, + "integrator": 0, + "n_steps": 10000, + "time_step": 0.002, + "eneout_period": 100, + "crdout_period": 100, + "nbupdate_period": 10, + "modeList": "", + "nm_dt": 0.001, + "nm_mass": 10.0, + "exchange_period": 1000, + "nreplica": 1, + "temperature": 300.0, + "ensemble": 0, + "tpcontrol": 1, + "pressure": 1.0, + "implicitSolvent": 1, + "boundary": 0, + "box_size_x": null, + "box_size_y": null, + "box_size_z": null, + "electrostatics": 1, + "vdw_force_switch": true, + "switch_dist": 10.0, + "cutoff_dist": 12.0, + "pairlist_dist": 15.0, + "rigid_bond": false, + "fast_water": false, + "water_model": "TIP3", + "EMfitChoice": 0, + "constantK": "10000", + "emfit_sigma": 2.0, + "emfit_tolerance": 0.01, + "emfit_period": 10, + "voxel_size": 1.0, + "centerOrigin": true, + "origin_x": 0.0, + "origin_y": 0.0, + "origin_z": 0.0, + "pixel_size": 1.0, + "projectAngleChoice": 0, + "projectAngleXmipp": null, + "parallelType": 0, + "use_rankfiles": false, + "use_parallelCmd": false, + "num_core_per_node": 0, + "num_socket_per_node": 1, + "num_node": 1, + "localhost": false, + "mpirun_arguments": "", + "md_program": 0, + "hostName": "localhost", + "numberOfThreads": 1, + "numberOfMpi": 4, + "topoProt": "204." + }, + { + "object.className": "FlexProtMDSPACE", + "object.id": "2368", + "object.label": "MDSPACE", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 1, + "numberOfIter": 4, + "numberOfPCA": 3, + "inputType": 1, + "forcefield": 0, + "inputTOP": null, + "inputPRM": null, + "inputRTF": null, + "inputPSF": null, + "inputSTR": "", + "centerPDB": false, + "simulationType": 2, + "integrator": 0, + "n_steps": 20000, + "time_step": 0.002, + "eneout_period": 100, + "crdout_period": 100, + "nbupdate_period": 10, + "modeList": "7-12", + "nm_dt": 0.002, + "nm_mass": 5.0, + "exchange_period": 1000, + "nreplica": 1, + "temperature": 50.0, + "ensemble": 0, + "tpcontrol": 1, + "pressure": 1.0, + "implicitSolvent": 1, + "boundary": 0, + "box_size_x": null, + "box_size_y": null, + "box_size_z": null, + "electrostatics": 1, + "vdw_force_switch": true, + "switch_dist": 10.0, + "cutoff_dist": 12.0, + "pairlist_dist": 15.0, + "rigid_bond": false, + "fast_water": false, + "water_model": "TIP3", + "EMfitChoice": 2, + "constantK": "3000", + "emfit_sigma": 2.0, + "emfit_tolerance": 0.01, + "emfit_period": 10, + "voxel_size": 1.0, + "centerOrigin": true, + "origin_x": 0.0, + "origin_y": 0.0, + "origin_z": 0.0, + "pixel_size": 2.0, + "projectAngleChoice": 0, + "projectAngleXmipp": null, + "parallelType": 0, + "use_rankfiles": false, + "use_parallelCmd": false, + "num_core_per_node": 0, + "num_socket_per_node": 1, + "num_node": 1, + "localhost": false, + "mpirun_arguments": "", + "md_program": 0, + "hostName": "localhost", + "numberOfThreads": 2, + "numberOfMpi": 10, + "restartProt": "392.", + "inputModes": "3479.outputModes", + "inputImage": "4106.outputParticles" + }, + { + "object.className": "FlexProtAlignPdb", + "object.id": "2567", + "object.label": "Rigid body align", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 1, + "pdbSource": 1, + "pdbs_file": null, + "dcds_file": null, + "dcd_start": 0, + "dcd_end": -1, + "dcd_step": 1, + "matchingType": 0, + "createOutput": true, + "applyAlignment": false, + "setOfPDBs": "2368.outputPDBs", + "alignRefPDB": "2368.outputMean" + }, + { + "object.className": "FlexProtDimredPdb", + "object.id": "2614", + "object.label": "PCA", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 1, + "pdbSource": 2, + "pdbs_file": null, + "dcds_file": null, + "dcd_start": 0, + "dcd_end": -1, + "dcd_step": 1, + "method": 0, + "reducedDim": 10, + "setOfPDBs": "2567.outputPDBs" + }, + { + "object.className": "FlexProtDimredPdb", + "object.id": "2615", + "object.label": "UMAP", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 1, + "pdbSource": 2, + "pdbs_file": null, + "dcds_file": null, + "dcd_start": 0, + "dcd_end": -1, + "dcd_step": 1, + "method": 1, + "reducedDim": 10, + "setOfPDBs": "2567.outputPDBs" + }, + { + "object.className": "XmippProtReconstructFourier", + "object.id": "3347", + "object.label": "3D reconstruction", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 1, + "useGpu": true, + "gpuList": "0", + "symmetryGroup": "c1", + "maxRes": -1.0, + "pad_proj": 2, + "pad_vol": 2, + "legacy": false, + "approx": true, + "extraParams": "", + "hostName": "localhost", + "numberOfThreads": 4, + "numberOfMpi": 1, + "inputParticles": "4106.outputParticles" + }, + { + "object.className": "ChimeraProtRigidFit", + "object.id": "3394", + "object.label": "Chimerax - Rigid Fit", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 1, + "inputVolumes": null, + "inputPdbFiles": null, + "extraCommands": "", + "pdbFileToBeRefined": "129.outputPdb", + "inputVolume": "3347.outputVolume" + }, + { + "object.className": "FlexProtNMA", + "object.id": "3479", + "object.label": "Normal Mode Analysis", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 1, + "numberOfModes": 20, + "cutoffMode": 0, + "rc": 8.0, + "rcPercentage": 95.0, + "collectivityThreshold": 0.15, + "rtbBlockSize": 10, + "amplitude": 50.0, + "nframes": 10, + "downsample": 1.0, + "pseudoAtomThreshold": 0.0, + "inputStructure": "392.outputPDB" + }, + { + "object.className": "ProtImportParticles", + "object.id": "4106", + "object.label": "Import Particles", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "importFrom": 3, + "filesPath": null, + "filesPattern": null, + "copyFiles": false, + "emxFile": null, + "alignType": 0, + "mdFile": null, + "starFile": null, + "ignoreIdColumn": false, + "sqliteFile": null, + "frealignLabel": null, + "stackFile": null, + "parFile": null, + "lstFile": null, + "csFile": null, + "haveDataBeenPhaseFlipped": false, + "acquisitionWizard": null, + "voltage": 300.0, + "sphericalAberration": 2.7, + "amplitudeContrast": 0.1, + "magnification": 50000, + "samplingRate": null, + "dataStreaming": false, + "timeout": 43200, + "fileTimeout": 30 + } +] diff --git a/continuousflex/templates/mdtomo.json.template b/continuousflex/templates/mdtomo.json.template new file mode 100644 index 0000000..7a80518 --- /dev/null +++ b/continuousflex/templates/mdtomo.json.template @@ -0,0 +1,378 @@ +MDTOMO basic workflow example +[ + { + "object.className": "ProtImportVolumes", + "object.id": "2", + "object.label": "Input subtomograms", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "importFrom": 0, + "filesPath": "", + "filesPattern": "", + "copyFiles": false, + "emdbId": null, + "setHalfMaps": false, + "half1map": null, + "half2map": null, + "samplingRate": null, + "setOrigCoord": false, + "x": null, + "y": null, + "z": null, + "dataStreaming": false, + "timeout": 43200, + "fileTimeout": 30 + }, + { + "object.className": "FlexProtApplyVolSetAlignment", + "object.id": "84", + "object.label": "Aligned subtomograms", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "importFrom": 0, + "xmdFile": null, + "dynamoTable": null, + "emanJSON": null, + "inputVolumes": "2.outputVolumes" + }, + { + "object.className": "FlexProtSubtomogramAveraging", + "object.id": "194", + "object.label": "Average subtomogram", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "StA_choice": 2, + "import_choice": 0, + "xmippMD": null, + "dynamoTable": null, + "tomBoxTable": null, + "StartingReference": 0, + "ReferenceVolume": null, + "applyMask": false, + "NumOfIters": 10, + "WedgeMode": 1, + "tiltLow": -60, + "tiltHigh": 60, + "frm_freq": 0.25, + "frm_maxshift": 10, + "hostName": "localhost", + "numberOfMpi": 5, + "inputVolumes": "84.outputVolumes" + }, + { + "object.className": "ProtImportPdb", + "object.id": "250", + "object.label": "Import PDB", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "inputPdbData": 1, + "pdbId": "", + "pdbFile": "" + }, + { + "object.className": "ProtGenerateTopology", + "object.id": "285", + "object.label": "C-Alpha Go model", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "forcefield": 2, + "reorderResidues": false, + "reorderType": false, + "inputPDB": "856.outputPDB" + }, + { + "object.className": "FlexProtGenesis", + "object.id": "320", + "object.label": "Energy Min", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "inputType": 0, + "forcefield": 0, + "inputTOP": null, + "inputPRM": null, + "inputRTF": null, + "inputPSF": null, + "inputSTR": "", + "centerPDB": false, + "simulationType": 0, + "integrator": 0, + "n_steps": 10000, + "time_step": 0.002, + "eneout_period": 100, + "crdout_period": 100, + "nbupdate_period": 10, + "modeList": "", + "nm_dt": 0.001, + "nm_mass": 10.0, + "exchange_period": 1000, + "nreplica": 1, + "temperature": 300.0, + "ensemble": 0, + "tpcontrol": 1, + "pressure": 1.0, + "implicitSolvent": 1, + "boundary": 0, + "box_size_x": null, + "box_size_y": null, + "box_size_z": null, + "electrostatics": 1, + "vdw_force_switch": true, + "switch_dist": 10.0, + "cutoff_dist": 12.0, + "pairlist_dist": 15.0, + "rigid_bond": false, + "fast_water": false, + "water_model": "TIP3", + "posi_restr": false, + "EMfitChoice": 0, + "constantK": "10000", + "emfit_sigma": 2.0, + "emfit_tolerance": 0.01, + "emfit_period": 10, + "voxel_size": 1.0, + "centerOrigin": true, + "origin_x": 0.0, + "origin_y": 0.0, + "origin_z": 0.0, + "pixel_size": 1.0, + "projectAngleChoice": 0, + "projectAngleXmipp": null, + "parallelType": 0, + "use_rankfiles": false, + "use_parallelCmd": false, + "num_core_per_node": 0, + "num_socket_per_node": 1, + "num_node": 1, + "localhost": false, + "mpirun_arguments": "", + "md_program": 0, + "hostName": "localhost", + "numberOfThreads": 1, + "numberOfMpi": 4, + "topoProt": "285." + }, + { + "object.className": "FlexProtAlignPdb", + "object.id": "526", + "object.label": "Rigid body align", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "pdbSource": 1, + "pdbs_file": null, + "dcds_file": null, + "dcd_start": 0, + "dcd_end": -1, + "dcd_step": 1, + "matchingType": 0, + "createOutput": true, + "applyAlignment": false, + "alignRefPDB": "320.outputPDB", + "setOfPDBs": "916.outputPDBs" + }, + { + "object.className": "FlexProtDimredPdb", + "object.id": "573", + "object.label": "PCA", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "pdbSource": 2, + "pdbs_file": null, + "dcds_file": null, + "dcd_start": 0, + "dcd_end": -1, + "dcd_step": 1, + "method": 0, + "n_neigbors": 15, + "n_epocks": 1000, + "metric_rmsd": false, + "low_memory": false, + "reducedDim": 10, + "setOfPDBs": "526.outputPDBs" + }, + { + "object.className": "FlexProtDimredPdb", + "object.id": "623", + "object.label": "UMAP", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "pdbSource": 2, + "pdbs_file": null, + "dcds_file": null, + "dcd_start": 0, + "dcd_end": -1, + "dcd_step": 1, + "method": 1, + "n_neigbors": 15, + "n_epocks": 1000, + "metric_rmsd": false, + "low_memory": false, + "reducedDim": 10, + "setOfPDBs": "526.outputPDBs" + }, + { + "object.className": "ChimeraProtRigidFit", + "object.id": "714", + "object.label": "Chimerax - Rigid Fit", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "inputVolumes": null, + "inputPdbFiles": null, + "extraCommands": "", + "inputVolume": "194.SubtomogramAverage", + "pdbFileToBeRefined": "250.outputPdb" + }, + { + "object.className": "FlexProtNMA", + "object.id": "751", + "object.label": "Normal Mode Analysis", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "numberOfModes": 20, + "cutoffMode": 0, + "rc": 8.0, + "rcPercentage": 95.0, + "collectivityThreshold": 0.15, + "rtbBlockSize": 10, + "amplitude": 50.0, + "nframes": 10, + "downsample": 1.0, + "pseudoAtomThreshold": 0.0, + "inputStructure": "320.outputPDB" + }, + { + "object.className": "ProtGenerateTopology", + "object.id": "856", + "object.label": "All-atom model", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "forcefield": 0, + "reorderResidues": false, + "reorderType": false, + "inputPDB": "714.output" + }, + { + "object.className": "FlexProtMDTOMO", + "object.id": "916", + "object.label": "MDTOMO", + "object.comment": "", + "_useQueue": false, + "_prerequisites": "", + "_queueParams": null, + "runName": null, + "runMode": 0, + "inputType": 0, + "forcefield": 0, + "inputTOP": null, + "inputPRM": null, + "inputRTF": null, + "inputPSF": null, + "inputSTR": "", + "centerPDB": false, + "simulationType": 2, + "integrator": 0, + "n_steps": 50000, + "time_step": 0.002, + "eneout_period": 100, + "crdout_period": 100, + "nbupdate_period": 10, + "modeList": "7-16", + "nm_dt": 0.002, + "nm_mass": 10.0, + "exchange_period": 1000, + "nreplica": 1, + "temperature": 50.0, + "ensemble": 0, + "tpcontrol": 1, + "pressure": 1.0, + "implicitSolvent": 1, + "boundary": 0, + "box_size_x": null, + "box_size_y": null, + "box_size_z": null, + "electrostatics": 1, + "vdw_force_switch": true, + "switch_dist": 10.0, + "cutoff_dist": 12.0, + "pairlist_dist": 15.0, + "rigid_bond": false, + "fast_water": false, + "water_model": "TIP3", + "posi_restr": false, + "EMfitChoice": 1, + "constantK": "1000", + "emfit_sigma": 2.0, + "emfit_tolerance": 0.01, + "emfit_period": 10, + "voxel_size": 1.0, + "centerOrigin": true, + "origin_x": 0.0, + "origin_y": 0.0, + "origin_z": 0.0, + "pixel_size": 1.0, + "projectAngleChoice": 0, + "projectAngleXmipp": null, + "parallelType": 0, + "use_rankfiles": false, + "use_parallelCmd": false, + "num_core_per_node": 0, + "num_socket_per_node": 1, + "num_node": 1, + "localhost": false, + "mpirun_arguments": "", + "md_program": 0, + "hostName": "localhost", + "numberOfThreads": 1, + "numberOfMpi": 10, + "inputVolume": "84.outputVolumes", + "topoProt": "285.", + "inputModes": "751.outputModes" + } +] \ No newline at end of file diff --git a/continuousflex/tests/__init__.py b/continuousflex/tests/__init__.py index 56829bc..18f729b 100644 --- a/continuousflex/tests/__init__.py +++ b/continuousflex/tests/__init__.py @@ -4,3 +4,27 @@ from .test_structure_mapping import * from .test_workflow_subtomogram_synthesize import * from .test_workflow_TomoFlow import * +from .test_workflow_GENESIS import * +from .test_workflow_Deep_HEMNMA import * +from pyworkflow.tests import DataSet + +files_dictionary = {'pdb': 'pdb/AK.pdb', 'particles': 'particles/img.stk', 'vol': 'volumes/AK_LP10.vol', + 'precomputed_atomic': 'gold/images_WS_atoms.xmd', + 'precomputed_pseudoatomic': 'gold/images_WS_pseudoatoms.xmd', + 'small_stk': 'test_alignment_10images/particles/smallstack_img.stk', + 'subtomograms':'HEMNMA_3D/subtomograms/*.vol', + 'precomputed_HEMNMA3D_atoms':'HEMNMA_3D/gold/precomputed_atomic.xmd', + 'precomputed_HEMNMA3D_pseudo':'HEMNMA_3D/gold/precomputed_pseudo.xmd', + + 'charmm_prm':'genesis/par_all36_prot.prm', + 'charmm_top':'genesis/top_all36_prot.rtf', + '1ake_pdb':'genesis/1ake.pdb', + '1ake_vol':'genesis/1ake.mrc', + '4ake_pdb':'genesis/4ake.pdb', + '4ake_aa_pdb':'genesis/4ake_aa.pdb', + '4ake_aa_psf':'genesis/4ake_aa.psf', + '4ake_ca_pdb':'genesis/4ake_ca.pdb', + '4ake_ca_top':'genesis/4ake_ca.top', + } +DataSet(name='nma_V2.0', folder='nma_V2.0', files=files_dictionary, + url='https://raw.githubusercontent.com/continuousflex-org/testdata-continuousflex/main') diff --git a/continuousflex/tests/test_workflow_Deep_HEMNMA.py b/continuousflex/tests/test_workflow_Deep_HEMNMA.py new file mode 100644 index 0000000..d289965 --- /dev/null +++ b/continuousflex/tests/test_workflow_Deep_HEMNMA.py @@ -0,0 +1,106 @@ +# ************************************************************************** +# * +# * Authors: Ilyes Hamitouche (ilyes.hamitouche@upmc.fr) +# * IMPMC, Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# * +# ************************************************************************** + +from pwem.protocols import ProtImportPdb, ProtImportParticles, ProtSubSet +from pwem.tests.workflows import TestWorkflow +from pyworkflow.tests import setupTestProject, DataSet +from continuousflex.protocols import (FlexProtNMA, FlexProtAlignmentNMA, + FlexProtDimredNMA, NMA_CUTOFF_ABS, + FlexProtDeepHEMNMATrain, + FlexProtDeepHEMNMAInfer) +from xmipp3.protocols import XmippProtCropResizeParticles + + +class TestDeepHEMNMA(TestWorkflow): + """ Test protocol for deepHEMNMA. """ + @classmethod + def setUpClass(cls): + # Create a new project + setupTestProject(cls) + cls.ds = DataSet.getDataSet('nma_V2.0') + + def test_HEMNMA_atomic(self): + protImportPdb = self.newProtocol(ProtImportPdb, inputPdbData=1, + pdbFile=self.ds.getFile('pdb')) + protImportPdb.setObjLabel('AK.pdb') + self.launchProtocol(protImportPdb) + + # Launch NMA for PDB imported + protNMA1 = self.newProtocol(FlexProtNMA, + cutoffMode=NMA_CUTOFF_ABS) + protNMA1.inputStructure.set(protImportPdb.outputPdb) + protNMA1.setObjLabel('NMA') + self.launchProtocol(protNMA1) + + # Import the set of particles + # (in this order just to be in the middle in the tree) + protImportParts = self.newProtocol(ProtImportParticles, + filesPath=self.ds.getFile('particles'), + samplingRate=1.0) + protImportParts.setObjLabel('Particles') + self.launchProtocol(protImportParts) + + protResizeParts= self.newProtocol(XmippProtCropResizeParticles) + protResizeParts.doResize.set(True) + protResizeParts.resizeOption.set(2) # this corresponds to factor + protResizeParts.resizeFactor.set(0.25) + protResizeParts.inputParticles.set(protImportParts.outputParticles) + protResizeParts.setObjLabel('Resizing (factor 0.25)') + self.launchProtocol(protResizeParts) + + protSubset1 = self.newProtocol(ProtSubSet, + objLabel='Training set', + chooseAtRandom=True, + nElements=4) + # protSubset1.inputFullSet.set(protImportParts.outputParticles) + protSubset1.inputFullSet.set(protResizeParts.outputParticles) + self.launchProtocol(protSubset1) + + + protSubset2 = self.newProtocol(ProtSubSet, + objLabel='Inference set', + chooseAtRandom=False, + setOperation=1) + protSubset2.inputFullSet.set(protResizeParts.outputParticles) + # protSubset2.inputFullSet.set(protImportParts.outputParticles) + protSubset2.inputSubSet.set(protSubset1.outputParticles) + self.launchProtocol(protSubset2) + + # Launch NMA alignment + protAlignment = self.newProtocol(FlexProtAlignmentNMA, + modeList='7-9') + protAlignment.inputModes.set(protNMA1.outputModes) + protAlignment.inputParticles.set(protSubset1.outputParticles) + protAlignment.setObjLabel('HEMNMA atomic ref') + self.launchProtocol(protAlignment) + + protTrain = self.newProtocol(FlexProtDeepHEMNMATrain) + protTrain.inputNMA.set(protAlignment) + self.launchProtocol(protTrain) + + protInfer = self.newProtocol(FlexProtDeepHEMNMAInfer) + protInfer.trained_model.set(protTrain) #angles and shifts + protInfer.inputParticles.set(protSubset2.outputParticles) + self.launchProtocol(protInfer) diff --git a/continuousflex/tests/test_workflow_GENESIS.py b/continuousflex/tests/test_workflow_GENESIS.py new file mode 100644 index 0000000..97e1124 --- /dev/null +++ b/continuousflex/tests/test_workflow_GENESIS.py @@ -0,0 +1,221 @@ +# ************************************************************************** +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * IMPMC, Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +from pwem.protocols import ProtImportPdb, ProtImportVolumes +from pwem.tests.workflows import TestWorkflow +from pyworkflow.tests import setupTestProject, DataSet +from continuousflex.protocols.protocol_generate_topology import ProtGenerateTopology +from continuousflex.protocols import FlexProtNMA, NMA_CUTOFF_ABS +from continuousflex.viewers.viewer_genesis import * +from continuousflex.protocols.utilities.pdb_handler import ContinuousFlexPDBHandler + + +class TestGENESIS(TestWorkflow): + """ Test Class for GENESIS. """ + @classmethod + def setUpClass(cls): + # Create a new project + setupTestProject(cls) + cls.ds = DataSet.getDataSet('nma_V2.0') + # Import Target EM map + protImportVol = cls.newProtocol(ProtImportVolumes, importFrom=ProtImportVolumes.IMPORT_FROM_FILES, + filesPath=cls.ds.getFile('1ake_vol'), samplingRate=2.0) + protImportVol.setObjLabel('EM map') + cls.launchProtocol(protImportVol) + + cls.protImportVol = protImportVol + cls.protPdb4ake = cls.newProtocol(ProtImportPdb, inputPdbData=1, + pdbFile=cls.ds.getFile('4ake_aa_pdb')) + cls.protPdb4ake.setObjLabel('Input PDB') + cls.launchProtocol(cls.protPdb4ake) + + def test1_EmfitVolumeCHARMM(self): + + # Generate topo + protGenTopo = self.newProtocol(ProtGenerateTopology, + inputPDB = self.protPdb4ake.outputPdb, + forcefield = FORCEFIELD_CHARMM) + protGenTopo.setObjLabel('CHARMM topology model') + self.launchProtocol(protGenTopo) + + # Energy min + protGenesisMin = self.newProtocol(FlexProtGenesis, + inputType = INPUT_TOPOLOGY, + topoProt = protGenTopo, + simulationType = SIMULATION_MIN, + n_steps = 100, + numberOfThreads = NUMBER_OF_CPU, + numberOfMpi = 1) + protGenesisMin.setObjLabel('Energy min') + self.launchProtocol(protGenesisMin) + + # Assert energy descreased + potential_ene = readLogFile(protGenesisMin.getOutputPrefix()+".log")["POTENTIAL_ENE"] + assert(potential_ene[0] > potential_ene[-1]) + + # Launch NMA for energy min PDB + protNMA = self.newProtocol(FlexProtNMA, + cutoffMode=NMA_CUTOFF_ABS) + protNMA.inputStructure.set(protGenesisMin.outputPDB) + protNMA.setObjLabel('NMA') + self.launchProtocol(protNMA) + + # Fit NMMD + protGenesisFitNMMD = self.newProtocol(FlexProtGenesis, + inputType=INPUT_RESTART, + restartProt = protGenesisMin, + simulationType=SIMULATION_NMMD, + time_step=0.002, + n_steps=100, + nm_number=6, + nm_mass=1.0, + inputModes=protNMA.outputModes, + EMfitChoice=EMFIT_VOLUMES, + constantK=10000, + inputVolume=self.protImportVol.outputVolume, + voxel_size=2.0, + centerOrigin=True, + numberOfThreads=NUMBER_OF_CPU, + numberOfMpi=1, + ) + protGenesisFitNMMD.setObjLabel('NMMD fitting') + self.launchProtocol(protGenesisFitNMMD) + + # Assert that the CC is increasing and the RMSD is decreasing + cc = readLogFile( protGenesisFitNMMD.getOutputPrefix()+".log")["RESTR_CVS001"] + inp = ContinuousFlexPDBHandler(protGenesisFitNMMD.getInputPDBprefix() + ".pdb") + ref = ContinuousFlexPDBHandler(self.ds.getFile('1ake_pdb')) + out = ContinuousFlexPDBHandler(protGenesisFitNMMD.getOutputPrefix()+".pdb") + matchingAtoms = inp.matchPDBatoms(reference_pdb=ref) + rmsd_inp = inp.getRMSD(reference_pdb=ref,idx_matching_atoms=matchingAtoms,align=True) + rmsd_out = out.getRMSD(reference_pdb=ref,idx_matching_atoms=matchingAtoms,align=True) + assert(cc[0] < cc[-1]) + assert(rmsd_inp >rmsd_out) + + def test2_EmfitVolumeCAGO(self): + # Generate topo + protGenTopo = self.newProtocol(ProtGenerateTopology, + inputPDB = self.protPdb4ake.outputPdb, + forcefield = FORCEFIELD_CAGO) + protGenTopo.setObjLabel('C-Alpha Go topology model') + self.launchProtocol(protGenTopo) + + # energy min + protGenesisMin = self.newProtocol(FlexProtGenesis, + inputType=INPUT_TOPOLOGY, + topoProt=protGenTopo, + simulationType=SIMULATION_MIN, + numberOfThreads=NUMBER_OF_CPU, + numberOfMpi=1) + protGenesisMin.setObjLabel('Energy min') + self.launchProtocol(protGenesisMin) + + # Launch NMA for energy min PDB + protNMA = self.newProtocol(FlexProtNMA, + cutoffMode=NMA_CUTOFF_ABS) + protNMA.inputStructure.set(protGenesisMin.outputPDB) + protNMA.setObjLabel('NMA') + self.launchProtocol(protNMA) + + protGenesisFitMD = self.newProtocol(FlexProtGenesis, + inputType=INPUT_RESTART, + restartProt=protGenesisMin, + simulationType=SIMULATION_MD, + time_step=0.001, + n_steps=1000, + temperature=50.0, + EMfitChoice=EMFIT_VOLUMES, + constantK="500", + inputVolume=self.protImportVol.outputVolume, + voxel_size=2.0, + centerOrigin=True, + numberOfThreads=NUMBER_OF_CPU, + numberOfMpi=1) + protGenesisFitMD.setObjLabel('MD fitting') + self.launchProtocol(protGenesisFitMD) + + # Get GENESIS log file + log_file = protGenesisFitMD.getOutputPrefix()+".log" + + # Get the CC from the log file + cc = readLogFile(log_file)["RESTR_CVS001"] + + # Get the RMSD + inp = ContinuousFlexPDBHandler(protGenesisFitMD.getInputPDBprefix() + ".pdb") + ref = ContinuousFlexPDBHandler(self.ds.getFile('1ake_pdb')) + out = ContinuousFlexPDBHandler(protGenesisFitMD.getOutputPrefix()+".pdb") + matchingAtoms = inp.matchPDBatoms(reference_pdb=ref) + rmsd_inp = inp.getRMSD(reference_pdb=ref,idx_matching_atoms=matchingAtoms,align=True) + rmsd_out = out.getRMSD(reference_pdb=ref,idx_matching_atoms=matchingAtoms,align=True) + assert (cc[0] < cc[-1]) + assert (rmsd_inp > rmsd_out) + + + # Need at least 4 cores + if NUMBER_OF_CPU >= 4: + protGenesisFitREUS = self.newProtocol(FlexProtGenesis, + inputType=INPUT_RESTART, + restartProt=protGenesisMin, + simulationType=SIMULATION_RENMMD, + time_step=0.0005, + n_steps=1000, + nm_number=6, + nm_mass=1.0, + inputModes=protNMA.outputModes, + exchange_period=100, # 100 + nreplica = 4, + temperature=50.0, + constantK="500-1500", + EMfitChoice=EMFIT_VOLUMES, + inputVolume=self.protImportVol.outputVolume, + voxel_size=2.0, + centerOrigin=True, + numberOfThreads=1, + numberOfMpi=NUMBER_OF_CPU, + ) + protGenesisFitREUS.setObjLabel('RENMMD fitting') + self.launchProtocol(protGenesisFitREUS) + + # Get GENESIS log file + outPref = protGenesisFitREUS.getOutputPrefixAll() + log_file1 = outPref[0] + ".log" + log_file2 = outPref[1] + ".log" + + # Get the CC from the log file + cc1 = readLogFile(log_file1)["RESTR_CVS001"] + cc2 = readLogFile(log_file2)["RESTR_CVS001"] + + # Get the RMSD + ref = ContinuousFlexPDBHandler(self.ds.getFile('1ake_pdb')) + inp = ContinuousFlexPDBHandler(protGenesisFitREUS.getInputPDBprefix() + ".pdb") + out1 = ContinuousFlexPDBHandler(outPref[0] + ".pdb") + out2 = ContinuousFlexPDBHandler(outPref[1] + ".pdb") + matchingAtoms = inp.matchPDBatoms(reference_pdb=ref) + rmsd_inp = inp.getRMSD(reference_pdb=ref, idx_matching_atoms=matchingAtoms, align=True) + rmsd_out2 = out2.getRMSD(reference_pdb=ref, idx_matching_atoms=matchingAtoms, align=True) + rmsd_out1 = out1.getRMSD(reference_pdb=ref, idx_matching_atoms=matchingAtoms, align=True) + assert (cc1[0] < cc1[-1]) + assert (cc2[0] < cc2[-1]) + assert (rmsd_inp> rmsd_out1) + assert (rmsd_inp > rmsd_out2) + diff --git a/continuousflex/tests/test_workflow_HEMNMA.py b/continuousflex/tests/test_workflow_HEMNMA.py index c762ff1..4a177c5 100644 --- a/continuousflex/tests/test_workflow_HEMNMA.py +++ b/continuousflex/tests/test_workflow_HEMNMA.py @@ -25,20 +25,19 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** + from pwem.protocols import ProtImportPdb, ProtImportParticles, ProtImportVolumes from pwem.tests.workflows import TestWorkflow -from pwem import Domain from pyworkflow.tests import setupTestProject, DataSet - from continuousflex.protocols import (FlexProtNMA, FlexProtAlignmentNMA, FlexProtDimredNMA, NMA_CUTOFF_ABS, - FlexProtConvertToPseudoAtoms, FlexBatchProtNMACluster) - + FlexProtConvertToPseudoAtoms) from continuousflex.protocols.pdb.protocol_pseudoatoms_base import NMA_MASK_THRE from continuousflex.protocols.protocol_nma_base import NMA_CUTOFF_REL from continuousflex.protocols.protocol_nma_alignment import NMA_ALIGNMENT_PROJ from xmipp3.protocols import XmippProtCropResizeParticles + class TestHEMNMA_1(TestWorkflow): """ Test protocol for HEMNMA (Hybrid Electron Microscopy Normal Mode Analysis). """ @classmethod @@ -90,22 +89,7 @@ def test_HEMNMA_atomic(self): protDimRed.setObjLabel('HEMNMA dimred') self.launchProtocol(protDimRed) - newProt = self.newProtocol(FlexBatchProtNMACluster) - newProt.setObjLabel('Cluster: x1 <- 30') - newProt.inputNmaDimred.set(protDimRed) - fnSqlite = self.ds.getFile('clusters/atomic/left.sqlite') - newProt.sqliteFile.set(fnSqlite) - self.launchProtocol(newProt) - - newProt = self.newProtocol(FlexBatchProtNMACluster) - newProt.setObjLabel('Cluster: x1 > 30') - newProt.inputNmaDimred.set(protDimRed) - fnSqlite = self.ds.getFile('clusters/atomic/right.sqlite') - newProt.sqliteFile.set(fnSqlite) - self.launchProtocol(newProt) - - - #------------------------------------------------ + #------------------------------------------------ # Case 2. Import Vol -> Pdb -> NMA #------------------------------------------------ @@ -149,21 +133,6 @@ def test_HEMNMA_atomic(self): protDimRed.setObjLabel('HEMNMA dimred') self.launchProtocol(protDimRed) - newProt = self.newProtocol(FlexBatchProtNMACluster) - newProt.setObjLabel('Cluster: x1 <- 15') - newProt.inputNmaDimred.set(protDimRed) - fnSqlite = self.ds.getFile('clusters/pseudo/left.sqlite') - newProt.sqliteFile.set(fnSqlite) - self.launchProtocol(newProt) - - newProt = self.newProtocol(FlexBatchProtNMACluster) - newProt.setObjLabel('Cluster: x1 > 15') - newProt.inputNmaDimred.set(protDimRed) - fnSqlite = self.ds.getFile('clusters/pseudo/right.sqlite') - newProt.sqliteFile.set(fnSqlite) - self.launchProtocol(newProt) - - class TestHEMNMA_2(TestWorkflow): """ Test protocol for HEMNMA (Hybrid Electron Microscopy Normal Mode Analysis). """ @@ -173,7 +142,6 @@ def setUpClass(cls): # Create a new project setupTestProject(cls) cls.ds = DataSet.getDataSet('nma_V2.0') - # cls.ds = DataSet.getDataSet('nma') def test_HEMNMA_atomic(self): """ Run NMA simple workflow for both Atomic and Pseudoatoms. """ diff --git a/continuousflex/tests/test_workflow_HEMNMA3D.py b/continuousflex/tests/test_workflow_HEMNMA3D.py index 83e15ae..08aa160 100644 --- a/continuousflex/tests/test_workflow_HEMNMA3D.py +++ b/continuousflex/tests/test_workflow_HEMNMA3D.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * IMPMC, Sorbonne University # * # * This program is free software; you can redistribute it and/or modify @@ -20,32 +20,18 @@ # * All comments concerning this program package may be sent to the # * e-mail address 'scipion@cnb.csic.es' # ************************************************************************** + from continuousflex.protocols import FlexProtAlignmentNMAVol, FlexProtDimredNMAVol -from pwem.protocols import ProtImportPdb, ProtImportParticles, ProtImportVolumes -from pwem.tests.workflows import TestWorkflow -from pyworkflow.tests import setupTestProject, DataSet -from continuousflex.protocols import (FlexProtNMA, NMA_CUTOFF_ABS, - FlexProtConvertToPseudoAtoms) +from continuousflex.protocols import FlexProtConvertToPseudoAtoms from continuousflex.protocols.pdb.protocol_pseudoatoms_base import NMA_MASK_THRE from continuousflex.protocols.protocol_nma_dimred_vol import DIMRED_SKLEAN_PCA -import os - -from pwem.protocols import ProtImportPdb, ProtImportParticles, ProtImportVolumes +from pwem.protocols import ProtImportPdb, ProtImportVolumes from pwem.tests.workflows import TestWorkflow -from pwem import Domain from pyworkflow.tests import setupTestProject, DataSet - from continuousflex.protocols import (FlexProtNMA, FlexProtSynthesizeSubtomo, NMA_CUTOFF_ABS, NMA_CUTOFF_REL) -from continuousflex.protocols.protocol_subtomogrmas_synthesize import MODE_RELATION_LINEAR, MODE_RELATION_3CLUSTERS, \ - MODE_RELATION_MESH, MODE_RELATION_RANDOM -from continuousflex.protocols.protocol_pdb_dimred import FlexProtDimredPdb -from continuousflex.protocols.protocol_subtomograms_classify import FlexProtSubtomoClassify -from continuousflex.protocols.protocol_subtomogram_averaging import FlexProtSubtomogramAveraging +from continuousflex.protocols.protocol_subtomograms_synthesize import MODE_RELATION_3CLUSTERS from xmipp3.protocols import XmippProtCropResizeVolumes -from continuousflex.protocols.protocol_batch_cluster_vol import FlexBatchProtNMAClusterVol - - class TestHEMNMA3D_1(TestWorkflow): """ Test protocol for HEMNMA-3D. """ @@ -96,20 +82,6 @@ def test_nma3D(self): protDimRed.setObjLabel('HEMNMA-3D dimred') self.launchProtocol(protDimRed) - newProt = self.newProtocol(FlexBatchProtNMAClusterVol) - newProt.setObjLabel('Cluster: x1 <- 100') - newProt.inputNmaDimred.set(protDimRed) - fnSqlite = self.ds.getFile('HEMNMA_3D/clusters/atomic_left.sqlite') - newProt.sqliteFile.set(fnSqlite) - self.launchProtocol(newProt) - - newProt = self.newProtocol(FlexBatchProtNMAClusterVol) - newProt.setObjLabel('Cluster: x1 > 100') - newProt.inputNmaDimred.set(protDimRed) - fnSqlite = self.ds.getFile('HEMNMA_3D/clusters/atomic_right.sqlite') - newProt.sqliteFile.set(fnSqlite) - self.launchProtocol(newProt) - # ------------------------------------------------ # Case 2. Import Vol -> Pdb -> NMA # ------------------------------------------------ @@ -150,20 +122,6 @@ def test_nma3D(self): protDimRed.setObjLabel('HEMNMA-3D dimred') self.launchProtocol(protDimRed) - newProt = self.newProtocol(FlexBatchProtNMAClusterVol) - newProt.setObjLabel('Cluster: x1 <- 100') - newProt.inputNmaDimred.set(protDimRed) - fnSqlite = self.ds.getFile('HEMNMA_3D/clusters/pseudo_left.sqlite') - newProt.sqliteFile.set(fnSqlite) - self.launchProtocol(newProt) - - newProt = self.newProtocol(FlexBatchProtNMAClusterVol) - newProt.setObjLabel('Cluster: x1 > 100') - newProt.inputNmaDimred.set(protDimRed) - fnSqlite = self.ds.getFile('HEMNMA_3D/clusters/pseudo_right.sqlite') - newProt.sqliteFile.set(fnSqlite) - self.launchProtocol(newProt) - class TestHEMNMA3D_2(TestWorkflow): """ Test protocol for HEMNMA-3D. """ diff --git a/continuousflex/tests/test_workflow_MDSPACE.py b/continuousflex/tests/test_workflow_MDSPACE.py new file mode 100644 index 0000000..9bd7bc9 --- /dev/null +++ b/continuousflex/tests/test_workflow_MDSPACE.py @@ -0,0 +1,166 @@ +# ************************************************************************** +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * IMPMC, Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +from pwem.protocols import ProtImportPdb +from pwem.tests.workflows import TestWorkflow +from pyworkflow.tests import setupTestProject, DataSet + +from continuousflex.protocols.protocol_mdspace import FlexProtMDSPACE +from continuousflex.protocols import FlexProtNMA, NMA_CUTOFF_ABS, FlexProtSynthesizeImages, \ + FlexProtDimredPdb, FlexProtAlignPdb,FlexProtGenesis +from continuousflex.protocols.utilities.genesis_utilities import * + +from continuousflex.protocols.protocol_align_pdbs import PDB_SOURCE_OBJECT +from continuousflex.protocols.protocol_pdb_dimred import PDB_SOURCE_ALIGNED, REDUCE_METHOD_PCA, REDUCE_METHOD_UMAP + +class TestMDSPACE(TestWorkflow): + """ Test Class for MDSPACE. """ + + @classmethod + def setUpClass(cls): + setupTestProject(cls) + cls. ds = DataSet.getDataSet('nma_V2.0') + + + def test_MDSPACE(self): + + + # ------------------------- Import PDB prot -------------------------------- + protPdb4ake = self.newProtocol(ProtImportPdb, inputPdbData=1, + pdbFile=self.ds.getFile('4ake_ca_pdb')) + protPdb4ake.setObjLabel('Input PDB (4AKE C-Alpha only)') + self.launchProtocol(protPdb4ake) + + # ------------------------- Genesis Min prot -------------------------------- + protGenesisMin = self.newProtocol(FlexProtGenesis, + inputPDB=protPdb4ake.outputPdb, + forcefield=FORCEFIELD_CAGO, + inputType=INPUT_NEW_SIM, + inputTOP=self.ds.getFile('4ake_ca_top'), + + simulationType=SIMULATION_MIN, + time_step=0.001, + n_steps=100, + eneout_period=10, + crdout_period=10, + nbupdate_period=10, + + implicitSolvent=IMPLICIT_SOLVENT_NONE, + electrostatics=ELECTROSTATICS_CUTOFF, + switch_dist=10.0, + cutoff_dist=12.0, + pairlist_dist=15.0, + + numberOfThreads=NUMBER_OF_CPU, + numberOfMpi=1, + ) + protGenesisMin.setObjLabel('Energy Minimization CAGO') + # Launch minimisation + self.launchProtocol(protGenesisMin) + + # ------------------------- NMA prot -------------------------------- + # Launch NMA for energy min PDB + protNMA = self.newProtocol(FlexProtNMA, + cutoffMode=NMA_CUTOFF_ABS) + protNMA.inputStructure.set(protGenesisMin.outputPDB) + protNMA.setObjLabel('NMA') + self.launchProtocol(protNMA) + + # ------------------------- synth images -------------------------------- + target_images = self.newProtocol(FlexProtSynthesizeImages, + inputModes=protNMA.outputModes, + numberOfVolumes=100, + samplingRate=2.0, + modesAmplitudeRange=50, + seedOption=False, + noiseCTFChoice=1, + volumeSize=64) + target_images.setObjLabel('Target particles') + self.launchProtocol(target_images) + + # ------------------------- MDSPACE -------------------------------- + protMDSPACE = self.newProtocol(FlexProtMDSPACE, + + inputType=INPUT_RESTART, + restartProt=protGenesisMin, + + simulationType=SIMULATION_NMMD, + time_step=0.001, + n_steps=5000, + eneout_period=100, + crdout_period=100, + nbupdate_period=10, + nm_number=6, + nm_mass=1.0, + inputModes=protNMA.outputModes, + + implicitSolvent=IMPLICIT_SOLVENT_NONE, + electrostatics=ELECTROSTATICS_CUTOFF, + switch_dist=10.0, + cutoff_dist=12.0, + pairlist_dist=15.0, + + ensemble=ENSEMBLE_NVT, + tpcontrol=TPCONTROL_LANGEVIN, + temperature=50.0, + + boundary=BOUNDARY_NOBC, + EMfitChoice=EMFIT_IMAGES, + constantK="100", + emfit_sigma=2.0, + emfit_tolerance=0.1, + inputImage=target_images.outputImages, + pixel_size=2.0, + imageAngleShift=target_images._getExtraPath("GroundTruth.xmd"), + + numberOfThreads=1, + numberOfMpi=NUMBER_OF_CPU, + ) + protMDSPACE.setObjLabel('MDSPACE') + + # Launch Fitting + self.launchProtocol(protMDSPACE) + + # ------------------------- align pdbs -------------------------------- + alignPDBs = self.newProtocol(FlexProtAlignPdb, + pdbSource = PDB_SOURCE_OBJECT, + setOfPDBs = protMDSPACE.outputPDBs, + alignRefPDB=protGenesisMin.outputPDB, + createOutput=False) + alignPDBs.setObjLabel('Align output PDBs') + self.launchProtocol(alignPDBs) + + # ------------------------- PCA -------------------------------- + protPca = self.newProtocol(FlexProtDimredPdb, + pdbSource=PDB_SOURCE_ALIGNED, + alignPdbProt=alignPDBs, + method=REDUCE_METHOD_PCA) + protPca.setObjLabel('PCA') + self.launchProtocol(protPca) + # ------------------------- UMAP -------------------------------- + protUmap = self.newProtocol(FlexProtDimredPdb, + pdbSource=PDB_SOURCE_ALIGNED, + alignPdbProt=alignPDBs, + method=REDUCE_METHOD_UMAP) + protUmap.setObjLabel('UMAP') + self.launchProtocol(protUmap) \ No newline at end of file diff --git a/continuousflex/tests/test_workflow_MDTOMO.py b/continuousflex/tests/test_workflow_MDTOMO.py new file mode 100644 index 0000000..fd03f43 --- /dev/null +++ b/continuousflex/tests/test_workflow_MDTOMO.py @@ -0,0 +1,149 @@ +# ************************************************************************** +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * IMPMC, Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +from pwem.protocols import ProtImportPdb +from pwem.tests.workflows import TestWorkflow +from pyworkflow.tests import setupTestProject, DataSet + +from continuousflex.protocols.protocol_mdtomo import FlexProtMDTOMO +from continuousflex.protocols import FlexProtNMA, NMA_CUTOFF_ABS, FlexProtSynthesizeSubtomo, \ + FlexProtDimredPdb, FlexProtAlignPdb,FlexProtGenesis +from continuousflex.protocols.utilities.genesis_utilities import * + +from continuousflex.protocols.protocol_align_pdbs import PDB_SOURCE_OBJECT +from continuousflex.protocols.protocol_pdb_dimred import PDB_SOURCE_ALIGNED, REDUCE_METHOD_PCA, REDUCE_METHOD_UMAP + +class TestMDTOMO(TestWorkflow): + """ Test Class for MDTOMO. """ + + @classmethod + def setUpClass(cls): + setupTestProject(cls) + cls. ds = DataSet.getDataSet('nma_V2.0') + + def test_MDTOMO(self): + # ------------------------- Import PDB prot -------------------------------- + protPdb4ake = self.newProtocol(ProtImportPdb, inputPdbData=1, + pdbFile=self.ds.getFile('4ake_ca_pdb')) + protPdb4ake.setObjLabel('Input PDB (4AKE C-Alpha only)') + self.launchProtocol(protPdb4ake) + # ------------------------- Genesis Min prot -------------------------------- + + protGenesisMin = self.newProtocol(FlexProtGenesis, + inputPDB=protPdb4ake.outputPdb, + forcefield=FORCEFIELD_CAGO, + inputType=INPUT_NEW_SIM, + inputTOP=self.ds.getFile('4ake_ca_top'), + + simulationType=SIMULATION_MIN, + time_step=0.001, + n_steps=100, + eneout_period=10, + crdout_period=10, + nbupdate_period=10, + + implicitSolvent=IMPLICIT_SOLVENT_NONE, + electrostatics=ELECTROSTATICS_CUTOFF, + switch_dist=10.0, + cutoff_dist=12.0, + pairlist_dist=15.0, + + numberOfThreads=NUMBER_OF_CPU, + numberOfMpi=1, + ) + protGenesisMin.setObjLabel('Energy Minimization CAGO') + # Launch minimisation + self.launchProtocol(protGenesisMin) + + # ------------------------- NMA prot -------------------------------- + # Launch NMA for energy min PDB + protNMA = self.newProtocol(FlexProtNMA, + cutoffMode=NMA_CUTOFF_ABS) + protNMA.inputStructure.set(protGenesisMin.outputPDB) + protNMA.setObjLabel('NMA') + self.launchProtocol(protNMA) + + # ------------------------- synth volumes -------------------------------- + target_subtomo = self.newProtocol(FlexProtSynthesizeSubtomo, + inputModes=protNMA.outputModes, + numberOfVolumes=10, + samplingRate=2.0, + modesAmplitudeRange=50, + seedOption=False, + noiseCTFChoice=1, + volumeSize=64, + rotationShiftChoice=1) + target_subtomo.setObjLabel('Subtomograms') + self.launchProtocol(target_subtomo) + + # ------------------------- MDTOMO -------------------------------- + protMDTOMO = self.newProtocol(FlexProtMDTOMO, + + inputType=INPUT_RESTART, + restartProt=protGenesisMin, + simulationType=SIMULATION_NMMD, + time_step=0.001, + n_steps=5000, + nm_number=6, + nm_mass=1.0, + inputModes=protNMA.outputModes, + temperature=50.0, + EMfitChoice=EMFIT_VOLUMES, + constantK="500", + inputVolume=target_subtomo.outputVolumes, + voxel_size=2.0, + centerOrigin=True, + numberOfThreads=1, + numberOfMpi=NUMBER_OF_CPU, + ) + protMDTOMO.setObjLabel('MDTOMO') + + # Launch Fitting + self.launchProtocol(protMDTOMO) + + # ------------------------- align pdbs -------------------------------- + alignPDBs = self.newProtocol(FlexProtAlignPdb, + pdbSource = PDB_SOURCE_OBJECT, + setOfPDBs = protMDTOMO.outputPDBs, + alignRefPDB=protGenesisMin.outputPDB, + createOutput=False) + alignPDBs.setObjLabel('Align output PDBs') + self.launchProtocol(alignPDBs) + + # ------------------------- PCA -------------------------------- + protPca = self.newProtocol(FlexProtDimredPdb, + pdbSource=PDB_SOURCE_ALIGNED, + alignPdbProt=alignPDBs, + method=REDUCE_METHOD_PCA, + reducedDim=3 + ) + protPca.setObjLabel('PCA') + self.launchProtocol(protPca) + # ------------------------- UMAP -------------------------------- + protUmap = self.newProtocol(FlexProtDimredPdb, + pdbSource=PDB_SOURCE_ALIGNED, + alignPdbProt=alignPDBs, + method=REDUCE_METHOD_UMAP, + reducedDim=3) + protUmap.setObjLabel('UMAP') + self.launchProtocol(protUmap) \ No newline at end of file diff --git a/continuousflex/tests/test_workflow_StA.py b/continuousflex/tests/test_workflow_StA.py index f48a713..7bfa8ce 100644 --- a/continuousflex/tests/test_workflow_StA.py +++ b/continuousflex/tests/test_workflow_StA.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Author: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Author: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * IMPMC, UPMC, Sorbonne University # * # * This program is free software; you can redistribute it and/or modify @@ -20,25 +20,26 @@ # * All comments concerning this program package may be sent to the # * e-mail address 'scipion@cnb.csic.es' # ************************************************************************** + from pwem.protocols import ProtImportPdb from pwem.tests.workflows import TestWorkflow from pyworkflow.tests import setupTestProject, DataSet - from continuousflex.protocols import (FlexProtNMA, FlexProtSynthesizeSubtomo, NMA_CUTOFF_ABS) -from continuousflex.protocols.protocol_subtomogrmas_synthesize import MODE_RELATION_LINEAR +from continuousflex.protocols.protocol_subtomograms_synthesize import MODE_RELATION_LINEAR from continuousflex.protocols.protocol_subtomograms_classify import FlexProtSubtomoClassify from continuousflex.protocols.protocol_subtomogram_averaging import FlexProtSubtomogramAveraging from xmipp3.protocols import XmippProtCreateMask3D -from continuousflex.protocols.protocol_subtomogram_refine_alignment import FlexProtRefineSubtomoAlign +from continuousflex.protocols.protocol_tomoflow_refine_alignment import FlexProtRefineSubtomoAlign + class TestStA(TestWorkflow): - """ Check the full StA protocol """ + """ tes for StA protocol """ @classmethod def setUpClass(cls): # Create a new project setupTestProject(cls) - cls.ds = DataSet.getDataSet('nma') + cls.ds = DataSet.getDataSet('nma_V2.0') def test_StA(self): """ Run NMA then synthesize sybtomograms""" diff --git a/continuousflex/tests/test_workflow_TomoFlow.py b/continuousflex/tests/test_workflow_TomoFlow.py index 833b124..fba31e4 100644 --- a/continuousflex/tests/test_workflow_TomoFlow.py +++ b/continuousflex/tests/test_workflow_TomoFlow.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Author: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Author: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * IMPMC, UPMC, Sorbonne University # * # * This program is free software; you can redistribute it and/or modify @@ -20,29 +20,30 @@ # * All comments concerning this program package may be sent to the # * e-mail address 'scipion@cnb.csic.es' # ************************************************************************** + from pwem.protocols import ProtImportPdb from pwem.tests.workflows import TestWorkflow from pyworkflow.tests import setupTestProject, DataSet - from continuousflex.protocols import (FlexProtNMA, FlexProtSynthesizeSubtomo, NMA_CUTOFF_ABS) -from continuousflex.protocols.protocol_subtomogrmas_synthesize import MODE_RELATION_3CLUSTERS, MODE_RELATION_PARABOLA +from continuousflex.protocols.protocol_subtomograms_synthesize import MODE_RELATION_3CLUSTERS, MODE_RELATION_PARABOLA from continuousflex.protocols.protocol_pdb_dimred import FlexProtDimredPdb from continuousflex.protocols.protocol_subtomogram_averaging import FlexProtSubtomogramAveraging, IMPORT_XMIPP_MD, COPY_STA -from continuousflex.protocols.protocol_heteroflow import FlexProtHeteroFlow -from continuousflex.protocols.protocol_heteroflow_dimred import FlexProtDimredHeteroFlow -from continuousflex.protocols.protocol_subtomogram_refine_alignment import FlexProtRefineSubtomoAlign +from continuousflex.protocols.protocol_tomoflow import FlexProtHeteroFlow +from continuousflex.protocols.protocol_tomoflow_dimred import FlexProtDimredHeteroFlow +from continuousflex.protocols.protocol_tomoflow_refine_alignment import FlexProtRefineSubtomoAlign from xmipp3.protocols import XmippProtCreateMask3D + class TestTomoFlow(TestWorkflow): - """ Check subtomograms are generated propoerly """ + """ TomoFlow pipeline test """ @classmethod def setUpClass(cls): # Create a new project setupTestProject(cls) - cls.ds = DataSet.getDataSet('nma') + cls.ds = DataSet.getDataSet('nma_V2.0') - def test_synthesize_all(self): + def test_all(self): """ Run NMA then synthesize sybtomograms""" # ------------------------------------------------ diff --git a/continuousflex/tests/test_workflow_subtomogram_synthesize.py b/continuousflex/tests/test_workflow_subtomogram_synthesize.py index b82a09f..90f125e 100644 --- a/continuousflex/tests/test_workflow_subtomogram_synthesize.py +++ b/continuousflex/tests/test_workflow_subtomogram_synthesize.py @@ -1,7 +1,7 @@ # ************************************************************************** # * -# * Authors: P. Conesa (pconesa@cnb.csic.es) [1] -# * J.M. De la Rosa Trevin (delarosatrevin@scilifelab.se) [2] +# * Author: Mohamad Harastani (mohamad.harastani@igbmc.fr) +# * IMPMC, UPMC, Sorbonne University # * # * [1] Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC # * [2] SciLifeLab, Stockholm University @@ -25,33 +25,28 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** -from pwem.protocols import ProtImportPdb, ProtImportParticles, ProtImportVolumes + +from pwem.protocols import ProtImportPdb from pwem.tests.workflows import TestWorkflow -from pwem import Domain from pyworkflow.tests import setupTestProject, DataSet - from continuousflex.protocols import (FlexProtNMA, FlexProtSynthesizeSubtomo,NMA_CUTOFF_ABS) -from continuousflex.protocols.protocol_subtomogrmas_synthesize import MODE_RELATION_LINEAR, MODE_RELATION_3CLUSTERS,\ - MODE_RELATION_MESH, MODE_RELATION_RANDOM +from continuousflex.protocols.protocol_subtomograms_synthesize import MODE_RELATION_MESH from continuousflex.protocols.protocol_pdb_dimred import FlexProtDimredPdb from continuousflex.protocols.protocol_subtomograms_classify import FlexProtSubtomoClassify + class TestSubtomogramSynthesize(TestWorkflow): - """ Check subtomograms are generated propoerly """ + """ subtomogram synthesize test """ @classmethod def setUpClass(cls): # Create a new project setupTestProject(cls) - cls.ds = DataSet.getDataSet('nma') + cls.ds = DataSet.getDataSet('nma_V2.0') def test_synthesize_all(self): """ Run NMA then synthesize sybtomograms""" - #------------------------------------------------ - # Import a Pdb -> NMA - #------------------------------------------------ - # Import a PDB protImportPdb = self.newProtocol(ProtImportPdb, inputPdbData=1, pdbFile=self.ds.getFile('pdb')) @@ -64,61 +59,7 @@ def test_synthesize_all(self): protNMA.inputStructure.set(protImportPdb.outputPdb) protNMA.setObjLabel('NMA') self.launchProtocol(protNMA) - #------------------------------------------------------------------------------------ - # Synthesize subtomograms with linear relationship - protSynthesize1 = self.newProtocol(FlexProtSynthesizeSubtomo, - modeList='7-8', - modeRelationChoice=MODE_RELATION_LINEAR) - protSynthesize1.inputModes.set(protNMA.outputModes) - protSynthesize1.setObjLabel('synthesized linear') - self.launchProtocol(protSynthesize1) - - protpdbdimred1 = self.newProtocol(FlexProtDimredPdb, - reducedDim=3) - protpdbdimred1.pdbs.set(protSynthesize1) - protpdbdimred1.setObjLabel('pdb dimred') - self.launchProtocol(protpdbdimred1) - protclassifyhierarchical1= self.newProtocol(FlexProtSubtomoClassify, - numOfClasses=3) - protclassifyhierarchical1.ProtSynthesize.set(protSynthesize1) - protclassifyhierarchical1.setObjLabel('hierarchical') - self.launchProtocol(protclassifyhierarchical1) - protclassifyKmeans1 = self.newProtocol(FlexProtSubtomoClassify, - numOfClasses=3, - classifyTechnique=1, - reducedDim=3) - protclassifyKmeans1.ProtSynthesize.set(protSynthesize1) - protclassifyKmeans1.setObjLabel('Kmeans') - self.launchProtocol(protclassifyKmeans1) - # ------------------------------------------------------------------------------------ - # Synthesize subtomograms with clusters relationship - protSynthesize2 = self.newProtocol(FlexProtSynthesizeSubtomo, - modeList='7-8', - modeRelationChoice=MODE_RELATION_3CLUSTERS) - protSynthesize2.inputModes.set(protNMA.outputModes) - protSynthesize2.setObjLabel('synthesized 3 clusters') - self.launchProtocol(protSynthesize2) - - protpdbdimred2 = self.newProtocol(FlexProtDimredPdb, - reducedDim=3) - protpdbdimred2.pdbs.set(protSynthesize2) - protpdbdimred2.setObjLabel('pdb dimred') - self.launchProtocol(protpdbdimred2) - - protclassifyhierarchical2= self.newProtocol(FlexProtSubtomoClassify, - numOfClasses=3) - protclassifyhierarchical2.ProtSynthesize.set(protSynthesize2) - protclassifyhierarchical2.setObjLabel('hierarchical') - self.launchProtocol(protclassifyhierarchical2) - protclassifyKmeans2 = self.newProtocol(FlexProtSubtomoClassify, - numOfClasses=3, - classifyTechnique=1, - reducedDim=3) - protclassifyKmeans2.ProtSynthesize.set(protSynthesize2) - protclassifyKmeans2.setObjLabel('Kmeans') - self.launchProtocol(protclassifyKmeans2) - # ------------------------------------------------------------------------------------ # Synthesize subtomograms with Mesh relationship protSynthesize3 = self.newProtocol(FlexProtSynthesizeSubtomo, modeList='7-8', @@ -145,32 +86,5 @@ def test_synthesize_all(self): protclassifyKmeans3.ProtSynthesize.set(protSynthesize3) protclassifyKmeans3.setObjLabel('Kmeans') self.launchProtocol(protclassifyKmeans3) - # ------------------------------------------------------------------------------------ - # Synthesize subtomograms with random relationship - protSynthesize4 = self.newProtocol(FlexProtSynthesizeSubtomo, - modeList='7-8', - modeRelationChoice=MODE_RELATION_RANDOM) - protSynthesize4.inputModes.set(protNMA.outputModes) - protSynthesize4.setObjLabel('synthesized random') - self.launchProtocol(protSynthesize4) - - protpdbdimred4 = self.newProtocol(FlexProtDimredPdb, - reducedDim=3) - protpdbdimred4.pdbs.set(protSynthesize4) - protpdbdimred4.setObjLabel('pdb dimred') - self.launchProtocol(protpdbdimred4) - - protclassifyhierarchical4= self.newProtocol(FlexProtSubtomoClassify, - numOfClasses=3) - protclassifyhierarchical4.ProtSynthesize.set(protSynthesize4) - protclassifyhierarchical4.setObjLabel('hierarchical') - self.launchProtocol(protclassifyhierarchical4) - protclassifyKmeans4 = self.newProtocol(FlexProtSubtomoClassify, - numOfClasses=3, - classifyTechnique=1, - reducedDim=3) - protclassifyKmeans4.ProtSynthesize.set(protSynthesize4) - protclassifyKmeans4.setObjLabel('Kmeans') - self.launchProtocol(protclassifyKmeans4) \ No newline at end of file diff --git a/continuousflex/tests/test_workflow_utilities.py b/continuousflex/tests/test_workflow_utilities.py new file mode 100644 index 0000000..8cda6e9 --- /dev/null +++ b/continuousflex/tests/test_workflow_utilities.py @@ -0,0 +1,71 @@ +# ************************************************************************** +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) +# * IMPMC, Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +from pwem.protocols import ProtImportPdb +from pwem.tests.workflows import TestWorkflow +from pyworkflow.tests import setupTestProject, DataSet +from continuousflex.protocols import FlexProtSynthesizeSubtomo, FlexProtMissingWedgeRestoration, FlexProtVolumeDenoise + + +class BM4D_and_MWR(TestWorkflow): + """ Test protocol for BM4D and MWR. """ + @classmethod + def setUpClass(cls): + # Create a new project + setupTestProject(cls) + cls.ds = DataSet.getDataSet('nma_V2.0') + + def test_BM4D(self): + """ Synthesize subtomograms and run missing wedge restoration and Bm4D volume denoising. """ + # Import PDB + protImportPdb = self.newProtocol(ProtImportPdb, inputPdbData=1, + pdbFile=self.ds.getFile('pdb')) + protImportPdb.setObjLabel('AK.pdb') + self.launchProtocol(protImportPdb) + SNR = 0.1 + N = 2 + # Synthesize subtomograms + protSynthesize = self.newProtocol(FlexProtSynthesizeSubtomo, + confVar=0, + numberOfVolumes=N, + targetSNR=SNR, + volumeSize=32, + samplingRate=4.4, + ) + protSynthesize.refAtomic.set(protImportPdb.outputPdb) + protSynthesize.setObjLabel('subtomograms') + self.launchProtocol(protSynthesize) + + # Missing wedge restoration + protMWC = self.newProtocol(FlexProtMissingWedgeRestoration, + T=5, + ) + protMWC.inputVolumes.set(protSynthesize.outputVolumes) + protMWC.setObjLabel('missing wedge restoration') + self.launchProtocol(protMWC) + + # Volume denoising + protDenoise = self.newProtocol(FlexProtVolumeDenoise) + protDenoise.inputVolumes.set(protSynthesize.outputVolumes) + protDenoise.setObjLabel('Bm4D volume denoising') + self.launchProtocol(protDenoise) diff --git a/continuousflex/viewers/__init__.py b/continuousflex/viewers/__init__.py index 1e7723e..05d858e 100644 --- a/continuousflex/viewers/__init__.py +++ b/continuousflex/viewers/__init__.py @@ -27,10 +27,15 @@ from .viewer_nma_dimred import FlexDimredNMAViewer from .viewer_structure_mapping import FlexProtStructureMappingViewer from .viewer_subtomograms_synthesize import FlexProtSynthesizeSubtomoViewer -from .viewer_pdb_dimred import FlexProtPdbDimredViewer +from .viewer_pdb_dimred import FlexProtPdbDimredViewer, VolumeTrajectoryViewer from .viewer_subtomograms_classify import FlexProtSubtomoClassifyViewer from .viewer_nma_alignment_vol import FlexAlignmentNMAVolViewer from .viewer_nma_dimred_vol import FlexDimredNMAVolViewer from .viewer_image_synthesize import FlexProtSynthesizeImageViewer from .viewer_heteroflow_dimred import FlexDimredHeteroFlowViewer from .viewer_heteroflow import FlexHeteroFlowViewer +from .viewer_mdspace import FlexMDSPACEViewer +from .viewer_genesis import FlexGenesisViewer +from .viewer_deephemnma_train import FlexDeepHEMNMAViewer +from .viewer_deephemnma_infer import FlexDeepHEMNMAinferViewer +from .viewer_batch_pdb_cluster import FlexProtBatchPdbCluster diff --git a/continuousflex/viewers/nma_gui/__init__.py b/continuousflex/viewers/nma_gui/__init__.py index d2e56f5..eb44df4 100644 --- a/continuousflex/viewers/nma_gui/__init__.py +++ b/continuousflex/viewers/nma_gui/__init__.py @@ -26,7 +26,6 @@ from .matplotlib_point_selector import PointSelector from .matplotlib_point_path import PointPath - from .tk_clustering import ClusteringWindow from .tk_trajectories import TrajectoriesWindow diff --git a/continuousflex/viewers/nma_gui/matplotlib_point_path.py b/continuousflex/viewers/nma_gui/matplotlib_point_path.py index b69871f..51c8049 100644 --- a/continuousflex/viewers/nma_gui/matplotlib_point_path.py +++ b/continuousflex/viewers/nma_gui/matplotlib_point_path.py @@ -24,8 +24,8 @@ # * # ************************************************************************** -from math import sqrt from continuousflex.viewers.nma_plotter import plotArray2D_xy +import numpy as np STATE_NO_POINTS = 0 # no points have been selected, double-click will add first one STATE_DRAW_POINTS = 1 # still adding points, double-click will set the last one @@ -120,13 +120,8 @@ def onClick(self, event): self.setState(STATE_ADJUST_POINTS, notify=True) if self.drawing == STATE_ADJUST_POINTS and not doubleClick: # Points moving state - self.dragIndex = None - for i, point in enumerate(self.pathData): - x = point.getX() - y = point.getY() - if sqrt((ex - x) ** 2 + (ey - y) ** 2) < self.tolerance: - self.dragIndex = i - break + trajectory = np.array([[p.getX(),p.getY()] for p in self.pathData]) + self.dragIndex = np.argmin(np.linalg.norm(trajectory - np.array([ex,ey]), axis=1)) def getXYData(self): xs = self.pathData.getXData() diff --git a/continuousflex/viewers/nma_gui/tk_clustering.py b/continuousflex/viewers/nma_gui/tk_clustering.py index 516c7e4..84b028a 100644 --- a/continuousflex/viewers/nma_gui/tk_clustering.py +++ b/continuousflex/viewers/nma_gui/tk_clustering.py @@ -69,6 +69,7 @@ def __init__(self, **kwargs): # Alpha and S are the transparancy and the size of the points, respectively self._alpha = kwargs.get('alpha') self._s = kwargs.get('s') + self.deep = kwargs.get('deepHEMNMA') content = tk.Frame(self.root) self._createContent(content) @@ -227,14 +228,21 @@ def _onUpdateClick(self, e=None): self._updateSelectionLabel() # ax = self.plotter.createSubPlot("Click and drag to add points to the Cluster", # *baseList) - ax = self.plotter.plotArray2D("Click and drag to add points to the Cluster", + if self.deep: + ax = self.plotter.plotArray2D_xy("Click and drag to add points to the Cluster", + *baseList) + else: + ax = self.plotter.plotArray2D("Click and drag to add points to the Cluster", *baseList) self.ps = PointSelector(ax, self.data, callback=self._updateSelectionLabel, LimitL=self.LimitLow, LimitH=self.LimitHigh, alpha=self._alpha, s=self._s) elif dim == 3: del self.ps # Remove PointSelector self.data.ZIND = modeList[2] - self.plotter.plotArray3D("%s %s %s" % tuple(baseList), *baseList) + if self.deep: + self.plotter.plotArray3D_xyz("%s %s %s" % tuple(baseList), *baseList) + else: + self.plotter.plotArray3D("%s %s %s" % tuple(baseList), *baseList) if doShow: self.plotter.show() diff --git a/continuousflex/viewers/nma_gui/tk_trajectories.py b/continuousflex/viewers/nma_gui/tk_trajectories.py index f39cbe8..f02a137 100644 --- a/continuousflex/viewers/nma_gui/tk_trajectories.py +++ b/continuousflex/viewers/nma_gui/tk_trajectories.py @@ -26,11 +26,9 @@ from os.path import basename import tkinter as tk - import pyworkflow.gui as gui from pyworkflow.utils.properties import Icon from pyworkflow.gui.widgets import Button, HotButton - from continuousflex.protocols.data import Point, PathData from . import PointPath from continuousflex.viewers.nma_plotter import FlexNmaPlotter @@ -38,6 +36,7 @@ FIGURE_LIMIT_NONE = 0 FIGURE_LIMITS = 1 + class TrajectoriesWindow(gui.Window): """ This class creates a Window that will display some Point's contained in a Data object. @@ -66,6 +65,8 @@ def __init__(self, **kwargs): self.zlim_high = kwargs.get('zlim_high') self.s = kwargs.get('s') self.alpha = kwargs.get('alpha') + self.deep = kwargs.get('deepHEMNMA') + self.cbar_label = kwargs.get('cbar_label') self.plotter = None content = tk.Frame(self.root) @@ -211,24 +212,22 @@ def _onUpdateClick(self, e=None): title="Invalid input")] if self.plotter is None or self.plotter.isClosed(): - # self.plotter = FlexNmaPlotter(data=self.data) # Actually plot if self.limits_modes == FIGURE_LIMIT_NONE: self.plotter = FlexNmaPlotter(data=self.data, xlim_low=self.xlim_low, xlim_high=self.xlim_high, ylim_low=self.ylim_low, ylim_high=self.ylim_high, zlim_low=self.zlim_low, zlim_high=self.zlim_high, - alpha=self.alpha, s=self.s) + alpha=self.alpha, s=self.s, cbar_label=self.cbar_label) else: self.plotter = FlexNmaPlotter(data=self.data, LimitL=self.LimitLow, LimitH=self.LimitHigh, xlim_low=self.xlim_low, xlim_high=self.xlim_high, ylim_low=self.ylim_low, ylim_high=self.ylim_high, zlim_low=self.zlim_low, zlim_high=self.zlim_high, - alpha=self.alpha, s=self.s) + alpha=self.alpha, s=self.s, cbar_label=self.cbar_label) doShow = True - # self.plotter.useLastPlot = True else: self.plotter.clear() doShow = False @@ -247,18 +246,24 @@ def _onUpdateClick(self, e=None): if dim == 2: self._evalExpression() self._updateSelectionLabel() - # ax = self.plotter.createSubPlot("Click and drag to add points to the Cluster", - # *baseList) - ax = self.plotter.plotArray2D("Click and drag to add points to the Cluster", + + if self.deep: + ax = self.plotter.plotArray2D_xy("Click and drag to add points to the Cluster", + *baseList) + else: + ax = self.plotter.plotArray2D("Click and drag to add points to the Cluster", *baseList) + self.ps = PointPath(ax, self.data, self.pathData, - callback=self._checkNumberOfPoints, + callback=self._checkNumberOfPoints, maxPoints=self.numberOfPoints, LimitL = self.LimitLow, LimitH = self.LimitHigh, alpha=self.alpha.get(), s = self.s.get()) elif dim == 3: - # del self.ps # Remove PointSelector self.setDataIndex('ZIND', modeList[2]) - self.plotter.plotArray3D("%s %s %s" % tuple(baseList), *baseList) + if self.deep: + self.plotter.plotArray3D_xyz("%s %s %s" % tuple(baseList), *baseList) + else: + self.plotter.plotArray3D("%s %s %s" % tuple(baseList), *baseList) if doShow: self.plotter.show() diff --git a/continuousflex/viewers/nma_plotter.py b/continuousflex/viewers/nma_plotter.py index 65121de..9047ed8 100644 --- a/continuousflex/viewers/nma_plotter.py +++ b/continuousflex/viewers/nma_plotter.py @@ -2,7 +2,7 @@ # * # * Authors: J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es) # * Slavica Jonic (jonic@impmc.upmc.fr) -# * Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Mohamad Harastani (mohamad.harastani@igbmc.fr) # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -45,6 +45,7 @@ def __init__(self, **kwargs): self._zlimhigh = kwargs.get('zlim_high') # Alpha and S are the transparancy and the size of the points, respectively self._alpha = kwargs.get('alpha') + self._cbar_label = kwargs.get('cbar_label', "Error") self._s = kwargs.get('s') FlexPlotter.__init__(self, **kwargs) self.useLastPlot = False @@ -76,16 +77,16 @@ def plotArray2D(self, title, xlabel, ylabel): ax.set_xlim([self._xlimlow.get(), self._xlimhigh.get()]) if lowy: ax.set_ylim([self._ylimlow.get(), self._ylimhigh.get()]) - s = alpha = None + s = alpha= None try: s = self._s.get() alpha = self._alpha.get() except: pass if s and alpha: - plotArray2D(ax, self._data, self._limitlow, self._limitup, s, alpha) + plotArray2D(ax, self._data, self._limitlow, self._limitup, s, alpha, cbar_label=self._cbar_label) else: - plotArray2D(ax, self._data, self._limitlow, self._limitup) + plotArray2D(ax, self._data, self._limitlow, self._limitup, cbar_label=self._cbar_label) return ax def plotArray2D_xy(self, title, xlabel, ylabel): @@ -238,22 +239,42 @@ def plotArray3D_xyz(self, title, xlabel, ylabel, zlabel): #---------- Utility functions ----------------- -def plotArray2D(ax, data, vvmin=None, vvmax=None, s = None, alpha = None): +def plotArray2D(ax, data, vvmin=None, vvmax=None, s = None, alpha = None, cbar_label=None): xdata = data.getXData() ydata = data.getYData() weights = data.getWeights() + + #Limit the number of points to 100000 otherwise, it slow down too much + npoints = len(xdata) + maxpoints = 100000 + if npoints > maxpoints : + scale = npoints//maxpoints + xdata = np.array(xdata)[::scale] + ydata = np.array(ydata)[::scale] + weights = np.array(weights)[::scale] + if vvmin: cax = ax.scatter(xdata, ydata, c=weights, vmin=vvmin.get(), vmax=vvmax.get(), s=s, alpha=alpha) else: # cax = ax.scatter(xdata, ydata, weights) cax = ax.scatter(xdata, ydata, c=weights, s=s, alpha=alpha) cb = ax.figure.colorbar(cax) - cb.set_label('Error') + cb.set_label(cbar_label) def plotArray2D_xy(ax, data, vvmin=None, vvmax=None, s = None, alpha = None): xdata = data.getXData() ydata = data.getYData() weights = data.getWeights() + + #Limit the number of points to 100000 otherwise, it slow down too much + npoints = len(xdata) + maxpoints = 100000 + if npoints > maxpoints : + scale = npoints//maxpoints + xdata = np.array(xdata)[::scale] + ydata = np.array(ydata)[::scale] + weights = np.array(weights)[::scale] + if vvmin: cax = ax.scatter(xdata, ydata, c=weights, vmin=vvmin.get(), vmax=vvmax.get(), s=s, alpha=alpha) else: diff --git a/continuousflex/viewers/nma_vol_gui/PointPathVol.py b/continuousflex/viewers/nma_vol_gui/PointPathVol.py index bbf1d9a..e2d296b 100755 --- a/continuousflex/viewers/nma_vol_gui/PointPathVol.py +++ b/continuousflex/viewers/nma_vol_gui/PointPathVol.py @@ -1,6 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -24,10 +24,8 @@ # ************************************************************************** from math import sqrt -# from continuousflex.viewers.plotter_vol import plotArray2D from continuousflex.viewers.plotter_vol import plotArray2D_xy - STATE_NO_POINTS = 0 # no points have been selected, double-click will add first one STATE_DRAW_POINTS = 1 # still adding points, double-click will set the last one STATE_ADJUST_POINTS = 2 # no more points will be added, just adjust the current ones diff --git a/continuousflex/viewers/nma_vol_gui/PointSelectorVol.py b/continuousflex/viewers/nma_vol_gui/PointSelectorVol.py index 836ffe4..0354730 100755 --- a/continuousflex/viewers/nma_vol_gui/PointSelectorVol.py +++ b/continuousflex/viewers/nma_vol_gui/PointSelectorVol.py @@ -1,6 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -23,10 +23,10 @@ # * # ************************************************************************** -from continuousflex.viewers.plotter_vol import plotArray2D from continuousflex.viewers.plotter_vol import plotArray2D_xy from math import sqrt + class PointSelectorVol(): """ Graphical manager based on Matplotlib to handle mouse events of click, drag and release and mark some point @@ -138,5 +138,4 @@ def update(self, event, addSelected=False): self.callback() self.plot_selected.set_data(xs1, ys1) self.rectangle_selection.set_data(xs, ys) - self.ax.figure.canvas.draw() diff --git a/continuousflex/viewers/nma_vol_gui/__init__.py b/continuousflex/viewers/nma_vol_gui/__init__.py index 8d44e11..bd0dd18 100644 --- a/continuousflex/viewers/nma_vol_gui/__init__.py +++ b/continuousflex/viewers/nma_vol_gui/__init__.py @@ -1,6 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify diff --git a/continuousflex/viewers/nma_vol_gui/tk_clustering_vol.py b/continuousflex/viewers/nma_vol_gui/tk_clustering_vol.py index e50740d..dd139d3 100755 --- a/continuousflex/viewers/nma_vol_gui/tk_clustering_vol.py +++ b/continuousflex/viewers/nma_vol_gui/tk_clustering_vol.py @@ -1,6 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -25,10 +25,8 @@ from os.path import basename import tkinter as tk - import pyworkflow.gui as gui from pyworkflow.gui.widgets import Button, HotButton - from continuousflex.protocols.data import Point from . import PointSelectorVol from continuousflex.viewers.plotter_vol import FlexNmaVolPlotter @@ -36,6 +34,7 @@ FIGURE_LIMIT_NONE = 0 FIGURE_LIMITS = 1 + class ClusteringWindowVol(gui.Window): """ This class creates a Window that will display some Point's contained in a Data object. @@ -224,14 +223,11 @@ def _onUpdateClick(self, e=None): if dim == 2: self._evalExpression() self._updateSelectionLabel() - # ax = self.plotter.createSubPlot("Click and drag to add some points to the Cluster", - # *baseList) ax = self.plotter.plotArray2D("Click and drag to add some points to the Cluster", *baseList) self.ps = PointSelectorVol(ax, self.data, callback=self._updateSelectionLabel, LimitL=self.LimitLow, LimitH=self.LimitHigh, alpha=self._alpha, s=self._s) - # self.ps = PointSelectorVol(ax, self.data, callback=None) elif dim == 3: try: del self.ps # Remove PointSelector diff --git a/continuousflex/viewers/nma_vol_gui/tk_trajectories_vol.py b/continuousflex/viewers/nma_vol_gui/tk_trajectories_vol.py index 0a844f9..5502fb5 100755 --- a/continuousflex/viewers/nma_vol_gui/tk_trajectories_vol.py +++ b/continuousflex/viewers/nma_vol_gui/tk_trajectories_vol.py @@ -1,6 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -25,11 +25,9 @@ from os.path import basename import tkinter as tk - import pyworkflow.gui as gui from pyworkflow.utils.properties import Icon from pyworkflow.gui.widgets import Button, HotButton - from continuousflex.protocols.data import Point, PathData from . import PointPathVol from continuousflex.viewers.plotter_vol import FlexNmaVolPlotter @@ -37,6 +35,7 @@ FIGURE_LIMIT_NONE = 0 FIGURE_LIMITS = 1 + class TrajectoriesWindowVol(gui.Window): """ This class creates a Window that will display some Point's contained in a Data object. @@ -210,7 +209,6 @@ def _onUpdateClick(self, e=None): title="Invalid input")] if self.plotter is None or self.plotter.isClosed(): - # self.plotter = FlexNmaVolPlotter(data=self.data) # Actually plot if self.limits_modes == FIGURE_LIMIT_NONE: self.plotter = FlexNmaVolPlotter(data=self.data, @@ -226,7 +224,6 @@ def _onUpdateClick(self, e=None): zlim_low=self.zlim_low, zlim_high=self.zlim_high, alpha=self.alpha, s=self.s) doShow = True - # self.plotter.useLastPlot = True else: self.plotter.clear() doShow = False @@ -305,7 +302,6 @@ def _onUpdateClick(self, e=None): title="Invalid input")] if self.plotter is None or self.plotter.isClosed(): - # self.plotter = FlexNmaVolPlotter(data=self.data) # Actually plot if self.limits_modes == FIGURE_LIMIT_NONE: @@ -322,7 +318,6 @@ def _onUpdateClick(self, e=None): zlim_low=self.zlim_low, zlim_high=self.zlim_high, alpha = self.alpha, s = self.s) doShow = True - # self.plotter.useLastPlot = True else: self.plotter.clear() doShow = False diff --git a/continuousflex/viewers/plotter.py b/continuousflex/viewers/plotter.py index 121da6d..fda1bc3 100644 --- a/continuousflex/viewers/plotter.py +++ b/continuousflex/viewers/plotter.py @@ -23,9 +23,6 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** -""" -This module implement the classes to create plots on xmipp. -""" from pwem.viewers.plotter import EmPlotter diff --git a/continuousflex/viewers/plotter_vol.py b/continuousflex/viewers/plotter_vol.py index e8fb9e7..5db9255 100755 --- a/continuousflex/viewers/plotter_vol.py +++ b/continuousflex/viewers/plotter_vol.py @@ -1,6 +1,6 @@ # ************************************************************************** # * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -253,6 +253,11 @@ def plotArray2D(ax, data, vvmin=None, vvmax=None, s = None, alpha = None): cb = ax.figure.colorbar(cax) cb.set_label('1- Cross Correlation') +def plotDataSet2D(ax, data, vvmin=None, vvmax=None, s = None, alpha = None): + xdata = data.getXData() + ydata = data.getYData() + weights = data.getWeights() + cax = ax.scatter(xdata, ydata, c=np.ones(len(weights)) - weights, s=s, alpha=alpha) def plotArray2D_xy(ax, data, vvmin=None, vvmax=None, s = None, alpha = None): xdata = data.getXData() diff --git a/continuousflex/viewers/tk_dimred.py b/continuousflex/viewers/tk_dimred.py new file mode 100644 index 0000000..984427c --- /dev/null +++ b/continuousflex/viewers/tk_dimred.py @@ -0,0 +1,389 @@ +# ************************************************************************** +# * +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# * +# ************************************************************************** + +from continuousflex.viewers.nma_gui import TrajectoriesWindow, ClusteringWindow +import tkinter as tk +from pyworkflow.gui.widgets import Button, ComboBox, HotButton +from tkinter import Radiobutton +import numpy as np +import scipy as sp +from continuousflex.protocols.data import Point +from sklearn.cluster import KMeans + +TOOL_TRAJECTORY = 1 +TOOL_CLUSTERING = 2 + +ANIMATION_INV=0 +ANIMATION_AVG=1 + + +class PCAWindowDimred(TrajectoriesWindow, ClusteringWindow): + + def __init__(self, **kwargs): + TrajectoriesWindow.__init__(self, **kwargs) + self.saveClusterCallback = kwargs.get('saveClusterCallback', None) + self.saveCallback = kwargs.get('saveCallback', None) + self.numberOfPoints = kwargs.get('numberOfPoints', 10) + + self._alpha=self.alpha + self._s=self.s + self._clusterNumber = 0 + + self._onUpdateClick() + + def _createContent(self, content): + self._createModeBox(content) + self._createFigureBox(content) + self._createTrajectoriesBox(content) + self._createClusteringBox(content) + self._exportBox(content) + + def _createModeBox(self, content): + frame = tk.LabelFrame(content, text='Interactive mode', font=self.fontBold) + + selFrame = tk.Frame(frame) + self.selectTool = tk.IntVar() + r1 = Radiobutton(selFrame, text="Trajectory Mode", variable=self.selectTool, value=TOOL_TRAJECTORY, command=self._onUpdateClick) + r1.grid(row=0, column=0, padx=5) + r2 = Radiobutton(selFrame, text="Selection Mode", variable=self.selectTool, value=TOOL_CLUSTERING, command=self._onUpdateClick) + r2.grid(row=0, column=1, padx=5) + self.selectTool.set(TOOL_TRAJECTORY) + selFrame.grid(row=0, column=0) + frame.grid(row=0, column=0, sticky='new', padx=5, pady=(10, 5)) + + + def _createFigureBox(self, content): + frame = tk.LabelFrame(content, text='Figure', font=self.fontBold) + frame.columnconfigure(0, minsize=50) + frame.columnconfigure(1, weight=1) # , minsize=30) + # Create the 'Axes' label + self._addLabel(frame, 'Axes', 0, 0) + + # Create a listbox with x1, x2 ... + listbox = tk.Listbox(frame, height=5, + selectmode=tk.MULTIPLE, bg='white', exportselection=False) + for x in range(1, self.dim + 1): + listbox.insert(tk.END, 'x%d' % x) + listbox.grid(row=0, column=1, padx=5, pady=5, sticky='w') + listbox.selection_set(0,1) + self.listbox = listbox + + self.selectionVar = tk.StringVar() + self.expressionVar = tk.StringVar() + + # Buttons + buttonFrame = tk.Frame(frame) + buttonFrame.grid(row=1, column=1, sticky='sew', pady=(10, 5)) + buttonFrame.columnconfigure(0, weight=1) + resetBtn = Button(buttonFrame, text='Reset', command=self._onResetClick) + resetBtn.grid(row=0, column=0, sticky='ne', padx=(5, 0)) + updateBtn = HotButton(buttonFrame, text='Update Plot', imagePath='fa-refresh.png', + command=self._onUpdateClick) + updateBtn.grid(row=0, column=1, sticky='ne', padx=5) + + frame.grid(row=1, column=0, sticky='new', padx=5, pady=(10, 5)) + + def _onUpdateClick(self,e=None): + if self.selectTool.get() == TOOL_TRAJECTORY : + TrajectoriesWindow._onUpdateClick(self,e) + self.createClusterBtn.config(state=tk.DISABLED) + if (self.pathData.getSize() < self.numberOfPoints): + self.updateClusterBtn.config(state=tk.NORMAL) + self.eraseBtn.config(state=tk.DISABLED) + self.trajSimBtn.config(state=tk.NORMAL) + + + if self.selectTool.get() == TOOL_CLUSTERING: + ClusteringWindow._onUpdateClick(self, e) + self.createClusterBtn.config(state=tk.NORMAL) + self.updateClusterBtn.config(state=tk.DISABLED) + self.trajSimBtn.config(state=tk.DISABLED) + self.eraseBtn.config(state=tk.NORMAL) + + def _exportBox(self,content): + frame = tk.LabelFrame(content, text='Import/Export', font=self.fontBold) + + nameFrame = tk.Frame(frame) + nameFrame.grid(row=0, column=0, sticky='w', pady=(10, 5)) + + label = tk.Label(nameFrame, text="Name", font=self.fontBold) + label.grid(row=0, column=0, padx=5, pady=5, sticky='w') + self.clusterName = tk.StringVar() + clusterEntry = tk.Entry(nameFrame, textvariable=self.clusterName, + width=30, bg='white') + clusterEntry.grid(row=0, column=2, pady=5) + + + buttonFrame = tk.Frame(frame) + buttonFrame.grid(row=1, column=0, sticky='w', pady=(10, 5)) + + self.saveClusterBtn = Button(buttonFrame, text='Export clusters to Scipion', state=tk.NORMAL, + tooltip='export clusters to scipion', command=self._onSaveClusterClick) + self.saveClusterBtn.grid(row=0, column=2, padx=5) + + self.saveBtn = Button(buttonFrame, text='Save animation state', + tooltip='Save the trajectory', command=self._onSaveClick) + self.saveBtn.grid(row=0, column=3) + + self.loadBtn = Button(buttonFrame, text='Load animation state', imagePath='fa-folder-open.png', + tooltip='Load a previous PCA clustering', command=self._onLoadClick) + self.loadBtn.grid(row=0, column=4) + + frame.grid(row=4, column=0, sticky='new', padx=5, pady=(10, 5)) + + + + def _createClusteringBox(self, content): + frame = tk.LabelFrame(content, text='Clustering', font=self.fontBold) + frame.columnconfigure(0, minsize=50) + frame.columnconfigure(1, weight=1) + + + buttonsFrame = tk.Frame(frame) + buttonsFrame.grid(row=0, column=0, + sticky='new', padx=5, pady=5) + + label = tk.Label(buttonsFrame, text="From trajectory", font = self.fontItalic) + label.grid(row=0, column=0, padx=5, pady=5, sticky='w') + + self.updateClusterBtn = Button(buttonsFrame, text='Cluster from traj', state=tk.DISABLED, + tooltip='Create new cluster', + imagePath='fa-plus-circle.png', command=self._onUpdateCluster) + self.updateClusterBtn.grid(row=0, column=1, padx=5) + + + buttonsFrame = tk.Frame(frame) + buttonsFrame.grid(row=1, column=0, + sticky='new', padx=5, pady=5) + + label = tk.Label(buttonsFrame, text="From selection", font = self.fontItalic) + label.grid(row=0, column=0, padx=5, pady=5, sticky='w') + + self.createClusterBtn = Button(buttonsFrame, text='New cluster from sel', state=tk.DISABLED, + tooltip='New clutser from sel', + imagePath='fa-plus-circle.png', command=self._onCreateCluster) + self.createClusterBtn.grid(row=0, column=1, padx=5) + + self.eraseBtn = Button(buttonsFrame, text='Erase sel', tooltip='Erase selection', command=self._onErase) + self.eraseBtn.grid(row=0, column=2, padx=5) + + buttonsFrame = tk.Frame(frame) + buttonsFrame.grid(row=2, column=0, + sticky='new', padx=5, pady=5) + + label = tk.Label(buttonsFrame, text="K-means", font = self.fontItalic) + label.grid(row=0, column=0, padx=5, pady=5, sticky='w') + + kmeansCluster = Button(buttonsFrame, text='Compute clusters', state=tk.NORMAL, + tooltip='K means clustering', command=self._onKMeansCluster) + kmeansCluster.grid(row=0, column=1, padx=5) + + label = tk.Label(buttonsFrame, text="Number of clusters") + label.grid(row=0, column=2, padx=5, pady=5, sticky='w') + self.numPointsKmean = tk.StringVar(value="3") + clusterEntry = tk.Entry(buttonsFrame, textvariable=self.numPointsKmean , + width=3, bg='white') + clusterEntry.grid(row=0, column=3, pady=5) + + buttonsFrame2 = tk.Frame(frame) + buttonsFrame2.grid(row=3, column=0, sticky='w', pady=(10, 5)) + buttonsFrame2.columnconfigure(0, weight=1) + self.generateBtn = HotButton(buttonsFrame2, text='Show cluster average in VMD', state=tk.NORMAL, + tooltip='Average clusters and show it in VMD', + imagePath='fa-plus-circle.png', command=self._onClusterAverageClick) + self.generateBtn.grid(row=0, column=0, padx=5) + + + frame.grid(row=3, column=0, sticky='new', padx=5, pady=(10, 5)) + + def _createTrajectoriesBox(self, content): + frame = tk.LabelFrame(content, text='Trajectories', font=self.fontBold, highlightcolor="cyan") + buttonsFrame = tk.Frame(frame) + buttonsFrame.grid(row=0, column=0, + sticky='w', padx=5, pady=5) + + label = tk.Label(buttonsFrame, text="Number of points") + label.grid(row=0, column=0, padx=5, pady=5, sticky='w') + self.numberOfPointsVar = tk.StringVar(value=str(self.numberOfPoints)) + nPointsEntry = tk.Entry(buttonsFrame, textvariable=self.numberOfPointsVar , + width=3, bg='white') + nPointsEntry.grid(row=0, column=1, pady=5) + setNPointsBtn = Button(buttonsFrame, text='Set', state=tk.NORMAL, + tooltip='Set the number of points for the trajectory', command=self._onSetNPoints) + setNPointsBtn.grid(row=0, column=2, padx=5) + + + buttonsFrame2 = tk.Frame(frame) + buttonsFrame2.grid(row=1, column=0, + sticky='w', padx=5, pady=5) + buttonsFrame2.columnconfigure(0, weight=1) + self.trajSimBtn = Button(buttonsFrame2, text='Generate points', state=tk.NORMAL, + tooltip='Generate trajectory points based on axis and trajectory type', command=self._onSimClick) + self.trajSimBtn.grid(row=0, column=0, padx=5) + self.trajAxisBtn = ComboBox(buttonsFrame2, choices=["axis %i"%(i+1) for i in range(self.dim)]) + self.trajAxisBtn.grid(row=0, column=1, padx=(5, 10)) + self.trajTypeBtn = ComboBox(buttonsFrame2, choices=["percentiles", + "linear betmeen min and max", "Linear betmeen -2*std and +2*std" + , "Gaussian betmeen min and max", "Gaussian betmeen -2*std and +2*std"]) + self.trajTypeBtn.grid(row=0, column=2, padx=(5, 5)) + + buttonsFrame3 = tk.Frame(frame) + buttonsFrame3.grid(row=2, column=0, sticky='w', pady=(10, 5)) + # buttonsFrame3.columnconfigure(0, weight=1) + self.generateBtn = HotButton(buttonsFrame3, text='Show trajectory in VMD', state=tk.NORMAL, + tooltip='Select trajectory points to generate the animations', + imagePath='fa-plus-circle.png', command=self._onCreateClick) + self.generateBtn.grid(row=0, column=0, padx=5) + + frame.grid(row=2, column=0, sticky='new', padx=5, pady=5) + + def _onClusterAverageClick(self, e=None): + if self.callback: + self.callback(animtype=ANIMATION_AVG) + + + def _onCreateClick(self, e=None): + if self.callback: + self.callback(animtype=ANIMATION_INV) + + def _onSaveClusterClick(self, e=None): + if self.saveClusterCallback: + self.saveClusterCallback(self) + + def _onSaveClick(self, e=None): + if self.saveCallback: + self.saveCallback(self) + + def _onSetNPoints(self): + try : + self.numberOfPoints = int(self.numberOfPointsVar.get()) + except: + self.showError("Can not read number of points.") + + def _onKMeansCluster(self): + try : + n_clusters = int(self.numPointsKmean.get()) + except: + return self.showError("Can not read number of clusters") + self._onUpdateClick() + + k_means = KMeans(init='k-means++', n_clusters=n_clusters) + selection = np.array(self.listbox.curselection()) + data_arr = np.array([p.getData()[selection] for p in self.data]) + k_means.fit(data_arr) + + classes = k_means.labels_ + 1 + i=0 + for point in self.data: + point._weight = classes[i] + i+=1 + self._onUpdateClick() + self.setClusterNumber(3) + + def _onSimClick(self, e=None): + TrajectoriesWindow._onResetClick(self, e) + traj_axis = self.trajAxisBtn.getValue() + traj_type = self.trajTypeBtn.getValue() + + data_axis = np.array([p.getData()[traj_axis] for p in self.data]) + mean_axis =data_axis.mean() + std_axis =data_axis.std() + min_axis =data_axis.min() + max_axis =data_axis.max() + + traj_points = np.zeros((self.numberOfPoints, self.dim)) + if traj_type== 0 : + traj_points[:,traj_axis] = np.array( + [np.percentile(data_axis,100*(i+1)/(self.numberOfPoints+1)) for i in range(self.numberOfPoints)] + ) + elif traj_type== 1 : + traj_points[:,traj_axis] = np.linspace(min_axis,max_axis,self.numberOfPoints) + elif traj_type== 2: + traj_points[:,traj_axis] = np.linspace(-2*std_axis,+2*std_axis,self.numberOfPoints) + elif traj_type== 3: + distribution = sp.stats.norm(loc=mean_axis, scale=std_axis) + bounds_for_range = distribution.cdf([min_axis, max_axis]) + gaussTraj = distribution.ppf(np.linspace(*bounds_for_range, num=self.numberOfPoints)) + traj_points[:, traj_axis] = gaussTraj + elif traj_type== 4: + distribution = sp.stats.norm(loc=mean_axis, scale=std_axis) + bounds_for_range = distribution.cdf([-2*std_axis, +2*std_axis]) + gaussTraj = distribution.ppf(np.linspace(*bounds_for_range, num=self.numberOfPoints)) + traj_points[:, traj_axis] = gaussTraj + + for i in range(self.numberOfPoints): + self.pathData.addPoint(Point(pointId=i + 1, data=traj_points[i], weight=0)) + + self._checkNumberOfPoints() + self._onUpdateClick() + + def _onUpdateCluster(self): + traj_arr = np.array([p.getData() for p in self.pathData]) + selection = np.array(self.listbox.curselection()) + traj_sel = traj_arr[:, selection] + + for point in self.data: + point_sel = point.getData()[selection] + closet_point = np.argmin(np.linalg.norm(traj_sel - point_sel, axis=1)) + point._weight = closet_point + 1 + + self._onUpdateClick() + self.setClusterNumber(self.numberOfPoints) + + + def _onCreateCluster(self): + self.setClusterNumber(self.getClusterNumber() +1) + for point in self.data: + if point.getState() == Point.SELECTED: + point._weight =self.getClusterNumber() + ClusteringWindow._onResetClick(self) + + def setClusterNumber(self, n): + self._clusterNumber = n + + def _onErase(self): + for point in self.data: + if point.getState() == Point.SELECTED: + point._weight =0.0 + ClusteringWindow._onResetClick(self) + + def _checkNumberOfPoints(self): + TrajectoriesWindow._checkNumberOfPoints(self) + self.updateClusterBtn.config(state=tk.NORMAL) + + def _onResetClick(self, e=None): + self.updateClusterBtn.config(state=tk.DISABLED) + self.setClusterNumber(0) + + for point in self.data: + point._weight = 0 + TrajectoriesWindow._onResetClick(self, e) + self.generateBtn.config(state=tk.NORMAL) + + + def getClusterName(self): + return self.clusterName.get().strip() + + def getClusterNumber(self): + return self._clusterNumber \ No newline at end of file diff --git a/continuousflex/viewers/viewer_batch_pdb_cluster.py b/continuousflex/viewers/viewer_batch_pdb_cluster.py new file mode 100644 index 0000000..d2cf31e --- /dev/null +++ b/continuousflex/viewers/viewer_batch_pdb_cluster.py @@ -0,0 +1,144 @@ +# ************************************************************************** +# * Authors: Remi Vuillemot (remi.vuillemot@upmc.fr) +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +import numpy as np +from pyworkflow.protocol.params import StringParam, LabelParam, EnumParam, FloatParam, PointerParam, IntParam, BooleanParam +from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) +from pwem.viewers import ChimeraView +from continuousflex.protocols.protocol_batch_pdb_cluster import FlexBatchProtClusterSet +from pyworkflow.utils.path import cleanPath, makePath, makeTmpPath +import os + +class FlexProtBatchPdbCluster(ProtocolViewer): + """ Visualization of density and PDB clusters + """ + _label = 'viewer batch pdb cluster' + _targets = [FlexBatchProtClusterSet] + _environments = [DESKTOP_TKINTER, WEB_DJANGO] + + def _defineParams(self, form): + form.addSection(label='Visualization') + + form.addParam('displayChimera', LabelParam, + label="Display clusters in ChimeraX", + help="") + + form.addParam('nsteps', IntParam, default="5", + label="Number of steps between models", + help="") + form.addParam('loop', IntParam, default=4, + label="Number of loop of the movie", + help="") + + form.addParam('volumes', BooleanParam, default=True, + label="Show maps ?", + help="") + + form.addParam('gaussian', BooleanParam, default=True, + label="Apply gaussian filter ?", + help="", condition="volumes") + form.addParam('sdev', FloatParam, default=1.0, + label="gaussian sigma", + help="", condition="gaussian") + + form.addParam('models', BooleanParam, default=True, + label="Show models ?", + help="") + form.addParam('fitmap', BooleanParam, default=True, + label="Fit models into maps ?", + help="", condition="volumes and models") + + def _getVisualizeDict(self): + return { + 'displayChimera': self._displayChimera, + } + + def _displayChimera(self, param): + + script_file = self._getTmpPath("cluster_chimerax.cxc") + makePath(script_file) + cleanPath(script_file) + nstep = self.nsteps.get() + loop = self.loop.get() + sdev= self.sdev.get() + + pdb_set = self.protocol.inputPDBs.get() + vol_set = self.protocol.outputVols + with open(script_file, "w") as f : + f.write("light full\n") + f.write("set bgColor white\n") + f.write("graphics silhouettes true\n") + start_pdb = 1 + stop_pdb = 0 + + if self.models.get(): + for pdb in pdb_set : + f.write("open " + os.path.abspath(pdb.getFileName()) + "\n") + f.write("color bychain\n") + stop_pdb+=1 + # f.write("hide atoms\n") + # f.write("show cartoons\n") + f.write("style sphere\n") + n_pdbs = stop_pdb-start_pdb +1 + + start_vol = stop_pdb+1 + stop_vol = stop_pdb + if self.volumes.get(): + for vol in vol_set : + f.write("open " + os.path.abspath(vol.getFileName()) + "\n") + stop_vol+=1 + n_vols = stop_vol-start_vol +1 + + if self.gaussian.get() and self.volumes.get(): + for i in range(n_vols): + f.write("vop gaussian #%i sdev %f \n"%(start_vol+i, sdev)) + start_vol+=n_vols + stop_vol+=n_vols + + if self.volumes.get(): + f.write("volume voxelSize %f origin %i transparency 0.5 color lightgrey \n"%(vol_set.getSamplingRate(), -vol_set.getXDim()//2)) + + if (self.models.get() and self.volumes.get()) and self.fitmap.get(): + for i in range(n_pdbs): + f.write("fitmap #%i inMap #%i \n"%(start_pdb+i, start_vol+i)) + + + + if self.models.get(): + f.write("morph #%i-%i frames %i same true\n"%(start_pdb, stop_pdb, nstep)) + + if self.volumes.get(): + nframes = 1+((n_vols-1)*nstep) + f.write("volume morph #%i-%i playStep %f frames %i ; "%(start_vol, stop_vol, 1/(nframes-0.5), (2*nframes)*loop)) + if self.models.get(): + f.write("coordset #%i loop %i bounce true\n"%(stop_vol+1, loop)) + else: + f.write("\n") + + f.write("hide #%i-%i \n"%(start_pdb, stop_vol)) + + # f.write("hide atoms\n") + # f.write("show cartoons\n") + + cv = ChimeraView(script_file) + cv.show() diff --git a/continuousflex/viewers/viewer_deephemnma_infer.py b/continuousflex/viewers/viewer_deephemnma_infer.py new file mode 100755 index 0000000..e0c2220 --- /dev/null +++ b/continuousflex/viewers/viewer_deephemnma_infer.py @@ -0,0 +1,192 @@ +# ************************************************************************** +# * +# * Authors: Ilyes Hamitouche (ilyes.hamitouche@upmc.fr) +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# * +# ************************************************************************** + +from os.path import basename +from pwem.emlib import MetaData, MDL_ORDER +from pyworkflow.protocol.params import StringParam +from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) +from pyworkflow.protocol import params +from continuousflex.protocols.data import Point, Data +from continuousflex.viewers.nma_plotter import FlexNmaPlotter +from continuousflex.protocols import FlexProtDeepHEMNMAInfer + +FIGURE_LIMIT_NONE = 0 +FIGURE_LIMITS = 1 + +X_LIMITS_NONE = 0 +X_LIMITS = 1 +Y_LIMITS_NONE = 0 +Y_LIMITS = 1 +Z_LIMITS_NONE = 0 +Z_LIMITS = 1 + + +class FlexDeepHEMNMAinferViewer(ProtocolViewer): + """ Visualization of results from the deepHEMNMA inference protocol + """ + _label = 'viewer nma alignment' + _targets = [FlexProtDeepHEMNMAInfer] + _environments = [DESKTOP_TKINTER, WEB_DJANGO] + + def __init__(self, **kwargs): + ProtocolViewer.__init__(self, **kwargs) + self._data = None + + def getData(self): + if self._data is None: + self._data = self.loadData() + return self._data + + def _defineParams(self, form): + form.addSection(label='Visualization') + form.addParam('displayRawDeformation', StringParam, default='7 8', + label='Display the computed normal-mode amplitudes', + help='Type 7 to see the histogram of amplitudes along mode 7; \n' + 'type 8 to see the histogram of amplitudes along mode 8, etc.\n' + 'Type 7 8 to see the 2D plot of amplitudes along modes 7 and 8.\n' + 'Type 7 8 9 to see the 3D plot of amplitudes along modes 7, 8 and 9; etc.' + ) + form.addParam('limits_modes', params.EnumParam, + choices=['Automatic (Recommended)', 'Set manually Use upper and lower values'], + default=FIGURE_LIMIT_NONE, + label='Error limits', display=params.EnumParam.DISPLAY_COMBO, + help='If you want to use a range of Error in the color bar choose to set it manually.') + form.addParam('LimitLow', params.FloatParam, default=None, + condition='limits_modes==%d' % FIGURE_LIMITS, + label='Lower Error value', + help='The lower Error used in the graph') + form.addParam('LimitHigh', params.FloatParam, default=None, + condition='limits_modes==%d' % FIGURE_LIMITS, + label='Upper Error value', + help='The upper Error used in the graph') + form.addParam('xlimits_mode', params.EnumParam, + choices=['Automatic (Recommended)', 'Set manually x-axis limits'], + default=X_LIMITS_NONE, + label='x-axis limits', display=params.EnumParam.DISPLAY_COMBO, + help='This allows you to use a specific range of x-axis limits') + form.addParam('xlim_low', params.FloatParam, default=None, + condition='xlimits_mode==%d' % X_LIMITS, + label='Lower x-axis limit') + form.addParam('xlim_high', params.FloatParam, default=None, + condition='xlimits_mode==%d' % X_LIMITS, + label='Upper x-axis limit') + form.addParam('ylimits_mode', params.EnumParam, + choices=['Automatic (Recommended)', 'Set manually y-axis limits'], + default=Y_LIMITS_NONE, + label='y-axis limits', display=params.EnumParam.DISPLAY_COMBO, + help='This allows you to use a specific range of y-axis limits') + form.addParam('ylim_low', params.FloatParam, default=None, + condition='ylimits_mode==%d' % Y_LIMITS, + label='Lower y-axis limit') + form.addParam('ylim_high', params.FloatParam, default=None, + condition='ylimits_mode==%d' % Y_LIMITS, + label='Upper y-axis limit') + form.addParam('zlimits_mode', params.EnumParam, + choices=['Automatic (Recommended)', 'Set manually z-axis limits'], + default=Z_LIMITS_NONE, + label='z-axis limits', display=params.EnumParam.DISPLAY_COMBO, + help='This allows you to use a specific range of z-axis limits') + form.addParam('zlim_low', params.FloatParam, default=None, + condition='zlimits_mode==%d' % Z_LIMITS, + label='Lower z-axis limit') + form.addParam('zlim_high', params.FloatParam, default=None, + condition='zlimits_mode==%d' % Z_LIMITS, + label='Upper z-axis limit') + + def _getVisualizeDict(self): + return {'displayRawDeformation': self._viewRawDeformation, + } + + def _viewRawDeformation(self, paramName): + components = self.displayRawDeformation.get() + return self._doViewRawDeformation(components) + + def _doViewRawDeformation(self, components): + components = list(map(int, components.split())) + dim = len(components) + views = [] + + if dim > 0: + modeList = [] + modeNameList = [] + missingList = [] + + for modeNumber in components: + found = False + md = MetaData(self.protocol.trained_model.get().inputNMA.get()._getExtraPath('modes.xmd')) + for i, objId in enumerate(md): + modeId = md.getValue(MDL_ORDER, objId) + if modeNumber == modeId: + modeNameList.append('Mode %d' % modeNumber) + modeList.append(i) + found = True + break + if not found: + missingList.append(str(modeNumber)) + + if missingList: + return [self.errorMessage("Invalid mode(s) *%s*\n." % (', '.join(missingList)), + title="Invalid input")] + + # Actually plot + if self.limits_modes == FIGURE_LIMIT_NONE: + plotter = FlexNmaPlotter(data=self.getData(), + xlim_low=self.xlim_low, xlim_high=self.xlim_high, + ylim_low=self.ylim_low, ylim_high=self.ylim_high, + zlim_low=self.zlim_low, zlim_high=self.zlim_high) + else: + plotter = FlexNmaPlotter(data=self.getData(), + LimitL=self.LimitLow, LimitH=self.LimitHigh, + xlim_low=self.xlim_low, xlim_high=self.xlim_high, + ylim_low=self.ylim_low, ylim_high=self.ylim_high, + zlim_low=self.zlim_low, zlim_high=self.zlim_high) + baseList = [basename(n) for n in modeNameList] + + self.getData().XIND = modeList[0] + if dim == 1: + plotter.plotArray1D("Histogram of normal-mode amplitudes: %s" % baseList[0], + "Amplitude", "Number of images") + else: + self.getData().YIND = modeList[1] + if dim == 2: + plotter.plotArray2D_xy("Normal-mode amplitudes: %s vs %s" % tuple(baseList), *baseList) + elif dim == 3: + self.getData().ZIND = modeList[2] + plotter.plotArray3D_xyz("Normal-mode amplitudes: %s %s %s" % tuple(baseList), *baseList) + views.append(plotter) + + return views + + def loadData(self): + """ Iterate over the images and their deformations + to create a Data object with theirs Points. + """ + particles = self.protocol.outputParticles + data = Data() + for i, particle in enumerate(particles): + pointData = list(map(float, particle._xmipp_nmaDisplacements)) + data.addPoint(Point(pointId=particle.getObjId(), + data=pointData, + weight=0)) + return data \ No newline at end of file diff --git a/continuousflex/viewers/viewer_deephemnma_train.py b/continuousflex/viewers/viewer_deephemnma_train.py new file mode 100755 index 0000000..03f8098 --- /dev/null +++ b/continuousflex/viewers/viewer_deephemnma_train.py @@ -0,0 +1,60 @@ +# ************************************************************************** +# * Authors: Ilyes Hamitouche (ilyes.hamitouche@upmc.fr) +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# * +# ************************************************************************** + +from continuousflex.protocols.protocol_deep_hemnma_train import FlexProtDeepHEMNMATrain +from pyworkflow.protocol.params import LabelParam +from pyworkflow.viewer import ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO +from subprocess import check_call +import sys +from continuousflex import Plugin + + +class FlexDeepHEMNMAViewer(ProtocolViewer): + """ Visualization of results from the deepHEMNMA training protocol + """ + _label = 'viewer deepHEMNMA' + _targets = [FlexProtDeepHEMNMATrain] + _environments = [DESKTOP_TKINTER, WEB_DJANGO] + + def __init__(self, **kwargs): + ProtocolViewer.__init__(self, **kwargs) + self._data = None + + def _defineParams(self, form): + form.addSection(label='Visualization') + form.addParam('displaycurves', LabelParam, + label="Display training curves", + help="Display the training and validation losses") + + + def _getVisualizeDict(self): + return {'displaycurves': self._viewcurves} + + + def _viewcurves(self, pramName): + import webbrowser + logdir = self.protocol._getExtraPath('scalars/') + command = "tensorboard --port=6006 --logdir " + logdir +'&' + command = Plugin.getContinuousFlexCmd(command) + check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr, env=None, cwd=None) + webbrowser.open_new("http://localhost:6006/") diff --git a/continuousflex/viewers/viewer_genesis.py b/continuousflex/viewers/viewer_genesis.py new file mode 100644 index 0000000..3b002b4 --- /dev/null +++ b/continuousflex/viewers/viewer_genesis.py @@ -0,0 +1,461 @@ +# ************************************************************************** +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + +from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) +from continuousflex.protocols.protocol_genesis import * +from continuousflex.protocols.utilities.genesis_utilities import * +from .plotter import FlexPlotter +from pwem.viewers import VmdView, ChimeraView +from pyworkflow.utils import getListFromRangeString +import numpy as np +import os +import glob +from matplotlib.pyplot import cm + +COMPARE_PDB_INIT = 0 +COMPARE_PDB_OTHER = 1 + +class FlexGenesisViewer(ProtocolViewer): + """ Visualization of results from the GENESIS protocol + """ + _label = 'MD-NMMD-Genesis Viewer' + _targets = [FlexProtGenesis] + _environments = [DESKTOP_TKINTER, WEB_DJANGO] + + def _defineParams(self, form): + form.addSection(label='Visualization') + + if self.protocol.getNumberOfSimulation() >1: + form.addParam('fitRange', params.NumericRangeParam, + label="Simulation selection", + default="1-%i"%self.protocol.getNumberOfSimulation(), + important = True, + help=' Select the simulation to display. Examples:' + ' "1,3-5" -> [1,3,4,5]' + ' "1, 2, 4" -> [1,2,4]') + if self.protocol.simulationType.get() == SIMULATION_REMD\ + or self.protocol.simulationType.get() == SIMULATION_RENMMD: + form.addParam('replicaRange', params.NumericRangeParam, + label="Replica selection", + default="1-%i"%self.protocol.nreplica.get(), + help=' Select the replicas to display. Examples:' + ' "1,3-5" -> [1,3,4,5]' + ' "1, 2, 4" -> [1,2,4]') + + form.addParam("numberCurvePerPlot",params.IntParam,default = 10, + label="Number of curve per plot ", help="Defines the maximum number of curve" + " per plot before averaging into one curve",expertLevel=params.LEVEL_ADVANCED + ) + group = form.addGroup('Chimera 3D view') + group.addParam('displayChimera', params.LabelParam, + label='Display results in Chimera', + help='Show initial and final structures in Chimera') + + group = form.addGroup('VMD trajectory view') + group.addParam('displayTrajVMD', params.LabelParam, + label='Display trajecory in VMD', + help='TODO') + + group = form.addGroup('Energy Analysis') + group.addParam('displayEnergy', params.LabelParam, + label='Display Potential Energy', + help='Show time series of the potentials used in MD simulation/Minimization') + + group = form.addGroup('RMSD analysis') + group.addParam('compareToPDB', params.EnumParam, default=COMPARE_PDB_INIT, + label="Compare to ", choices=['initial PDB', 'another PDB'], + help='Perform RMSD between the trajectory and another PDB') + group.addParam('targetPDB', params.PathParam, default=None, + label="Target PDB (s)", important=True, + help=' Target PDBs to compute RMSD against. Atom mathcing is performed between ' + ' the output PDBs and the target PDBs. Use the file pattern as file location with /*.pdb', + condition= "compareToPDB==%i"%COMPARE_PDB_OTHER) + group.addParam('referencePDB', params.PathParam, default="", + label="Intial PDB (optional)", + help='Atom matching will replace the structural information of the output PDBs by the new PDB ', + expertLevel=params.LEVEL_ADVANCED,condition= "compareToPDB==%i"%COMPARE_PDB_OTHER) + + group.addParam('alignTarget', params.BooleanParam, default=False, + label="Align Target PDB", + help='Rigid body align (rotation +translation) the PDBs before RMSD analysis', + condition= "compareToPDB==%i"%COMPARE_PDB_OTHER) + + group.addParam('displayRMSDts', params.LabelParam, + label='Display RMSD time series') + + group.addParam('displayRMSD', params.LabelParam, + label='Display final RMSD') + + if self.protocol.simulationType.get() == SIMULATION_NMMD\ + or self.protocol.simulationType.get() == SIMULATION_RENMMD: + group = form.addGroup('NMMD') + group.addParam('displayNMMD', params.LabelParam, + label='Display normal modes time series', + help='Show normal mode amplitude time series during the simulation') + + if self.protocol.EMfitChoice.get() != EMFIT_NONE: + group = form.addGroup('Cryo EM fitting') + group.addParam('displayCC', params.LabelParam, + label='Display Correlation Coefficient', + help='Show C.C. time series during the simulation') + + def _getVisualizeDict(self): + return { + 'displayChimera': self._plotChimera, + 'displayEnergy': self._plotEnergy, + 'displayCC': self._plotCC, + 'displayNMMD': self._plotNMMD, + 'displayRMSDts': self._plotRMSDts, + 'displayRMSD': self._plotRMSD, + 'displayTrajVMD': self._plotTrajVMD, + } + + def _plotChimera(self, paramName): + tmpChimeraFile = self.protocol._getExtraPath("chimera.cxc") + index = self.getSimulationList()[0] + + with open(tmpChimeraFile, "w") as f: + f.write("open %s.pdb \n"% os.path.abspath(self.protocol.getInputPDBprefix(index))) + f.write("color #1 magenta \n" ) + count = 1 + + outpdbfile = self.getOutputPrefixAll(index)[0] +".pdb" + if os.path.exists(outpdbfile): + if os.path.getsize(outpdbfile) != 0: + f.write("open %s \n"% os.path.abspath(outpdbfile)) + count+=1 + f.write("color #%s lime \n"%count) + + if self.compareToPDB.get() == COMPARE_PDB_OTHER: + f.write("open %s \n" % os.path.abspath(self.getTargetPDB(index))) + count+=1 + f.write("color #%s orange \n"%count) + + if self.protocol.EMfitChoice.get() == EMFIT_VOLUMES: + f.write("open %s.mrc \n" % os.path.abspath(self.protocol.getInputEMprefix(index))) + count+=1 + f.write("volume #%i transparency 0.5\n"%count) + + f.write("hide atoms \n") + f.write("show cartoons \n") + f.write("lighting soft \n") + + cv = ChimeraView(tmpChimeraFile) + cv.show() + + def _plotTrajVMD(self, paramName): + tmpVmdFile = self.protocol._getExtraPath("vmd.tcl") + index = self.getSimulationList()[0] + with open(tmpVmdFile, "w") as f: + f.write("mol new %s.pdb waitfor all\n" % self.protocol.getInputPDBprefix(index)) + f.write("mol addfile %s.dcd waitfor all\n" % self.getOutputPrefixAll(index)[0]) + + if self.protocol.getForceField()== FORCEFIELD_CHARMM: + f.write("mol modstyle 0 0 NewCartoon \n") + else: + f.write("mol modstyle 0 0 Tube \n") + f.write("mol modcolor 0 0 Molecule\n") + + if self.protocol.EMfitChoice.get() == EMFIT_VOLUMES: + f.write("mol addfile %s.mrc waitfor all\n" % self.protocol.getInputEMprefix(index)) + f.write("mol addrep 0 \n") + f.write("mol modstyle 1 0 Isosurface 0.5 0 0 0 1 1 \n") + f.write("mol modmaterial 1 0 Transparent \n") + + if self.compareToPDB.get() == COMPARE_PDB_OTHER: + targetFile = self.getTargetPDB(index) + f.write("set nf [molinfo top get numframes]\n") + f.write("mol new %s waitfor all\n" %targetFile) + f.write( "for {set i 1 } {$i < $nf} {incr i} {\n") + f.write( "animate dup frame 0 1\n") + f.write("}\n") + if self.protocol.getForceField() == FORCEFIELD_CHARMM: + f.write("mol modstyle 0 1 NewCartoon \n") + else: + f.write("mol modstyle 0 1 Tube \n") + f.write("mol modcolor 0 1 Molecule\n") + f.write("animate style Loop\n") + f.write("display projection Orthographic\n") + + vmdviewer = VmdView(" -e " + tmpVmdFile) + vmdviewer.show() + + def _plotEnergy(self, paramName): + self._plotEnergyTotal() + self._plotEnergyDetail() + + def _plotEnergyTotal(self): + ene_default = ["TOTAL_ENE", "POTENTIAL_ENE", "KINETIC_ENE"] + + ene = {} + for i in self.getSimulationList(): + outputPrefix = self.getOutputPrefixAll(i) + for j in outputPrefix: + log_file = readLogFile(j + ".log") + for e in ene_default: + if e in log_file: + if e in ene : + ene[e].append(log_file[e]) + else: + ene[e] = [log_file[e]] + enelist =[] + labels=[] + for e in ene : + labels.append(e) + enelist.append(ene[e]) + + + self.genesisPlotter(title="Energy (kcal/mol)", data=enelist, ndata=len(enelist), + nrep=len(enelist[0]), labels=labels) + def _plotNMMD(self, paramName): + nm = {} + for i in self.getSimulationList(): + outputPrefix = self.getOutputPrefixAll(i) + for j in outputPrefix: + log_file = readLogFile(j + ".log") + for e in range(self.protocol.getNumberOfNormalModes()): + nm_name = "NM_AMP%s"%str(e+1).zfill(3) + if nm_name in log_file: + if nm_name in nm : + nm[nm_name].append(log_file[nm_name]) + else: + nm[nm_name] = [log_file[nm_name]] + nmlist =[] + labels=[] + for i in nm : + labels.append(i) + nmlist.append(nm[i]) + + self.genesisPlotter(title="Normal Mode Amplitude", data=nmlist, ndata=len(nmlist), + nrep=len(nmlist[0]), labels=labels) + def _plotEnergyDetail(self): + ene_default = ["BOND", "ANGLE", "UREY-BRADLEY", "DIHEDRAL", "IMPROPER", "CMAP", "VDWAALS", "ELECT", "NATIVE_CONTACT", + "NON-NATIVE_CONT", "RESTRAINT_TOTAL", "SOLVATION"] + + ene = {} + for i in self.getSimulationList(): + outputPrefix = self.getOutputPrefixAll(i) + for j in outputPrefix: + log_file = readLogFile(j+".log") + for e in ene_default: + if e in log_file: + if e in ene : + ene[e].append(log_file[e]) + else: + ene[e] = [log_file[e]] + enelist =[] + labels=[] + for e in ene : + labels.append(e) + enelist.append(ene[e]) + + self.genesisPlotter(title="Energy (kcal/mol)", data=enelist, ndata=len(enelist), + nrep=len(enelist[0]), labels=labels) + + def _plotCC(self, paramName): + # Get CC list + cc = [] + labels=[] + simlist = self.getSimulationList() + for i in simlist: + outputPrefix = self.getOutputPrefixAll(i) + cc_rep = [] + if len(simlist) == 1: + labels.append("CC") + else: + labels.append("CC %s" % str(i + 1)) + for j in outputPrefix: + log_file = readLogFile(j + ".log") + if 'RESTR_CVS001' in log_file: + cc_rep.append(log_file['RESTR_CVS001']) + else: + raise RuntimeError("CC not present in the log file") + cc.append(cc_rep) + + self.genesisPlotter(title="CC", data=cc, ndata=len(simlist), + nrep=len(self.getOutputPrefixAll()), labels=labels) + + + def genesisPlotter(self, title, data, ndata, nrep, labels): + plotter = FlexPlotter() + nmax = self.numberCurvePerPlot.get() + ax = plotter.createSubPlot(title, "", title) + colors = [cm.get_cmap("tab10", nmax)(i) for i in range(nmax) ] + + for i in range(ndata): + if ndata <= nmax and nrep > 1: + try: + meandata = np.mean(data[i], axis=0) + stddata = np.std(data[i], axis=0) + x = self.getTimePeriod(len(meandata)) + ax.errorbar(x=x, y=meandata, yerr=stddata, + capthick=1.7, capsize=5, elinewidth=1.7, color=colors[i] if ndata!= 1 else "black", + errorevery=np.max([len(meandata) // 10, 1]), label="%s Average" % labels[i]) + except TypeError: + x = self.getTimePeriod(len(data[i][0])) + ax.plot(x, data[i][0], color=colors[i], label=labels[i]) + + for j in range(nrep): + x = self.getTimePeriod(len(data[i][j])) + if 1 < nrep <= nmax: + if ndata == 1 : + ax.plot(x, data[i][j], color= colors[j], alpha=0.5, label="#%i"%(j+1)) + if nrep == 1 and ndata <= nmax: + ax.plot(x, data[i][j], color= colors[i],label=labels[i]) + if ndata > nmax : + try: + meandata = np.mean(data, axis=(0,1)) + stddata = np.std(data, axis=(0,1)) + x = self.getTimePeriod(len(meandata)) + ax.errorbar(x=x, y=meandata, yerr=stddata, + capthick=1.7, capsize=5, elinewidth=1.7, color="black", + errorevery=np.max([len(meandata) // 10, 1]), label="Global Average") + except TypeError: + x = self.getTimePeriod(len(data[0][0])) + ax.plot(x, data[0][0], color=colors[0], label=labels[0]) + xlabel = "Number of iterations" if self.protocol.simulationType.get() == SIMULATION_MIN else "Time (ps)" + ax.set_xlabel(xlabel) + plotter.legend() + plotter.show() + + def _plotRMSDts(self, paramName): + + # Get matching atoms + if self.referencePDB.get() != "": + ref_pdb = ContinuousFlexPDBHandler(self.referencePDB.get()) + else: + ref_pdb = ContinuousFlexPDBHandler(self.protocol.getInputPDBprefix()+".pdb") + if self.compareToPDB.get() == 1: + target_pdb = ContinuousFlexPDBHandler(self.getTargetPDB()) + idx_matchin_atoms = ref_pdb.matchPDBatoms(reference_pdb=target_pdb, ca_only=True) + else: + idx_matchin_atoms = None + + # Get RMSD list + rmsd = [] + labels=[] + simlist = self.getSimulationList() + for i in simlist: + outputPrefix = self.getOutputPrefixAll(i) + if len(simlist) == 1: + labels.append("RMSD") + else: + labels.append("RMSD %s"%str(i+1)) + rmsd_rep=[] + for outprf in outputPrefix: + rmsd_curr = [] + + inputPDB = ContinuousFlexPDBHandler(self.protocol.getInputPDBprefix(i)+".pdb") + if self.compareToPDB.get() == 1: + targetPDB = ContinuousFlexPDBHandler(self.getTargetPDB(i)) + else: + targetPDB = ref_pdb + rmsd_curr.append(inputPDB.getRMSD(reference_pdb=targetPDB, align=self.alignTarget.get(), idx_matching_atoms=idx_matchin_atoms)) + coord_arr = dcd2numpyArr(outprf + ".dcd") + for i in range(len(coord_arr)): + inputPDB.coords[:, :] = coord_arr[i] + rmsd_curr.append(inputPDB.getRMSD(reference_pdb=targetPDB, align=self.alignTarget.get(), idx_matching_atoms=idx_matchin_atoms)) + + rmsd_rep.append(rmsd_curr) + rmsd.append(rmsd_rep) + + self.genesisPlotter(title="RMSD ($\AA$)", data=rmsd, ndata=len(simlist), + nrep=len(self.getOutputPrefixAll()), labels=labels) + + + def _plotRMSD(self, paramName): + plotter = FlexPlotter() + ax = plotter.createSubPlot("RMSD ($\AA$)", "# Simulation", "RMSD ($\AA$)") + + # Get RMSD list + initial_mols = [] + final_mols = [] + target_mols = [] + for i in self.getSimulationList(): + inputPDB = self.protocol.getInputPDBprefix(i)+".pdb" + if self.compareToPDB.get() == 1: + targetPDB = self.getTargetPDB(i) + else: + targetPDB = inputPDB + outputPrefs = self.getOutputPrefixAll(i) + target_mols.append(ContinuousFlexPDBHandler(targetPDB)) + initial_mols.append(ContinuousFlexPDBHandler(inputPDB)) + for outputPrefix in outputPrefs: + outputPDB = outputPrefix +".pdb" + final_mols.append(ContinuousFlexPDBHandler(outputPDB)) + + if self.referencePDB.get() != "": + ref_mol = ContinuousFlexPDBHandler(self.referencePDB.get()) + else: + ref_mol = initial_mols[0] + if self.compareToPDB.get() == 1: + idx_match = ref_mol.matchPDBatoms(reference_pdb=target_mols[0],ca_only=True) + else: + idx_match = None + rmsdi=[] + rmsdf=[] + for i in range(len(self.getSimulationList())): + for j in range(len(outputPrefs)): + rmsdi.append(initial_mols[i].getRMSD(reference_pdb=target_mols[i], + idx_matching_atoms=idx_match, + align=self.alignTarget.get())) + rmsdf.append(final_mols[i*len(outputPrefs) + j].getRMSD(reference_pdb=target_mols[i], + idx_matching_atoms=idx_match, align=self.alignTarget.get())) + + ax.plot(rmsdf, "o", color="tab:blue", label="Final RMSD", markeredgecolor='black') + ax.plot(rmsdi, "o", color="tab:green", label="Initial RMSD", markeredgecolor='black') + plotter.legend() + plotter.show() + + def getSimulationList(self): + if self.protocol.getNumberOfSimulation() > 1: + return np.array(getListFromRangeString(self.fitRange.get())) -1 + else: + return np.array([0]) + + def getTargetPDB(self, index=0): + targetPDBlist = [f for f in glob.glob(self.targetPDB.get())] + targetPDBlist.sort() + if index < len(targetPDBlist): + return targetPDBlist[index] + else: + return targetPDBlist[0] + + def getOutputPrefixAll(self, index=0): + outPrf = np.array(self.protocol.getOutputPrefixAll(index)) + if self.protocol.simulationType.get() == SIMULATION_REMD \ + or self.protocol.simulationType.get() == SIMULATION_RENMMD: + return outPrf[np.array(getListFromRangeString(self.replicaRange.get())) - 1] + else: + return outPrf + + def getTimePeriod(self, length): + if self.protocol.simulationType.get() == SIMULATION_MIN: + timestep = 1.0 + else: + timestep = float(self.protocol.time_step.get()) + eneperiod = int(self.protocol.eneout_period.get()) + + return np.arange(length) * eneperiod * timestep + diff --git a/continuousflex/viewers/viewer_heteroflow.py b/continuousflex/viewers/viewer_heteroflow.py index 5c11cc2..d831cfa 100755 --- a/continuousflex/viewers/viewer_heteroflow.py +++ b/continuousflex/viewers/viewer_heteroflow.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -20,11 +20,8 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** -""" -This module implement the wrappers aroung Xmipp CL2D protocol -visualization program. -""" -from continuousflex.protocols.protocol_heteroflow import FlexProtHeteroFlow + +from continuousflex.protocols.protocol_tomoflow import FlexProtHeteroFlow from pwem.viewers import EmProtocolViewer from pyworkflow.protocol.params import LabelParam, IntParam, EnumParam, StringParam from pyworkflow.viewer import ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO @@ -147,6 +144,7 @@ def _viewFlow(self, paramName): def _viewFlow2(self, paramName): number = str(self.FlowNumber).zfill(6) + flow3D = self.read_optical_flow_by_number(number) op_path = self.protocol._getExtraPath() + '/optical_flows/' path_flowx = op_path + str(number).zfill(6) + '_opflowx.spi' path_flowy = op_path + str(number).zfill(6) + '_opflowy.spi' @@ -190,6 +188,16 @@ def _viewFlow2(self, paramName): flow2D = np.zeros([np.shape(px)[0], np.shape(px)[1], 2]) flow2D[:,:,0] = pn[0,:,:] flow2D[:,:,1] = pn[1,:,:] + + # We need to scale flow2D by the magnitude of flow3D + mag_3D = np.sqrt(flow3D[0, :, :, :] * flow3D[0, :, :, :] + + flow3D[1, :, :, :] * flow3D[1, :, :, :] + + flow3D[2, :, :, :] * flow3D[2, :, :, :]) + max_3D = np.max(mag_3D) + mag_2D = np.sqrt(flow2D[:, :, 0] * flow2D[:, :, 0] + + flow2D[:, :, 1] * flow2D[:, :, 1]) + max_2D = np.max(mag_2D) + flow2D = (max_3D/max_2D)*flow2D plot_quiver_2d(flow2D, title=title) pass diff --git a/continuousflex/viewers/viewer_heteroflow_dimred.py b/continuousflex/viewers/viewer_heteroflow_dimred.py index 4efb45d..f1b1807 100755 --- a/continuousflex/viewers/viewer_heteroflow_dimred.py +++ b/continuousflex/viewers/viewer_heteroflow_dimred.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -21,35 +21,30 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** -from continuousflex.protocols.data import PathData - -""" -This module implement the wrappers around Xmipp CL2D protocol -visualization program. -""" import os from os.path import basename, join, exists, isfile import numpy as np import pwem.emlib.metadata as md -from pyworkflow.utils.path import cleanPath, makePath, cleanPattern +from pyworkflow.utils.path import cleanPath, makePath from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) from pyworkflow.protocol.params import StringParam, LabelParam from pwem.objects import SetOfParticles from pyworkflow.gui.browser import FileBrowserWindow -from continuousflex.protocols.protocol_heteroflow_dimred import FlexProtDimredHeteroFlow +from continuousflex.protocols.protocol_tomoflow_dimred import FlexProtDimredHeteroFlow from continuousflex.protocols.data import Point, Data from .plotter_vol import FlexNmaVolPlotter from continuousflex.viewers.nma_vol_gui import ClusteringWindowVolHeteroFlow from continuousflex.viewers.nma_vol_gui import TrajectoriesWindowVolHeteroFlow from pwem.viewers.viewer_chimera import Chimera - from joblib import load, dump from continuousflex.protocols.utilities.spider_files3 import open_volume, save_volume -import farneback3d +import continuousflex +from continuousflex import Plugin +from subprocess import check_call +import sys import matplotlib.pyplot as plt from pwem.emlib.image import ImageHandler - from pyworkflow.protocol import params FIGURE_LIMIT_NONE = 0 @@ -66,7 +61,7 @@ class FlexDimredHeteroFlowViewer(ProtocolViewer): - """ Visualization of results from the NMA protocol + """ Visualization of results from TomoFlow Dimred protocol """ _label = 'viewer heteroflow dimred' _targets = [FlexProtDimredHeteroFlow] @@ -298,9 +293,9 @@ def _createCluster(self): partSet.write() partSet.close() - from continuousflex.protocols.protocol_batch_cluster_heteroflow import FlexBatchProtHeteroFlowCluster + from continuousflex.protocols.protocol_batch_cluster_tomoflow import FlexBatchProtTomoFlowCluster - newProt = project.newProtocol(FlexBatchProtHeteroFlowCluster) + newProt = project.newProtocol(FlexBatchProtTomoFlowCluster) clusterName = self.clusterWindow.getClusterName() if clusterName: newProt.setObjLabel(clusterName) @@ -310,38 +305,8 @@ def _createCluster(self): project.getRunsGraph() - - + #TODO def _loadAnimationData(self, obj): - # prot = self.protocol - # animationName = obj.getFileName() # assumes that obj.getFileName is the folder of animation - # animationPath = prot._getExtraPath(animationName) - # # animationName = animationPath.split('animation_')[-1] - # animationRoot = join(animationPath, animationName) - # - # animationSuffixes = ['.vmd', '.pdb', 'trajectory.txt'] - # for s in animationSuffixes: - # f = animationRoot + s - # if not exists(f): - # self.errorMessage('Animation file "%s" not found. ' % f) - # return - # - # # Load animation trajectory points - # trajectoryPoints = np.loadtxt(animationRoot + 'trajectory.txt') - # data = PathData(dim=trajectoryPoints.shape[1]) - # - # for i, row in enumerate(trajectoryPoints): - # data.addPoint(Point(pointId=i + 1, data=list(row), weight=1)) - # - # self.trajectoriesWindow.setPathData(data) - # self.trajectoriesWindow.setAnimationName(animationName) - # self.trajectoriesWindow._onUpdateClick() - # - # def _showVmd(): - # vmdFn = animationRoot + '.vmd' - # VmdView(' -e %s' % vmdFn).show() - # - # self.getTkRoot().after(500, _showVmd) pass def _loadAnimation(self): @@ -418,16 +383,26 @@ def _generateAnimation(self): bigmat_pinv = None # removing if from the memory fnref = self.protocol._getExtraPath('reference.spi') shape = np.shape(open_volume(fnref)) - + ref = open_volume(fnref) + # dumping the reference volume to use it in an outside script + # creating the directory Tmp since it is usually deleted after the execution of the protocol + if not exists(self.protocol._getTmpPath()): + os.mkdir(self.protocol._getTmpPath()) + ref_dump = self.protocol._getTmpPath('ref_dump.pkl') + dump(ref, ref_dump) for i, trash in enumerate(deformations): flowi = np.transpose(line[:, i]) flowi = np.reshape(flowi, [3, shape[0], shape[1], shape[2]]) pathi = animationRoot + str(i).zfill(3) + 'deformed_by_opflow.vol' - ref = open_volume(fnref) - ref = farneback3d.warp_by_flow(ref, np.float32(flowi)) - save_volume(ref, pathi) - # command = '-i ' + pathi + ' --select below 0.6 --substitute value 0' - # runJob(None,'xmipp_transform_threshold',command) + flow_dump = self.protocol._getTmpPath('flow_dump.pkl') + dump(np.float32(flowi), flow_dump) + args = " %s %s %s" % (ref_dump, flow_dump, pathi) + script_path = continuousflex.__path__[0] + '/protocols/utilities/optflow_warp.py' + command = "python " + script_path + args + command = Plugin.getContinuousFlexCmd(command) + check_call(command, shell=True, stdout=sys.stdout, stderr=sys.stderr, + env=None, cwd=None) + fn_cxc = self.protocol._getExtraPath('chimera_%s.cxc' % animation) # cxc_command = 'open ' + animationPath + '/*.vol vseries true\n' cxc_command = 'open animation_%s/*.vol vseries true\n' % animation @@ -489,4 +464,4 @@ def viewPcaSinglularValues(self, paramName): plt.stem(pca.singular_values_) plt.xticks(np.arange(0, len(pca.singular_values_), 1)) plt.show() - pass \ No newline at end of file + pass diff --git a/continuousflex/viewers/viewer_image_synthesize.py b/continuousflex/viewers/viewer_image_synthesize.py index 8ffd80a..4029582 100644 --- a/continuousflex/viewers/viewer_image_synthesize.py +++ b/continuousflex/viewers/viewer_image_synthesize.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Rémi Vuillemot (remi.vuillemot@upmc.fr) # * IMPMC, UPMC Sorbonne University # * @@ -22,18 +22,14 @@ # * e-mail address 'scipion@cnb.csic.es' # ************************************************************************** - from os.path import basename - from pwem.emlib import MetaData, MDL_ORDER from pyworkflow.protocol.params import StringParam, LabelParam from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) -from pyworkflow.utils import replaceBaseExt, replaceExt - +from pyworkflow.utils import replaceExt from continuousflex.protocols.data import Point, Data from continuousflex.viewers.nma_plotter import FlexNmaPlotter from continuousflex.protocols import FlexProtSynthesizeImages -import xmipp3 import pwem.emlib.metadata as md from pwem.viewers import ObjectView from continuousflex.protocols.protocol_image_synthesize import NMA_YES @@ -41,7 +37,7 @@ class FlexProtSynthesizeImageViewer(ProtocolViewer): - """ Visualization of results from synthesized images + """ Visualization of results from synthesized images protocol """ _label = 'viewer synthetic images' _targets = [FlexProtSynthesizeImages] @@ -169,12 +165,10 @@ def loadData(self): mdVolumes = md.MetaData(self.protocol._getExtraPath('GroundTruth.xmd')) data = Data() for objId in mdVolumes: - # pointData = list(map(float, particle._xmipp_nmaDisplacements)) pointData = list(mdVolumes.getValue(md.MDL_NMA,objId)) # inserting 6 zeros for the first 6 never used modes for j in range(6): pointData.insert(0, 0) - # print(pointData) data.addPoint(Point(pointId=objId, data=pointData, weight=0.0)) diff --git a/continuousflex/viewers/viewer_mdspace.py b/continuousflex/viewers/viewer_mdspace.py new file mode 100644 index 0000000..63622df --- /dev/null +++ b/continuousflex/viewers/viewer_mdspace.py @@ -0,0 +1,118 @@ +# ************************************************************************** +# * Authors: Rémi Vuillemot (remi.vuillemot@upmc.fr) +# * +# * IMPMC, UPMC Sorbonne University +# * +# * This program is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, write to the Free Software +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# * 02111-1307 USA +# * +# * All comments concerning this program package may be sent to the +# * e-mail address 'scipion@cnb.csic.es' +# ************************************************************************** + + +from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) +import pyworkflow.protocol.params as params +from continuousflex.protocols.protocol_mdspace import FlexProtMDSPACE +from continuousflex.viewers.viewer_genesis import FlexGenesisViewer +from continuousflex.protocols.utilities.genesis_utilities import * + +from .plotter import FlexPlotter +from pwem.viewers import VmdView, ChimeraView +from pyworkflow.utils import getListFromRangeString +import numpy as np +import os +import glob +import pwem.emlib.metadata as md +import re + +from matplotlib.pyplot import cm + +class FlexMDSPACEViewer(FlexGenesisViewer): + """ Visualization of results from the MDSPACE protocol + """ + _label = 'MDSPACE Viewer' + _targets = [FlexProtMDSPACE] + _environments = [DESKTOP_TKINTER, WEB_DJANGO] + + def _defineParams(self, form): + FlexGenesisViewer._defineParams(self, form) + group = form.addGroup('MDSPACE') + group.addParam('displayPCA', params.LabelParam, + label='Display PCA space') + group.addParam('pcaAxes', params.StringParam, default="1 2", + label='Axes to display' ) + group.addParam('displayFE', params.LabelParam, + label='Display free energy') + group.addParam('feAxes', params.StringParam, default="1 2", + label='Axes to display' ) + group.addParam('freeEnergySize', params.IntParam, default=20, + label='Sampling size' ) + def _getVisualizeDict(self): + dict = FlexGenesisViewer._getVisualizeDict(self) + dict['displayPCA'] = self._plotPCA + dict['displayFE'] = self._plotFE + return dict + + def _plotPCA(self, p): + axes_str = str.split(self.pcaAxes.get()) + axes = [] + for i in axes_str: axes.append(int(i.strip())-1) + + plotter = FlexPlotter(1,self.protocol.numberOfIter.get() + , figsize=(self.protocol.numberOfIter.get()*3,3)) + for i in range(self.protocol.numberOfIter.get()): + self.protocol._iter= i + pca = np.loadtxt(self.protocol.getPCAPrefix() + "_matrix.txt")[:,axes] + ax = plotter.createSubPlot("PCA iter "+str(i+1), "component " + axes_str[0], + "component " + axes_str[1], xpos=1, ypos=i+1) + ax.scatter(pca[:,0],pca[:,1]) + plotter.show() + def _plotFE(self, p): + axes_str = str.split(self.feAxes.get()) + axes = [] + for i in axes_str: axes.append(int(i.strip())-1) + size =self.freeEnergySize.get() + + plotter = FlexPlotter(1,self.protocol.numberOfIter.get() + , figsize=(self.protocol.numberOfIter.get()*3,3)) + for i in range(self.protocol.numberOfIter.get()): + self.protocol._iter= i + + data = np.loadtxt(self.protocol.getPCAPrefix() + "_matrix.txt")[:,axes] + xmin = np.min(data[:,0]) + xmax = np.max(data[:,0]) + ymin = np.min(data[:,1]) + ymax = np.max(data[:,1]) + x = np.linspace(xmin, xmax, size) + y = np.linspace(ymin, ymax, size) + count = np.zeros((size, size)) + for j in range(data.shape[0]): + count[np.argmin(np.abs(x.T - data[j, 0])), + np.argmin(np.abs(y.T - data[j, 1]))] += 1 + img = -np.log(count / count.max()) + img[img == np.inf] = img[img != np.inf].max() + + xx, yy = np.mgrid[xmin:xmax:size * 1j, ymin:ymax:size * 1j] + + ax = plotter.createSubPlot("Free energy iter "+str(i+1), "component " + axes_str[0], + "component " + axes_str[1], xpos=1, ypos=i+1) + im = ax.contourf(xx, yy, img, cmap='jet') + # im = ax.imshow(img.T[::-1, :], + # cmap="jet", interpolation="bicubic", + # extent=[xmin, xmax, ymin, ymax]) + cbar = plotter.figure.colorbar(im) + cbar.set_label("$\Delta G / k_{B}T$") + plotter.show() \ No newline at end of file diff --git a/continuousflex/viewers/viewer_nma.py b/continuousflex/viewers/viewer_nma.py index 4a0501f..3076835 100644 --- a/continuousflex/viewers/viewer_nma.py +++ b/continuousflex/viewers/viewer_nma.py @@ -22,19 +22,16 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** -""" -This module implement the wrappers around Xmipp NMA protocol -visualization program. -""" from pyworkflow.gui.project import ProjectWindow from pyworkflow.protocol.params import LabelParam, IntParam from pyworkflow.viewer import ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO -from pwem.viewers import ObjectView, VmdView +from pwem.viewers import VmdView, DataView from pwem.emlib import MDL_NMA_ATOMSHIFT +from pwem.objects import SetOfNormalModes from continuousflex.protocols import FlexProtNMA from continuousflex.viewers.nma_plotter import FlexNmaPlotter - +import os OBJCMD_NMA_PLOTDIST = "Plot distance profile" OBJCMD_NMA_VMD = "Display VMD animation" @@ -45,15 +42,20 @@ class FlexNMAViewer(ProtocolViewer): Normally, NMA modes with high collectivity and low NMA score are preferred. """ _label = 'viewer nma' - _targets = [FlexProtNMA] + _targets = [FlexProtNMA, SetOfNormalModes] _environments = [DESKTOP_TKINTER, WEB_DJANGO] -# def setProtocol(self, protocol): -# ProtocolViewer.setProtocol(self, protocol) -# inputPdb = protocol.inputStructure.get() -# self.isEm.set(inputPdb.getPseudoAtoms()) - + def _defineParams(self, form): + + if isinstance(self.protocol, SetOfNormalModes): + protocol_path = os.path.dirname(os.path.dirname(self.protocol[1].getModeFile())) + vmdFiles = protocol_path + "/extra/animations/" + nmdFile = protocol_path + "/modes.nmd" + else: + vmdFiles = self.protocol._getExtraPath("animations") + nmdFile = self.protocol._getPath("modes.nmd") + form.addSection(label='Visualization') form.addParam('displayModes', LabelParam, @@ -66,29 +68,48 @@ def _defineParams(self, form): group.addParam('modeNumber', IntParam, default=7, label='Mode number') group.addParam('displayVmd', LabelParam, + condition=os.path.isdir(vmdFiles), label='Display mode animation with VMD?') group.addParam('displayDistanceProfile', LabelParam, default=False, label="Plot mode distance profile?", help="Unitary shift of each atom or pseudoatom along the mode that is requested to be animated.") + + form.addParam('displayVmd2', LabelParam, + condition=os.path.isfile(nmdFile), + label="Display mode animations with VMD NMWiz?", + help="Use ProDy Normal Mode Wizard to view all modes in a more interactive way. " + "See http://prody.csb.pitt.edu/tutorials/nmwiz_tutorial/nmwiz.html") def _getVisualizeDict(self): return {'displayModes': self._viewParam, 'displayMaxDistanceProfile': self._viewParam, 'displayVmd': self._viewSingleMode, + 'displayVmd2': self._viewSingleMode, 'displayDistanceProfile': self._viewSingleMode, } def _viewParam(self, paramName): if paramName == 'displayModes': - modes = self.protocol.outputModes - return [ObjectView(self._project, modes.strId(), modes.getFileName())] + if isinstance(self.protocol, SetOfNormalModes): + modes = os.path.dirname(self.protocol[1].getModeFile()) + ".xmd" + else: + modes = self.protocol._getPath("modes.xmd") + return [DataView(modes)] + elif paramName == 'displayMaxDistanceProfile': - fn = self.protocol._getExtraPath("maxAtomShifts.xmd") + if isinstance(self.protocol, SetOfNormalModes): + fn = os.path.dirname(os.path.dirname(self.protocol[1].getModeFile())) + "/extra/maxAtomShifts.xmd" + else: + fn = self.protocol._getExtraPath("maxAtomShifts.xmd") return [createShiftPlot(fn, "Maximum atom shifts", "maximum shift")] def _viewSingleMode(self, paramName): """ visualization for a selected mode. """ - modes = self.protocol.outputModes + if isinstance(self.protocol, SetOfNormalModes): + modes = self.protocol + else: + modes = self.protocol.outputModes + modeNumber = self.modeNumber.get() mode = modes[modeNumber] @@ -97,8 +118,11 @@ def _viewSingleMode(self, paramName): "Display the output Normal Modes to see " "the availables ones." % modeNumber, title="Invalid input")] + elif paramName == 'displayVmd': return [createVmdView(self.protocol, modeNumber)] + elif paramName == 'displayVmd2': + return [createVmdNmwizView(self.protocol, modeNumber)] elif paramName == 'displayDistanceProfile': return [createDistanceProfilePlot(self.protocol, modeNumber)] @@ -111,18 +135,31 @@ def createShiftPlot(mdFn, title, ylabel): def createDistanceProfilePlot(protocol, modeNumber): - vectorMdFn = protocol._getExtraPath("distanceProfiles","vec%d.xmd" - % modeNumber) + if isinstance(protocol, SetOfNormalModes): + vectorMdFn = os.path.dirname(os.path.dirname(protocol[1].getModeFile( + ))) + "/extra/distanceProfiles/vec%d.xmd" % modeNumber + else: + vectorMdFn = protocol._getExtraPath("distanceProfiles","vec%d.xmd" + % modeNumber) plotter = createShiftPlot(vectorMdFn, "Atom shifts for mode %d" % modeNumber, "shift") return plotter def createVmdView(protocol, modeNumber): - vmdFile = protocol._getExtraPath("animations", "animated_mode_%03d.vmd" - % modeNumber) + if isinstance(protocol, SetOfNormalModes): + vmdFile = os.path.dirname(os.path.dirname(protocol[1].getModeFile())) + "/extra/animations/animated_mode_%03d.vmd" % modeNumber + else: + vmdFile = protocol._getExtraPath("animations", "animated_mode_%03d.vmd" + % modeNumber) return VmdView('-e "%s"' % vmdFile) +def createVmdNmwizView(protocol, modeNumber): + if isinstance(protocol, SetOfNormalModes): + nmdFile = os.path.dirname(os.path.dirname(protocol[1].getModeFile())) + "/modes.nmd" + else: + nmdFile = protocol._getPath("modes.nmd") + return VmdView('-e %s' % nmdFile) def showDistanceProfilePlot(protocol, modeNumber): createDistanceProfilePlot(protocol, modeNumber).show() diff --git a/continuousflex/viewers/viewer_nma_alignment.py b/continuousflex/viewers/viewer_nma_alignment.py index e6771b3..2532250 100644 --- a/continuousflex/viewers/viewer_nma_alignment.py +++ b/continuousflex/viewers/viewer_nma_alignment.py @@ -22,20 +22,21 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** -""" -This module implement the wrappers aroung Xmipp CL2D protocol -visualization program. -""" - from os.path import basename - -from pwem.emlib import MetaData, MDL_ORDER -from pyworkflow.protocol.params import StringParam +from pyworkflow.protocol.params import StringParam, LEVEL_ADVANCED from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) from pyworkflow.protocol import params from continuousflex.protocols.data import Point, Data from continuousflex.viewers.nma_plotter import FlexNmaPlotter from continuousflex.protocols import FlexProtAlignmentNMA +from pwem.emlib import MetaData, MDL_ORDER, MDL_ANGLE_ROT, MDL_ANGLE_TILT, MDL_ANGLE_PSI, MDL_SHIFT_X, MDL_SHIFT_Y, \ + MDL_SHIFT_Z, MDL_NMA +from continuousflex.protocols.convert import l2 +from xmippLib import SymList +import numpy as np +import tkinter.messagebox as mb +import matplotlib.pyplot as plt +from continuousflex.protocols.protocol_image_synthesize import FlexProtSynthesizeImages FIGURE_LIMIT_NONE = 0 FIGURE_LIMITS = 1 @@ -47,8 +48,11 @@ Z_LIMITS_NONE = 0 Z_LIMITS = 1 +METADATA_PROJECT = 0 +METADATA_FILE = 1 + class FlexAlignmentNMAViewer(ProtocolViewer): - """ Visualization of results from the NMA protocol + """ Visualization of results from the NMA alignment protocol (HEMNMA) """ _label = 'viewer nma alignment' _targets = [FlexProtAlignmentNMA] @@ -118,9 +122,29 @@ def _defineParams(self, form): form.addParam('zlim_high', params.FloatParam, default=None, condition='zlimits_mode==%d' % Z_LIMITS, label='Upper z-axis limit') + group = form.addGroup('Comparing with ground-truth', expertLevel=LEVEL_ADVANCED) + group.addParam('GroundTruth', params.EnumParam, + choices=['From volume synthesis protocol', 'From an external metadata file'], + default=METADATA_PROJECT, + label='Ground-Truth parameters', display=params.EnumParam.DISPLAY_COMBO, + help='Use this is only when testing the method with synthetic data') + group.addParam('SynthesisProject', params.PointerParam, pointerClass='FlexProtSynthesizeImages', + condition='GroundTruth==%d' % METADATA_PROJECT, + allowsNull=True, + label="Project for image synthesize", + help='Select a previous run for image synthesize.') + group.addParam('MetadataFile', params.FileParam, + pointerClass='params.FileParam', allowsNull=True, + condition='GroundTruth==%d' % METADATA_FILE, + label="Metadata file (xmd)", + help='Choose a metadata file containing angles, shifts and NM amplitudes, typically a metadata' + ' file from synthesizing volumes') + group.addParam('displayStatistics', params.LabelParam, + label="Display error statistics and plots?") def _getVisualizeDict(self): return {'displayRawDeformation': self._viewRawDeformation, + 'displayStatistics': self._viewErrorStatistics, } def _viewRawDeformation(self, paramName): @@ -183,6 +207,99 @@ def _doViewRawDeformation(self, components): return views + def _viewErrorStatistics(self, paramName): + if self.GroundTruth.get() == METADATA_PROJECT: + metadata_file = self.SynthesisProject.get()._getExtraPath('GroundTruth.xmd') + else: + metadata_file = self.MetadataFile.get() + return self._doViewErrorStatistics(metadata_file) + + def _doViewErrorStatistics(self, metadata_file): + md_gt = MetaData(metadata_file) + md_protocol = MetaData(self.protocol._getExtraPath('images.xmd')) + md_protocol.sort() + # Get the matching modes: + md_modes = MetaData(self.protocol._getExtraPath('modes.xmd')) + modeIds = [] + for i, objId in enumerate(md_modes): + modeIds.append(md_modes.getValue(MDL_ORDER, objId)) + # Get the parameters from both lists: + rtp_protocol = [] + xy_protocol = [] + mode_ampl_protocol = [] + rtp_gt = [] + xy_gt = [] + mode_ampl_gt = [] + for objId in md_protocol: + rtp_protocol.append([md_protocol.getValue(MDL_ANGLE_ROT, objId), + md_protocol.getValue(MDL_ANGLE_TILT, objId), + md_protocol.getValue(MDL_ANGLE_PSI, objId)]) + xy_protocol.append([md_protocol.getValue(MDL_SHIFT_X, objId), + md_protocol.getValue(MDL_SHIFT_Y, objId),]) + mode_ampl_protocol.append(md_protocol.getValue(MDL_NMA, objId)) + + rtp_gt.append([md_gt.getValue(MDL_ANGLE_ROT, objId), + md_gt.getValue(MDL_ANGLE_TILT, objId), + md_gt.getValue(MDL_ANGLE_PSI, objId)]) + xy_gt.append([md_gt.getValue(MDL_SHIFT_X, objId), + md_gt.getValue(MDL_SHIFT_Y, objId)]) + mode_ampl_gt.append(md_gt.getValue(MDL_NMA, objId)) + + # Angular and shift distances + shift_distance = [] + angular_distance = [] + # The full description of computeDistanceAngles function is: + # A = SymList.computeDistanceAngles(SymList(), rot1, tilt1, psi1, rot2, tilt2, psi2, projdir_mode, check_mirrors, object_rotation) + # By default, they are all set to False. However, check_mirrors should be true in general. + for i in range(len(rtp_protocol)): + shift_distance.append(l2(xy_gt[i], xy_protocol[i])) + angular_distance.append(SymList.computeDistanceAngles(SymList(), + rtp_protocol[i][0], rtp_protocol[i][1], rtp_protocol[i][2], + rtp_gt[i][0], rtp_gt[i][1], rtp_gt[i][2], + False, True, False)) + # Normal mode amplitudes distances: we need to find the subset of normal modes used in alignment in the groundtruth + counter = 0 + plt.figure() + mean_amplitudes = [] + std_amplitudes = [] + label = [] + dist = [] + for i in modeIds: + # mode 7 corresponds to zero in the ground truth, so we need to subtract 7 + A = np.array(mode_ampl_gt)[:,i - 7] + B = np.array(mode_ampl_protocol)[:, counter] + mean_amplitudes.append(np.mean(np.array(A - B))) + std_amplitudes.append(np.std(np.array(A - B))) + label.append('mode ' + str(i)) + dist.append(np.array(A - B)) + counter +=1 + plt.title('histogram of normal mode amplitude distances') + plt.hist(dist, bins=100, label=label) + plt.legend(loc='upper right') + + plt.figure() + plt.hist(np.array(angular_distance), bins=100) + plt.title('histogram of angular distance') + plt.figure() + plt.hist(np.array(shift_distance), bins=100) + plt.title('histogram of shift distance') + + message = 'mean and standard deviation angular distance: ' + str(np.mean(np.array(angular_distance)))[:7] + message += ' and ' + str(np.std(np.array(angular_distance)))[:7] + message += '\nmean and standard deviation shift distance: ' + str(np.mean(np.array(shift_distance)))[:7] + message += ' and ' + str(np.std(np.array(shift_distance)))[:7] + + counter = 0 + for i in modeIds: + message += '\nmean and standard deviation for mode ' + str(i) + ': ' + str(mean_amplitudes[counter])[:7] + \ + ' ' + str(std_amplitudes[counter])[:7] + counter +=1 + + mb.showinfo('Distances compared to the ground truth', message) + plt.show() + pass + + def loadData(self): """ Iterate over the images and their deformations to create a Data object with theirs Points. diff --git a/continuousflex/viewers/viewer_nma_alignment_vol.py b/continuousflex/viewers/viewer_nma_alignment_vol.py index 7b64cdf..c6f8c16 100755 --- a/continuousflex/viewers/viewer_nma_alignment_vol.py +++ b/continuousflex/viewers/viewer_nma_alignment_vol.py @@ -1,6 +1,5 @@ # ************************************************************************** -# * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -22,19 +21,22 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** -""" -This module implement the wrappers aroung Xmipp CL2D protocol -visualization program. -""" from os.path import basename from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) -from pyworkflow.protocol.params import StringParam +from pyworkflow.protocol.params import StringParam, LEVEL_ADVANCED from pyworkflow.protocol import params from continuousflex.protocols.protocol_nma_alignment_vol import FlexProtAlignmentNMAVol +from continuousflex.protocols.protocol_subtomograms_synthesize import FlexProtSynthesizeSubtomo from continuousflex.protocols.data import Point, Data -from pwem.emlib import MetaData, MDL_ORDER +from pwem.emlib import MetaData, MDL_ORDER, MDL_ANGLE_ROT, MDL_ANGLE_TILT, MDL_ANGLE_PSI, MDL_SHIFT_X, MDL_SHIFT_Y, \ + MDL_SHIFT_Z, MDL_NMA from .plotter_vol import FlexNmaVolPlotter +from continuousflex.protocols.convert import l2 +from xmippLib import SymList +import numpy as np +import tkinter.messagebox as mb +import matplotlib.pyplot as plt FIGURE_LIMIT_NONE = 0 FIGURE_LIMITS = 1 @@ -46,9 +48,12 @@ Z_LIMITS_NONE = 0 Z_LIMITS = 1 +METADATA_PROJECT = 0 +METADATA_FILE = 1 + class FlexAlignmentNMAVolViewer(ProtocolViewer): - """ Visualization of results from the NMA protocol + """ Visualization of results from the NMA alignment vol protocol (HEMNMA-3D) """ _label = 'viewer nma alignment vol' _targets = [FlexProtAlignmentNMAVol] @@ -118,9 +123,29 @@ def _defineParams(self, form): form.addParam('zlim_high', params.FloatParam, default=None, condition='zlimits_mode==%d' % Z_LIMITS, label='Upper z-axis limit') + group = form.addGroup('Comparing with ground-truth', expertLevel=LEVEL_ADVANCED) + group.addParam('GroundTruth', params.EnumParam, + choices=['From volume synthesis protocol', 'From an external metadata file'], + default=METADATA_PROJECT, + label='Ground-Truth parameters', display=params.EnumParam.DISPLAY_COMBO, + help='Use this is only when testing the method with synthetic data') + group.addParam('SynthesisProject', params.PointerParam, pointerClass='FlexProtSynthesizeSubtomo', + condition='GroundTruth==%d' % METADATA_PROJECT, + allowsNull=True, + label="Project for volume synthesize", + help='Select a previous run for volume (subtomograms) synthesize.') + group.addParam('MetadataFile', params.FileParam, + pointerClass='params.FileParam', allowsNull=True, + condition='GroundTruth==%d' % METADATA_FILE, + label="Metadata file (xmd)", + help='Choose a metadata file containing angles, shifts and NM amplitudes, typically a metadata' + ' file from synthesizing volumes') + group.addParam('displayStatistics', params.LabelParam, + label="Display error statistics and plots?") def _getVisualizeDict(self): return {'displayRawDeformation': self._viewRawDeformation, + 'displayStatistics': self._viewErrorStatistics, } @@ -188,6 +213,100 @@ def _doViewRawDeformation(self, components): return views + def _viewErrorStatistics(self, paramName): + if self.GroundTruth.get() == METADATA_PROJECT: + metadata_file = self.SynthesisProject.get()._getExtraPath('GroundTruth.xmd') + else: + metadata_file = self.MetadataFile.get() + return self._doViewErrorStatistics(metadata_file) + + def _doViewErrorStatistics(self, metadata_file): + md_gt = MetaData(metadata_file) + md_protocol = MetaData(self.protocol._getExtraPath('volumes.xmd')) + md_protocol.sort() + # Get the matching modes: + md_modes = MetaData(self.protocol._getExtraPath('modes.xmd')) + modeIds = [] + for i, objId in enumerate(md_modes): + modeIds.append(md_modes.getValue(MDL_ORDER, objId)) + # Get the parameters from both lists: + rtp_protocol = [] + xyz_protocol = [] + mode_ampl_protocol = [] + rtp_gt = [] + xyz_gt = [] + mode_ampl_gt = [] + for objId in md_protocol: + rtp_protocol.append([md_protocol.getValue(MDL_ANGLE_ROT, objId), + md_protocol.getValue(MDL_ANGLE_TILT, objId), + md_protocol.getValue(MDL_ANGLE_PSI, objId)]) + xyz_protocol.append([md_protocol.getValue(MDL_SHIFT_X, objId), + md_protocol.getValue(MDL_SHIFT_Y, objId), + md_protocol.getValue(MDL_SHIFT_Z, objId)]) + mode_ampl_protocol.append(md_protocol.getValue(MDL_NMA, objId)) + + rtp_gt.append([md_gt.getValue(MDL_ANGLE_ROT, objId), + md_gt.getValue(MDL_ANGLE_TILT, objId), + md_gt.getValue(MDL_ANGLE_PSI, objId)]) + xyz_gt.append([md_gt.getValue(MDL_SHIFT_X, objId), + md_gt.getValue(MDL_SHIFT_Y, objId), + md_gt.getValue(MDL_SHIFT_Z, objId)]) + mode_ampl_gt.append(md_gt.getValue(MDL_NMA, objId)) + + # Angular and shift distances + shift_distance = [] + angular_distance = [] + # The full description of computeDistanceAngles function is: + # A = SymList.computeDistanceAngles(SymList(), rot1, tilt1, psi1, rot2, tilt2, psi2, projdir_mode, check_mirrors, object_rotation) + # By default, they are all set to False. However, check_mirrors should be true in general. + for i in range(len(rtp_protocol)): + shift_distance.append(l2(xyz_gt[i], xyz_protocol[i])) + angular_distance.append(SymList.computeDistanceAngles(SymList(), + rtp_protocol[i][0], rtp_protocol[i][1], rtp_protocol[i][2], + rtp_gt[i][0], rtp_gt[i][1], rtp_gt[i][2], + False, True, False)) + # Normal mode amplitudes distances: we need to find the subset of normal modes used in alignment in the groundtruth + counter = 0 + plt.figure() + mean_amplitudes = [] + std_amplitudes = [] + label = [] + dist = [] + for i in modeIds: + # mode 7 corresponds to zero in the ground truth, so we need to subtract 7 + A = np.array(mode_ampl_gt)[:,i - 7] + B = np.array(mode_ampl_protocol)[:, counter] + mean_amplitudes.append(np.mean(np.array(A - B))) + std_amplitudes.append(np.std(np.array(A - B))) + label.append('mode ' + str(i)) + dist.append(np.array(A - B)) + counter +=1 + plt.title('histogram of normal mode amplitude distances') + plt.hist(dist, bins=100, label=label) + plt.legend(loc='upper right') + + plt.figure() + plt.hist(np.array(angular_distance), bins=100) + plt.title('histogram of angular distance') + plt.figure() + plt.hist(np.array(shift_distance), bins=100) + plt.title('histogram of shift distance') + + message = 'mean and standard deviation angular distance: ' + str(np.mean(np.array(angular_distance)))[:7] + message += ' and ' + str(np.std(np.array(angular_distance)))[:7] + message += '\nmean and standard deviation shift distance: ' + str(np.mean(np.array(shift_distance)))[:7] + message += ' and ' + str(np.std(np.array(shift_distance)))[:7] + + counter = 0 + for i in modeIds: + message += '\nmean and standard deviation for mode ' + str(i) + ': ' + str(mean_amplitudes[counter])[:7] + \ + ' ' + str(std_amplitudes[counter])[:7] + counter +=1 + + mb.showinfo('Distances compared to the ground truth', message) + plt.show() + pass + def loadData(self): """ Iterate over the images and their deformations to create a Data object with theirs Points. diff --git a/continuousflex/viewers/viewer_nma_dimred.py b/continuousflex/viewers/viewer_nma_dimred.py index 58f7601..9c483b2 100644 --- a/continuousflex/viewers/viewer_nma_dimred.py +++ b/continuousflex/viewers/viewer_nma_dimred.py @@ -1,7 +1,7 @@ # ************************************************************************** -# * Authors: J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) +# * J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es) # * Slavica Jonic (slavica.jonic@upmc.fr) -# * Mohamad Harastani (mohamad.harastani@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by @@ -22,35 +22,24 @@ # * e-mail address 'scipion@cnb.csic.es' # * # ************************************************************************** -from continuousflex.protocols.data import PathData - -""" -This module implement the wrappers around Xmipp CL2D protocol -visualization program. -""" -from os.path import basename, join, exists +from continuousflex.protocols.data import PathData +from os.path import basename, join, exists, isfile import numpy as np - -from pwem.convert.atom_struct import cifToPdb -from pyworkflow.utils import replaceBaseExt - -from pyworkflow.utils.path import cleanPath, makePath, cleanPattern +from joblib import load +from pyworkflow.utils.path import cleanPath, makePath from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) from pyworkflow.protocol.params import StringParam, LabelParam from pwem.objects import SetOfParticles from pwem.viewers import VmdView from pyworkflow.gui.browser import FileBrowserWindow - from continuousflex.protocols.protocol_nma_dimred import FlexProtDimredNMA - from continuousflex.protocols.data import Point, Data - from continuousflex.viewers.nma_plotter import FlexNmaPlotter - from continuousflex.viewers.nma_gui import ClusteringWindow, TrajectoriesWindow from pwem.utils import runProgram from pyworkflow.protocol import params +from continuousflex.protocols import FlexProtDeepHEMNMAInfer FIGURE_LIMIT_NONE = 0 FIGURE_LIMITS = 1 @@ -66,7 +55,7 @@ POINT_LIMITS = 1 class FlexDimredNMAViewer(ProtocolViewer): - """ Visualization of results from the NMA protocol + """ Visualization of results from the NMA alingment dimred protocol (HEMNMA) """ _label = 'viewer nma dimred' _targets = [FlexProtDimredNMA] @@ -178,6 +167,9 @@ def _viewRawDeformation(self, paramName): return self._doViewRawDeformation(components) def _doViewRawDeformation(self, components): + ProtDeepHEMNMA = False + if (isinstance(self.protocol.inputNMA.get(), FlexProtDeepHEMNMAInfer)): + ProtDeepHEMNMA = True components = list(map(int, components.split())) dim = len(components) views = [] @@ -214,7 +206,12 @@ def _doViewRawDeformation(self, components): else: self.getData().YIND = modeList[1] if dim == 2: - plotter.plotArray2D("Normal-mode amplitudes in low-dimensional space: %s vs %s" % tuple(baseList), + if ProtDeepHEMNMA: + plotter.plotArray2D_xy( + "Normal-mode amplitudes in low-dimensional space: %s vs %s" % tuple(baseList), + *baseList) + else: + plotter.plotArray2D("Normal-mode amplitudes in low-dimensional space: %s vs %s" % tuple(baseList), *baseList) elif dim == 3: self.getData().ZIND = modeList[2] @@ -225,6 +222,9 @@ def _doViewRawDeformation(self, components): return views def _displayClustering(self, paramName): + ProtDeepHEMNMA = False + if (isinstance(self.protocol.inputNMA.get(), FlexProtDeepHEMNMAInfer)): + ProtDeepHEMNMA = True self.clusterWindow = self.tkWindow(ClusteringWindow, title='Clustering Tool', dim=self.protocol.reducedDim.get(), @@ -240,10 +240,15 @@ def _displayClustering(self, paramName): zlim_low=self.zlim_low, zlim_high=self.zlim_high, s=self.s, - alpha=self.alpha) + alpha=self.alpha, + deepHEMNMA=ProtDeepHEMNMA) return [self.clusterWindow] def _displayTrajectories(self, paramName): + ProtDeepHEMNMA = False + if (isinstance(self.protocol.inputNMA.get(), FlexProtDeepHEMNMAInfer)): + ProtDeepHEMNMA = True + self.trajectoriesWindow = self.tkWindow(TrajectoriesWindow, title='Trajectories Tool', dim=self.protocol.reducedDim.get(), @@ -261,7 +266,8 @@ def _displayTrajectories(self, paramName): zlim_low=self.zlim_low, zlim_high=self.zlim_high, s=self.s, - alpha=self.alpha) + alpha=self.alpha, + deepHEMNMA=ProtDeepHEMNMA) return [self.trajectoriesWindow] def _createCluster(self): @@ -335,7 +341,13 @@ def _loadAnimation(self): def _generateAnimation(self): prot = self.protocol - projectorFile = prot.getProjectorFile() + # This is not getting the file correctly, we are workingaround it: + # projectorFile = prot.getProjectorFile() + projectorFile = prot._getExtraPath() + '/projector.txt' + if isfile(projectorFile): + print('Mapping found, the animation is exact inverse of the dimensionality reduction method') + else: + print('Mapping not found, the animation is an estimation of reversing the dimensionality reduction method') animation = self.trajectoriesWindow.getAnimationName() animationPath = prot._getExtraPath('animation_%s' % animation) @@ -343,34 +355,53 @@ def _generateAnimation(self): cleanPath(animationPath) makePath(animationPath) animationRoot = join(animationPath, 'animation_%s' % animation) - trajectoryPoints = np.array([p.getData() for p in self.trajectoriesWindow.pathData]) - np.savetxt(join(animationPath, 'trajectory.txt'), trajectoryPoints) - if projectorFile: + if isfile(projectorFile): M = np.loadtxt(projectorFile) - deformations = np.dot(trajectoryPoints, np.linalg.pinv(M)) + if prot.getMethodName() == 'sklearn_PCA': + pca = load(prot._getExtraPath('pca_pickled.txt')) + deformations = pca.inverse_transform(trajectoryPoints) + else: + deformations = np.dot(trajectoryPoints, np.linalg.pinv(M)) + temp = np.loadtxt(prot._getExtraPath('deformations.txt')) # the original matrix file + deformations += np.outer(np.ones(deformations.shape[0]),np.mean(temp, axis=0)) + temp = None + np.savetxt(animationRoot + 'trajectory.txt', trajectoryPoints) else: Y = np.loadtxt(prot.getOutputMatrixFile()) X = np.loadtxt(prot.getDeformationFile()) # Find closest points in deformations deformations = [X[np.argmin(np.sum((Y - p) ** 2, axis=1))] for p in trajectoryPoints] - pdb = prot.getInputPdb() - pdbFile = pdb.getFileName() - - structureEM = prot.getInputPdb().getPseudoAtoms() - if not structureEM: - localFn = replaceBaseExt(basename(pdbFile), 'pdb') - cifToPdb(pdbFile, localFn) - pdbFile = basename(localFn) - - modesFn = prot.inputNMA.get()._getExtraPath('modes.xmd') - - for i, d in enumerate(deformations): - atomsFn = animationRoot + 'atomsDeformed_%02d.pdb' % (i + 1) - cmd = '-o %s --pdb %s --nma %s --deformations %s' % (atomsFn, pdbFile, modesFn, str(d)[1:-1]) - runProgram('xmipp_pdb_nma_deform', cmd) + if prot.getDataChoice() == 'NMAs': + pdb = prot.getInputPdb() + pdbFile = pdb.getFileName() + modesFn = prot.getInputModes() + for i, d in enumerate(deformations): + atomsFn = animationRoot + 'atomsDeformed_%02d.pdb' % (i + 1) + cmd = '-o %s --pdb %s --nma %s --deformations ' % (atomsFn, pdbFile, modesFn) + for l in d: + cmd += str(l) + ' ' + # because it doesn't have an independent protocol we don't use self.runJob + runProgram('xmipp_pdb_nma_deform', cmd) + + elif prot.getDataChoice() == 'PDBs': + # There is incompatibility issue with the rest of the code, we have to use the fahterPDB as one of the + # deformed PDBs (the first one) + # fatherPDB = prot._getExtraPath('pdb_file.pdb') + fatherPDB = prot._getExtraPath('generated_pdbs/000001.pdb') + lines_father = self.readPDB(fatherPDB) + list_father = self.PDB2List(lines_father) + i = 0 + for line in deformations: + # reshaped pdb xyz coordinates + list_xyz = np.reshape(line, np.shape(list_father)) + lines_i = self.list2PDBlines(list_xyz, lines_father) + atomsFn = animationRoot + 'atomsDeformed_%02d.pdb' % (i + 1) + self.writePDB(lines_i, atomsFn) + i += 1 + pass # Join all deformations in a single pdb # iterating going up and down through all points @@ -394,7 +425,7 @@ def _generateAnimation(self): trajFile.close() # Delete temporary atom files - cleanPattern(animationRoot + 'atomsDeformed_??.pdb') + # cleanPattern(animationRoot + 'atomsDeformed_??.pdb') # Generate the vmd script vmdFn = animationRoot + '.vmd' @@ -420,9 +451,61 @@ def loadData(self): particles = self.protocol.getInputParticles() data = Data() - for i, particle in enumerate(particles): - data.addPoint(Point(pointId=particle.getObjId(), - data=matrix[i, :], - weight=particle._xmipp_cost.get())) + + ProtDeepHEMNMA = False + if (isinstance(self.protocol.inputNMA.get(), FlexProtDeepHEMNMAInfer)): + ProtDeepHEMNMA = True + + if ProtDeepHEMNMA: + for i, particle in enumerate(particles): + data.addPoint(Point(pointId=particle.getObjId(), + data=matrix[i, :], + weight=0.0)) + else: + for i, particle in enumerate(particles): + data.addPoint(Point(pointId=particle.getObjId(), + data=matrix[i, :], + weight=particle._xmipp_cost.get())) return data + + def readPDB(self, fnIn): + with open(fnIn) as f: + lines = f.readlines() + return lines + + def PDB2List(self, lines): + newlines = [] + for line in lines: + if line.startswith("ATOM "): + try: + x = float(line[30:38]) + y = float(line[38:46]) + z = float(line[46:54]) + newline = [x, y, z] + newlines.append(newline) + except: + pass + return newlines + + def list2PDBlines(self, list, lines): + newLines = [] + i = 0 + for line in lines: + if line.startswith("ATOM "): + try: + x = list[i][0] + y = list[i][1] + z = list[i][2] + newLine = line[0:30] + "%8.3f%8.3f%8.3f" % (x, y, z) + line[54:] + i += 1 + except: + pass + else: + newLine = line + newLines.append(newLine) + return newLines + + def writePDB(self, lines, fnOut): + with open(fnOut, mode='w') as f: + f.writelines(lines) diff --git a/continuousflex/viewers/viewer_nma_dimred_vol.py b/continuousflex/viewers/viewer_nma_dimred_vol.py index 77a8471..7905386 100755 --- a/continuousflex/viewers/viewer_nma_dimred_vol.py +++ b/continuousflex/viewers/viewer_nma_dimred_vol.py @@ -1,6 +1,5 @@ # ************************************************************************** -# * -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * # * This program is free software; you can redistribute it and/or modify @@ -20,21 +19,13 @@ # * # * All comments concerning this program package may be sent to the # * e-mail address 'scipion@cnb.csic.es' -# * # ************************************************************************** -from continuousflex.protocols.data import PathData - -""" -This module implement the wrappers around Xmipp CL2D protocol -visualization program. -""" +from continuousflex.protocols.data import PathData from os.path import basename, join, exists, isfile import numpy as np - -from pyworkflow.utils.path import cleanPath, makePath, cleanPattern +from pyworkflow.utils.path import cleanPath, makePath from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) - from pyworkflow.protocol.params import StringParam, LabelParam from pwem.objects import SetOfParticles from pwem.viewers import VmdView @@ -272,14 +263,10 @@ def _createCluster(self): cleanPath(fnSqlite) partSet = SetOfParticles(filename=fnSqlite) partSet.copyInfo(inputSet) - first = True for point in self.getData(): if point.getState() == Point.SELECTED: particle = inputSet[point.getId()] partSet.append(particle) - if first: - flag = particle._xmipp_angleY.get() - first = False partSet.write() partSet.close() @@ -291,7 +278,6 @@ def _createCluster(self): newProt.setObjLabel(clusterName) newProt.inputNmaDimred.set(prot) newProt.sqliteFile.set(fnSqlite) - newProt.angleYflag.set(flag) project.launchProtocol(newProt) project.getRunsGraph() diff --git a/continuousflex/viewers/viewer_pdb_dimred.py b/continuousflex/viewers/viewer_pdb_dimred.py index 5d41b35..1812ed4 100644 --- a/continuousflex/viewers/viewer_pdb_dimred.py +++ b/continuousflex/viewers/viewer_pdb_dimred.py @@ -1,5 +1,6 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) +# * Remi Vuillemot (remi.vuillemot@upmc.fr) # * IMPMC, UPMC Sorbonne University # * # * This program is free software; you can redistribute it and/or modify @@ -21,23 +22,31 @@ # * e-mail address 'scipion@cnb.csic.es' # ************************************************************************** - -from os.path import basename import numpy as np -from pwem.emlib import MetaData, MDL_ORDER -from pyworkflow.protocol.params import StringParam, LabelParam, EnumParam, FloatParam +from pyworkflow.protocol.params import StringParam, LabelParam, EnumParam, FloatParam, PointerParam, IntParam, BooleanParam from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) -from pyworkflow.utils import replaceBaseExt, replaceExt - -from continuousflex.protocols.data import Point, Data +from pwem.viewers import ChimeraView +from pwem.objects.data import SetOfParticles,SetOfVolumes, AtomStruct from continuousflex.viewers.nma_plotter import FlexNmaPlotter from continuousflex.protocols import FlexProtDimredPdb -import xmipp3 -import pwem.emlib.metadata as md -from pwem.viewers import ObjectView import matplotlib.pyplot as plt - +from pwem.emlib.image import ImageHandler from joblib import load +from continuousflex.viewers.tk_dimred import PCAWindowDimred, ANIMATION_INV, ANIMATION_AVG +from continuousflex.protocols.data import Point, Data, PathData +from pwem.viewers import VmdView +from pyworkflow.utils.path import cleanPath, makePath, makeTmpPath +from continuousflex.protocols.utilities.genesis_utilities import numpyArr2dcd, dcd2numpyArr +from continuousflex.protocols.utilities.pdb_handler import ContinuousFlexPDBHandler +from pyworkflow.gui.browser import FileBrowserWindow +from continuousflex.protocols.protocol_pdb_dimred import REDUCE_METHOD_PCA, REDUCE_METHOD_UMAP +from continuousflex.protocols.protocol_batch_pdb_cluster import FlexBatchProtClusterSet +from .plotter import FlexPlotter +import os +from matplotlib.ticker import MaxNLocator +import tkinter as tk +import matplotlib +import mrcfile X_LIMITS_NONE = 0 X_LIMITS = 1 @@ -46,9 +55,11 @@ Z_LIMITS_NONE = 0 Z_LIMITS = 1 +NUM_POINTS_TRAJECTORY=10 + class FlexProtPdbDimredViewer(ProtocolViewer): - """ Visualization of dimensionality reduction on PDBs + """ Visualization of dimensionality reduction on atomic structures """ _label = 'viewer PDBs dimred' _targets = [FlexProtDimredPdb] @@ -60,109 +71,605 @@ def __init__(self, **kwargs): def _defineParams(self, form): form.addSection(label='Visualization') - form.addParam('displayRawDeformation', StringParam, default='1 2', - label='Display the principal axes', - help='Type 1 to see the histogram of PCA axis 1; \n' - 'type 2 to to see the histogram of PCA axis 2, etc.\n' - 'Type 1 2 to see the 2D plot of amplitudes for PCA axes 1 2.\n' - 'Type 1 2 3 to see the 3D plot of amplitudes for PCA axes 1 2 3; etc.' - ) - form.addParam('displayPcaSingularValues', LabelParam, - label="Display PCA singular values", - help="The values should help you see how many dimensions are in the data ") - form.addParam('xlimits_mode', EnumParam, + + group = form.addGroup("Display Explained Variance") + group.addParam('displayPcaExplainedVariance', LabelParam, + label="Display Explained Variance", + help="Display the amount of variance explained by each PCA component. ", + condition=self.protocol.method.get()==REDUCE_METHOD_PCA) + + group = form.addGroup("Display landscape") + group.addParam('displayPCA', LabelParam, + label='Display PCA/UMAP axes', + help='Open a GUI to visualize the PCA/UMAP space') + + group.addParam('pcaAxes', StringParam, default="1 2", + label='Axes to display' ) + + group = form.addGroup("Display free energy") + group.addParam('displayFreeEnergy', LabelParam, + label='Display free energy', + help='Open a GUI to visualize the PCA space as free energy landscape') + group.addParam('freeEnergyAxes', StringParam, default="1 2", + label='Axes to display' ) + group.addParam('freeEnergySize', IntParam, default=50, + label='Resolution (pix)' ) + group.addParam('freeEnergyCmap', StringParam, default="jet", + label='Colormap' , help="See matplotlib colormaps for available colormaps") + group.addParam('freeEnergyInterpolate', BooleanParam, default=False, + label='Interpolate contours ?' ) + + group = form.addGroup("Animation tool") + + group.addParam('displayAnimationtool', LabelParam, + label='Open Animation tool ', + help='Open a GUI to analyze the PCA/UMAP space' + ' to draw and adjust trajectories and create clusters.') + + group.addParam('inputSet', PointerParam, pointerClass ='SetOfParticles,SetOfVolumes', + label='(Optional) Set of particles for clustering animation', allowsNull=True, + help="Provide a set of particles that match the PDB data set to visualize animation on 3D reconstructions") + + group = form.addGroup("Figure parameters") + + group.addParam('s', FloatParam, default=10, allowsNull=True, + label='Point radius') + group.addParam('alpha', FloatParam, default=0.5, allowsNull=True, + label='Point transparancy') + group.addParam('xlimits_mode', EnumParam, choices=['Automatic (Recommended)', 'Set manually x-axis limits'], default=X_LIMITS_NONE, label='x-axis limits', display=EnumParam.DISPLAY_COMBO, help='This allows you to use a specific range of x-axis limits') - form.addParam('xlim_low', FloatParam, default=None, + group.addParam('xlim_low', FloatParam, default=None, condition='xlimits_mode==%d' % X_LIMITS, label='Lower x-axis limit') - form.addParam('xlim_high', FloatParam, default=None, + group.addParam('xlim_high', FloatParam, default=None, condition='xlimits_mode==%d' % X_LIMITS, label='Upper x-axis limit') - form.addParam('ylimits_mode', EnumParam, + group.addParam('ylimits_mode', EnumParam, choices=['Automatic (Recommended)', 'Set manually y-axis limits'], default=Y_LIMITS_NONE, label='y-axis limits', display=EnumParam.DISPLAY_COMBO, help='This allows you to use a specific range of y-axis limits') - form.addParam('ylim_low', FloatParam, default=None, + group.addParam('ylim_low', FloatParam, default=None, condition='ylimits_mode==%d' % Y_LIMITS, label='Lower y-axis limit') - form.addParam('ylim_high', FloatParam, default=None, + group.addParam('ylim_high', FloatParam, default=None, condition='ylimits_mode==%d' % Y_LIMITS, label='Upper y-axis limit') - form.addParam('zlimits_mode', EnumParam, + group.addParam('zlimits_mode', EnumParam, choices=['Automatic (Recommended)', 'Set manually z-axis limits'], default=Z_LIMITS_NONE, label='z-axis limits', display=EnumParam.DISPLAY_COMBO, help='This allows you to use a specific range of z-axis limits') - form.addParam('zlim_low', FloatParam, default=None, + group.addParam('zlim_low', FloatParam, default=None, condition='zlimits_mode==%d' % Z_LIMITS, label='Lower z-axis limit') - form.addParam('zlim_high', FloatParam, default=None, + group.addParam('zlim_high', FloatParam, default=None, condition='zlimits_mode==%d' % Z_LIMITS, label='Upper z-axis limit') + def _getVisualizeDict(self): - return {'displayRawDeformation': self._viewRawDeformation, - 'displayPcaSingularValues': self.viewPcaSinglularValues} - - def _viewRawDeformation(self, paramName): - components = self.displayRawDeformation.get() - return self._doViewRawDeformation(components) - - def _doViewRawDeformation(self, components): - components = list(map(int, components.split())) - # print(components) - dim = len(components) - if self.xlimits_mode.get() == X_LIMITS: - x_low = self.xlim_low.get() - x_high = self.xlim_high.get() - if self.ylimits_mode.get() == Y_LIMITS: - y_low = self.ylim_low.get() - y_high = self.ylim_high.get() - if self.zlimits_mode.get() == Z_LIMITS: - z_low = self.zlim_low.get() - z_high = self.zlim_high.get() - - # print(self.protocol.getOutputMatrixFile()) - X = np.loadtxt(fname=self.protocol.getOutputMatrixFile()) + return { + 'displayPCA': self._displayPCA, + 'displayFreeEnergy': self._displayFreeEnergy, + 'displayAnimationtool': self._displayAnimationtool, + 'displayPcaExplainedVariance': self.viewPcaExplainedVariance, + } + + def _displayPCA(self, paramName): + axes_str = str.split(self.pcaAxes.get()) + axes = [] + for i in axes_str : axes.append(int(i.strip())) + + dim = len(axes) + if dim ==0 or dim >3: + return self.errorMessage("Can not read input PCA axes selection", "Invalid Input") + + data = self.getData() + plotter = FlexNmaPlotter(data= data, + xlim_low=self.xlim_low.get(), xlim_high=self.xlim_high.get(), + ylim_low=self.ylim_low.get(), ylim_high=self.ylim_high.get(), + zlim_low=self.zlim_low.get(), zlim_high=self.zlim_high.get(), + alpha=self.alpha, s=self.s, cbar_label=None) if dim == 1: - plt.hist(X[:,components[0]-1]) - plt.title('Histogram of principal axis %d values' %components[0]) + data.XIND = axes[0]-1 + plotter.plotArray1D("","%i component"%(axes[0]),"") if dim == 2: - plt.scatter(X[:,components[0]-1],X[:,components[1]-1]) - if self.xlimits_mode.get() == X_LIMITS: - plt.xlim([x_low,x_high]) - if self.ylimits_mode.get() == Y_LIMITS: - plt.ylim([y_low,y_high]) - plt.xlabel('Principal Component Axis %d' %components[0]) - plt.ylabel('Principal Component Axis %d' %components[1]) - modeNameList = 'Principal Axes %d vs %d' %(components[0], components[1]) - plt.title(modeNameList) - + data.YIND = axes[1]-1 + plotter.plotArray2D_xy("","%i component"%(axes[0]),"%i component"%(axes[1])) if dim == 3: - fig = plt.figure() - ax = fig.gca(projection='3d') - ax.scatter(X[:,components[0]-1],X[:,components[1]-1],X[:,components[2]-1]) - if self.xlimits_mode.get() == X_LIMITS: - ax.set_xlim([x_low,x_high]) - if self.ylimits_mode.get() == Y_LIMITS: - ax.set_ylim([y_low,y_high]) - if self.zlimits_mode.get() == Z_LIMITS: - ax.set_zlim([z_low,z_high]) - ax.set_xlabel('Principal Component Axis %d' %components[0]) - ax.set_ylabel('Principal Component Axis %d' %components[1]) - ax.set_zlabel('Principal Component Axis %d' %components[2]) - modeNameList = 'Principal Axes %d vs %d vs %d' %(components[0], components[1], components[2]) - ax.set_title(modeNameList) - plt.show() - - def viewPcaSinglularValues(self, paramName): - pca = load(self.protocol._getExtraPath('pca_pickled.txt')) - fig = plt.figure('PCA singlular values') - plt.stem(pca.singular_values_) - plt.xticks(np.arange(0, len(pca.singular_values_), 1)) - plt.show() + data.ZIND = axes[2]-1 + plotter.plotArray3D_xyz("","%i component"%(axes[0]),"%i component"%(axes[1]),"%i component"%(axes[2])) + plotter.show() + + def _displayFreeEnergy(self, paramName): + axes_str = str.split(self.freeEnergyAxes.get()) + axes = [] + for i in axes_str : axes.append(int(i.strip())-1) + + dim = len(axes) + if dim == 2: + + data = np.array([p.getData()[axes] for p in self.getData()]) + size =self.freeEnergySize.get() + xmin = np.min(data[:,0]) + xmax = np.max(data[:,0]) + ymin = np.min(data[:,1]) + ymax = np.max(data[:,1]) + xm = (xmax-xmin)*0.1 + ym = (ymax-ymin)*0.1 + xmin -= xm + xmax += xm + ymin -= ym + ymax += ym + x = np.linspace(xmin, xmax, size) + y = np.linspace(ymin, ymax, size) + count = np.zeros((size, size)) + for i in range(data.shape[0]): + count[np.argmin(np.abs(x.T - data[i, 0])), + np.argmin(np.abs(y.T - data[i, 1]))] += 1 + img = -np.log(count / count.max()) + img[img == np.inf] = img[img != np.inf].max() + + plotter = FlexPlotter() + ax = plotter.createSubPlot("Free energy", "component "+axes_str[0], + "component " + axes_str[1]) + if self.freeEnergyInterpolate.get(): + im = ax.imshow(img.T[::-1,:], + cmap = self.freeEnergyCmap.get(), interpolation="bicubic", + extent=[xmin,xmax,ymin,ymax]) + else: + xx, yy = np.mgrid[xmin:xmax:size * 1j, ymin:ymax:size * 1j] + im = ax.contourf(xx, yy, img, cmap=self.freeEnergyCmap.get(),levels=12) + cbar = plotter.figure.colorbar(im) + cbar.set_label("$\Delta G / k_{B}T$") + plotter.show() + + elif dim ==3 : + + data = np.array([p.getData()[axes] for p in self.getData()]) + size =self.freeEnergySize.get() + xmin = np.min(data[:, 0]) + xmax = np.max(data[:, 0]) + ymin = np.min(data[:, 1]) + ymax = np.max(data[:, 1]) + zmin = np.min(data[:, 2]) + zmax = np.max(data[:, 2]) + xm = (xmax - xmin) * 0.1 + ym = (ymax - ymin) * 0.1 + zm = (zmax - zmin) * 0.1 + xmin -= xm + xmax += xm + ymin -= ym + ymax += ym + zmin -= zm + zmax += zm + x = np.linspace(xmin, xmax, size) + y = np.linspace(ymin, ymax, size) + z = np.linspace(zmin, zmax, size) + count = np.zeros((size, size, size)) + for i in range(data.shape[0]): + count[np.argmin(np.abs(x.T - data[i, 0])), + np.argmin(np.abs(y.T - data[i, 1])), + np.argmin(np.abs(z.T - data[i, 2]))] += 1 + img = -np.log(count / count.max()) + img[img == np.inf] = img[img != np.inf].max() + + + tmpChimeraFile = self._getTmpPath("3d_plot_chimera.cxc") + tmpDensityFile = self._getTmpPath("3d_plot_chimera.mrc") + makePath(tmpChimeraFile) + makePath(tmpDensityFile) + cleanPath(tmpChimeraFile) + cleanPath(tmpDensityFile) + with mrcfile.new(self._getTmpPath("3d_plot_chimera.mrc"), overwrite=True) as mrc: + mrc.set_data(np.float32(-img)) + + N = 20 + colors = ["white"] + for i in range(N - 1): + cmap = matplotlib.cm.get_cmap(self.freeEnergyCmap.get()) + col = matplotlib.colors.to_hex(cmap(1- ((1 /N)*(i+1)))) + colors.append(col) + + points = np.linspace(-img.max(), 0, N) + thresh = 1 - np.exp(-0.7 * np.linspace(0, 10, N)) + + with open(tmpChimeraFile, "w") as f: + f.write("open %s\n"%os.path.abspath(tmpDensityFile)) + f.write("set bgColor white\n") + f.write("volume showOutlineBox true\n") + f.write("graphics silhouettes true\n") + f.write("volume style image\n") + f.write("volume #1 ") + for i in range(N): + f.write("level %.2f,%.2f " % (points[i], thresh[i])) + for i in colors: + f.write("color %s " % i) + f.write("\n") + + cv = ChimeraView(tmpChimeraFile) + cv.show() + + else: + return self.errorMessage("Please select only 2 or 3 axes", "Invalid Input") + + def _displayAnimationtool(self, paramName): + self.trajectoriesWindow = self.tkWindow(PCAWindowDimred, + title='Animation tool', + dim=self.protocol.reducedDim.get(), + data=self.getData(), + callback=self._generateAnimation, + loadCallback=self._loadAnimation, + saveCallback=self._saveAnimation, + saveClusterCallback=self.saveClusterCallback, + numberOfPoints=5, + limits_mode=0, + LimitL=None, + LimitH=None, + xlim_low=self.xlim_low.get(), + xlim_high=self.xlim_high.get(), + ylim_low=self.ylim_low.get(), + ylim_high=self.ylim_high.get(), + zlim_low=self.zlim_low.get(), + zlim_high=self.zlim_high.get(), + s=self.s, + alpha=self.alpha, + cbar_label="Cluster") + return [self.trajectoriesWindow] + + + def viewPcaExplainedVariance(self, paramName): + pca = load(self.protocol._getExtraPath('pca_pickled.joblib')) + plotter = FlexPlotter() + ax = plotter.createSubPlot("Explained variance","PCA component", "EV (%)") + ax.stem(np.arange(1, len(pca.explained_variance_ratio_)+1), 100*pca.explained_variance_ratio_) + ax.xaxis.set_major_locator(MaxNLocator(integer=True)) + plotter.show() pass + + def getData(self): + if self._data is None: + self._data = self.loadData() + return self._data + + def loadData(self): + data = Data() + pdb_matrix = np.loadtxt(self.protocol.getOutputMatrixFile()) + weights = [0 for i in range(pdb_matrix.shape[0])] + + for i in range(pdb_matrix.shape[0]): + data.addPoint(Point(pointId=i+1, data=pdb_matrix[i, :],weight=weights[i])) + return data + + def _generateAnimation(self, animtype): + prot = self.protocol + + if prot.method.get() == REDUCE_METHOD_UMAP and animtype == ANIMATION_INV: + return self.trajectoriesWindow.showError("Can not show the inverse tranform for UMAP. Try viewing cluster average instead.") + + if all([int(p._weight) == 0 for p in self.trajectoriesWindow.data]) and animtype == ANIMATION_AVG: + return self.trajectoriesWindow.showError("No clustering detected.") + + initPDB = ContinuousFlexPDBHandler(prot.getPDBRef()) + + # Get animation root + animation = self.trajectoriesWindow.getClusterName() + animationPath = prot._getExtraPath('animation_%s' % animation) + if not os.path.isdir(animationPath): + cleanPath(animationPath) + makePath(animationPath) + animationRoot = os.path.join(animationPath, '') + + # get trajectory coordinates + coords_list = [] + if animtype ==ANIMATION_INV: + coords_list = self.computeInv() + else : + coords_list = self.computeAvg() + + + # Generate DCD trajectory + initdcdcp = initPDB.copy() + initdcdcp.coords = coords_list[0] + if animtype == ANIMATION_INV: + outprefix = "trajectory" + else: + outprefix = "clusterAvg" + + initdcdcp.write_pdb(animationRoot+"reference.pdb") + numpyArr2dcd(arr = np.array(coords_list), filename=animationRoot+outprefix+".dcd") + for i in range(len(coords_list)): + initPDB.coords = coords_list[i] + initPDB.write_pdb(animationRoot+outprefix+"%s.pdb"%(str(i+1).zfill(3))) + + # Generate the vmd script + vmdFn = animationRoot + 'trajectory.vmd' + vmdFile = open(vmdFn, 'w') + vmdFile.write(""" + mol new %sreference.pdb waitfor all + mol addfile %s%s.dcd waitfor all + animate style Rock + display projection Orthographic + mol modcolor 0 0 Index + mol modstyle 0 0 Tube 1.000000 8.000000 + animate speed 0.75 + animate forward + animate delete beg 0 end 0 skip 0 0 + """ % (animationRoot,animationRoot,outprefix)) + vmdFile.close() + + VmdView(' -e ' + vmdFn).show() + + def computeAvg(self): + # read save coordinates + coords = dcd2numpyArr(self.protocol._getExtraPath("coords.dcd")) + + # get class dict + classDict = {} + count = 0 # CLUSTERINGTAG + for p in self.trajectoriesWindow.data: + clsId = int(p._weight) # CLUSTERINGTAG + if clsId != 0: + if clsId in classDict: + classDict[clsId].append(count) + else: + classDict[clsId] = [count] + count += 1 + + keys = list(classDict.keys()) + keys.sort() + + # compute avg + initPDB = ContinuousFlexPDBHandler(self.protocol.getPDBRef()) + coords_list= [] + for i in keys: + coord_avg = np.mean(coords[np.array(classDict[i])], axis=0) + coords_list.append(coord_avg.reshape((initPDB.n_atoms, 3))) + + return coords_list + + def computeInv(self): + trajectoryPoints = np.array([p.getData() for p in self.trajectoriesWindow.pathData]) + if trajectoryPoints.shape[0] == 0: + return self.trajectoriesWindow.showError("No animation to show.") + + pca_file =self.protocol._getExtraPath('pca_pickled.joblib') + if not os.path.exists(pca_file): + return self.trajectoriesWindow.showError("Missing PCA file") + # np.savetxt(animationRoot + 'trajectory.txt', trajectoryPoints) + pca = load(pca_file) + deformations = pca.inverse_transform(trajectoryPoints) + + coords_list = [] + initPDB = ContinuousFlexPDBHandler(self.protocol.getPDBRef()) + + for i in range(self.trajectoriesWindow.numberOfPoints): + coords_list.append(deformations[i].reshape((initPDB.n_atoms, 3))) + + return coords_list + + def saveClusterCallback(self, tkWindow): + if all([int(p._weight) == 0 for p in tkWindow.data]): + return tkWindow.showError("No clustering detected.") + + # get cluster name + clusterName = "animation_" + tkWindow.getClusterName() + + # get input metadata + inputSet = self.inputSet.get() + if inputSet is None: + tkWindow.showError("Select a set of particles to apply clustering to.") + return + + if inputSet.getSize() != tkWindow.data.getSize(): + return tkWindow.showError("The number of particles differs from the number of data points. Select a set of particles that match the data.") + + + classID=[] + for p in tkWindow.data: + classID.append(int(p._weight)) + + if isinstance(inputSet, SetOfParticles): + classSet = self.protocol._createSetOfClasses2D(self.inputSet, clusterName) + else: + classSet = self.protocol._createSetOfClasses3D(self.inputSet,clusterName) + + def updateItemCallback(item, row): + item.setClassId(row) + + class itemDataIterator: + def __init__(self, clsID): + self.clsID = clsID + + def __iter__(self): + self.n = 0 + return self + + def __next__(self): + if self.n > len(self.clsID)-1: + raise StopIteration + else: + index = self.clsID[self.n] + self.n += 1 + return index + + classSet.classifyItems( + updateItemCallback=updateItemCallback, + updateClassCallback=None, + itemDataIterator=iter(itemDataIterator(classID)), + classifyDisabled=False, + iterParams=None, + doClone=True) + + # self._saveAnimation(tkWindow) + + coordlist = self.computeAvg() + animationPath = self.protocol._getExtraPath(clusterName) + if not os.path.isdir(animationPath): + cleanPath(animationPath) + makePath(animationPath) + animationRoot = os.path.join(animationPath, '') + + outprefix = "clusterAvg" + initPDB = ContinuousFlexPDBHandler(self.protocol.getPDBRef()) + + clusterAvgName = clusterName+" "+ outprefix + PDBSet = self.protocol._createSetOfPDBs(clusterAvgName) + + for i in range(len(coordlist)): + initPDB.coords = coordlist[i] + pdb_file = animationRoot+outprefix+"%s.pdb"%(str(i+1).zfill(3)) + initPDB.write_pdb(pdb_file) + PDBSet.append(AtomStruct(pdb_file)) + + + # Run reconstruction + self.protocol._defineOutputs(**{clusterName : classSet, + clusterAvgName : PDBSet}) + project = self.protocol.getProject() + newProt = project.newProtocol(FlexBatchProtClusterSet) + newProt.setObjLabel(clusterName) + # newProt.inputSet.set(getattr(self, "inputSet")) + newProt.inputClasses.set(getattr(self.protocol, clusterName)) + newProt.inputPDBs.set(getattr(self.protocol, clusterAvgName)) + project.launchProtocol(newProt) + project.getRunsGraph() + + tkWindow.showInfo("Successfully exported clustering.") + + def _loadAnimation(self): + browser = FileBrowserWindow("Select animation directory", + self.getWindow(), self.protocol._getExtraPath(), + onSelect=self._loadAnimationData) + browser.show() + + def _loadAnimationData(self, obj): + + if not obj.isDir() : + return self.trajectoriesWindow.showError('Not a directory') + + loaded = [] + trajPath = obj.getPath() + trajFile = os.path.join(trajPath,'trajectory.txt') + if os.path.isfile(trajFile) and os.path.getsize(trajFile) != 0: + trajectoryPoints = np.loadtxt(trajFile) + data = PathData(dim=trajectoryPoints.shape[1]) + n=0 + for i, row in enumerate(trajectoryPoints): + data.addPoint(Point(pointId=i + 1, data=list(row), weight=0)) + n+=1 + loaded.append("trajectory") + self.trajectoriesWindow.numberOfPointsVar.set(n) + self.trajectoriesWindow.numberOfPoints = n + self.trajectoriesWindow.setPathData(data) + self.trajectoriesWindow._checkNumberOfPoints() + + clusterFile = os.path.join(trajPath,'clusters.txt') + if os.path.isfile(clusterFile) and os.path.getsize(clusterFile) != 0: + clusterPoints = np.loadtxt(clusterFile) + i=0 + for p in self.trajectoriesWindow.data: + p._weight = clusterPoints[i] + i+=1 + loaded.append("clusters") + if len(loaded) ==0: + return self.trajectoriesWindow.showError('Animation files not found. ') + else: + self.trajectoriesWindow._onUpdateClick() + # self.trajectoriesWindow.saveClusterBtn.config(state=tk.NORMAL) + dirpath, dirname = os.path.split(trajPath) + if dirname == '': + dirname = os.path.basename(dirpath) + if dirname.startswith("animation_"): + dirname = dirname[10:] + self.trajectoriesWindow.clusterName.set(dirname) + + self.trajectoriesWindow.showInfo('Successfully loaded : %s.' %str(loaded)) + + + + def _saveAnimation(self, tkWindow): + # get cluster name + animationPath = self.protocol._getExtraPath("animation_" + tkWindow.getClusterName()) + if not os.path.isdir(animationPath): + cleanPath(animationPath) + makePath(animationPath) + animationRoot = os.path.join(animationPath, '') + trajectoryPoints = np.array([p.getData() for p in self.trajectoriesWindow.pathData]) + saved=[] + if trajectoryPoints.shape[0] != 0: + np.savetxt(animationRoot + 'trajectory.txt', trajectoryPoints) + saved.append('trajectory.txt') + + classID=[] + for p in tkWindow.data: + classID.append(int(p._weight)) + if set(classID) != {0}: + np.savetxt(animationRoot + 'clusters.txt', np.array(classID)) + saved.append('clusters.txt') + + try : + self.trajectoriesWindow.plotter.figure.savefig(animationRoot + 'figure.png',dpi=500) + except: + pass + + if len(saved) != 0: + self.trajectoriesWindow.showInfo('Successfully saved : %s.' % str(saved)) + else: + self.trajectoriesWindow.showError('No animation state to save.') + + +class VolumeTrajectoryViewer(ProtocolViewer): + """ Visualization of a SetOfVolumes as a trajectory with ChimeraX + """ + _label = 'Volume trajectory viewer' + _targets = [SetOfVolumes] + + def _defineParams(self, form): + form.addSection(label='Visualization') + form.addParam('displayTrajectories', LabelParam, + label='ChimeraX', + help='Open the trajectory in ChimeraX.') + form.addParam('morph', BooleanParam, default=True, + label='morph volumes ?', + help='If set, will use morphing of volumes in ChimeraX') + form.addParam('rock', BooleanParam, default=True, + label='rock trajectory ?', condition="morph", + help='If set, will loop the trajectory back and forth') + def _getVisualizeDict(self): + return { + 'displayTrajectories': self._visualize, + } + + def _visualize(self, obj, **kwargs): + """visualisation for volumes set""" + volNames = [] + for i in self.protocol: + i.setSamplingRate(self.protocol.getSamplingRate()) + vol = ImageHandler().read(i) + volName = os.path.abspath(self._getPath("tmp%i.vol"%i.getObjId())) + vol.write(volName) + volNames.append(volName) + # Show Chimera + tmpChimeraFile = self._getPath("chimera.cxc") + with open(tmpChimeraFile, "w") as f: + if self.morph.get(): + if self.rock.get(): + nvol = len(volNames) + for i in range(nvol): + volNames.append(volNames[nvol-i-1]) + for n in volNames: + f.write("open %s\n"%n) + f.write("color #1-%i lightgrey\n"%len(volNames)) + f.write("volume morph #1-%i\n"%len(volNames)) + else: + f.write("open %s vseries true \n" % " ".join(volNames)) + # f.write("volume #1 style surface level 0.5") + f.write("vseries play #1 loop true maxFrameRate 7 direction oscillate \n") + + cv = ChimeraView(tmpChimeraFile) + return [cv] diff --git a/continuousflex/viewers/viewer_structure_mapping.py b/continuousflex/viewers/viewer_structure_mapping.py index fbb2227..f9b4a00 100644 --- a/continuousflex/viewers/viewer_structure_mapping.py +++ b/continuousflex/viewers/viewer_structure_mapping.py @@ -21,7 +21,6 @@ # * # * All comments concerning this program package may be sent to the # * e-mail address 'scipion@cnb.csic.es' -# * # ************************************************************************** import os diff --git a/continuousflex/viewers/viewer_subtomograms_classify.py b/continuousflex/viewers/viewer_subtomograms_classify.py index 8447922..dc27d96 100644 --- a/continuousflex/viewers/viewer_subtomograms_classify.py +++ b/continuousflex/viewers/viewer_subtomograms_classify.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * IMPMC, UPMC Sorbonne University # * # * This program is free software; you can redistribute it and/or modify @@ -21,20 +21,10 @@ # * e-mail address 'scipion@cnb.csic.es' # ************************************************************************** - -from os.path import basename import numpy as np -from pwem.emlib import MetaData, MDL_ORDER from pyworkflow.protocol.params import StringParam, LabelParam, EnumParam, FloatParam, IntParam, LEVEL_ADVANCED from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) -from pyworkflow.utils import replaceBaseExt, replaceExt - -from continuousflex.protocols.data import Point, Data -from continuousflex.viewers.nma_plotter import FlexNmaPlotter from continuousflex.protocols import FlexProtSubtomoClassify -import xmipp3 -import pwem.emlib.metadata as md -from pwem.viewers import ObjectView import matplotlib.pyplot as plt from joblib import load import scipy.cluster.hierarchy as sch @@ -60,69 +50,71 @@ def __init__(self, **kwargs): def _defineParams(self, form): form.addSection(label='Visualization') - form.addParam('displayAgglomarative', LabelParam, - label="Display Hierarchical Clustering Tree", - help="Display the dendrogram that corresponds to the Hierarchical clustering") - form.addParam('displayFullAgglomarative', LabelParam, - expertLevel=LEVEL_ADVANCED, - label="Display Full Hierarchical Clustering Tree", - help="Display the full tree without truncating for the first p clusters") - form.addParam('displayRawDeformation', StringParam, default='1 2', - label='Display the principle axes', - help='Type 1 to see the histogram of PCA axis 1; \n' - 'type 2 to to see the histogram of PCA axis 2, etc.\n' - 'Type 1 2 to see the 2D plot of amplitudes for PCA axes 1 2.\n' - 'Type 1 2 3 to see the 3D plot of amplitudes for PCA axes 1 2 3; etc.' - ) - form.addParam('displayPcaSingularValues', LabelParam, - label="Display PCA singular values", - help="The values should help you see how many dimensions are in the data ") - form.addParam('displayKmeans', StringParam, default='1 2', - label='Display Kmeans classification on the principle axes', - help='Type 1 2 to see the classification 2D plot on the PCA axes 1 2.\n' - 'Type 1 2 3 to see the classification 3D plot on the PCA axes 1 2 3; etc.' - ) - form.addParam('blacked', IntParam, - default=None, - allowsNull=True, - expertLevel=LEVEL_ADVANCED, - label='blacked cluster', - help='This allows you to make a specific cluster color to black to identify it.' - 'If 0 this will make cluster 0 black on the graph' - 'If 1 this will make cluster 1 black on the graph, etc.') - form.addParam('xlimits_mode', EnumParam, - choices=['Automatic (Recommended)', 'Set manually x-axis limits'], - default=X_LIMITS_NONE, - label='x-axis limits', display=EnumParam.DISPLAY_COMBO, - help='This allows you to use a specific range of x-axis limits') - form.addParam('xlim_low', FloatParam, default=None, - condition='xlimits_mode==%d' % X_LIMITS, - label='Lower x-axis limit') - form.addParam('xlim_high', FloatParam, default=None, - condition='xlimits_mode==%d' % X_LIMITS, - label='Upper x-axis limit') - form.addParam('ylimits_mode', EnumParam, - choices=['Automatic (Recommended)', 'Set manually y-axis limits'], - default=Y_LIMITS_NONE, - label='y-axis limits', display=EnumParam.DISPLAY_COMBO, - help='This allows you to use a specific range of y-axis limits') - form.addParam('ylim_low', FloatParam, default=None, - condition='ylimits_mode==%d' % Y_LIMITS, - label='Lower y-axis limit') - form.addParam('ylim_high', FloatParam, default=None, - condition='ylimits_mode==%d' % Y_LIMITS, - label='Upper y-axis limit') - form.addParam('zlimits_mode', EnumParam, - choices=['Automatic (Recommended)', 'Set manually z-axis limits'], - default=Z_LIMITS_NONE, - label='z-axis limits', display=EnumParam.DISPLAY_COMBO, - help='This allows you to use a specific range of z-axis limits') - form.addParam('zlim_low', FloatParam, default=None, - condition='zlimits_mode==%d' % Z_LIMITS, - label='Lower z-axis limit') - form.addParam('zlim_high', FloatParam, default=None, - condition='zlimits_mode==%d' % Z_LIMITS, - label='Upper z-axis limit') + if(self.protocol.classifyTechnique.get()==0): + form.addParam('displayAgglomarative', LabelParam, + label="Display Hierarchical Clustering Tree", + help="Display the dendrogram that corresponds to the Hierarchical clustering") + form.addParam('displayFullAgglomarative', LabelParam, + expertLevel=LEVEL_ADVANCED, + label="Display Full Hierarchical Clustering Tree", + help="Display the full tree without truncating for the first p clusters") + if (self.protocol.classifyTechnique.get() == 1): + form.addParam('displayRawDeformation', StringParam, default='1 2', + label='Display the principle axes', + help='Type 1 to see the histogram of PCA axis 1; \n' + 'type 2 to to see the histogram of PCA axis 2, etc.\n' + 'Type 1 2 to see the 2D plot of amplitudes for PCA axes 1 2.\n' + 'Type 1 2 3 to see the 3D plot of amplitudes for PCA axes 1 2 3; etc.' + ) + form.addParam('displayPcaSingularValues', LabelParam, + label="Display PCA singular values", + help="The values should help you see how many dimensions are in the data ") + form.addParam('displayKmeans', StringParam, default='1 2', + label='Display Kmeans classification on the principle axes', + help='Type 1 2 to see the classification 2D plot on the PCA axes 1 2.\n' + 'Type 1 2 3 to see the classification 3D plot on the PCA axes 1 2 3; etc.' + ) + form.addParam('blacked', IntParam, + default=None, + allowsNull=True, + expertLevel=LEVEL_ADVANCED, + label='blacked cluster', + help='This allows you to make a specific cluster color to black to identify it.' + 'If 0 this will make cluster 0 black on the graph' + 'If 1 this will make cluster 1 black on the graph, etc.') + form.addParam('xlimits_mode', EnumParam, + choices=['Automatic (Recommended)', 'Set manually x-axis limits'], + default=X_LIMITS_NONE, + label='x-axis limits', display=EnumParam.DISPLAY_COMBO, + help='This allows you to use a specific range of x-axis limits') + form.addParam('xlim_low', FloatParam, default=None, + condition='xlimits_mode==%d' % X_LIMITS, + label='Lower x-axis limit') + form.addParam('xlim_high', FloatParam, default=None, + condition='xlimits_mode==%d' % X_LIMITS, + label='Upper x-axis limit') + form.addParam('ylimits_mode', EnumParam, + choices=['Automatic (Recommended)', 'Set manually y-axis limits'], + default=Y_LIMITS_NONE, + label='y-axis limits', display=EnumParam.DISPLAY_COMBO, + help='This allows you to use a specific range of y-axis limits') + form.addParam('ylim_low', FloatParam, default=None, + condition='ylimits_mode==%d' % Y_LIMITS, + label='Lower y-axis limit') + form.addParam('ylim_high', FloatParam, default=None, + condition='ylimits_mode==%d' % Y_LIMITS, + label='Upper y-axis limit') + form.addParam('zlimits_mode', EnumParam, + choices=['Automatic (Recommended)', 'Set manually z-axis limits'], + default=Z_LIMITS_NONE, + label='z-axis limits', display=EnumParam.DISPLAY_COMBO, + help='This allows you to use a specific range of z-axis limits') + form.addParam('zlim_low', FloatParam, default=None, + condition='zlimits_mode==%d' % Z_LIMITS, + label='Lower z-axis limit') + form.addParam('zlim_high', FloatParam, default=None, + condition='zlimits_mode==%d' % Z_LIMITS, + label='Upper z-axis limit') def _getVisualizeDict(self): return {'displayAgglomarative': self.viewDendrogram, diff --git a/continuousflex/viewers/viewer_subtomograms_synthesize.py b/continuousflex/viewers/viewer_subtomograms_synthesize.py index c4cd8c6..84e0311 100644 --- a/continuousflex/viewers/viewer_subtomograms_synthesize.py +++ b/continuousflex/viewers/viewer_subtomograms_synthesize.py @@ -1,5 +1,5 @@ # ************************************************************************** -# * Authors: Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Rémi Vuillemot (remi.vuillemot@upmc.fr) # * IMPMC, UPMC Sorbonne University # * @@ -22,22 +22,19 @@ # * e-mail address 'scipion@cnb.csic.es' # ************************************************************************** - from os.path import basename - from pwem.emlib import MetaData, MDL_ORDER from pyworkflow.protocol.params import StringParam, LabelParam from pyworkflow.viewer import (ProtocolViewer, DESKTOP_TKINTER, WEB_DJANGO) -from pyworkflow.utils import replaceBaseExt, replaceExt - +from pyworkflow.utils import replaceExt from continuousflex.protocols.data import Point, Data from continuousflex.viewers.nma_plotter import FlexNmaPlotter from continuousflex.protocols import FlexProtSynthesizeSubtomo -import xmipp3 import pwem.emlib.metadata as md from pwem.viewers import ObjectView import matplotlib.pyplot as plt -from continuousflex.protocols.protocol_subtomogrmas_synthesize import NMA_YES +from continuousflex.protocols.protocol_subtomograms_synthesize import NMA_YES + class FlexProtSynthesizeSubtomoViewer(ProtocolViewer): """ Visualization of results from synthesized subtomogrmas @@ -59,7 +56,7 @@ def _defineParams(self, form): form.addSection(label='Visualization') form.addParam('displayRawDeformation', StringParam, default='7 8', condition=self.protocol.confVar.get() == NMA_YES, - label='Display the computed normal-mode amplitudes', + label='Display normal-mode amplitudes relationship', help='Type 7 to see the histogram of amplitudes along mode 7; \n' 'type 8 to see the histogram of amplitudes along mode 8, etc.\n' 'Type 7 8 to see the 2D plot of amplitudes along modes 7 and 8.\n' @@ -169,12 +166,10 @@ def loadData(self): mdVolumes = md.MetaData(self.protocol._getExtraPath('GroundTruth.xmd')) data = Data() for objId in mdVolumes: - # pointData = list(map(float, particle._xmipp_nmaDisplacements)) pointData = list(mdVolumes.getValue(md.MDL_NMA,objId)) # inserting 6 zeros for the first 6 never used modes for j in range(6): pointData.insert(0, 0) - # print(pointData) data.addPoint(Point(pointId=objId, data=pointData, weight=0.0)) diff --git a/continuousflex/wizards.py b/continuousflex/wizards.py index fd7097e..5fab901 100644 --- a/continuousflex/wizards.py +++ b/continuousflex/wizards.py @@ -1,6 +1,5 @@ from pwem.constants import * from pwem.wizards import * -from pyworkflow.wizard import Wizard from continuousflex.protocols.protocol_denoise_volumes import FlexProtVolumeDenoise class FlexFilterVolumesWizard(FilterVolumesWizard): diff --git a/requirements.txt b/requirements.txt index a91b731..78f8749 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,2 @@ matplotlib -farneback3d -pycuda==2020.1 -scikit-image +mrcfile \ No newline at end of file diff --git a/setup.py b/setup.py index 8593dfe..81c6f99 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,8 @@ # ************************************************************************** -# * -# * Authors: -# * Mohamad Harastani (mohamad.harastani@upmc.fr) +# * Authors: +# * Mohamad Harastani (mohamad.harastani@igbmc.fr) # * Slavica Jonic (slavica.jonic@upmc.fr) # * -# * # * This program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by # * the Free Software Foundation; either version 2 of the License, or @@ -22,183 +20,48 @@ # * # * All comments concerning this program package may be sent to the # * e-mail address 'scipion@cnb.csic.es' -# * # ************************************************************************** -"""A setuptools based setup module. -See: -https://packaging.python.org/en/latest/distributing.html -https://github.com/pypa/sampleproject -""" - -# Always prefer setuptools over distutils from setuptools import setup, find_packages -# To use a consistent encoding from codecs import open from os import path from continuousflex import __version__ here = path.abspath(path.dirname(__file__)) -# Get the long description from the README file with open(path.join(here, 'README.rst'), encoding='utf-8') as f: long_description = f.read() -# Arguments marked as "Required" below must be included for upload to PyPI. -# Fields marked as "Optional" may be commented out. -# Load requirements.txt with open('requirements.txt') as f: requirements = f.read().splitlines() setup( - # This is the name of your project. The first time you publish this - # package, this name will be registered for you. It will determine how - # users can install this project, e.g.: - # - # $ pip install sampleproject - # - # And where it will live on PyPI: https://pypi.org/project/sampleproject/ - # - # There are some restrictions on what makes a valid project name - # specification here: - # https://packaging.python.org/specifications/core-metadata/#name - name='scipion-em-continuousflex', # Required - - # Versions should comply with PEP 440: - # https://www.python.org/dev/peps/pep-0440/ - # - # For a discussion on single-sourcing the version across setup.py and the - # project code, see - # https://packaging.python.org/en/latest/single_source_version.html - version=__version__, # Required - - # This is a one-line description or tagline of what your project does. This - # corresponds to the "Summary" metadata field: - # https://packaging.python.org/specifications/core-metadata/#summary - description='Plugin to use continuousflex protocols within the Scipion framework', # Required - - # This is an optional longer description of your project that represents - # the body of text which users will see when they visit PyPI. - # - # Often, this is the same as your README, so you can just read it in from - # that file directly (as we have already done above) - # - # This field corresponds to the "Description" metadata field: - # https://packaging.python.org/specifications/core-metadata/#description-optional - long_description=long_description, # Optional - - # This should be a valid link to your project's main homepage. - # - # This field corresponds to the "Home-Page" metadata field: - # https://packaging.python.org/specifications/core-metadata/#home-page-optional - url='https://github.com/scipion-em/scipion-em-continuousflex', # Optional - - # This should be your name or the name of the organization which owns the - # project. - author='Slavica Jonic & Mohamad Harastani', # Optional - - # This should be a valid email address corresponding to the author listed - # above. - author_email='slavica.jonic@upmc.fr', # Optional - - # Classifiers help users find your project by categorizing it. - # - # For a list of valid classifiers, see - # https://pypi.python.org/pypi?%3Aaction=list_classifiers - classifiers=[ # Optional - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable + name='scipion-em-continuousflex', + version=__version__, + description='Plugin to use continuousflex protocols within the Scipion framework', + long_description=long_description, + url='https://github.com/scipion-em/scipion-em-continuousflex', + author='Mohamad Harastani, Remi Vuillemot, Ilyes Hamitouche and Slavica Jonic', + author_email='slavica.jonic@upmc.fr', + classifiers=[ 'Development Status :: 4 - Beta', - - # Indicate who your project is intended for - # 'Intended Audience :: Users', - - # Pick your license as you wish 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', - - # Specify the Python versions you support here. In particular, ensure - # that you indicate whether you support Python 2, Python 3 or both. 'Programming Language :: Python :: 3' ], - # This field adds keywords for your project which will appear on the - # project page. What does your project relate to? - # - # Note that this is a string of words separated by whitespace, not a list. - keywords='scipion NMA HEMNMA StuctMap electron-microscopy cryo-em structural-biology image-processing scipion-3.0', # Optional - - # You can just specify package directories manually here if your project is - # simple. Or you can use find_packages(). - # - # Alternatively, if you just want to distribute a single Python file, use - # the `py_modules` argument instead as follows, which will expect a file - # called `my_module.py` to exist: - # - # py_modules=["my_module"], - # - #packages=find_packages(exclude=['contrib', 'docs', 'tests']), # Required + keywords='cryo-em cryo-et image-processing continuous-conformational-variability', # Optional packages=find_packages(), - # This field lists other packages that your project depends on to run. - # Any package you put here will be installed by pip when your project is - # installed, so they must be valid existing projects. - # - # For an analysis of "install_requires" vs pip's requirements files see: - # https://packaging.python.org/en/latest/requirements.html - install_requires=[requirements], # Optional - - # List additional groups of dependencies here (e.g. development - # dependencies). Users will be able to install these using the "extras" - # syntax, for example: - # - # $ pip install sampleproject[dev] - # - # Similar to `install_requires` above, these must be valid existing - # projects. - #extras_require={ # Optional - # 'dev': ['check-manifest'], - # 'test': ['coverage'], - #}, - - # If there are data files included in your packages that need to be - # installed, specify them here. - # - # If using Python 2.6 or earlier, then these have to be included in - # MANIFEST.in as well. + install_requires=[requirements], include_package_data=True, - package_data={ # Optional + package_data={ 'continuousflex': ['protocols.conf'], }, - # Although 'package_data' is the preferred approach, in some case you may - # need to place data files outside of your packages. See: - # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files - # - # In this case, 'data_file' will be installed into '/my_data' - #data_files=[('my_data', ['data/data_file'])], # Optional - - # To provide executable scripts, use entry points in preference to the - # "scripts" keyword. Entry points provide cross-platform support and allow - # `pip` to create the appropriate form of executable for the target - # platform. - # - # For example, the following would provide a command called `sample` which - # executes the function `main` from this package when invoked: entry_points={ 'pyworkflow.plugin': 'continuousflex = continuousflex' }, - # List additional URLs that are relevant to your project as a dict. - # - # This field corresponds to the "Project-URL" metadata fields: - # https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use - # - # Examples listed include a pattern for specifying where the package tracks - # issues, where the source is hosted, where to say thanks to the package - # maintainers, and where to support the project financially. The key is - # what's used to render the link text on PyPI. - project_urls={ # Optional + project_urls={ 'Bug Reports': 'https://github.com/scipion-em/scipion-em-continuousflex/issues', 'Source': 'https://github.com/scipion-em/scipion-em-continuousflex/', },