diff --git a/chilife/chilife.py b/chilife/chilife.py index dfe0fde2..69292ed6 100644 --- a/chilife/chilife.py +++ b/chilife/chilife.py @@ -562,6 +562,7 @@ def create_dlibrary( resname: str = None, dihedrals: ArrayLike = None, weights: ArrayLike = None, + sort_atoms = True, permanent: bool = False, default: bool = False, force: bool = False, @@ -649,7 +650,7 @@ def create_dlibrary( "residue number" ) - struct, spin_atoms = pre_add_library(pdb, spin_atoms, uniform_topology=False) + struct, spin_atoms = pre_add_library(pdb, spin_atoms, uniform_topology=False, sort_atoms=sort_atoms) res1 = struct.select_atoms(f'resnum {site1}') res2 = struct.select_atoms(f'resnum {site2}') @@ -769,6 +770,7 @@ def pre_add_library( pdb: str, spin_atoms: List[str], uniform_topology: bool = True, + sort_atoms = True, ) -> Tuple[MDAnalysis.Universe, Dict]: """Helper function to sort PDBs, save spin atoms, update lists, etc. when adding a SpinLabel or dSpinLabel. @@ -790,27 +792,32 @@ def pre_add_library( spin_atoms : dict Dictionary of spin atoms and weights if specified. """ - # Sort the PDB for optimal dihedral definitions - pdb_lines, bonds = sort_pdb(pdb, uniform_topology=uniform_topology, return_bonds=True) - bonds = get_min_topol(pdb_lines, forced_bonds=bonds) - - # Write a temporary file with the sorted atoms - if isinstance(pdb_lines[0], list): - with tempfile.NamedTemporaryFile(suffix=".pdb", mode="w+", delete=False) as tmpfile: - for i, model in enumerate(pdb_lines): - tmpfile.write(f"MODEL {i + 1}\n") - for atom in model: - tmpfile.write(atom) - tmpfile.write("ENDMDL\n") - else: - with tempfile.NamedTemporaryFile(suffix=".pdb", mode="w+", delete=False) as tmpfile: - for line in pdb_lines: - tmpfile.write(line) + if sort_atoms: + # Sort the PDB for optimal dihedral definitions + pdb_lines, bonds = sort_pdb(pdb, uniform_topology=uniform_topology, return_bonds=True) + bonds = get_min_topol(pdb_lines, forced_bonds=bonds) + + # Write a temporary file with the sorted atoms + if isinstance(pdb_lines[0], list): + with tempfile.NamedTemporaryFile(suffix=".pdb", mode="w+", delete=False) as tmpfile: + for i, model in enumerate(pdb_lines): + tmpfile.write(f"MODEL {i + 1}\n") + for atom in model: + tmpfile.write(atom) + tmpfile.write("ENDMDL\n") + else: + with tempfile.NamedTemporaryFile(suffix=".pdb", mode="w+", delete=False) as tmpfile: + for line in pdb_lines: + tmpfile.write(line) # Load sorted atom pdb using MDAnalysis and remove tempfile - struct = mda.Universe(tmpfile.name, in_memory=True) - struct.universe.add_bonds(bonds) - os.remove(tmpfile.name) + struct = mda.Universe(tmpfile.name, in_memory=True) + struct.add_bonds(bonds) + os.remove(tmpfile.name) + else: + struct = mda.Universe(pdb, in_memory=True) + bonds = chilife.guess_bonds(struct.atoms.positions, struct.atoms.types) + struct.add_bonds(bonds) # Store spin atoms if provided if spin_atoms is not None: diff --git a/examples/09 - Bifunctional Labels/09 - Bifunctional Labels.ipynb b/examples/09 - Bifunctional Labels/09 - Bifunctional Labels.ipynb new file mode 100644 index 00000000..883a4cb2 --- /dev/null +++ b/examples/09 - Bifunctional Labels/09 - Bifunctional Labels.ipynb @@ -0,0 +1,116 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Bifunctional Spin Labeling" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-20T21:45:16.684539500Z", + "start_time": "2023-11-20T21:45:15.201127800Z" + } + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import chilife as xl\n", + "np.random.seed(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-20T21:45:22.103498800Z", + "start_time": "2023-11-20T21:45:17.206194800Z" + } + }, + "outputs": [], + "source": [ + "# Fetch maltodextrin binding protein structure from the PDB\n", + "protein = xl.fetch('2qmt')\n", + "\n", + "# Create spin labels using the off-rotamer sampling method\n", + "SL1 = xl.dSpinLabel('DCN', (6, 8), protein)\n", + "SL2 = xl.dSpinLabel('DCN', (28,32), protein)\n", + "\n", + "# Predict distance distributions over an experimental axis\n", + "r, Pexp = np.loadtxt('Exp_Data.txt').T\n", + "Pexp /= np.trapz(Pexp, r)\n", + "P = xl.distance_distribution(SL1, SL2, r=r)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "tags": [ + "nbsphinx-thumbnail" + ], + "ExecuteTime": { + "end_time": "2023-11-20T21:45:23.085049900Z", + "start_time": "2023-11-20T21:45:22.915361Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "
", + "image/png": "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KyZL9UEiMlubNm0SDz74oHB2dhbe3t5i7NixIjY2VsybN6/RhaC3bNkiXnjhBdGtWzfh5eUlXFxcRMeOHcVLL70krl27prVvRkaGmDp1qggKChK2trYCgJg2bZrWPrGxseLxxx8XAQEBwsXFRfTq1Ut8++23eq/fUHFpQ59DkpCQIF577TUREREhHBwchI+Pj+jdu7dYsGCBKCws1No3LS1NvPPOO6Jbt27CxcVFuLi4iMjISDF27FgRHR2tU2y6PqWlpcLT01N07dpVq/2FF14QAMTs2bMbPMeNGzcEAOHu7i5KSko07Q8//LCwt7cX6enpjY6HiCybQoh6FsUkIiKTmTVrFhYvXozTp08bZXIJAKSkpCA8PBwTJkyot04gEVkXDgETEZmJuXPnws3NDR9//LHRzrlo0SLY2NjonRlMRNaLCSARkZkICAjA22+/jY0bN+LSpUt3fb60tDR8++23ePnll/WuikJE1otDwERERERWhj2ARERERFaGCSARERGRlWECSERERGRlmAASERERWRkmgERERERWhgkgERERkZVhAkhERERkZZgAEhEREVkZJoBEREREVoYJIBEREZGVYQJIREREZGX+HwwrGoONN9FFAAAAAElFTkSuQmCC\n" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "plt.style.use('chiLife')\n", + "plt.rcParams.update({'font.size': 15})\n", + "\n", + "fig, ax = plt.subplots(figsize=(8, 3))\n", + "\n", + "ax.fill_between(r, Pexp, label='Experiment', color='k')\n", + "\n", + "ax.plot(r, P, label='Model Prediction', color='C0')\n", + "\n", + "\n", + "ax.set_yticks([])\n", + "ax.set_xlabel(r'distance ($\\rm\\AA$)')\n", + "ax.legend(frameon=False)\n", + "for spine in ['left', 'top', 'right']:\n", + " ax.spines[spine].set_visible(False)\n", + "\n", + "plt.show()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.10", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/09 - Bifunctional Labels/DCNip2_drotlib.zip b/examples/09 - Bifunctional Labels/DCNip2_drotlib.zip new file mode 100644 index 00000000..4bbcb04a Binary files /dev/null and b/examples/09 - Bifunctional Labels/DCNip2_drotlib.zip differ diff --git a/examples/09 - Bifunctional Labels/DCNip4_drotlib.zip b/examples/09 - Bifunctional Labels/DCNip4_drotlib.zip new file mode 100644 index 00000000..bc5565e7 Binary files /dev/null and b/examples/09 - Bifunctional Labels/DCNip4_drotlib.zip differ diff --git a/examples/09 - Bifunctional Labels/Exp_Data.txt b/examples/09 - Bifunctional Labels/Exp_Data.txt new file mode 100644 index 00000000..0d5d18c0 --- /dev/null +++ b/examples/09 - Bifunctional Labels/Exp_Data.txt @@ -0,0 +1,57 @@ +19.04371135 0 +19.52893153 0 +20.01415171 0 +20.49937088 0 +20.98459106 0 +21.46981124 0.000148602 +21.95503143 0 +22.44025161 0.001277658 +22.9254718 0.001709512 +23.41069198 0.002466733 +23.89591216 0.006279774 +24.38113132 0.011409769 +24.86635151 0.014555304 +25.35157169 0.014929992 +25.83679188 0.01278915 +26.32201206 0.008920883 +26.80723225 0.004488191 +27.29245243 0.001023366 +27.77767261 0 +28.26289177 0 +28.74811196 0 +29.23333214 0.000203712 +29.71855233 0.00051705 +30.20377251 0.000427106 +30.68899269 1.6869E-05 +31.17421288 0 +31.65943306 0 +32.14465222 0 +32.62987241 0 +33.11509259 0 +33.60031278 0 +34.08553296 0 +34.57075314 0 +35.05597333 0 +35.54119351 0 +36.02641267 0 +36.51163286 0 +36.99685304 0 +37.48207322 0 +37.96729341 0 +38.45251359 0 +38.93773378 0 +39.42295396 0 +39.90817312 0 +40.39339331 0 +40.87861349 0 +41.36383367 0 +41.84905386 0 +42.33427404 0 +42.81949423 0 +43.30471441 0 +43.78993357 0 +44.27515376 0 +44.76037394 0 +45.24559412 0 +45.73081431 0 +46.21603449 0 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 6d5fd7df..56f94357 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,34 @@ [project] name = "chilife" -dynamic = ["version"] +description = 'A package for modeling non-canonical amino acid side chain ensembles.' +license= {name = 'GNU GPLv3', file = 'LICENSE'} +authors=[{name = 'Maxx Tessmer', email='mhtessmer@gmail.com'}, + {name = 'Stefan Stoll', email='stst@uw.edu'}] +keywords=['Spin-label', 'EPR', 'DEER', 'PELDOR', 'Side-chain'] +dynamic = ["version", "readme"] +requires-python = ">= 3.8,<=3.11" +dependencies = ['numpy>=1.23.0', + 'scipy>=1.6.3', + 'matplotlib>=3.3.4', + 'numba>=0.57.0', + 'mdanalysis>=2.0.0', + 'tqdm>=4.45.0', + 'pytest>=6.2.2', + 'memoization>=0.3.1', + 'argparse>=1.4.0', + 'setuptools>=53.0.0', + 'igraph>=0.11.2', + 'rtoml>=0.9.0'] + +classifiers=['License :: OSI Approved :: GNU General Public License v3 (GPLv3)', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11'] + +[project.urls] +homepage = 'https://github.com/StollLab/chiLife' +documentation = "stolllab.github.io/chiLife/" [tool.setuptools.dynamic] version = {attr = "chilife.__version__"} diff --git a/setup.py b/setup.py index f22d7d83..d68c805d 100644 --- a/setup.py +++ b/setup.py @@ -23,35 +23,11 @@ def __init__(self, *args, **kwargs): setup( name='chilife', - python_requires='>=3.8', packages=['chilife'], package_data={'chilife': ['data/*', 'data/*/*', 'data/*/*/*']}, scripts=['scripts/update_rotlib.py', 'scripts/oldProteinIC.py'], - license='GNU GPLv3', - license_files=('LICENSE'), - author='Maxx Tessmer', - author_email='mhtessmer@gmail.com', - install_requires=['numpy>=1.23.0', - 'scipy>=1.6.3', - 'matplotlib>=3.3.4', - 'numba>=0.57.0', - 'mdanalysis>=2.0.0', - 'tqdm>=4.45.0', - 'pytest>=6.2.2', - 'memoization>=0.3.1', - 'argparse>=1.4.0', - 'setuptools>=53.0.0', - 'igraph>=0.11.2', - 'rtoml>=0.9.0'], - url='https://github.com/StollLab/chiLife', project_urls = {'Source': 'https://github.com/StollLab/chiLife'}, - keywords=['Spin label', 'EPR', 'DEER', 'PELDOR', 'Side chain'], - description='A package for modeling non-canonical amino acid side chain ensembles.', long_description=readme, long_description_content_type='text/markdown', - cmdclass={'install': PostInstall}, - classifiers=['License :: OSI Approved :: GNU General Public License v3 (GPLv3)', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11']) + cmdclass={'install': PostInstall}) +